feat(bootstrap): Bun-workspace skeleton + typed config + vendored modules — T02
- Bun workspaces (packages/* + bootstrap); Pulumi nodejs runtime under
packagemanager: bun (no npm fallback needed).
- bootstrap/config.ts: typed FoundationConfig per CONTRACT_001; loadConfig()
fails closed, aggregating all missing+malformed keys in one error. Reads flat
dotted keys; image digests excluded (they live in VERSIONS, D5).
- bootstrap/Pulumi.foundation.yaml: non-secret placeholders only (RFC-5737 vm.host,
.invalid offsite); no encryptionsalt/secrets committed (D2). pulumi preview = 0
resources under the passphrase provider via gitignored file:// state backend.
- Stage-1 vendoring: packages/pulumi-{docker,vault} as @olsitec/* (source-only,
logic unchanged). vault's 5 type-only imports from modules/olsitec re-homed
verbatim into pulumi-vault/olsitec-types.ts to keep the egg self-contained.
Realizes PLAN-002 §10 T02; ADR-005 / 000_TOPOLOGY.md §5 Stage-1.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
edc708b826
commit
57c4eadea7
26 changed files with 2758 additions and 0 deletions
770
packages/pulumi-vault/index.ts
Normal file
770
packages/pulumi-vault/index.ts
Normal file
|
|
@ -0,0 +1,770 @@
|
|||
// modules/vault/index.ts
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
import * as vault from "@pulumi/vault";
|
||||
import { RandomPassword } from "@pulumi/random";
|
||||
|
||||
import { adminPolicyContent } from "./policy";
|
||||
import { Secret } from "@pulumi/vault/generic";
|
||||
|
||||
import {
|
||||
type OlsitecProjectFeatureFlags,
|
||||
type OlsitecCredentialTypes,
|
||||
type GitProjectCredentials,
|
||||
type OciRegistryCredentials,
|
||||
type MinioBackupProjectCredentials,
|
||||
} from "./olsitec-types";
|
||||
|
||||
interface VaultInitializationArgs {
|
||||
url: pulumi.Input<string>;
|
||||
shares: number;
|
||||
threshold: number;
|
||||
}
|
||||
|
||||
interface InitResponse {
|
||||
keys: string[];
|
||||
root_token: string;
|
||||
}
|
||||
|
||||
export class VaultInitialization extends pulumi.ComponentResource {
|
||||
public readonly unsealKeys: pulumi.Output<string[] | undefined>;
|
||||
public readonly rootToken: pulumi.Output<string>;
|
||||
public readonly url: pulumi.Output<string>;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: VaultInitializationArgs,
|
||||
opts?: pulumi.ComponentResourceOptions,
|
||||
) {
|
||||
super("custom:resource:VaultInitialization", name, {}, opts);
|
||||
|
||||
const config = new pulumi.Config("vaultCredentials"); // Specify a namespace if needed
|
||||
const storedUnsealKeys = config.getSecret("unsealKeys");
|
||||
const storedRootToken = config.getSecret("rootToken");
|
||||
|
||||
this.url = pulumi.output(args.url);
|
||||
|
||||
const initResult = pulumi
|
||||
.all([
|
||||
args.url,
|
||||
pulumi.output(args.shares),
|
||||
pulumi.output(args.threshold),
|
||||
storedUnsealKeys,
|
||||
storedRootToken,
|
||||
])
|
||||
.apply(async ([url, shares, threshold, keys, token]) => {
|
||||
// Check if it's a preview; skip initialization if so
|
||||
if (pulumi.runtime.isDryRun()) {
|
||||
pulumi.log.info("Skipping Vault initialization during preview.");
|
||||
return { keys: [], root_token: "" };
|
||||
}
|
||||
|
||||
// Implement polling to ensure Vault is ready
|
||||
await VaultInitialization.waitForVault(url);
|
||||
|
||||
// Perform the initialization
|
||||
pulumi.log.info(`Attempting to initialize Vault at ${url}/v1/sys/init`);
|
||||
const response = await fetch(`${url}/v1/sys/init`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Referer: url,
|
||||
"Referrer-Policy": "strict-origin-when-cross-origin",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
secret_shares: shares,
|
||||
secret_threshold: threshold,
|
||||
}),
|
||||
method: "PUT",
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
const errorMsg = errorData.errors
|
||||
? errorData.errors.join(", ")
|
||||
: response.statusText;
|
||||
|
||||
if (
|
||||
response.status === 400 &&
|
||||
errorMsg.toLowerCase().includes("already initialized")
|
||||
) {
|
||||
if (keys && token) {
|
||||
pulumi.log.info(
|
||||
"Vault is already initialized. Using stored keys and token.",
|
||||
);
|
||||
await this.unsealVault(url, JSON.parse(keys));
|
||||
return {
|
||||
keys: JSON.parse(keys), // Assuming keys are stored as a JSON string
|
||||
root_token: token,
|
||||
};
|
||||
}
|
||||
pulumi.log.info("Vault is already initialized.");
|
||||
return { keys: [], root_token: "" };
|
||||
}
|
||||
|
||||
throw new Error(`Failed to initialize Vault: ${errorMsg}`);
|
||||
}
|
||||
|
||||
const result = (await response.json()) as InitResponse;
|
||||
pulumi.log.info("Vault initialized successfully.");
|
||||
await this.unsealVault(url, result.keys);
|
||||
return {
|
||||
keys: result.keys,
|
||||
root_token: result.root_token,
|
||||
};
|
||||
});
|
||||
|
||||
// Assign the outputs
|
||||
this.unsealKeys = initResult.apply((result) =>
|
||||
pulumi.secret((result.keys as string[]) ?? []),
|
||||
);
|
||||
this.rootToken = initResult.apply((result) =>
|
||||
pulumi.secret(result.root_token),
|
||||
);
|
||||
|
||||
// Register outputs
|
||||
this.registerOutputs({
|
||||
unsealKeys: this.unsealKeys,
|
||||
rootToken: this.rootToken,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits until the Vault service is reachable by polling the /v1/sys/init endpoint.
|
||||
* Retries up to 10 times with a 2-second delay between attempts.
|
||||
*/
|
||||
private static async waitForVault(url: string): Promise<void> {
|
||||
const maxRetries = 12;
|
||||
const retryDelay = 10000; // 10 seconds
|
||||
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
const response = await fetch(`${url}/v1/sys/init`, {
|
||||
method: "GET",
|
||||
});
|
||||
if (response.ok || response.status === 403) {
|
||||
// 403 means Vault is already initialized
|
||||
pulumi.log.info("Vault is reachable and ready.");
|
||||
return;
|
||||
}
|
||||
} catch (error: any) {
|
||||
pulumi.log.info(
|
||||
`Attempt ${attempt}: Failed to reach Vault - ${error.message}`,
|
||||
);
|
||||
// Ignore errors and retry
|
||||
}
|
||||
|
||||
if (attempt < maxRetries) {
|
||||
pulumi.log.info(
|
||||
`Vault not ready, retrying in ${retryDelay / 1000} seconds...`,
|
||||
);
|
||||
await new Promise((res) => setTimeout(res, retryDelay));
|
||||
} else {
|
||||
throw new Error(
|
||||
"Vault service is not reachable after multiple attempts.",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Unseals the Vault service using the provided unseal keys.
|
||||
*/
|
||||
public async unsealVault(url: string, unsealKeys: string[]): Promise<void> {
|
||||
if (unsealKeys.length === 0) {
|
||||
throw new Error(
|
||||
"Failed to unseal Vault: insufficient unseal keys provided.",
|
||||
);
|
||||
}
|
||||
const sealStatusResponse = await fetch(`${url}/v1/sys/seal-status`, {
|
||||
method: "GET",
|
||||
});
|
||||
const sealStatus = await sealStatusResponse.json();
|
||||
if (!sealStatus.sealed) {
|
||||
pulumi.log.info("Vault is already unsealed.");
|
||||
return;
|
||||
}
|
||||
for (const key of unsealKeys) {
|
||||
const unsealResponse = await fetch(`${url}/v1/sys/unseal`, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ key }),
|
||||
method: "PUT",
|
||||
});
|
||||
if (!unsealResponse.ok) {
|
||||
throw new Error(`Failed to unseal Vault: ${unsealResponse.statusText}`);
|
||||
}
|
||||
const unsealResult = await unsealResponse.json();
|
||||
if (!unsealResult.sealed) {
|
||||
pulumi.log.info("Vault unsealed successfully.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new Error("Failed to unseal Vault.");
|
||||
}
|
||||
}
|
||||
|
||||
interface VaultBootstrapArgs {
|
||||
prefix: string;
|
||||
url: pulumi.Input<string>;
|
||||
token: pulumi.Input<string>;
|
||||
userNames: string[];
|
||||
secrets?: {
|
||||
name: string;
|
||||
path?: string;
|
||||
data: pulumi.Input<{ [key: string]: any }>;
|
||||
disableRead?: boolean;
|
||||
}[];
|
||||
}
|
||||
export class VaultBootstrap extends pulumi.ComponentResource {
|
||||
public readonly url: pulumi.Output<string>;
|
||||
public readonly vaultMount: vault.Mount;
|
||||
public readonly vaultProvider: vault.Provider;
|
||||
public readonly sourceCredentialsPath: pulumi.Output<string>;
|
||||
public readonly path: pulumi.Output<string>;
|
||||
public readonly roleId: pulumi.Output<string>;
|
||||
public readonly secretId: pulumi.Output<string>;
|
||||
public readonly users: {
|
||||
username: string;
|
||||
password: pulumi.Output<string>;
|
||||
}[];
|
||||
private readonly secrets: Secret[];
|
||||
constructor(
|
||||
name: string,
|
||||
args: VaultBootstrapArgs,
|
||||
opts?: pulumi.ComponentResourceOptions,
|
||||
) {
|
||||
super("custom:resource:VaultBootstrap", name, {}, opts);
|
||||
this.users = [];
|
||||
this.url = pulumi.output(args.url);
|
||||
// pulumi.output(args.token).apply((token) => {
|
||||
// console.log("VaultBootstrap: token: ", token);
|
||||
// pulumi.log.info(`VaultBootstrap: token: ${token}`);
|
||||
// });
|
||||
this.vaultProvider = new vault.Provider(
|
||||
`${args.prefix}-vault-provider`,
|
||||
{
|
||||
address: args.url,
|
||||
token: args.token,
|
||||
},
|
||||
{ parent: this },
|
||||
);
|
||||
|
||||
this.vaultMount = new vault.Mount(
|
||||
`${args.prefix}-vault-mount`,
|
||||
{
|
||||
path: args.prefix,
|
||||
type: "kv",
|
||||
options: {
|
||||
version: "2",
|
||||
},
|
||||
},
|
||||
{ provider: this.vaultProvider, parent: this },
|
||||
);
|
||||
this.sourceCredentialsPath = this.vaultMount.path;
|
||||
|
||||
const sourceCredentialsSecret = new vault.generic.Secret(
|
||||
`${args.prefix}-vault-source-credentials`,
|
||||
{
|
||||
path: `${args.prefix}/source-credentials`,
|
||||
dataJson: "{}",
|
||||
disableRead: true,
|
||||
},
|
||||
{
|
||||
provider: this.vaultProvider,
|
||||
parent: this,
|
||||
dependsOn: this.vaultMount,
|
||||
},
|
||||
);
|
||||
|
||||
this.secrets =
|
||||
args.secrets?.map((secret) => {
|
||||
return new vault.generic.Secret(
|
||||
`${args.prefix}-vault-secret-${secret.name}`,
|
||||
{
|
||||
path: secret.path ? secret.path : `${args.prefix}/${secret.name}`,
|
||||
dataJson: pulumi
|
||||
.output(secret.data)
|
||||
.apply((data) => JSON.stringify(data)),
|
||||
disableRead: secret.disableRead,
|
||||
},
|
||||
{
|
||||
provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
}) || [];
|
||||
|
||||
const pulumiPolicy = new vault.Policy(
|
||||
`${args.prefix}-vault-policy-pulumi`,
|
||||
{
|
||||
name: `pulumi-${args.prefix}-vault-policy-pulumi`,
|
||||
policy: adminPolicyContent,
|
||||
},
|
||||
{ provider: this.vaultProvider, parent: this },
|
||||
);
|
||||
|
||||
const pulumiAuthBackend = new vault.AuthBackend(
|
||||
`${args.prefix}-vault-auth-backend-pulumi`,
|
||||
{
|
||||
type: "approle",
|
||||
path: `pulumi-${args.prefix}-vault-auth-backend-pulumi`,
|
||||
},
|
||||
{
|
||||
provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const pulumiAuthBackendRole = new vault.approle.AuthBackendRole(
|
||||
`${args.prefix}-vault-auth-backend-role-pulumi`,
|
||||
{
|
||||
backend: pulumiAuthBackend.path,
|
||||
roleName: `pulumi-${args.prefix}-vault-auth-backend-role-pulumi`,
|
||||
tokenPolicies: [pulumiPolicy.name],
|
||||
},
|
||||
{ provider: this.vaultProvider, parent: this },
|
||||
);
|
||||
|
||||
const pulumiSecretId = new vault.approle.AuthBackendRoleSecretID(
|
||||
`${args.prefix}-vault-auth-backend-role-secret-id-pulumi`,
|
||||
{
|
||||
backend: pulumiAuthBackend.path,
|
||||
roleName: pulumiAuthBackendRole.roleName,
|
||||
},
|
||||
{ provider: this.vaultProvider, parent: this },
|
||||
);
|
||||
|
||||
const userpassAuth = new vault.AuthBackend(
|
||||
`${args.prefix}-vault-auth-backend-userpass`,
|
||||
{
|
||||
type: "userpass",
|
||||
path: `userpass`,
|
||||
},
|
||||
{ provider: this.vaultProvider, parent: this },
|
||||
);
|
||||
|
||||
// Create the admin policy
|
||||
const adminPolicy = new vault.Policy(
|
||||
`${args.prefix}-vault-policy-admin`,
|
||||
{
|
||||
name: `pulumi-${args.prefix}-vault-policy-admin`,
|
||||
policy: adminPolicyContent,
|
||||
},
|
||||
{ provider: this.vaultProvider, parent: this, dependsOn: userpassAuth },
|
||||
);
|
||||
// Create the admin user
|
||||
this.users = args.userNames.map((userName) => {
|
||||
const password = new RandomPassword(`${userName}-password`, {
|
||||
length: 22,
|
||||
special: false,
|
||||
}).result;
|
||||
const endpoint = new vault.generic.Endpoint(
|
||||
"admin-user",
|
||||
{
|
||||
path: pulumi.interpolate`auth/${userpassAuth.path}/users/${userName}`,
|
||||
dataJson: pulumi
|
||||
.all({
|
||||
policy: adminPolicy.name,
|
||||
password: password,
|
||||
})
|
||||
.apply((data) => {
|
||||
return JSON.stringify({
|
||||
policies: [data.policy],
|
||||
password: data.password,
|
||||
});
|
||||
}),
|
||||
},
|
||||
{
|
||||
provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
return { username: userName, password };
|
||||
});
|
||||
|
||||
this.path = pulumiAuthBackend.path;
|
||||
this.roleId = pulumiAuthBackendRole.roleId;
|
||||
this.secretId = pulumiSecretId.secretId;
|
||||
|
||||
this.registerOutputs({
|
||||
path: this.path,
|
||||
roleId: this.roleId,
|
||||
secretId: this.secretId,
|
||||
users: this.users.map((user) => ({
|
||||
username: user.username,
|
||||
password: pulumi.secret(user.password),
|
||||
})),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface VaultExternalSecretsClusterAppRoleArgs {
|
||||
// url: pulumi.Input<string>;
|
||||
// token: pulumi.Input<string>;
|
||||
prefix: string;
|
||||
vaultMountId: pulumi.Input<string>;
|
||||
}
|
||||
|
||||
export class VaultExternalSecretsClusterAppRole extends pulumi.ComponentResource {
|
||||
public readonly path: pulumi.Output<string>;
|
||||
public readonly roleId: pulumi.Output<string>;
|
||||
public readonly secretId: pulumi.Output<string>;
|
||||
// public readonly vaultProvider: vault.Provider;
|
||||
public readonly vaultMount: vault.Mount;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: VaultExternalSecretsClusterAppRoleArgs,
|
||||
opts?: pulumi.ResourceOptions,
|
||||
) {
|
||||
super("custom:resource:VaultExternalSecretsClusterAppRole", name, {}, opts);
|
||||
// this.vaultProvider = new vault.Provider(
|
||||
// `${args.prefix}-vault-provider`,
|
||||
// {
|
||||
// address: args.url,
|
||||
// token: args.token,
|
||||
// },
|
||||
// { parent: this },
|
||||
// );
|
||||
this.vaultMount = vault.Mount.get(
|
||||
`${args.prefix}-vault-mount`,
|
||||
args.vaultMountId,
|
||||
{
|
||||
path: args.prefix,
|
||||
type: "kv",
|
||||
options: {
|
||||
version: "2",
|
||||
},
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
// Define the policy
|
||||
const paths = {
|
||||
[`${args.prefix}/data`]: '["read", "list"]',
|
||||
[`${args.prefix}/data/*`]: '["read", "list"]',
|
||||
[`${args.prefix}/metadata`]: '["read", "list"]',
|
||||
[`${args.prefix}/metadata/*`]: '["read", "list"]',
|
||||
};
|
||||
|
||||
let policyStatements = "";
|
||||
for (const [path, capabilities] of Object.entries(paths)) {
|
||||
policyStatements += `
|
||||
path "${path}" {
|
||||
capabilities = ${capabilities}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const externalSecretsPolicy = new vault.Policy(
|
||||
`${args.prefix}-vault-policy-external-secrets`,
|
||||
{
|
||||
name: `pulumi-${args.prefix}-vault-policy-external-secrets`,
|
||||
policy: policyStatements,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const externalSecretsAuthBackend = new vault.AuthBackend(
|
||||
`${args.prefix}-vault-auth-backend-external-secrets`,
|
||||
{
|
||||
type: "approle",
|
||||
path: `pulumi-${args.prefix}-vault-auth-backend-external-secrets`,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider,
|
||||
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const externalSecretsAuthBackendRole = new vault.approle.AuthBackendRole(
|
||||
`${args.prefix}-vault-auth-backend-role-external-secrets`,
|
||||
{
|
||||
backend: externalSecretsAuthBackend.path,
|
||||
roleName: `pulumi-${args.prefix}-vault-auth-backend-role-external-secrets`,
|
||||
tokenPolicies: [externalSecretsPolicy.name],
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const externalSecretsSecretId = new vault.approle.AuthBackendRoleSecretID(
|
||||
`${args.prefix}-vault-auth-backend-role-secret-id-external-secrets`,
|
||||
{
|
||||
backend: externalSecretsAuthBackend.path,
|
||||
roleName: externalSecretsAuthBackendRole.roleName,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider,
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
this.path = externalSecretsAuthBackend.path;
|
||||
this.roleId = externalSecretsAuthBackendRole.roleId;
|
||||
this.secretId = externalSecretsSecretId.secretId;
|
||||
|
||||
this.registerOutputs({
|
||||
path: this.path,
|
||||
roleId: this.roleId,
|
||||
secretId: this.secretId,
|
||||
vaultMount: this.vaultMount,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface VaultProjectArgs {
|
||||
// vaultProvider: vault.Provider;
|
||||
// vaultMount: vault.Mount;
|
||||
prefix: string;
|
||||
projectName: string;
|
||||
projectStage: string;
|
||||
featureFlags: OlsitecProjectFeatureFlags[];
|
||||
credentials: OlsitecCredentialTypes;
|
||||
gitCredentials: GitProjectCredentials;
|
||||
ociRegistryCredentials: OciRegistryCredentials;
|
||||
minioBackupProjectCredentials?: MinioBackupProjectCredentials;
|
||||
additionalPolicyPaths?: string[];
|
||||
}
|
||||
|
||||
export class VaultProject extends pulumi.ComponentResource {
|
||||
// public readonly vaultProvider: vault.Provider;
|
||||
public readonly path: pulumi.Output<string>;
|
||||
public readonly roleId: pulumi.Output<string>;
|
||||
public readonly secretId: pulumi.Output<string>;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: VaultProjectArgs,
|
||||
opts?: pulumi.ResourceOptions,
|
||||
) {
|
||||
super("custom:resource:VaultProject", name, {}, opts);
|
||||
// this.vaultProvider = args.vaultProvider;
|
||||
|
||||
// Define the policy
|
||||
let paths = {
|
||||
[`${args.prefix}/data/${args.projectName}/${args.projectStage}`]:
|
||||
'["read", "list"]',
|
||||
[`${args.prefix}/data/${args.projectName}/${args.projectStage}/*`]:
|
||||
'["read", "list"]',
|
||||
[`${args.prefix}/metadata/${args.projectName}/${args.projectStage}`]:
|
||||
'["read", "list"]',
|
||||
[`${args.prefix}/metadata/${args.projectName}/${args.projectStage}/*`]:
|
||||
'["read", "list"]',
|
||||
};
|
||||
|
||||
for (const path of args.additionalPolicyPaths ?? []) {
|
||||
paths = {
|
||||
...paths,
|
||||
[`${args.prefix}/data/${path}`]: '["read", "list"]',
|
||||
[`${args.prefix}/data/${path}/*`]: '["read", "list"]',
|
||||
[`${args.prefix}/metadata/${path}`]: '["read", "list"]',
|
||||
[`${args.prefix}/metadata/${path}/*`]: '["read", "list"]',
|
||||
};
|
||||
}
|
||||
let policyStatements = "";
|
||||
for (const [path, capabilities] of Object.entries(paths)) {
|
||||
policyStatements += `
|
||||
path "${path}" {
|
||||
capabilities = ${capabilities}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
const externalSecretsPolicy = new vault.Policy(
|
||||
`${name}-vault-policy-external-secrets`,
|
||||
{
|
||||
name: `pulumi-${args.prefix}-${args.projectName}-${args.projectStage}-vault-policy-external-secrets`,
|
||||
policy: policyStatements,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const externalSecretsAuthBackend = new vault.AuthBackend(
|
||||
`${name}-vault-auth-backend-external-secrets`,
|
||||
{
|
||||
type: "approle",
|
||||
path: `pulumi-${args.prefix}-${args.projectName}-${args.projectStage}-vault-auth-backend-external-secrets`,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const externalSecretsAuthBackendRole = new vault.approle.AuthBackendRole(
|
||||
`${name}-vault-auth-backend-role`,
|
||||
{
|
||||
backend: externalSecretsAuthBackend.path,
|
||||
roleName: `pulumi-${args.prefix}-${args.projectName}-${args.projectStage}-vault-auth-backend-role`,
|
||||
tokenPolicies: [externalSecretsPolicy.name],
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
const externalSecretsAuthBackendRoleSecretId =
|
||||
new vault.approle.AuthBackendRoleSecretID(
|
||||
`${name}-vault-auth-backend-role-secret-id-external-secrets`,
|
||||
{
|
||||
backend: externalSecretsAuthBackend.path,
|
||||
roleName: externalSecretsAuthBackendRole.roleName,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
// minioBackup
|
||||
if (
|
||||
args.featureFlags.includes("minioBackup") &&
|
||||
args.minioBackupProjectCredentials
|
||||
) {
|
||||
const minioBackupCredentialsSecret = new vault.generic.Secret(
|
||||
`${name}-secret-backup-credentials`,
|
||||
{
|
||||
path: `${args.prefix}/${args.projectName}/${args.projectStage}/backup-credentials`,
|
||||
dataJson: pulumi
|
||||
.all({
|
||||
minioBackupAccessKey:
|
||||
args.minioBackupProjectCredentials.minioBackupAccessKey,
|
||||
minioBackupSecretKey:
|
||||
args.minioBackupProjectCredentials.minioBackupSecretKey,
|
||||
minioBackupEndpoint:
|
||||
args.minioBackupProjectCredentials.minioBackupEndpoint,
|
||||
})
|
||||
.apply((data) => JSON.stringify(data)),
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// project-credentials
|
||||
const projectCredentialsSecret = new vault.generic.Secret(
|
||||
`${name}-secret-project-credentials`,
|
||||
{
|
||||
path: `${args.prefix}/${args.projectName}/${args.projectStage}/project-credentials`,
|
||||
dataJson: "{}",
|
||||
disableRead: true,
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
// service-credentials
|
||||
const serviceCredentialsSecret = new vault.generic.Secret(
|
||||
`${name}-secret-service-credentials`,
|
||||
{
|
||||
path: `${args.prefix}/${args.projectName}/${args.projectStage}/service-credentials`,
|
||||
dataJson: pulumi
|
||||
.all({
|
||||
cockroachdbAdminUser: args.credentials.cockroachdbAdminUser,
|
||||
cockroachdbAdminPassword: args.credentials.cockroachdbAdminPassword,
|
||||
cockroachdbServiceUser: args.credentials.cockroachdbServiceUser,
|
||||
cockroachdbServicePassword:
|
||||
args.credentials.cockroachdbServicePassword,
|
||||
mongodbAdminUser: args.credentials.mongodbAdminUser,
|
||||
mongodbAdminPassword: args.credentials.mongodbAdminPassword,
|
||||
mongodbBackupUser: args.credentials.mongodbBackupUser,
|
||||
mongodbBackupPassword: args.credentials.mongodbBackupPassword,
|
||||
mongodbServiceUser: args.credentials.mongodbServiceUser,
|
||||
mongodbServicePassword: args.credentials.mongodbServicePassword,
|
||||
mongodbKeyfile: args.credentials.mongodbKeyfile,
|
||||
minioAdminUser: args.credentials.minioAdminUser,
|
||||
minioAdminPassword: args.credentials.minioAdminPassword,
|
||||
minioServiceUser: args.credentials.minioServiceUser,
|
||||
minioServicePassword: args.credentials.minioServicePassword,
|
||||
rustfsAdminUser: args.credentials.rustfsAdminUser,
|
||||
rustfsAdminPassword: args.credentials.rustfsAdminPassword,
|
||||
rustfsServiceUser: args.credentials.rustfsServiceUser,
|
||||
rustfsServicePassword: args.credentials.rustfsServicePassword,
|
||||
garageRpcSecret: args.credentials.garageRpcSecret,
|
||||
garageAdminToken: args.credentials.garageAdminToken,
|
||||
garageServiceKeyId: args.credentials.garageServiceKeyId,
|
||||
garageServiceKeySecret: args.credentials.garageServiceKeySecret,
|
||||
natsToken: args.credentials.natsToken,
|
||||
grafanaAdminPassword: args.credentials.grafanaAdminPassword,
|
||||
postgresUser: args.credentials.postgresUser,
|
||||
postgresPassword: args.credentials.postgresPassword,
|
||||
postgresServiceUser: args.credentials.postgresServiceUser,
|
||||
postgresServicePassword: args.credentials.postgresServicePassword,
|
||||
basicAuthUser: args.credentials.basicAuthUser,
|
||||
basicAuthPassword: args.credentials.basicAuthPassword,
|
||||
basicAuthHtpasswd: args.credentials.basicAuthHtpasswd,
|
||||
nominatimPassword: args.credentials.nominatimPassword,
|
||||
})
|
||||
.apply((data) => JSON.stringify(data)),
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
// git-credentials
|
||||
const gitCredentialsSecret = new vault.generic.Secret(
|
||||
`${name}-secret-git-credentials`,
|
||||
{
|
||||
path: `${args.prefix}/${args.projectName}/${args.projectStage}/git-credentials`,
|
||||
dataJson: pulumi
|
||||
.all({
|
||||
gitArgocdUser: args.gitCredentials.gitArgocdUser,
|
||||
gitArgocdPassword: args.gitCredentials.gitArgocdToken,
|
||||
})
|
||||
.apply((data) => JSON.stringify(data)),
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
// registry-credentials
|
||||
const ociRegistryCredentialsSecret = new vault.generic.Secret(
|
||||
`${name}-secret-oci-registry-credentials`,
|
||||
{
|
||||
path: `${args.prefix}/${args.projectName}/${args.projectStage}/registry-credentials`,
|
||||
dataJson: pulumi
|
||||
.all({
|
||||
ociRegistryAddress: args.ociRegistryCredentials.ociRegistryAddress,
|
||||
ociRegistryUser: args.ociRegistryCredentials.ociRegistryUser,
|
||||
ociRegistryPassword:
|
||||
args.ociRegistryCredentials.ociRegistryPassword,
|
||||
})
|
||||
.apply((data) => JSON.stringify(data)),
|
||||
},
|
||||
{
|
||||
// provider: this.vaultProvider
|
||||
parent: this,
|
||||
},
|
||||
);
|
||||
|
||||
this.path = externalSecretsAuthBackend.path;
|
||||
this.roleId = externalSecretsAuthBackendRole.roleId;
|
||||
this.secretId = externalSecretsAuthBackendRoleSecretId.secretId;
|
||||
|
||||
this.registerOutputs({
|
||||
path: this.path,
|
||||
roleId: this.roleId,
|
||||
secretId: this.secretId,
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue