PR fix suggestions for aws secret rotations

This commit is contained in:
carlosmonastyrski
2025-04-22 17:40:15 -03:00
parent b85809293c
commit 5819b8c576
15 changed files with 66 additions and 48 deletions

View File

@@ -8,7 +8,7 @@ export const AWS_IAM_USER_SECRET_ROTATION_LIST_OPTION: TSecretRotationV2ListItem
connection: AppConnection.AWS,
template: {
secretsMapping: {
accessKeyId: "AWS_ACCESS_KEY",
accessKeyId: "AWS_ACCESS_KEY_ID",
secretAccessKey: "AWS_SECRET_ACCESS_KEY"
}
}

View File

@@ -18,7 +18,7 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
TAwsIamUserSecretRotationGeneratedCredentials
> = (secretRotation) => {
const {
parameters: { region, clientName },
parameters: { region, userName },
connection,
secretsMapping
} = secretRotation;
@@ -27,26 +27,29 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
const { credentials } = await getAwsConnectionConfig(connection, region);
const iam = new AWS.IAM({ credentials });
const { AccessKeyMetadata } = await iam.listAccessKeys({ UserName: clientName }).promise();
const { AccessKeyMetadata } = await iam.listAccessKeys({ UserName: userName }).promise();
if (AccessKeyMetadata && AccessKeyMetadata.length > 0) {
for (const key of AccessKeyMetadata) {
if (key.Status === "Inactive" && key.AccessKeyId) {
// eslint-disable-next-line no-await-in-loop
await iam
.deleteAccessKey({
UserName: clientName,
AccessKeyId: key.AccessKeyId
})
.promise();
}
}
// Delete inactive keys
await Promise.all(
AccessKeyMetadata.map((key) => {
if (key.Status === "Inactive" && key.AccessKeyId) {
return iam
.deleteAccessKey({
UserName: userName,
AccessKeyId: key.AccessKeyId
})
.promise();
}
return Promise.resolve();
})
);
const activeKey = AccessKeyMetadata.find((k) => k.Status === "Active");
if (activeKey && activeKey.AccessKeyId) {
await iam
.updateAccessKey({
UserName: clientName,
UserName: userName,
AccessKeyId: activeKey.AccessKeyId,
Status: "Inactive"
})
@@ -54,7 +57,7 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
}
}
const { AccessKey } = await iam.createAccessKey({ UserName: clientName }).promise();
const { AccessKey } = await iam.createAccessKey({ UserName: userName }).promise();
return {
accessKeyId: AccessKey.AccessKeyId,
@@ -77,15 +80,16 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
const { credentials } = await getAwsConnectionConfig(connection, region);
const iam = new AWS.IAM({ credentials });
for (const generatedCredential of generatedCredentials) {
// eslint-disable-next-line no-await-in-loop
await iam
.deleteAccessKey({
UserName: clientName,
AccessKeyId: generatedCredential.accessKeyId
})
.promise();
}
await Promise.all(
generatedCredentials.map((generatedCredential) =>
iam
.deleteAccessKey({
UserName: userName,
AccessKeyId: generatedCredential.accessKeyId
})
.promise()
)
);
return callback();
};

View File

@@ -20,11 +20,11 @@ export const AwsIamUserSecretRotationGeneratedCredentialsSchema = z
.max(2);
const AwsIamUserSecretRotationParametersSchema = z.object({
clientName: z
userName: z
.string()
.trim()
.min(1, "Client Name Required")
.describe(SecretRotations.PARAMETERS.AWS_IAM_USER_SECRET.clientName),
.describe(SecretRotations.PARAMETERS.AWS_IAM_USER_SECRET.userName),
region: z.nativeEnum(AWSRegion).describe(SecretRotations.PARAMETERS.AWS_IAM_USER_SECRET.region)
});

View File

@@ -3,7 +3,7 @@ import { AppConnection } from "@app/services/app-connection/app-connection-enums
export const SECRET_ROTATION_NAME_MAP: Record<SecretRotation, string> = {
[SecretRotation.PostgresCredentials]: "PostgreSQL Credentials",
[SecretRotation.MsSqlCredentials]: "Microsoft SQL Sever Credentials",
[SecretRotation.MsSqlCredentials]: "Microsoft SQL Server Credentials",
[SecretRotation.Auth0ClientSecret]: "Auth0 Client Secret",
[SecretRotation.AwsIamUserSecret]: "AWS IAM User Secret"
};

View File

@@ -2017,7 +2017,7 @@ export const SecretRotations = {
clientId: "The client ID of the Auth0 Application to rotate the client secret for."
},
AWS_IAM_USER_SECRET: {
clientName: "The name of the client to rotate credentials for.",
userName: "The name of the client to rotate credentials for.",
region: "The AWS region to rotate credentials for."
}
},

View File

