Skip to content

Commit d0b353c

Browse files
authored
Mariano/agent 5 (#1922)
* refactor(aws-security): simplify AWS credentials handling and improve logging
1 parent ca79bc8 commit d0b353c

File tree

1 file changed

+61
-24
lines changed

1 file changed

+61
-24
lines changed

apps/api/src/cloud-security/providers/aws-security.service.ts

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ import {
77
} from '@aws-sdk/client-securityhub';
88
import type { SecurityFinding } from '../cloud-security.service';
99

10+
type AwsCredentials = {
11+
accessKeyId: string;
12+
secretAccessKey: string;
13+
sessionToken?: string;
14+
};
15+
1016
@Injectable()
1117
export class AWSSecurityService {
1218
private readonly logger = new Logger(AWSSecurityService.name);
@@ -15,10 +21,10 @@ export class AWSSecurityService {
1521
credentials: Record<string, unknown>,
1622
variables: Record<string, unknown>,
1723
): Promise<SecurityFinding[]> {
18-
// Determine auth method
19-
const isRoleAuth = credentials.roleArn && credentials.externalId;
20-
const isKeyAuth =
21-
credentials.access_key_id && credentials.secret_access_key;
24+
const isRoleAuth = Boolean(credentials.roleArn && credentials.externalId);
25+
const isKeyAuth = Boolean(
26+
credentials.access_key_id && credentials.secret_access_key,
27+
);
2228

2329
if (!isRoleAuth && !isKeyAuth) {
2430
throw new Error(
@@ -31,54 +37,85 @@ export class AWSSecurityService {
3137
(variables.region as string) ||
3238
'us-east-1';
3339

34-
let awsCredentials: {
35-
accessKeyId: string;
36-
secretAccessKey: string;
37-
sessionToken?: string;
38-
};
40+
let awsCredentials: AwsCredentials;
3941

4042
if (isRoleAuth) {
41-
// IAM Role assumption
42-
const roleArn = credentials.roleArn as string;
43+
const customerRoleArn = credentials.roleArn as string;
4344
const externalId = credentials.externalId as string;
4445

45-
this.logger.log(`Assuming role ${roleArn} in region ${region}`);
46+
const roleAssumerArn = process.env.SECURITY_HUB_ROLE_ASSUMER_ARN;
47+
if (!roleAssumerArn) {
48+
throw new Error(
49+
'Missing SECURITY_HUB_ROLE_ASSUMER_ARN (our roleAssumer ARN).',
50+
);
51+
}
52+
53+
// Hop 1: task role -> roleAssumer
54+
const baseSts = new STSClient({ region });
55+
const roleAssumerResp = await baseSts.send(
56+
new AssumeRoleCommand({
57+
RoleArn: roleAssumerArn,
58+
RoleSessionName: 'CompRoleAssumer',
59+
DurationSeconds: 3600,
60+
}),
61+
);
62+
63+
const roleAssumerCreds = roleAssumerResp.Credentials;
64+
if (!roleAssumerCreds?.AccessKeyId || !roleAssumerCreds.SecretAccessKey) {
65+
throw new Error(
66+
'Failed to assume roleAssumer - no credentials returned',
67+
);
68+
}
69+
70+
const roleAssumerAwsCreds: AwsCredentials = {
71+
accessKeyId: roleAssumerCreds.AccessKeyId,
72+
secretAccessKey: roleAssumerCreds.SecretAccessKey,
73+
sessionToken: roleAssumerCreds.SessionToken,
74+
};
75+
76+
// Hop 2: roleAssumer -> customer role (ExternalId enforced by customer trust policy)
77+
const roleAssumerSts = new STSClient({
78+
region,
79+
credentials: roleAssumerAwsCreds,
80+
});
81+
82+
this.logger.log(
83+
`Assuming customer role ${customerRoleArn} in region ${region}`,
84+
);
4685

47-
const sts = new STSClient({ region });
48-
const assumeRoleResponse = await sts.send(
86+
const customerResp = await roleAssumerSts.send(
4987
new AssumeRoleCommand({
50-
RoleArn: roleArn,
88+
RoleArn: customerRoleArn,
5189
ExternalId: externalId,
5290
RoleSessionName: 'CompSecurityAudit',
5391
DurationSeconds: 3600,
5492
}),
5593
);
5694

57-
if (!assumeRoleResponse.Credentials) {
58-
throw new Error('Failed to assume role - no credentials returned');
95+
const customerCreds = customerResp.Credentials;
96+
if (!customerCreds?.AccessKeyId || !customerCreds.SecretAccessKey) {
97+
throw new Error(
98+
'Failed to assume customer role - no credentials returned',
99+
);
59100
}
60101

61102
awsCredentials = {
62-
accessKeyId: assumeRoleResponse.Credentials.AccessKeyId!,
63-
secretAccessKey: assumeRoleResponse.Credentials.SecretAccessKey!,
64-
sessionToken: assumeRoleResponse.Credentials.SessionToken!,
103+
accessKeyId: customerCreds.AccessKeyId,
104+
secretAccessKey: customerCreds.SecretAccessKey,
105+
sessionToken: customerCreds.SessionToken,
65106
};
66107
} else {
67-
// Direct access keys
68108
awsCredentials = {
69109
accessKeyId: credentials.access_key_id as string,
70110
secretAccessKey: credentials.secret_access_key as string,
71111
};
72112
}
73113

74-
// Create Security Hub client
75114
const securityHub = new SecurityHubClient({
76115
region,
77116
credentials: awsCredentials,
78117
});
79118

80-
this.logger.log(`Scanning AWS Security Hub in region ${region}`);
81-
82119
try {
83120
const findings = await this.fetchSecurityHubFindings(securityHub);
84121
this.logger.log(`Found ${findings.length} AWS security findings`);

0 commit comments

Comments
 (0)