mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 09:28:28 +00:00
PR fix suggestions for aws secret rotations
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ export const AWS_IAM_USER_SECRET_ROTATION_LIST_OPTION: TSecretRotationV2ListItem
|
|||||||
connection: AppConnection.AWS,
|
connection: AppConnection.AWS,
|
||||||
template: {
|
template: {
|
||||||
secretsMapping: {
|
secretsMapping: {
|
||||||
accessKeyId: "AWS_ACCESS_KEY",
|
accessKeyId: "AWS_ACCESS_KEY_ID",
|
||||||
secretAccessKey: "AWS_SECRET_ACCESS_KEY"
|
secretAccessKey: "AWS_SECRET_ACCESS_KEY"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
-24
@@ -18,7 +18,7 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
|
|||||||
TAwsIamUserSecretRotationGeneratedCredentials
|
TAwsIamUserSecretRotationGeneratedCredentials
|
||||||
> = (secretRotation) => {
|
> = (secretRotation) => {
|
||||||
const {
|
const {
|
||||||
parameters: { region, clientName },
|
parameters: { region, userName },
|
||||||
connection,
|
connection,
|
||||||
secretsMapping
|
secretsMapping
|
||||||
} = secretRotation;
|
} = secretRotation;
|
||||||
@@ -27,26 +27,29 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
|
|||||||
const { credentials } = await getAwsConnectionConfig(connection, region);
|
const { credentials } = await getAwsConnectionConfig(connection, region);
|
||||||
const iam = new AWS.IAM({ credentials });
|
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) {
|
if (AccessKeyMetadata && AccessKeyMetadata.length > 0) {
|
||||||
for (const key of AccessKeyMetadata) {
|
// Delete inactive keys
|
||||||
if (key.Status === "Inactive" && key.AccessKeyId) {
|
await Promise.all(
|
||||||
// eslint-disable-next-line no-await-in-loop
|
AccessKeyMetadata.map((key) => {
|
||||||
await iam
|
if (key.Status === "Inactive" && key.AccessKeyId) {
|
||||||
.deleteAccessKey({
|
return iam
|
||||||
UserName: clientName,
|
.deleteAccessKey({
|
||||||
AccessKeyId: key.AccessKeyId
|
UserName: userName,
|
||||||
})
|
AccessKeyId: key.AccessKeyId
|
||||||
.promise();
|
})
|
||||||
}
|
.promise();
|
||||||
}
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const activeKey = AccessKeyMetadata.find((k) => k.Status === "Active");
|
const activeKey = AccessKeyMetadata.find((k) => k.Status === "Active");
|
||||||
if (activeKey && activeKey.AccessKeyId) {
|
if (activeKey && activeKey.AccessKeyId) {
|
||||||
await iam
|
await iam
|
||||||
.updateAccessKey({
|
.updateAccessKey({
|
||||||
UserName: clientName,
|
UserName: userName,
|
||||||
AccessKeyId: activeKey.AccessKeyId,
|
AccessKeyId: activeKey.AccessKeyId,
|
||||||
Status: "Inactive"
|
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 {
|
return {
|
||||||
accessKeyId: AccessKey.AccessKeyId,
|
accessKeyId: AccessKey.AccessKeyId,
|
||||||
@@ -77,15 +80,16 @@ export const awsIamUserSecretRotationFactory: TRotationFactory<
|
|||||||
const { credentials } = await getAwsConnectionConfig(connection, region);
|
const { credentials } = await getAwsConnectionConfig(connection, region);
|
||||||
const iam = new AWS.IAM({ credentials });
|
const iam = new AWS.IAM({ credentials });
|
||||||
|
|
||||||
for (const generatedCredential of generatedCredentials) {
|
await Promise.all(
|
||||||
// eslint-disable-next-line no-await-in-loop
|
generatedCredentials.map((generatedCredential) =>
|
||||||
await iam
|
iam
|
||||||
.deleteAccessKey({
|
.deleteAccessKey({
|
||||||
UserName: clientName,
|
UserName: userName,
|
||||||
AccessKeyId: generatedCredential.accessKeyId
|
AccessKeyId: generatedCredential.accessKeyId
|
||||||
})
|
})
|
||||||
.promise();
|
.promise()
|
||||||
}
|
)
|
||||||
|
);
|
||||||
|
|
||||||
return callback();
|
return callback();
|
||||||
};
|
};
|
||||||
|
|||||||
+2
-2
@@ -20,11 +20,11 @@ export const AwsIamUserSecretRotationGeneratedCredentialsSchema = z
|
|||||||
.max(2);
|
.max(2);
|
||||||
|
|
||||||
const AwsIamUserSecretRotationParametersSchema = z.object({
|
const AwsIamUserSecretRotationParametersSchema = z.object({
|
||||||
clientName: z
|
userName: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(1, "Client Name Required")
|
.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)
|
region: z.nativeEnum(AWSRegion).describe(SecretRotations.PARAMETERS.AWS_IAM_USER_SECRET.region)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { AppConnection } from "@app/services/app-connection/app-connection-enums
|
|||||||
|
|
||||||
export const SECRET_ROTATION_NAME_MAP: Record<SecretRotation, string> = {
|
export const SECRET_ROTATION_NAME_MAP: Record<SecretRotation, string> = {
|
||||||
[SecretRotation.PostgresCredentials]: "PostgreSQL Credentials",
|
[SecretRotation.PostgresCredentials]: "PostgreSQL Credentials",
|
||||||
[SecretRotation.MsSqlCredentials]: "Microsoft SQL Sever Credentials",
|
[SecretRotation.MsSqlCredentials]: "Microsoft SQL Server Credentials",
|
||||||
[SecretRotation.Auth0ClientSecret]: "Auth0 Client Secret",
|
[SecretRotation.Auth0ClientSecret]: "Auth0 Client Secret",
|
||||||
[SecretRotation.AwsIamUserSecret]: "AWS IAM User Secret"
|
[SecretRotation.AwsIamUserSecret]: "AWS IAM User Secret"
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2017,7 +2017,7 @@ export const SecretRotations = {
|
|||||||
clientId: "The client ID of the Auth0 Application to rotate the client secret for."
|
clientId: "The client ID of the Auth0 Application to rotate the client secret for."
|
||||||
},
|
},
|
||||||
AWS_IAM_USER_SECRET: {
|
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."
|
region: "The AWS region to rotate credentials for."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,7 +69,17 @@ export const registerAwsConnectionRouter = async (server: FastifyZodProvider) =>
|
|||||||
schema: {
|
schema: {
|
||||||
params: z.object({
|
params: z.object({
|
||||||
connectionId: z.string().uuid()
|
connectionId: z.string().uuid()
|
||||||
})
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
iamUsers: z
|
||||||
|
.object({
|
||||||
|
UserName: z.string(),
|
||||||
|
Arn: z.string()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
|||||||
@@ -78,9 +78,16 @@ const listAwsIamUsers = async (appConnection: TAwsConnection) => {
|
|||||||
|
|
||||||
const iam = new AWS.IAM({ credentials });
|
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) => {
|
export const awsConnectionService = (getAppConnection: TGetAppConnectionFunc) => {
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ In the following steps, we explore the end-to-end workflow for setting up this s
|
|||||||
"minutes": 29.5
|
"minutes": 29.5
|
||||||
},
|
},
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"clientName": "<string>",
|
"userName": "<string>",
|
||||||
"region": "us-east-1"
|
"region": "us-east-1"
|
||||||
},
|
},
|
||||||
"secretsMapping": {
|
"secretsMapping": {
|
||||||
@@ -171,7 +171,7 @@ In the following steps, we explore the end-to-end workflow for setting up this s
|
|||||||
"lastRotationMessage": "<string>",
|
"lastRotationMessage": "<string>",
|
||||||
"type": "aws-iam-user-secret",
|
"type": "aws-iam-user-secret",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"clientName": "<string>",
|
"userName": "<string>",
|
||||||
"region": "us-east-1"
|
"region": "us-east-1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -25,7 +25,7 @@ export const AwsIamUserSecretRotationParametersFields = () => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Controller
|
<Controller
|
||||||
name="parameters.clientName"
|
name="parameters.userName"
|
||||||
control={control}
|
control={control}
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
@@ -70,13 +70,13 @@ export const AwsIamUserSecretRotationParametersFields = () => {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Controller
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="parameters.region"
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
<FormControl isError={Boolean(error)} errorText={error?.message} label="Region">
|
<FormControl isError={Boolean(error)} errorText={error?.message} label="Region">
|
||||||
<AwsRegionSelect value={value} onChange={onChange} />
|
<AwsRegionSelect value={value} onChange={onChange} />
|
||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
control={control}
|
|
||||||
name="parameters.region"
|
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
+3
-3
@@ -19,11 +19,11 @@ export const AwsIamUserSecretRotationReviewFields = () => {
|
|||||||
<>
|
<>
|
||||||
<SecretRotationReviewSection label="Parameters">
|
<SecretRotationReviewSection label="Parameters">
|
||||||
<GenericFieldLabel label="Region">{parameters.region}</GenericFieldLabel>
|
<GenericFieldLabel label="Region">{parameters.region}</GenericFieldLabel>
|
||||||
<GenericFieldLabel label="User Name">{parameters.clientName}</GenericFieldLabel>
|
<GenericFieldLabel label="User Name">{parameters.userName}</GenericFieldLabel>
|
||||||
</SecretRotationReviewSection>
|
</SecretRotationReviewSection>
|
||||||
<SecretRotationReviewSection label="Secrets Mapping">
|
<SecretRotationReviewSection label="Secrets Mapping">
|
||||||
<GenericFieldLabel label="Access Key ID">{accessKeyId}</GenericFieldLabel>
|
<GenericFieldLabel label="Secret Access Key ID">{accessKeyId}</GenericFieldLabel>
|
||||||
<GenericFieldLabel label="Access Key Secret">{secretAccessKey}</GenericFieldLabel>
|
<GenericFieldLabel label="Secret Access Key">{secretAccessKey}</GenericFieldLabel>
|
||||||
</SecretRotationReviewSection>
|
</SecretRotationReviewSection>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ export const AwsIamUserSecretRotationSecretsMappingFields = () => {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Client Secret",
|
name: "Secret Access Key",
|
||||||
input: (
|
input: (
|
||||||
<Controller
|
<Controller
|
||||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ export const AwsIamUserSecretRotationSchema = z
|
|||||||
.object({
|
.object({
|
||||||
type: z.literal(SecretRotation.AwsIamUserSecret),
|
type: z.literal(SecretRotation.AwsIamUserSecret),
|
||||||
parameters: z.object({
|
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")
|
region: z.string().trim().min(1, "Region required")
|
||||||
}),
|
}),
|
||||||
secretsMapping: z.object({
|
secretsMapping: z.object({
|
||||||
|
|||||||
@@ -28,7 +28,4 @@ export type TAwsConnectionListIamUsersResponse = {
|
|||||||
iamUsers: TAwsConnectionIamUser[];
|
iamUsers: TAwsConnectionIamUser[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAwsIamUserSecret = {
|
export type TAwsIamUserSecret = TAwsConnectionIamUser;
|
||||||
arn: string;
|
|
||||||
UserName: string;
|
|
||||||
};
|
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ export type TAwsIamUserSecretRotation = TSecretRotationV2Base & {
|
|||||||
type: SecretRotation.AwsIamUserSecret;
|
type: SecretRotation.AwsIamUserSecret;
|
||||||
parameters: {
|
parameters: {
|
||||||
region: string;
|
region: string;
|
||||||
clientName: string;
|
userName: string;
|
||||||
};
|
};
|
||||||
secretsMapping: {
|
secretsMapping: {
|
||||||
accessKeyId: string;
|
accessKeyId: string;
|
||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
TAwsIamUserSecretRotation,
|
TAwsIamUserSecretRotation,
|
||||||
TAwsIamUserSecretRotationGeneratedCredentialsResponse,
|
TAwsIamUserSecretRotationGeneratedCredentialsResponse,
|
||||||
TAwsIamUserSecretRotationOption
|
TAwsIamUserSecretRotationOption
|
||||||
} from "@app/hooks/api/secretRotationsV2/types/aws-iam-access-key-rotation";
|
} from "@app/hooks/api/secretRotationsV2/types/aws-iam-user-secret-rotation";
|
||||||
import {
|
import {
|
||||||
TMsSqlCredentialsRotation,
|
TMsSqlCredentialsRotation,
|
||||||
TMsSqlCredentialsRotationGeneratedCredentialsResponse
|
TMsSqlCredentialsRotationGeneratedCredentialsResponse
|
||||||
|
|||||||
Reference in New Issue
Block a user