@@ -69,7 +69,17 @@ export const registerAwsConnectionRouter = async (server: FastifyZodProvider) =>
schema: {
params: z.object({
connectionId: z.string().uuid()
})
}),
response: {
200: z.object({
iamUsers: z
.object({
UserName: z.string(),
Arn: z.string()
})
.array()
})
}
},
onRequest: verifyAuth([AuthMode.JWT]),
handler: async (req) => {

View File

@@ -78,9 +78,16 @@ const listAwsIamUsers = async (appConnection: TAwsConnection) => {
const iam = new AWS.IAM({ credentials });
const users = await iam.listUsers().promise();
const userEntries: AWS.IAM.User[] = [];
let userMarker: string | undefined;
do {
// eslint-disable-next-line no-await-in-loop
const response = await iam.listUsers({ MaxItems: 100, Marker: userMarker }).promise();
userEntries.push(...(response.Users || []));
userMarker = response.Marker;
} while (userMarker);
return users.Users;
return userEntries;
};
export const awsConnectionService = (getAppConnection: TGetAppConnectionFunc) => {

View File

@@ -114,7 +114,7 @@ In the following steps, we explore the end-to-end workflow for setting up this s
"minutes": 29.5
},
"parameters": {
"clientName": "<string>",
"userName": "<string>",
"region": "us-east-1"
},
"secretsMapping": {
@@ -171,7 +171,7 @@ In the following steps, we explore the end-to-end workflow for setting up this s
"lastRotationMessage": "<string>",
"type": "aws-iam-user-secret",
"parameters": {
"clientName": "<string>",
"userName": "<string>",
"region": "us-east-1"
}
}

View File

@@ -25,7 +25,7 @@ export const AwsIamUserSecretRotationParametersFields = () => {
return (
<>
<Controller
name="parameters.clientName"
name="parameters.userName"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
@@ -70,13 +70,13 @@ export const AwsIamUserSecretRotationParametersFields = () => {
)}
/>
<Controller
control={control}
name="parameters.region"
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl isError={Boolean(error)} errorText={error?.message} label="Region">
<AwsRegionSelect value={value} onChange={onChange} />
</FormControl>
)}
control={control}
name="parameters.region"
/>
</>
);

View File

@@ -19,11 +19,11 @@ export const AwsIamUserSecretRotationReviewFields = () => {
<>
<SecretRotationReviewSection label="Parameters">
<GenericFieldLabel label="Region">{parameters.region}</GenericFieldLabel>
<GenericFieldLabel label="User Name">{parameters.clientName}</GenericFieldLabel>
<GenericFieldLabel label="User Name">{parameters.userName}</GenericFieldLabel>
</SecretRotationReviewSection>
<SecretRotationReviewSection label="Secrets Mapping">
<GenericFieldLabel label="Access Key ID">{accessKeyId}</GenericFieldLabel>
<GenericFieldLabel label="Access Key Secret">{secretAccessKey}</GenericFieldLabel>
<GenericFieldLabel label="Secret Access Key ID">{accessKeyId}</GenericFieldLabel>
<GenericFieldLabel label="Secret Access Key">{secretAccessKey}</GenericFieldLabel>
</SecretRotationReviewSection>
</>
);

View File

@@ -35,7 +35,7 @@ export const AwsIamUserSecretRotationSecretsMappingFields = () => {
)
},
{
name: "Client Secret",
name: "Secret Access Key",
input: (
<Controller
render={({ field: { value, onChange }, fieldState: { error } }) => (

View File

@@ -7,7 +7,7 @@ export const AwsIamUserSecretRotationSchema = z
.object({
type: z.literal(SecretRotation.AwsIamUserSecret),
parameters: z.object({
clientName: z.string().trim().min(1, "Client Name required"),
userName: z.string().trim().min(1, "User Name required"),
region: z.string().trim().min(1, "Region required")
}),
secretsMapping: z.object({

View File

@@ -28,7 +28,4 @@ export type TAwsConnectionListIamUsersResponse = {
iamUsers: TAwsConnectionIamUser[];
};
export type TAwsIamUserSecret = {
arn: string;
UserName: string;
};
export type TAwsIamUserSecret = TAwsConnectionIamUser;

View File

@@ -9,7 +9,7 @@ export type TAwsIamUserSecretRotation = TSecretRotationV2Base & {
type: SecretRotation.AwsIamUserSecret;
parameters: {
region: string;
clientName: string;
userName: string;
};
secretsMapping: {
accessKeyId: string;

View File

@@ -8,7 +8,7 @@ import {
TAwsIamUserSecretRotation,
TAwsIamUserSecretRotationGeneratedCredentialsResponse,
TAwsIamUserSecretRotationOption
} from "@app/hooks/api/secretRotationsV2/types/aws-iam-access-key-rotation";
} from "@app/hooks/api/secretRotationsV2/types/aws-iam-user-secret-rotation";
import {
TMsSqlCredentialsRotation,
TMsSqlCredentialsRotationGeneratedCredentialsResponse