mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 05:28:29 +00:00
Add AWS secret manager PKI Sync
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
import {
|
||||
AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION,
|
||||
AwsSecretsManagerPkiSyncSchema,
|
||||
CreateAwsSecretsManagerPkiSyncSchema,
|
||||
UpdateAwsSecretsManagerPkiSyncSchema
|
||||
} from "@app/services/pki-sync/aws-secrets-manager";
|
||||
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
|
||||
|
||||
import { registerSyncPkiEndpoints } from "./pki-sync-endpoints";
|
||||
|
||||
export const registerAwsSecretsManagerPkiSyncRouter = async (server: FastifyZodProvider) =>
|
||||
registerSyncPkiEndpoints({
|
||||
destination: PkiSync.AwsSecretsManager,
|
||||
server,
|
||||
responseSchema: AwsSecretsManagerPkiSyncSchema,
|
||||
createSchema: CreateAwsSecretsManagerPkiSyncSchema,
|
||||
updateSchema: UpdateAwsSecretsManagerPkiSyncSchema,
|
||||
syncOptions: {
|
||||
canImportCertificates: AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION.canImportCertificates,
|
||||
canRemoveCertificates: AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION.canRemoveCertificates
|
||||
}
|
||||
});
|
||||
@@ -1,6 +1,7 @@
|
||||
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
|
||||
|
||||
import { registerAwsCertificateManagerPkiSyncRouter } from "./aws-certificate-manager-pki-sync-router";
|
||||
import { registerAwsSecretsManagerPkiSyncRouter } from "./aws-secrets-manager-pki-sync-router";
|
||||
import { registerAzureKeyVaultPkiSyncRouter } from "./azure-key-vault-pki-sync-router";
|
||||
import { registerChefPkiSyncRouter } from "./chef-pki-sync-router";
|
||||
|
||||
@@ -9,5 +10,6 @@ export * from "./pki-sync-router";
|
||||
export const PKI_SYNC_REGISTER_ROUTER_MAP: Record<PkiSync, (server: FastifyZodProvider) => Promise<void>> = {
|
||||
[PkiSync.AzureKeyVault]: registerAzureKeyVaultPkiSyncRouter,
|
||||
[PkiSync.AwsCertificateManager]: registerAwsCertificateManagerPkiSyncRouter,
|
||||
[PkiSync.AwsSecretsManager]: registerAwsSecretsManagerPkiSyncRouter,
|
||||
[PkiSync.Chef]: registerChefPkiSyncRouter
|
||||
};
|
||||
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
import RE2 from "re2";
|
||||
|
||||
import { AppConnection } from "@app/services/app-connection/app-connection-enums";
|
||||
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
|
||||
|
||||
/**
|
||||
* AWS Secrets Manager naming constraints for secrets
|
||||
*/
|
||||
export const AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING = {
|
||||
/**
|
||||
* Regular expression pattern for valid AWS Secrets Manager secret names
|
||||
* Must contain only alphanumeric characters, hyphens, and underscores
|
||||
* Must be 1-512 characters long
|
||||
*/
|
||||
NAME_PATTERN: new RE2("^[\\w-]+$"),
|
||||
|
||||
/**
|
||||
* String of characters that are forbidden in AWS Secrets Manager secret names
|
||||
*/
|
||||
FORBIDDEN_CHARACTERS: " @#$%^&*()+=[]{}|;':\"<>?,./",
|
||||
|
||||
/**
|
||||
* Minimum length for secret names in AWS Secrets Manager
|
||||
*/
|
||||
MIN_LENGTH: 1,
|
||||
|
||||
/**
|
||||
* Maximum length for secret names in AWS Secrets Manager
|
||||
*/
|
||||
MAX_LENGTH: 512,
|
||||
|
||||
/**
|
||||
* String representation of the allowed character pattern (for UI display)
|
||||
*/
|
||||
ALLOWED_CHARACTER_PATTERN: "^[\\w-]+$"
|
||||
} as const;
|
||||
|
||||
export const AWS_SECRETS_MANAGER_PKI_SYNC_DEFAULTS = {
|
||||
INFISICAL_PREFIX: "infisical-",
|
||||
DEFAULT_ENVIRONMENT: "production",
|
||||
DEFAULT_CERTIFICATE_NAME_SCHEMA: "infisical-{{certificateId}}",
|
||||
DEFAULT_FIELD_MAPPINGS: {
|
||||
certificate: "certificate",
|
||||
privateKey: "private_key",
|
||||
certificateChain: "certificate_chain",
|
||||
caCertificate: "ca_certificate"
|
||||
}
|
||||
};
|
||||
|
||||
export const AWS_SECRETS_MANAGER_PKI_SYNC_OPTIONS = {
|
||||
DEFAULT_CAN_REMOVE_CERTIFICATES: true,
|
||||
DEFAULT_PRESERVE_SECRET_ON_RENEWAL: true,
|
||||
DEFAULT_UPDATE_EXISTING_CERTIFICATES: true,
|
||||
DEFAULT_CAN_IMPORT_CERTIFICATES: false
|
||||
};
|
||||
|
||||
/**
|
||||
* AWS Secrets Manager PKI Sync list option configuration
|
||||
*/
|
||||
export const AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION = {
|
||||
name: "AWS Secrets Manager" as const,
|
||||
connection: AppConnection.AWS,
|
||||
destination: PkiSync.AwsSecretsManager,
|
||||
canImportCertificates: false,
|
||||
canRemoveCertificates: true,
|
||||
defaultCertificateNameSchema: "infisical-{{certificateId}}",
|
||||
forbiddenCharacters: AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.FORBIDDEN_CHARACTERS,
|
||||
allowedCharacterPattern: AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.ALLOWED_CHARACTER_PATTERN,
|
||||
maxCertificateNameLength: AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.MAX_LENGTH,
|
||||
minCertificateNameLength: AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.MIN_LENGTH
|
||||
} as const;
|
||||
+635
@@ -0,0 +1,635 @@
|
||||
/* eslint-disable no-continue */
|
||||
/* eslint-disable no-await-in-loop */
|
||||
import {
|
||||
CreateSecretCommand,
|
||||
DeleteSecretCommand,
|
||||
GetSecretValueCommand,
|
||||
ListSecretsCommand,
|
||||
SecretsManagerClient,
|
||||
UpdateSecretCommand
|
||||
} from "@aws-sdk/client-secrets-manager";
|
||||
import RE2 from "re2";
|
||||
|
||||
import { TCertificateSyncs } from "@app/db/schemas";
|
||||
import { CustomAWSHasher } from "@app/lib/aws/hashing";
|
||||
import { crypto } from "@app/lib/crypto";
|
||||
import { logger } from "@app/lib/logger";
|
||||
import { AWSRegion } from "@app/services/app-connection/app-connection-enums";
|
||||
import { getAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-fns";
|
||||
import { TAwsConnectionConfig } from "@app/services/app-connection/aws/aws-connection-types";
|
||||
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
|
||||
import { TCertificateSyncDALFactory } from "@app/services/certificate-sync/certificate-sync-dal";
|
||||
import { CertificateSyncStatus } from "@app/services/certificate-sync/certificate-sync-enums";
|
||||
import { createConnectionQueue, RateLimitConfig } from "@app/services/connection-queue";
|
||||
import { matchesCertificateNameSchema } from "@app/services/pki-sync/pki-sync-fns";
|
||||
import { TCertificateMap, TPkiSyncWithCredentials } from "@app/services/pki-sync/pki-sync-types";
|
||||
|
||||
import { AWS_SECRETS_MANAGER_PKI_SYNC_DEFAULTS } from "./aws-secrets-manager-pki-sync-constants";
|
||||
import {
|
||||
AwsSecretsManagerCertificateSecret,
|
||||
SyncCertificatesResult,
|
||||
TAwsSecretsManagerPkiSyncWithCredentials
|
||||
} from "./aws-secrets-manager-pki-sync-types";
|
||||
|
||||
const AWS_SECRETS_MANAGER_RATE_LIMIT_CONFIG: RateLimitConfig = {
|
||||
MAX_CONCURRENT_REQUESTS: 10,
|
||||
BASE_DELAY: 1000,
|
||||
MAX_DELAY: 30000,
|
||||
MAX_RETRIES: 3,
|
||||
RATE_LIMIT_STATUS_CODES: [429, 503]
|
||||
};
|
||||
|
||||
const awsSecretsManagerConnectionQueue = createConnectionQueue(AWS_SECRETS_MANAGER_RATE_LIMIT_CONFIG);
|
||||
const { withRateLimitRetry } = awsSecretsManagerConnectionQueue;
|
||||
|
||||
const MAX_RETRIES = 10;
|
||||
|
||||
const sleep = async () =>
|
||||
new Promise((resolve) => {
|
||||
setTimeout(resolve, 1000);
|
||||
});
|
||||
|
||||
const isInfisicalManagedCertificate = (secretName: string, pkiSync: TPkiSyncWithCredentials): boolean => {
|
||||
const syncOptions = pkiSync.syncOptions as { certificateNameSchema?: string } | undefined;
|
||||
const certificateNameSchema = syncOptions?.certificateNameSchema;
|
||||
|
||||
if (certificateNameSchema) {
|
||||
const environment = AWS_SECRETS_MANAGER_PKI_SYNC_DEFAULTS.DEFAULT_ENVIRONMENT;
|
||||
return matchesCertificateNameSchema(secretName, environment, certificateNameSchema);
|
||||
}
|
||||
|
||||
return secretName.startsWith(AWS_SECRETS_MANAGER_PKI_SYNC_DEFAULTS.INFISICAL_PREFIX);
|
||||
};
|
||||
|
||||
const parseErrorMessage = (error: unknown): string => {
|
||||
if (error instanceof Error) {
|
||||
return error.message;
|
||||
}
|
||||
|
||||
if (typeof error === "string") {
|
||||
return error;
|
||||
}
|
||||
|
||||
if (error && typeof error === "object" && "message" in error) {
|
||||
const { message } = error as { message: unknown };
|
||||
if (typeof message === "string") {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown error occurred";
|
||||
};
|
||||
|
||||
const getSecretsManagerClient = async (pkiSync: TAwsSecretsManagerPkiSyncWithCredentials) => {
|
||||
const { destinationConfig, connection } = pkiSync;
|
||||
|
||||
const config = await getAwsConnectionConfig(
|
||||
connection as TAwsConnectionConfig,
|
||||
destinationConfig.region as AWSRegion
|
||||
);
|
||||
|
||||
if (!config.credentials) {
|
||||
throw new Error("AWS credentials not found in connection configuration");
|
||||
}
|
||||
|
||||
const secretsManagerClient = new SecretsManagerClient({
|
||||
region: config.region,
|
||||
useFipsEndpoint: crypto.isFipsModeEnabled(),
|
||||
sha256: CustomAWSHasher,
|
||||
credentials: config.credentials
|
||||
});
|
||||
|
||||
return secretsManagerClient;
|
||||
};
|
||||
|
||||
type TAwsSecretsManagerPkiSyncFactoryDeps = {
|
||||
certificateDAL: Pick<TCertificateDALFactory, "findById">;
|
||||
certificateSyncDAL: Pick<
|
||||
TCertificateSyncDALFactory,
|
||||
| "removeCertificates"
|
||||
| "addCertificates"
|
||||
| "findByPkiSyncAndCertificate"
|
||||
| "updateById"
|
||||
| "findByPkiSyncId"
|
||||
| "updateSyncStatus"
|
||||
>;
|
||||
};
|
||||
|
||||
export const awsSecretsManagerPkiSyncFactory = ({
|
||||
certificateDAL,
|
||||
certificateSyncDAL
|
||||
}: TAwsSecretsManagerPkiSyncFactoryDeps) => {
|
||||
const $getSecretsManagerSecrets = async (
|
||||
pkiSync: TAwsSecretsManagerPkiSyncWithCredentials,
|
||||
syncId = "unknown"
|
||||
): Promise<Record<string, string>> => {
|
||||
const client = await getSecretsManagerClient(pkiSync);
|
||||
const secrets: Record<string, string> = {};
|
||||
let hasNext = true;
|
||||
let nextToken: string | undefined;
|
||||
let attempt = 0;
|
||||
|
||||
while (hasNext) {
|
||||
try {
|
||||
const currentToken = nextToken;
|
||||
const output = await withRateLimitRetry(
|
||||
() => client.send(new ListSecretsCommand({ NextToken: currentToken })),
|
||||
{
|
||||
operation: "list-secrets-manager-secrets",
|
||||
syncId
|
||||
}
|
||||
);
|
||||
|
||||
attempt = 0;
|
||||
|
||||
if (output.SecretList) {
|
||||
output.SecretList.forEach((secretEntry) => {
|
||||
if (
|
||||
secretEntry.Name &&
|
||||
isInfisicalManagedCertificate(secretEntry.Name, pkiSync as unknown as TPkiSyncWithCredentials)
|
||||
) {
|
||||
secrets[secretEntry.Name] = secretEntry.ARN || secretEntry.Name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
hasNext = Boolean(output.NextToken);
|
||||
nextToken = output.NextToken;
|
||||
} catch (e) {
|
||||
if (
|
||||
e &&
|
||||
typeof e === "object" &&
|
||||
"name" in e &&
|
||||
(e as { name: string }).name === "ThrottlingException" &&
|
||||
attempt < MAX_RETRIES
|
||||
) {
|
||||
attempt += 1;
|
||||
await sleep();
|
||||
continue;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
return secrets;
|
||||
};
|
||||
|
||||
const syncCertificates = async (
|
||||
pkiSync: TPkiSyncWithCredentials,
|
||||
certificateMap: TCertificateMap
|
||||
): Promise<SyncCertificatesResult> => {
|
||||
const awsPkiSync = pkiSync as unknown as TAwsSecretsManagerPkiSyncWithCredentials;
|
||||
const client = await getSecretsManagerClient(awsPkiSync);
|
||||
|
||||
const existingSecrets = await $getSecretsManagerSecrets(awsPkiSync, pkiSync.id);
|
||||
|
||||
const existingSyncRecords = await certificateSyncDAL.findByPkiSyncId(pkiSync.id);
|
||||
const syncRecordsByCertId = new Map<string, TCertificateSyncs>();
|
||||
const syncRecordsByExternalId = new Map<string, TCertificateSyncs>();
|
||||
|
||||
existingSyncRecords.forEach((record: TCertificateSyncs) => {
|
||||
if (record.certificateId) {
|
||||
syncRecordsByCertId.set(record.certificateId, record);
|
||||
}
|
||||
if (record.externalIdentifier) {
|
||||
syncRecordsByExternalId.set(record.externalIdentifier, record);
|
||||
}
|
||||
});
|
||||
|
||||
type CertificateUploadData = {
|
||||
secretName: string;
|
||||
certificateData: AwsSecretsManagerCertificateSecret;
|
||||
certificateId: string;
|
||||
isUpdate: boolean;
|
||||
targetSecretName: string;
|
||||
oldCertificateIdToRemove?: string;
|
||||
};
|
||||
|
||||
const setCertificates: CertificateUploadData[] = [];
|
||||
const validationErrors: Array<{ name: string; error: string }> = [];
|
||||
|
||||
const syncOptions = pkiSync.syncOptions as
|
||||
| {
|
||||
canRemoveCertificates?: boolean;
|
||||
preserveSecretOnRenewal?: boolean;
|
||||
fieldMappings?: {
|
||||
certificate?: string;
|
||||
privateKey?: string;
|
||||
certificateChain?: string;
|
||||
caCertificate?: string;
|
||||
};
|
||||
certificateNameSchema?: string;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
const canRemoveCertificates = syncOptions?.canRemoveCertificates ?? true;
|
||||
const preserveSecretOnRenewal = syncOptions?.preserveSecretOnRenewal ?? true;
|
||||
|
||||
const fieldMappings = {
|
||||
certificate: syncOptions?.fieldMappings?.certificate ?? "certificate",
|
||||
privateKey: syncOptions?.fieldMappings?.privateKey ?? "private_key",
|
||||
certificateChain: syncOptions?.fieldMappings?.certificateChain ?? "certificate_chain",
|
||||
caCertificate: syncOptions?.fieldMappings?.caCertificate ?? "ca_certificate"
|
||||
};
|
||||
|
||||
const activeExternalIdentifiers = new Set<string>();
|
||||
|
||||
for (const [certName, certData] of Object.entries(certificateMap)) {
|
||||
const { cert, privateKey: certPrivateKey, certificateChain, caCertificate, certificateId } = certData;
|
||||
|
||||
if (!cert || cert.trim().length === 0) {
|
||||
validationErrors.push({
|
||||
name: certName,
|
||||
error: "Certificate content is empty or missing"
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!certPrivateKey || certPrivateKey.trim().length === 0) {
|
||||
validationErrors.push({
|
||||
name: certName,
|
||||
error: "Private key content is empty or missing"
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!certificateId || typeof certificateId !== "string") {
|
||||
continue;
|
||||
}
|
||||
|
||||
const certificateData: AwsSecretsManagerCertificateSecret = {
|
||||
[fieldMappings.certificate]: cert,
|
||||
[fieldMappings.privateKey]: certPrivateKey
|
||||
};
|
||||
|
||||
if (certificateChain && certificateChain.trim().length > 0) {
|
||||
certificateData[fieldMappings.certificateChain] = certificateChain;
|
||||
}
|
||||
|
||||
if (caCertificate && typeof caCertificate === "string" && caCertificate.trim().length > 0) {
|
||||
certificateData[fieldMappings.caCertificate] = caCertificate;
|
||||
}
|
||||
|
||||
let targetSecretName = certName;
|
||||
if (syncOptions?.certificateNameSchema) {
|
||||
const extendedCertData = certData as Record<string, unknown>;
|
||||
const safeCommonName = typeof extendedCertData.commonName === "string" ? extendedCertData.commonName : "";
|
||||
|
||||
targetSecretName = syncOptions.certificateNameSchema
|
||||
.replace(new RE2("\\{\\{certificateId\\}\\}", "g"), certificateId)
|
||||
.replace(new RE2("\\{\\{commonName\\}\\}", "g"), safeCommonName);
|
||||
} else {
|
||||
targetSecretName = `${AWS_SECRETS_MANAGER_PKI_SYNC_DEFAULTS.INFISICAL_PREFIX}${certificateId}`;
|
||||
}
|
||||
|
||||
const certificate = await certificateDAL.findById(certificateId);
|
||||
|
||||
if (certificate?.renewedByCertificateId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const syncRecordLookupId = certificate?.renewedFromCertificateId || certificateId;
|
||||
const existingRecord = syncRecordsByCertId.get(syncRecordLookupId);
|
||||
|
||||
let shouldProcess = true;
|
||||
let isUpdate = false;
|
||||
|
||||
if (existingRecord?.externalIdentifier) {
|
||||
const existingSecret = existingSecrets[existingRecord.externalIdentifier];
|
||||
|
||||
if (existingSecret) {
|
||||
if (certificate?.renewedFromCertificateId && preserveSecretOnRenewal) {
|
||||
targetSecretName = existingRecord.externalIdentifier;
|
||||
isUpdate = true;
|
||||
} else if (certificate?.renewedFromCertificateId && !preserveSecretOnRenewal) {
|
||||
activeExternalIdentifiers.add(existingRecord.externalIdentifier);
|
||||
} else if (!certificate?.renewedFromCertificateId) {
|
||||
shouldProcess = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shouldProcess) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (existingSecrets[targetSecretName]) {
|
||||
isUpdate = true;
|
||||
}
|
||||
|
||||
activeExternalIdentifiers.add(targetSecretName);
|
||||
|
||||
setCertificates.push({
|
||||
secretName: certName,
|
||||
certificateData,
|
||||
certificateId,
|
||||
isUpdate,
|
||||
targetSecretName,
|
||||
oldCertificateIdToRemove:
|
||||
certificate?.renewedFromCertificateId && preserveSecretOnRenewal
|
||||
? certificate.renewedFromCertificateId
|
||||
: undefined
|
||||
});
|
||||
}
|
||||
|
||||
const result: SyncCertificatesResult = {
|
||||
uploaded: 0,
|
||||
updated: 0,
|
||||
removed: 0,
|
||||
failedRemovals: 0,
|
||||
skipped: 0,
|
||||
details: {
|
||||
failedUploads: [],
|
||||
failedRemovals: [],
|
||||
validationErrors
|
||||
}
|
||||
};
|
||||
|
||||
for (const certData of setCertificates) {
|
||||
const { secretName, certificateData, certificateId, isUpdate, targetSecretName, oldCertificateIdToRemove } =
|
||||
certData;
|
||||
|
||||
try {
|
||||
const secretValue = JSON.stringify(certificateData);
|
||||
const configKeyId: unknown = awsPkiSync.destinationConfig.keyId;
|
||||
const keyId: string = typeof configKeyId === "string" ? configKeyId : "alias/aws/secretsmanager";
|
||||
|
||||
if (isUpdate) {
|
||||
await withRateLimitRetry(
|
||||
() =>
|
||||
client.send(
|
||||
new UpdateSecretCommand({
|
||||
SecretId: targetSecretName,
|
||||
SecretString: secretValue,
|
||||
KmsKeyId: keyId
|
||||
})
|
||||
),
|
||||
{
|
||||
operation: "update-secret",
|
||||
syncId: pkiSync.id
|
||||
}
|
||||
);
|
||||
result.updated += 1;
|
||||
} else {
|
||||
await withRateLimitRetry(
|
||||
() =>
|
||||
client.send(
|
||||
new CreateSecretCommand({
|
||||
Name: targetSecretName,
|
||||
SecretString: secretValue,
|
||||
KmsKeyId: keyId,
|
||||
Description: `Certificate managed by Infisical`
|
||||
})
|
||||
),
|
||||
{
|
||||
operation: "create-secret",
|
||||
syncId: pkiSync.id
|
||||
}
|
||||
);
|
||||
result.uploaded += 1;
|
||||
}
|
||||
|
||||
const existingRecord = syncRecordsByCertId.get(certificateId);
|
||||
if (existingRecord?.id) {
|
||||
await certificateSyncDAL.updateById(existingRecord.id, {
|
||||
externalIdentifier: targetSecretName,
|
||||
syncStatus: CertificateSyncStatus.Succeeded,
|
||||
lastSyncedAt: new Date(),
|
||||
lastSyncMessage: "Certificate successfully synced to AWS Secrets Manager"
|
||||
});
|
||||
|
||||
if (oldCertificateIdToRemove && oldCertificateIdToRemove !== certificateId) {
|
||||
await certificateSyncDAL.removeCertificates(pkiSync.id, [oldCertificateIdToRemove]);
|
||||
}
|
||||
} else {
|
||||
await certificateSyncDAL.addCertificates(pkiSync.id, [
|
||||
{
|
||||
certificateId,
|
||||
externalIdentifier: targetSecretName
|
||||
}
|
||||
]);
|
||||
|
||||
const newCertSync = await certificateSyncDAL.findByPkiSyncAndCertificate(pkiSync.id, certificateId);
|
||||
if (newCertSync?.id) {
|
||||
await certificateSyncDAL.updateById(newCertSync.id, {
|
||||
syncStatus: CertificateSyncStatus.Succeeded,
|
||||
lastSyncedAt: new Date(),
|
||||
lastSyncMessage: "Certificate successfully synced to AWS Secrets Manager"
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
result.details?.failedUploads?.push({
|
||||
name: secretName,
|
||||
error: parseErrorMessage(error)
|
||||
});
|
||||
logger.error(
|
||||
{
|
||||
secretName,
|
||||
certificateId,
|
||||
error: parseErrorMessage(error),
|
||||
pkiSyncId: pkiSync.id
|
||||
},
|
||||
"Failed to sync certificate"
|
||||
);
|
||||
|
||||
const existingRecord = syncRecordsByCertId.get(certificateId);
|
||||
if (existingRecord?.id) {
|
||||
await certificateSyncDAL.updateById(existingRecord.id, {
|
||||
syncStatus: CertificateSyncStatus.Failed,
|
||||
lastSyncMessage: parseErrorMessage(error)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (canRemoveCertificates) {
|
||||
for (const [secretName] of Object.entries(existingSecrets)) {
|
||||
if (!activeExternalIdentifiers.has(secretName)) {
|
||||
try {
|
||||
await withRateLimitRetry(
|
||||
() =>
|
||||
client.send(
|
||||
new DeleteSecretCommand({
|
||||
SecretId: secretName,
|
||||
ForceDeleteWithoutRecovery: true
|
||||
})
|
||||
),
|
||||
{
|
||||
operation: "delete-secret",
|
||||
syncId: pkiSync.id
|
||||
}
|
||||
);
|
||||
|
||||
result.removed += 1;
|
||||
|
||||
const recordToRemove = syncRecordsByExternalId.get(secretName);
|
||||
if (recordToRemove?.id) {
|
||||
await certificateSyncDAL.updateById(recordToRemove.id, {
|
||||
syncStatus: CertificateSyncStatus.Failed
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
result.failedRemovals += 1;
|
||||
result.details?.failedRemovals?.push({
|
||||
name: secretName,
|
||||
error: parseErrorMessage(error)
|
||||
});
|
||||
logger.error(
|
||||
{
|
||||
secretName,
|
||||
error: parseErrorMessage(error),
|
||||
pkiSyncId: pkiSync.id
|
||||
},
|
||||
"Failed to remove certificate secret"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
const removeCertificates = async (
|
||||
pkiSync: TPkiSyncWithCredentials,
|
||||
certificateMap: TCertificateMap
|
||||
): Promise<{ removed: number; failed: number }> => {
|
||||
const awsPkiSync = pkiSync as unknown as TAwsSecretsManagerPkiSyncWithCredentials;
|
||||
const client = await getSecretsManagerClient(awsPkiSync);
|
||||
|
||||
const existingSecrets = await $getSecretsManagerSecrets(awsPkiSync, pkiSync.id);
|
||||
const existingSyncRecords = await certificateSyncDAL.findByPkiSyncId(pkiSync.id);
|
||||
|
||||
let removed = 0;
|
||||
let failed = 0;
|
||||
|
||||
for (const [, certData] of Object.entries(certificateMap)) {
|
||||
if (!certData.certificateId) continue;
|
||||
|
||||
const syncRecord = existingSyncRecords.find((record) => record.certificateId === certData.certificateId);
|
||||
if (!syncRecord?.externalIdentifier) continue;
|
||||
|
||||
const secretName = syncRecord.externalIdentifier;
|
||||
|
||||
if (existingSecrets[secretName]) {
|
||||
try {
|
||||
await withRateLimitRetry(
|
||||
() =>
|
||||
client.send(
|
||||
new DeleteSecretCommand({
|
||||
SecretId: secretName,
|
||||
ForceDeleteWithoutRecovery: true
|
||||
})
|
||||
),
|
||||
{
|
||||
operation: "delete-secret",
|
||||
syncId: pkiSync.id
|
||||
}
|
||||
);
|
||||
|
||||
if (syncRecord.id) {
|
||||
await certificateSyncDAL.updateById(syncRecord.id, {
|
||||
syncStatus: CertificateSyncStatus.Failed
|
||||
});
|
||||
}
|
||||
|
||||
removed += 1;
|
||||
} catch (error) {
|
||||
failed += 1;
|
||||
logger.error(
|
||||
{
|
||||
secretName,
|
||||
certificateId: certData.certificateId,
|
||||
error: parseErrorMessage(error),
|
||||
pkiSyncId: pkiSync.id
|
||||
},
|
||||
"Failed to remove certificate secret"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { removed, failed };
|
||||
};
|
||||
|
||||
const importCertificates = async (pkiSync: TPkiSyncWithCredentials): Promise<TCertificateMap> => {
|
||||
const awsPkiSync = pkiSync as unknown as TAwsSecretsManagerPkiSyncWithCredentials;
|
||||
const client = await getSecretsManagerClient(awsPkiSync);
|
||||
|
||||
const existingSecrets = await $getSecretsManagerSecrets(awsPkiSync, pkiSync.id);
|
||||
const certificateMap: TCertificateMap = {};
|
||||
|
||||
const syncOptions = pkiSync.syncOptions as
|
||||
| {
|
||||
fieldMappings?: {
|
||||
certificate?: string;
|
||||
privateKey?: string;
|
||||
certificateChain?: string;
|
||||
caCertificate?: string;
|
||||
};
|
||||
}
|
||||
| undefined;
|
||||
const fieldMappings = {
|
||||
certificate: syncOptions?.fieldMappings?.certificate ?? "certificate",
|
||||
privateKey: syncOptions?.fieldMappings?.privateKey ?? "private_key",
|
||||
certificateChain: syncOptions?.fieldMappings?.certificateChain ?? "certificate_chain",
|
||||
caCertificate: syncOptions?.fieldMappings?.caCertificate ?? "ca_certificate"
|
||||
};
|
||||
|
||||
for (const [secretName] of Object.entries(existingSecrets)) {
|
||||
try {
|
||||
const secretValueResult = await withRateLimitRetry(
|
||||
() =>
|
||||
client.send(
|
||||
new GetSecretValueCommand({
|
||||
SecretId: secretName
|
||||
})
|
||||
),
|
||||
{
|
||||
operation: "get-secret-value",
|
||||
syncId: pkiSync.id
|
||||
}
|
||||
);
|
||||
|
||||
if (secretValueResult.SecretString) {
|
||||
const secretData = JSON.parse(secretValueResult.SecretString) as AwsSecretsManagerCertificateSecret;
|
||||
|
||||
const cert = secretData[fieldMappings.certificate];
|
||||
const privateKey = secretData[fieldMappings.privateKey];
|
||||
const certificateChain = secretData[fieldMappings.certificateChain];
|
||||
const caCertificate = secretData[fieldMappings.caCertificate];
|
||||
|
||||
if (typeof cert === "string" && typeof privateKey === "string") {
|
||||
certificateMap[secretName] = {
|
||||
cert,
|
||||
privateKey,
|
||||
certificateChain: typeof certificateChain === "string" ? certificateChain : undefined,
|
||||
caCertificate: typeof caCertificate === "string" ? caCertificate : undefined,
|
||||
certificateId: secretName
|
||||
};
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
{
|
||||
secretName,
|
||||
error: parseErrorMessage(error),
|
||||
pkiSyncId: pkiSync.id
|
||||
},
|
||||
"Failed to import certificate from secret"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return certificateMap;
|
||||
};
|
||||
|
||||
return {
|
||||
syncCertificates,
|
||||
removeCertificates,
|
||||
importCertificates
|
||||
};
|
||||
};
|
||||
|
||||
export type TAwsSecretsManagerPkiSyncFactory = ReturnType<typeof awsSecretsManagerPkiSyncFactory>;
|
||||
+103
@@ -0,0 +1,103 @@
|
||||
import RE2 from "re2";
|
||||
import { z } from "zod";
|
||||
|
||||
import { AppConnection, AWSRegion } from "@app/services/app-connection/app-connection-enums";
|
||||
import { PkiSync } from "@app/services/pki-sync/pki-sync-enums";
|
||||
import { PkiSyncSchema } from "@app/services/pki-sync/pki-sync-schemas";
|
||||
|
||||
import { AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING } from "./aws-secrets-manager-pki-sync-constants";
|
||||
|
||||
export const AwsSecretsManagerPkiSyncConfigSchema = z.object({
|
||||
region: z.nativeEnum(AWSRegion),
|
||||
keyId: z.string().trim().optional()
|
||||
});
|
||||
|
||||
export const AwsSecretsManagerFieldMappingsSchema = z.object({
|
||||
certificate: z.string().min(1, "Certificate field name is required").default("certificate"),
|
||||
privateKey: z.string().min(1, "Private key field name is required").default("private_key"),
|
||||
certificateChain: z.string().min(1, "Certificate chain field name is required").default("certificate_chain"),
|
||||
caCertificate: z.string().min(1, "CA certificate field name is required").default("ca_certificate")
|
||||
});
|
||||
|
||||
const AwsSecretsManagerPkiSyncOptionsSchema = z.object({
|
||||
canImportCertificates: z.boolean().default(false),
|
||||
canRemoveCertificates: z.boolean().default(true),
|
||||
preserveSecretOnRenewal: z.boolean().default(true),
|
||||
updateExistingCertificates: z.boolean().default(true),
|
||||
certificateNameSchema: z
|
||||
.string()
|
||||
.optional()
|
||||
.refine(
|
||||
(schema) => {
|
||||
if (!schema) return true;
|
||||
|
||||
if (!schema.includes("{{certificateId}}")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const testName = schema
|
||||
.replace(new RE2("\\{\\{certificateId\\}\\}", "g"), "test-cert-id")
|
||||
.replace(new RE2("\\{\\{profileId\\}\\}", "g"), "test-profile-id")
|
||||
.replace(new RE2("\\{\\{commonName\\}\\}", "g"), "test-common-name")
|
||||
.replace(new RE2("\\{\\{friendlyName\\}\\}", "g"), "test-friendly-name")
|
||||
.replace(new RE2("\\{\\{environment\\}\\}", "g"), "test-env");
|
||||
|
||||
const hasForbiddenChars = AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.FORBIDDEN_CHARACTERS.split("").some(
|
||||
(char) => testName.includes(char)
|
||||
);
|
||||
|
||||
return (
|
||||
AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.NAME_PATTERN.test(testName) &&
|
||||
!hasForbiddenChars &&
|
||||
testName.length >= AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.MIN_LENGTH &&
|
||||
testName.length <= AWS_SECRETS_MANAGER_PKI_SYNC_CERTIFICATE_NAMING.MAX_LENGTH
|
||||
);
|
||||
},
|
||||
{
|
||||
message:
|
||||
"Certificate name schema must include {{certificateId}} placeholder and result in names that contain only alphanumeric characters, underscores, and hyphens and be 1-512 characters long for AWS Secrets Manager."
|
||||
}
|
||||
),
|
||||
fieldMappings: AwsSecretsManagerFieldMappingsSchema.optional().default({
|
||||
certificate: "certificate",
|
||||
privateKey: "private_key",
|
||||
certificateChain: "certificate_chain",
|
||||
caCertificate: "ca_certificate"
|
||||
})
|
||||
});
|
||||
|
||||
export const AwsSecretsManagerPkiSyncSchema = PkiSyncSchema.extend({
|
||||
destination: z.literal(PkiSync.AwsSecretsManager),
|
||||
destinationConfig: AwsSecretsManagerPkiSyncConfigSchema,
|
||||
syncOptions: AwsSecretsManagerPkiSyncOptionsSchema
|
||||
});
|
||||
|
||||
export const CreateAwsSecretsManagerPkiSyncSchema = z.object({
|
||||
name: z.string().trim().min(1).max(64),
|
||||
description: z.string().optional(),
|
||||
isAutoSyncEnabled: z.boolean().default(true),
|
||||
destinationConfig: AwsSecretsManagerPkiSyncConfigSchema,
|
||||
syncOptions: AwsSecretsManagerPkiSyncOptionsSchema.optional().default({}),
|
||||
subscriberId: z.string().nullish(),
|
||||
connectionId: z.string(),
|
||||
projectId: z.string().trim().min(1),
|
||||
certificateIds: z.array(z.string().uuid()).optional()
|
||||
});
|
||||
|
||||
export const UpdateAwsSecretsManagerPkiSyncSchema = z.object({
|
||||
name: z.string().trim().min(1).max(64).optional(),
|
||||
description: z.string().optional(),
|
||||
isAutoSyncEnabled: z.boolean().optional(),
|
||||
destinationConfig: AwsSecretsManagerPkiSyncConfigSchema.optional(),
|
||||
syncOptions: AwsSecretsManagerPkiSyncOptionsSchema.optional(),
|
||||
subscriberId: z.string().nullish(),
|
||||
connectionId: z.string().optional()
|
||||
});
|
||||
|
||||
export const AwsSecretsManagerPkiSyncListItemSchema = z.object({
|
||||
name: z.literal("AWS Secrets Manager"),
|
||||
connection: z.literal(AppConnection.AWS),
|
||||
destination: z.literal(PkiSync.AwsSecretsManager),
|
||||
canImportCertificates: z.literal(false),
|
||||
canRemoveCertificates: z.literal(true)
|
||||
});
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
import { z } from "zod";
|
||||
|
||||
import { TAwsConnection } from "@app/services/app-connection/aws/aws-connection-types";
|
||||
|
||||
import {
|
||||
AwsSecretsManagerFieldMappingsSchema,
|
||||
AwsSecretsManagerPkiSyncConfigSchema,
|
||||
AwsSecretsManagerPkiSyncSchema,
|
||||
CreateAwsSecretsManagerPkiSyncSchema,
|
||||
UpdateAwsSecretsManagerPkiSyncSchema
|
||||
} from "./aws-secrets-manager-pki-sync-schemas";
|
||||
|
||||
export type TAwsSecretsManagerPkiSyncConfig = z.infer<typeof AwsSecretsManagerPkiSyncConfigSchema>;
|
||||
|
||||
export type TAwsSecretsManagerFieldMappings = z.infer<typeof AwsSecretsManagerFieldMappingsSchema>;
|
||||
|
||||
export type TAwsSecretsManagerPkiSync = z.infer<typeof AwsSecretsManagerPkiSyncSchema>;
|
||||
|
||||
export type TAwsSecretsManagerPkiSyncInput = z.infer<typeof CreateAwsSecretsManagerPkiSyncSchema>;
|
||||
|
||||
export type TAwsSecretsManagerPkiSyncUpdate = z.infer<typeof UpdateAwsSecretsManagerPkiSyncSchema>;
|
||||
|
||||
export type TAwsSecretsManagerPkiSyncWithCredentials = TAwsSecretsManagerPkiSync & {
|
||||
connection: TAwsConnection;
|
||||
appConnectionName: string;
|
||||
appConnectionApp: string;
|
||||
};
|
||||
|
||||
export interface AwsSecretsManagerCertificateSecret {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
export interface SyncCertificatesResult {
|
||||
uploaded: number;
|
||||
updated: number;
|
||||
removed: number;
|
||||
failedRemovals: number;
|
||||
skipped: number;
|
||||
details?: {
|
||||
failedUploads?: Array<{ name: string; error: string }>;
|
||||
failedRemovals?: Array<{ name: string; error: string }>;
|
||||
validationErrors?: Array<{ name: string; error: string }>;
|
||||
};
|
||||
}
|
||||
|
||||
export interface RemoveCertificatesResult {
|
||||
removed: number;
|
||||
failed: number;
|
||||
skipped: number;
|
||||
}
|
||||
|
||||
export interface CertificateImportRequest {
|
||||
name: string;
|
||||
certificate: string;
|
||||
privateKey: string;
|
||||
certificateChain?: string;
|
||||
caCertificate?: string;
|
||||
certificateId?: string;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./aws-secrets-manager-pki-sync-constants";
|
||||
export * from "./aws-secrets-manager-pki-sync-fns";
|
||||
export * from "./aws-secrets-manager-pki-sync-schemas";
|
||||
export * from "./aws-secrets-manager-pki-sync-types";
|
||||
@@ -1,6 +1,7 @@
|
||||
export enum PkiSync {
|
||||
AzureKeyVault = "azure-key-vault",
|
||||
AwsCertificateManager = "aws-certificate-manager",
|
||||
AwsSecretsManager = "aws-secrets-manager",
|
||||
Chef = "chef"
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||
|
||||
import { AWS_CERTIFICATE_MANAGER_PKI_SYNC_LIST_OPTION } from "./aws-certificate-manager/aws-certificate-manager-pki-sync-constants";
|
||||
import { awsCertificateManagerPkiSyncFactory } from "./aws-certificate-manager/aws-certificate-manager-pki-sync-fns";
|
||||
import { AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION } from "./aws-secrets-manager/aws-secrets-manager-pki-sync-constants";
|
||||
import { awsSecretsManagerPkiSyncFactory } from "./aws-secrets-manager/aws-secrets-manager-pki-sync-fns";
|
||||
import { AZURE_KEY_VAULT_PKI_SYNC_LIST_OPTION } from "./azure-key-vault/azure-key-vault-pki-sync-constants";
|
||||
import { azureKeyVaultPkiSyncFactory } from "./azure-key-vault/azure-key-vault-pki-sync-fns";
|
||||
import { chefPkiSyncFactory } from "./chef/chef-pki-sync-fns";
|
||||
@@ -22,6 +24,7 @@ const ENTERPRISE_PKI_SYNCS: PkiSync[] = [];
|
||||
const PKI_SYNC_LIST_OPTIONS = {
|
||||
[PkiSync.AzureKeyVault]: AZURE_KEY_VAULT_PKI_SYNC_LIST_OPTION,
|
||||
[PkiSync.AwsCertificateManager]: AWS_CERTIFICATE_MANAGER_PKI_SYNC_LIST_OPTION,
|
||||
[PkiSync.AwsSecretsManager]: AWS_SECRETS_MANAGER_PKI_SYNC_LIST_OPTION,
|
||||
[PkiSync.Chef]: CHEF_PKI_SYNC_LIST_OPTION
|
||||
};
|
||||
|
||||
@@ -165,6 +168,8 @@ export const PkiSyncFns = {
|
||||
dependencies: {
|
||||
appConnectionDAL: Pick<TAppConnectionDALFactory, "findById" | "updateById">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||
certificateDAL: TCertificateDALFactory;
|
||||
certificateSyncDAL: TCertificateSyncDALFactory;
|
||||
}
|
||||
): Promise<TCertificateMap> => {
|
||||
switch (pkiSync.destination) {
|
||||
@@ -178,6 +183,14 @@ export const PkiSyncFns = {
|
||||
"AWS Certificate Manager does not support importing certificates into Infisical (private keys cannot be extracted)"
|
||||
);
|
||||
}
|
||||
case PkiSync.AwsSecretsManager: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsSecretsManager as PkiSync);
|
||||
const awsSecretsManagerPkiSync = awsSecretsManagerPkiSyncFactory({
|
||||
certificateDAL: dependencies.certificateDAL,
|
||||
certificateSyncDAL: dependencies.certificateSyncDAL
|
||||
});
|
||||
return awsSecretsManagerPkiSync.importCertificates(pkiSync);
|
||||
}
|
||||
case PkiSync.Chef: {
|
||||
throw new Error(
|
||||
"Chef does not support importing certificates into Infisical (private keys cannot be extracted securely)"
|
||||
@@ -211,7 +224,7 @@ export const PkiSyncFns = {
|
||||
}> => {
|
||||
switch (pkiSync.destination) {
|
||||
case PkiSync.AzureKeyVault: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AzureKeyVault);
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AzureKeyVault as PkiSync);
|
||||
const azureKeyVaultPkiSync = azureKeyVaultPkiSyncFactory({
|
||||
appConnectionDAL: dependencies.appConnectionDAL,
|
||||
kmsService: dependencies.kmsService,
|
||||
@@ -221,7 +234,7 @@ export const PkiSyncFns = {
|
||||
return azureKeyVaultPkiSync.syncCertificates(pkiSync, certificateMap);
|
||||
}
|
||||
case PkiSync.AwsCertificateManager: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsCertificateManager);
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsCertificateManager as PkiSync);
|
||||
const awsCertificateManagerPkiSync = awsCertificateManagerPkiSyncFactory({
|
||||
appConnectionDAL: dependencies.appConnectionDAL,
|
||||
kmsService: dependencies.kmsService,
|
||||
@@ -230,8 +243,16 @@ export const PkiSyncFns = {
|
||||
});
|
||||
return awsCertificateManagerPkiSync.syncCertificates(pkiSync, certificateMap);
|
||||
}
|
||||
case PkiSync.AwsSecretsManager: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsSecretsManager as PkiSync);
|
||||
const awsSecretsManagerPkiSync = awsSecretsManagerPkiSyncFactory({
|
||||
certificateDAL: dependencies.certificateDAL,
|
||||
certificateSyncDAL: dependencies.certificateSyncDAL
|
||||
});
|
||||
return awsSecretsManagerPkiSync.syncCertificates(pkiSync, certificateMap);
|
||||
}
|
||||
case PkiSync.Chef: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.Chef);
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.Chef as PkiSync);
|
||||
const chefPkiSync = chefPkiSyncFactory({
|
||||
certificateDAL: dependencies.certificateDAL,
|
||||
certificateSyncDAL: dependencies.certificateSyncDAL
|
||||
@@ -256,7 +277,7 @@ export const PkiSyncFns = {
|
||||
): Promise<void> => {
|
||||
switch (pkiSync.destination) {
|
||||
case PkiSync.AzureKeyVault: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AzureKeyVault);
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AzureKeyVault as PkiSync);
|
||||
const azureKeyVaultPkiSync = azureKeyVaultPkiSyncFactory({
|
||||
appConnectionDAL: dependencies.appConnectionDAL,
|
||||
kmsService: dependencies.kmsService,
|
||||
@@ -270,7 +291,7 @@ export const PkiSyncFns = {
|
||||
break;
|
||||
}
|
||||
case PkiSync.AwsCertificateManager: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsCertificateManager);
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsCertificateManager as PkiSync);
|
||||
const awsCertificateManagerPkiSync = awsCertificateManagerPkiSyncFactory({
|
||||
appConnectionDAL: dependencies.appConnectionDAL,
|
||||
kmsService: dependencies.kmsService,
|
||||
@@ -283,8 +304,17 @@ export const PkiSyncFns = {
|
||||
});
|
||||
break;
|
||||
}
|
||||
case PkiSync.AwsSecretsManager: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.AwsSecretsManager as PkiSync);
|
||||
const awsSecretsManagerPkiSync = awsSecretsManagerPkiSyncFactory({
|
||||
certificateDAL: dependencies.certificateDAL,
|
||||
certificateSyncDAL: dependencies.certificateSyncDAL
|
||||
});
|
||||
await awsSecretsManagerPkiSync.removeCertificates(pkiSync, dependencies.certificateMap);
|
||||
break;
|
||||
}
|
||||
case PkiSync.Chef: {
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.Chef);
|
||||
checkPkiSyncDestination(pkiSync, PkiSync.Chef as PkiSync);
|
||||
const chefPkiSync = chefPkiSyncFactory({
|
||||
certificateDAL: dependencies.certificateDAL,
|
||||
certificateSyncDAL: dependencies.certificateSyncDAL
|
||||
|
||||
@@ -5,11 +5,13 @@ import { PkiSync } from "./pki-sync-enums";
|
||||
export const PKI_SYNC_NAME_MAP: Record<PkiSync, string> = {
|
||||
[PkiSync.AzureKeyVault]: "Azure Key Vault",
|
||||
[PkiSync.AwsCertificateManager]: "AWS Certificate Manager",
|
||||
[PkiSync.AwsSecretsManager]: "AWS Secrets Manager",
|
||||
[PkiSync.Chef]: "Chef"
|
||||
};
|
||||
|
||||
export const PKI_SYNC_CONNECTION_MAP: Record<PkiSync, AppConnection> = {
|
||||
[PkiSync.AzureKeyVault]: AppConnection.AzureKeyVault,
|
||||
[PkiSync.AwsCertificateManager]: AppConnection.AWS,
|
||||
[PkiSync.AwsSecretsManager]: AppConnection.AWS,
|
||||
[PkiSync.Chef]: AppConnection.Chef
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user