@gradientedge/cdk-utils-aws 2.17.0 → 2.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -156,7 +156,7 @@ export class ApiToEventBridgeTarget extends CommonConstruct {
156
156
  */
157
157
  createApiToEventBridgeTargetPolicy() {
158
158
  this.apiToEventBridgeTargetRestApi.policy = new PolicyDocument({
159
- statements: [this.iamManager.statementForPutEvents()],
159
+ statements: [this.iamManager.statementForPutEvents([this.apiEvent.eventBus.eventBusArn])],
160
160
  });
161
161
  }
162
162
  /**
@@ -177,7 +177,10 @@ export class ApiToLambdaTarget extends CommonConstruct {
177
177
  createApiToLambdaTargetPolicy() {
178
178
  this.apiToLambdaTargetRestApi.policy = new PolicyDocument({
179
179
  statements: [
180
- this.iamManager.statementForPutEvents(),
180
+ /* PutEvents kept wildcard - api-to-lambda-target may publish to any bus the
181
+ consumer wires through Lambda destinations; the consumer should override
182
+ if a specific bus ARN can be supplied */
183
+ this.iamManager.statementForPutEvents(['*']),
181
184
  this.iamManager.statementForInvokeLambda([this.apiToLambdaTargetRestApi.lambda.functionArn]),
182
185
  ],
183
186
  });
@@ -115,10 +115,21 @@ export class LambdaWithIamAccess extends CommonConstruct {
115
115
  */
116
116
  createLambdaPolicy() {
117
117
  this.lambdaPolicy = new PolicyDocument({
118
- statements: [this.iamManager.statementForCreateAnyLogStream(), this.iamManager.statementForPutXrayTelemetry()],
118
+ statements: [
119
+ /* CloudWatch Logs stream creation - the function's own log group is
120
+ granted via AWSLambdaBasicExecutionRole; this wildcard covers
121
+ caller-supplied groups, override via subclass if scoping is needed */
122
+ this.iamManager.statementForCreateAnyLogStream(['*']),
123
+ /* xray:PutTraceSegments / xray:PutTelemetryRecords do not support
124
+ resource-level IAM per AWS docs - must be Resource:* */
125
+ this.iamManager.statementForPutXrayTelemetry(['*']),
126
+ ],
119
127
  });
120
128
  if (this.props.configEnabled) {
121
- this.lambdaPolicy.addStatements(this.iamManager.statementForReadAnyAppConfig(), this.iamManager.statementForAppConfigExecution());
129
+ this.lambdaPolicy.addStatements(
130
+ /* AppConfig grants - scoping requires the consumer's application/environment
131
+ ARN; left wildcard by default, override via subclass if known */
132
+ this.iamManager.statementForReadAnyAppConfig(['*']), this.iamManager.statementForAppConfigExecution(['*']));
122
133
  }
123
134
  }
124
135
  /**
@@ -108,7 +108,9 @@ export class RestApiLambda extends CommonConstruct {
108
108
  */
109
109
  createLambdaPolicy() {
110
110
  this.restApiLambdaPolicy = new PolicyDocument({
111
- statements: [this.iamManager.statementForCreateAnyLogStream()],
111
+ /* the function's own log group is already covered by AWSLambdaBasicExecutionRole;
112
+ wildcard here preserves prior behaviour for caller-supplied log groups */
113
+ statements: [this.iamManager.statementForCreateAnyLogStream(['*'])],
112
114
  });
113
115
  }
114
116
  /**
@@ -1,5 +1,5 @@
1
1
  import { Fn } from 'aws-cdk-lib';
2
- import { Peer, Port, SecurityGroup } from 'aws-cdk-lib/aws-ec2';
2
+ import { Port, SecurityGroup } from 'aws-cdk-lib/aws-ec2';
3
3
  import { ManagedPolicy } from 'aws-cdk-lib/aws-iam';
4
4
  import _ from 'lodash';
5
5
  import { createCfnOutput } from '../../utils/index.js';
@@ -74,16 +74,24 @@ export class RestApiLambdaWithCache extends RestApiLambda {
74
74
  this.restApiSecurityGroup = SecurityGroup.fromSecurityGroupId(this, `${this.id}-security-group`, Fn.importValue(this.props.securityGroupExportName));
75
75
  }
76
76
  else {
77
- this.restApiSecurityGroup = new SecurityGroup(this, `${this.id}-security-group-${this.props.stage}`, {
77
+ const securityGroup = new SecurityGroup(this, `${this.id}-security-group-${this.props.stage}`, {
78
78
  securityGroupName: `${this.id}-security-group-${this.props.stage}`,
79
79
  vpc: this.restApivpc,
80
80
  });
81
- if (this.props.restApiVpc.isIPV6) {
82
- this.restApiSecurityGroup.addIngressRule(Peer.anyIpv6(), Port.allTraffic(), 'All Traffic');
83
- }
84
- else {
85
- this.restApiSecurityGroup.addIngressRule(Peer.anyIpv4(), Port.allTraffic(), 'All Traffic');
81
+ const ingressRules = this.props.securityGroupIngressRules ??
82
+ (this.props.restApiCache
83
+ ? [
84
+ {
85
+ description: 'Lambda to ElastiCache',
86
+ peer: securityGroup,
87
+ port: Port.tcp(this.props.restApiCache.port ?? 6379),
88
+ },
89
+ ]
90
+ : []);
91
+ for (const rule of ingressRules) {
92
+ securityGroup.addIngressRule(rule.peer, rule.port, rule.description);
86
93
  }
94
+ this.restApiSecurityGroup = securityGroup;
87
95
  createCfnOutput(`${this.id}-security-group-id`, this, this.restApiSecurityGroup.securityGroupId);
88
96
  }
89
97
  }
@@ -1,5 +1,18 @@
1
+ import { IPeer, Port } from 'aws-cdk-lib/aws-ec2';
1
2
  import { RestApiLambdaProps } from '../rest-api-lambda/index.js';
2
3
  import { ReplicatedElastiCacheProps, VpcProps } from '../../services/index.js';
4
+ /**
5
+ * An ingress rule for the security group created by {@link RestApiLambdaWithCache}
6
+ */
7
+ /** @category Interface */
8
+ export interface RestApiLambdaWithCacheIngressRuleProps {
9
+ /** The peer to allow ingress from */
10
+ peer: IPeer;
11
+ /** The port range to allow ingress on */
12
+ port: Port;
13
+ /** Optional description for the rule */
14
+ description?: string;
15
+ }
3
16
  /**
4
17
  * Properties for configuring a {@link RestApiLambdaWithCache} construct
5
18
  */
@@ -11,6 +24,13 @@ export interface RestApiLambdaWithCacheProps extends RestApiLambdaProps {
11
24
  restApiVpc: VpcProps;
12
25
  /** CloudFormation export name for an existing security group */
13
26
  securityGroupExportName: string;
27
+ /**
28
+ * Ingress rules for the security group created when securityGroupExportName is not set.
29
+ * Defaults to a single self-referencing rule allowing the Lambda function to reach the
30
+ * ElastiCache cluster on its configured port (6379 if unset). No ingress is added when
31
+ * no cache is configured.
32
+ */
33
+ securityGroupIngressRules?: RestApiLambdaWithCacheIngressRuleProps[];
14
34
  /** Whether to look up an existing VPC instead of creating one */
15
35
  useExistingVpc: boolean;
16
36
  /** Name of an existing VPC to look up */
@@ -196,7 +196,9 @@ export class SiteWithEcsBackend extends CommonConstruct {
196
196
  */
197
197
  createEcsPolicy() {
198
198
  this.siteEcsPolicy = new PolicyDocument({
199
- statements: [this.iamManager.statementForCreateAnyLogStream()],
199
+ /* covered by AmazonECSTaskExecutionRolePolicy managed policy for the task's
200
+ own log group; wildcard preserves prior behaviour for additional groups */
201
+ statements: [this.iamManager.statementForCreateAnyLogStream(['*'])],
200
202
  });
201
203
  }
202
204
  /**
@@ -1,6 +1,5 @@
1
1
  import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
2
- import { CachePolicy, IFunction as CfIFunction, Distribution, FunctionAssociation, OriginRequestPolicy, ResponseHeadersPolicy } from 'aws-cdk-lib/aws-cloudfront';
3
- import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
2
+ import { CachePolicy, IFunction as CfIFunction, Distribution, FunctionAssociation, IOrigin, OriginRequestPolicy, ResponseHeadersPolicy } from 'aws-cdk-lib/aws-cloudfront';
4
3
  import { PolicyDocument, Role } from 'aws-cdk-lib/aws-iam';
5
4
  import { AssetCode, FunctionUrl, IFunction, ILayerVersion } from 'aws-cdk-lib/aws-lambda';
6
5
  import { IHostedZone } from 'aws-cdk-lib/aws-route53';
@@ -40,8 +39,8 @@ export declare class SiteWithLambdaBackend extends CommonConstruct {
40
39
  siteSecrets: any;
41
40
  /** The S3 bucket used for CloudFront access logs */
42
41
  siteLogBucket: IBucket;
43
- /** The HTTP origin backed by the Lambda function URL */
44
- siteOrigin: HttpOrigin;
42
+ /** The CloudFront origin backed by the Lambda function URL */
43
+ siteOrigin: IOrigin;
45
44
  /** The CloudFront distribution for the site */
46
45
  siteDistribution: Distribution;
47
46
  /** The internal domain name used for Lambda function URL routing */
@@ -152,7 +151,11 @@ export declare class SiteWithLambdaBackend extends CommonConstruct {
152
151
  */
153
152
  protected createSiteStaticAssetDeployment(): void;
154
153
  /**
155
- * @summary Create the IAM policy for the site Lambda function
154
+ * @summary Create the IAM policy for the site Lambda function.
155
+ * Defaults to an empty document — CloudWatch Logs access is supplied by
156
+ * `AWSLambdaBasicExecutionRole` which `createRoleForLambda` attaches separately.
157
+ * Consumers granting the Lambda access to specific resources should set
158
+ * `siteLambdaAdditionalPolicyStatements` rather than override this method.
156
159
  */
157
160
  protected createSiteLambdaPolicy(): void;
158
161
  /**
@@ -1,6 +1,6 @@
1
1
  import { Duration, Fn } from 'aws-cdk-lib';
2
2
  import { CachePolicy, FunctionEventType, OriginProtocolPolicy, OriginRequestPolicy, ResponseHeadersPolicy, } from 'aws-cdk-lib/aws-cloudfront';
3
- import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
3
+ import { FunctionUrlOrigin, HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
4
4
  import { AnyPrincipal, Effect, PolicyDocument, PolicyStatement } from 'aws-cdk-lib/aws-iam';
5
5
  import { Function, FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda';
6
6
  import _ from 'lodash';
@@ -37,7 +37,7 @@ export class SiteWithLambdaBackend extends CommonConstruct {
37
37
  siteSecrets;
38
38
  /** The S3 bucket used for CloudFront access logs */
39
39
  siteLogBucket;
40
- /** The HTTP origin backed by the Lambda function URL */
40
+ /** The CloudFront origin backed by the Lambda function URL */
41
41
  siteOrigin;
42
42
  /** The CloudFront distribution for the site */
43
43
  siteDistribution;
@@ -253,11 +253,21 @@ export class SiteWithLambdaBackend extends CommonConstruct {
253
253
  */
254
254
  createSiteOrigin() {
255
255
  this.createSiteOriginResources();
256
- this.siteOrigin = new HttpOrigin(Fn.select(2, Fn.split('/', this.siteLambdaUrl.url)), {
257
- httpPort: 443,
258
- originId: `${this.id}-server`,
259
- protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
260
- });
256
+ const authType = this.props.siteLambdaUrlAuthType ?? FunctionUrlAuthType.AWS_IAM;
257
+ if (authType === FunctionUrlAuthType.AWS_IAM) {
258
+ /* CloudFront signs requests to the Function URL via an automatically-provisioned
259
+ Origin Access Control. The OAC also attaches a scoped lambda:InvokeFunctionUrl
260
+ resource policy permitting only cloudfront.amazonaws.com sourced from this
261
+ distribution ARN. */
262
+ this.siteOrigin = FunctionUrlOrigin.withOriginAccessControl(this.siteLambdaUrl);
263
+ }
264
+ else {
265
+ this.siteOrigin = new HttpOrigin(Fn.select(2, Fn.split('/', this.siteLambdaUrl.url)), {
266
+ httpPort: 443,
267
+ originId: `${this.id}-server`,
268
+ protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
269
+ });
270
+ }
261
271
  }
262
272
  /**
263
273
  * @summary Orchestrate creation of all Lambda-based origin resources
@@ -277,17 +287,15 @@ export class SiteWithLambdaBackend extends CommonConstruct {
277
287
  */
278
288
  createSiteStaticAssetDeployment() { }
279
289
  /**
280
- * @summary Create the IAM policy for the site Lambda function
290
+ * @summary Create the IAM policy for the site Lambda function.
291
+ * Defaults to an empty document — CloudWatch Logs access is supplied by
292
+ * `AWSLambdaBasicExecutionRole` which `createRoleForLambda` attaches separately.
293
+ * Consumers granting the Lambda access to specific resources should set
294
+ * `siteLambdaAdditionalPolicyStatements` rather than override this method.
281
295
  */
282
296
  createSiteLambdaPolicy() {
283
297
  this.siteLambdaPolicy = new PolicyDocument({
284
- statements: [
285
- new PolicyStatement({
286
- actions: ['lambda:InvokeFunctionUrl'],
287
- effect: Effect.ALLOW,
288
- resources: ['*'],
289
- }),
290
- ],
298
+ statements: [...(this.props.siteLambdaAdditionalPolicyStatements ?? [])],
291
299
  });
292
300
  }
293
301
  /**
@@ -343,22 +351,32 @@ export class SiteWithLambdaBackend extends CommonConstruct {
343
351
  })
344
352
  : this.siteLambdaFunction;
345
353
  lambdaFn.node.addDependency(this.siteLambdaFunction);
346
- /* Explicit dependencies ensure the function and alias exist before the URL is created */
347
- this.siteLambdaUrl = lambdaFn.addFunctionUrl({
348
- authType: FunctionUrlAuthType.NONE,
349
- });
354
+ /* Explicit dependencies ensure the function and alias exist before the URL is created.
355
+ Default to AWS_IAM so the URL is reachable only via the CloudFront distribution
356
+ (signed through Origin Access Control) and not as a public endpoint. */
357
+ const authType = this.props.siteLambdaUrlAuthType ?? FunctionUrlAuthType.AWS_IAM;
358
+ this.siteLambdaUrl = lambdaFn.addFunctionUrl({ authType });
350
359
  this.siteLambdaUrl.node.addDependency(this.siteLambdaFunction);
351
360
  this.siteLambdaUrl.node.addDependency(lambdaFn);
352
- /* Grant public invoke access the resource-based policy is applied via
353
- grantInvokeUrl, restricted by the FunctionUrlAuthType condition */
354
- const principal = new AnyPrincipal();
355
- principal.addToPolicy(new PolicyStatement({
356
- actions: ['lambda:InvokeFunctionUrl'],
357
- conditions: { StringEquals: { 'lambda:FunctionUrlAuthType': FunctionUrlAuthType.NONE } },
358
- effect: Effect.ALLOW,
359
- resources: ['*'],
360
- }));
361
- lambdaFn.grantInvokeUrl({ grantPrincipal: principal });
361
+ /* When the consumer explicitly opts into a public URL (authType=NONE), preserve the
362
+ previous behaviour and grant invoke access to the configured grantees
363
+ (defaulting to AnyPrincipal). When AWS_IAM is in effect, the resource policy is
364
+ added automatically by FunctionUrlOrigin.withOriginAccessControl, scoped to the
365
+ distribution ARN. */
366
+ if (authType === FunctionUrlAuthType.NONE) {
367
+ const grantees = this.props.siteLambdaUrlInvokeGrantees ?? [new AnyPrincipal()];
368
+ for (const grantee of grantees) {
369
+ if (grantee instanceof AnyPrincipal) {
370
+ grantee.addToPolicy(new PolicyStatement({
371
+ actions: ['lambda:InvokeFunctionUrl'],
372
+ conditions: { StringEquals: { 'lambda:FunctionUrlAuthType': FunctionUrlAuthType.NONE } },
373
+ effect: Effect.ALLOW,
374
+ resources: ['*'],
375
+ }));
376
+ }
377
+ lambdaFn.grantInvokeUrl({ grantPrincipal: grantee });
378
+ }
379
+ }
362
380
  this.addCfnOutput(`${this.id}-url`, this.siteLambdaUrl.url);
363
381
  }
364
382
  /**
@@ -1,4 +1,6 @@
1
1
  import { CachePolicyProps, OriginRequestPolicyProps, ResponseHeadersPolicyProps, ResponseHeadersStrictTransportSecurity, ResponseSecurityHeadersBehavior } from 'aws-cdk-lib/aws-cloudfront';
2
+ import { IPrincipal, PolicyStatement } from 'aws-cdk-lib/aws-iam';
3
+ import { FunctionUrlAuthType } from 'aws-cdk-lib/aws-lambda';
2
4
  import { CommonStackProps } from '../../common/index.js';
3
5
  import { AcmProps, CloudfrontFunctionProps, DistributionProps, LambdaProps, LogProps, S3BucketProps } from '../../services/index.js';
4
6
  import { SiteWithLambdaBackendResponseHeaderPolicyType } from './constants.js';
@@ -27,6 +29,26 @@ export interface SiteWithLambdaBackendProps extends CommonStackProps {
27
29
  siteHealthEndpoint: string;
28
30
  /** Configuration for the site Lambda function */
29
31
  siteLambda: LambdaProps;
32
+ /**
33
+ * Additional IAM policy statements to attach to the site Lambda execution role.
34
+ * Defaults to none — the role only has the CloudWatch Logs permissions granted by
35
+ * `AWSLambdaBasicExecutionRole`. Use this to grant the Lambda access to specific
36
+ * resources (e.g. invoking a sibling Function URL scoped to its ARN).
37
+ */
38
+ siteLambdaAdditionalPolicyStatements?: PolicyStatement[];
39
+ /**
40
+ * Auth type for the site Lambda Function URL.
41
+ * Defaults to `FunctionUrlAuthType.AWS_IAM` so the URL is reachable only via the
42
+ * CloudFront distribution signed through Origin Access Control. Set to
43
+ * `FunctionUrlAuthType.NONE` to publish a public unauthenticated URL.
44
+ */
45
+ siteLambdaUrlAuthType?: FunctionUrlAuthType;
46
+ /**
47
+ * Principals permitted to invoke the Function URL when `siteLambdaUrlAuthType` is
48
+ * `FunctionUrlAuthType.NONE`. Defaults to `[new AnyPrincipal()]` for backwards
49
+ * compatibility. Ignored when the auth type is `AWS_IAM`.
50
+ */
51
+ siteLambdaUrlInvokeGrantees?: IPrincipal[];
30
52
  /** Configuration for the site log group */
31
53
  siteLog: LogProps;
32
54
  /** Configuration for the S3 bucket used for access logs */
@@ -1,7 +1,6 @@
1
1
  import { ICertificate } from 'aws-cdk-lib/aws-certificatemanager';
2
2
  import * as cf from 'aws-cdk-lib/aws-cloudfront';
3
- import { DistributionAttributes, FunctionAssociation, IDistribution, IResponseHeadersPolicyRef, OriginAccessIdentity } from 'aws-cdk-lib/aws-cloudfront';
4
- import { HttpOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
3
+ import { DistributionAttributes, FunctionAssociation, IDistribution, IOrigin, IResponseHeadersPolicyRef, OriginAccessIdentity } from 'aws-cdk-lib/aws-cloudfront';
5
4
  import { ISecurityGroup, IVpc } from 'aws-cdk-lib/aws-ec2';
6
5
  import { IAccessPoint } from 'aws-cdk-lib/aws-efs';
7
6
  import { Role } from 'aws-cdk-lib/aws-iam';
@@ -67,7 +66,7 @@ export declare class CloudFrontManager {
67
66
  * @param defaultFunctionAssociations optional CloudFront function associations for the default behavior
68
67
  * @param responseHeadersPolicy optional response headers policy for the default behavior
69
68
  */
70
- createDistributionWithHttpOrigin(id: string, scope: CommonConstruct, props: DistributionProps, origin: HttpOrigin, domainNames: string[], logBucket?: IBucket, certificate?: ICertificate, defaultFunctionAssociations?: FunctionAssociation[], responseHeadersPolicy?: IResponseHeadersPolicyRef): cf.Distribution;
69
+ createDistributionWithHttpOrigin(id: string, scope: CommonConstruct, props: DistributionProps, origin: IOrigin, domainNames: string[], logBucket?: IBucket, certificate?: ICertificate, defaultFunctionAssociations?: FunctionAssociation[], responseHeadersPolicy?: IResponseHeadersPolicyRef): cf.Distribution;
71
70
  /**
72
71
  * @summary Method to provision a Lambda@Edge function
73
72
  * @param id scoped id of the resource
@@ -1,4 +1,4 @@
1
- import { Duration } from 'aws-cdk-lib';
1
+ import { Duration, Stack } from 'aws-cdk-lib';
2
2
  import { BuildSpec, ComputeType, LinuxBuildImage, Project } from 'aws-cdk-lib/aws-codebuild';
3
3
  /**
4
4
  * Provides operations on AWS Code Build.
@@ -37,6 +37,11 @@ export class CodeBuildManager {
37
37
  */
38
38
  createProjectForCloudfrontInvalidation(id, scope, dockerFilepath, distributionId, paths) {
39
39
  const invalidationPaths = paths ?? '/*';
40
+ const stack = Stack.of(scope);
41
+ const distributionArn = `arn:${stack.partition}:cloudfront::${stack.account}:distribution/${distributionId}`;
42
+ const logGroup = scope.logManager.createLogGroup(`${id}-project-log-group`, scope, {
43
+ logGroupName: `${id}-cloudfront-invalidation`,
44
+ });
40
45
  return new Project(scope, `${id}-install-deps-project`, {
41
46
  buildSpec: BuildSpec.fromObject({
42
47
  phases: {
@@ -56,12 +61,10 @@ export class CodeBuildManager {
56
61
  logging: {
57
62
  cloudWatch: {
58
63
  enabled: true,
59
- logGroup: scope.logManager.createLogGroup(`${id}-project-log-group`, scope, {
60
- logGroupName: `${id}-cloudfront-invalidation`,
61
- }),
64
+ logGroup,
62
65
  },
63
66
  },
64
- role: scope.iamManager.createRoleForCloudfrontInvalidation(id, scope),
67
+ role: scope.iamManager.createRoleForCloudfrontInvalidation(id, scope, [distributionArn], [logGroup.logGroupArn]),
65
68
  timeout: Duration.minutes(5),
66
69
  });
67
70
  }
@@ -28,47 +28,47 @@ export declare class IamManager {
28
28
  * @param scope scope in which this resource is defined
29
29
  * @param resourceArns list of ARNs to allow access to
30
30
  */
31
- statementForReadSecrets(scope: CommonConstruct, resourceArns?: string[]): PolicyStatement;
31
+ statementForReadSecrets(scope: CommonConstruct, resourceArns: string[]): PolicyStatement;
32
32
  /**
33
33
  * @summary Method to create iam statement to put events
34
34
  * @param resourceArns list of ARNs to allow access to
35
35
  */
36
- statementForPutEvents(resourceArns?: string[]): PolicyStatement;
36
+ statementForPutEvents(resourceArns: string[]): PolicyStatement;
37
37
  /**
38
38
  * @summary Method to create iam statement to start step function execution
39
39
  * @param resourceArns list of ARNs to allow access to
40
40
  */
41
- statementForStartExecution(resourceArns?: string[]): PolicyStatement;
41
+ statementForStartExecution(resourceArns: string[]): PolicyStatement;
42
42
  /**
43
43
  * @summary Method to create iam statement to poll queue
44
44
  * @param resourceArns list of ARNs to allow access to
45
45
  */
46
- statementForPollQueue(resourceArns?: string[]): PolicyStatement;
46
+ statementForPollQueue(resourceArns: string[]): PolicyStatement;
47
47
  /**
48
48
  * @summary Method to create iam statement to invoke lambda function
49
49
  * @param resourceArns list of ARNs to allow access to
50
50
  */
51
- statementForInvokeLambda(resourceArns?: string[]): PolicyStatement;
51
+ statementForInvokeLambda(resourceArns: string[]): PolicyStatement;
52
52
  /**
53
53
  * @summary Method to create iam statement to read app config
54
54
  * @param resourceArns list of ARNs to allow access to
55
55
  */
56
- statementForReadAnyAppConfig(resourceArns?: string[]): PolicyStatement;
56
+ statementForReadAnyAppConfig(resourceArns: string[]): PolicyStatement;
57
57
  /**
58
58
  * @summary Method to create iam statement to access app config
59
59
  * @param resourceArns list of ARNs to allow access to
60
60
  */
61
- statementForAppConfigExecution(resourceArns?: string[]): PolicyStatement;
61
+ statementForAppConfigExecution(resourceArns: string[]): PolicyStatement;
62
62
  /**
63
63
  * @summary Method to create iam statement to put xray telemetry
64
64
  * @param resourceArns list of ARNs to allow access to
65
65
  */
66
- statementForPutXrayTelemetry(resourceArns?: string[]): PolicyStatement;
66
+ statementForPutXrayTelemetry(resourceArns: string[]): PolicyStatement;
67
67
  /**
68
68
  * @summary Method to create iam statement to decrypt kms
69
69
  * @param resourceArns list of ARNs to allow access to
70
70
  */
71
- statementForDecryptKms(resourceArns?: string[]): PolicyStatement;
71
+ statementForDecryptKms(resourceArns: string[]): PolicyStatement;
72
72
  /**
73
73
  * @summary Method to create iam statement to list s3 buckets
74
74
  * @param scope scope in which this resource is defined
@@ -79,7 +79,7 @@ export declare class IamManager {
79
79
  * @summary Method to create iam statement to list all s3 buckets
80
80
  * @param resourceArns list of ARNs to allow access to
81
81
  */
82
- statementForListAllMyBuckets(resourceArns?: string[]): PolicyStatement;
82
+ statementForListAllMyBuckets(resourceArns: string[]): PolicyStatement;
83
83
  /**
84
84
  * @summary Method to create iam statement to get s3 objects in buckets
85
85
  * @param scope scope in which this resource is defined
@@ -105,17 +105,17 @@ export declare class IamManager {
105
105
  * @summary Method to create iam statement to pass iam role
106
106
  * @param resourceArns list of ARNs to allow access to
107
107
  */
108
- statementForPassRole(resourceArns?: string[]): PolicyStatement;
108
+ statementForPassRole(resourceArns: string[]): PolicyStatement;
109
109
  /**
110
110
  * @summary Method to create iam statement to invalidate cloudfront cache
111
111
  * @param resourceArns list of ARNs to allow access to
112
112
  */
113
- statementForCloudfrontInvalidation(resourceArns?: string[]): PolicyStatement;
113
+ statementForCloudfrontInvalidation(resourceArns: string[]): PolicyStatement;
114
114
  /**
115
115
  * @summary Method to create iam statement to access efs
116
116
  * @param resourceArns list of ARNs to allow access to
117
117
  */
118
- statementForWriteEfs(resourceArns?: string[]): PolicyStatement;
118
+ statementForWriteEfs(resourceArns: string[]): PolicyStatement;
119
119
  /**
120
120
  * @summary Method to create iam statement to assume iam role
121
121
  * @param scope scope in which this resource is defined
@@ -126,7 +126,7 @@ export declare class IamManager {
126
126
  * @summary Method to create iam statement to pass ecs role
127
127
  * @param resourceArns list of ARNs to allow access to
128
128
  */
129
- statementForEcsPassRole(resourceArns?: string[]): PolicyStatement;
129
+ statementForEcsPassRole(resourceArns: string[]): PolicyStatement;
130
130
  /**
131
131
  * @summary Method to create iam statement to run ecs task
132
132
  * @param scope scope in which this resource is defined
@@ -144,7 +144,7 @@ export declare class IamManager {
144
144
  * @summary Method to create iam statement to create any log stream
145
145
  * @param resourceArns list of ARNs to allow access to
146
146
  */
147
- statementForCreateAnyLogStream(resourceArns?: string[]): PolicyStatement;
147
+ statementForCreateAnyLogStream(resourceArns: string[]): PolicyStatement;
148
148
  /**
149
149
  * @summary Method to create iam statement to write log events
150
150
  * @param scope scope in which this resource is defined
@@ -155,27 +155,28 @@ export declare class IamManager {
155
155
  * @summary Method to create iam statement to write any log events
156
156
  * @param resourceArns list of ARNs to allow access to
157
157
  */
158
- statementForPutAnyLogEvent(resourceArns?: string[]): PolicyStatement;
158
+ statementForPutAnyLogEvent(resourceArns: string[]): PolicyStatement;
159
159
  /**
160
160
  * @summary Method to create iam statement to read items from dynamodb table
161
161
  * @param resourceArns list of ARNs to allow access to
162
162
  */
163
- statementForReadTableItems(resourceArns?: string[]): PolicyStatement;
163
+ statementForReadTableItems(resourceArns: string[]): PolicyStatement;
164
164
  /**
165
165
  * @summary Method to create iam statement to write items from dynamodb table
166
166
  * @param resourceArns list of ARNs to allow access to
167
167
  */
168
- statementForWriteTableItems(resourceArns?: string[]): PolicyStatement;
168
+ statementForWriteTableItems(resourceArns: string[]): PolicyStatement;
169
169
  /**
170
170
  * @summary Method to create iam statement to poll from dynamodb table
171
171
  * @param resourceArns list of ARNs to allow access to
172
172
  */
173
- statementFordynamoDbStream(resourceArns?: string[]): PolicyStatement;
173
+ statementFordynamoDbStream(resourceArns: string[]): PolicyStatement;
174
174
  /**
175
175
  * @summary Method to create iam policy to invalidate cloudfront cache
176
- * @param resourceArns list of ARNs to allow access to
176
+ * @param distributionArns CloudFront distribution ARNs to allow invalidation against
177
+ * @param logGroupArns CloudWatch log group ARNs the CodeBuild project writes to
177
178
  */
178
- createPolicyForCloudfrontInvalidation(resourceArns?: string[]): PolicyDocument;
179
+ createPolicyForCloudfrontInvalidation(distributionArns: string[], logGroupArns: string[]): PolicyDocument;
179
180
  /**
180
181
  * @summary Method to create iam policy for SQS event processing
181
182
  * @param id scoped id of the resource
@@ -189,8 +190,10 @@ export declare class IamManager {
189
190
  * @summary Method to create iam role to invalidate cloudfront cache
190
191
  * @param id scoped id of the resource
191
192
  * @param scope scope in which this resource is defined
193
+ * @param distributionArns CloudFront distribution ARNs to allow invalidation against
194
+ * @param logGroupArns CloudWatch log group ARNs the CodeBuild project writes to
192
195
  */
193
- createRoleForCloudfrontInvalidation(id: string, scope: CommonConstruct): Role;
196
+ createRoleForCloudfrontInvalidation(id: string, scope: CommonConstruct, distributionArns: string[], logGroupArns: string[]): Role;
194
197
  /**
195
198
  * @summary Method to create iam role for CloudTrail
196
199
  * @param id scoped id of the resource
@@ -28,9 +28,7 @@ export class IamManager {
28
28
  return new PolicyStatement({
29
29
  actions: ['secretsmanager:GetSecretValue'],
30
30
  effect: Effect.ALLOW,
31
- resources: resourceArns ?? [
32
- `arn:aws:secretsmanager:${Stack.of(scope).region}:${Stack.of(scope).account}:secret:*`,
33
- ],
31
+ resources: resourceArns,
34
32
  });
35
33
  }
36
34
  /**
@@ -41,7 +39,7 @@ export class IamManager {
41
39
  return new PolicyStatement({
42
40
  actions: ['events:PutEvents'],
43
41
  effect: Effect.ALLOW,
44
- resources: resourceArns ?? ['*'],
42
+ resources: resourceArns,
45
43
  });
46
44
  }
47
45
  /**
@@ -52,7 +50,7 @@ export class IamManager {
52
50
  return new PolicyStatement({
53
51
  actions: ['states:StartExecution'],
54
52
  effect: Effect.ALLOW,
55
- resources: resourceArns ?? ['*'],
53
+ resources: resourceArns,
56
54
  });
57
55
  }
58
56
  /**
@@ -63,7 +61,7 @@ export class IamManager {
63
61
  return new PolicyStatement({
64
62
  actions: ['sqs:ReceiveMessage', 'sqs:DeleteMessage', 'sqs:GetQueueAttributes'],
65
63
  effect: Effect.ALLOW,
66
- resources: resourceArns ?? ['*'],
64
+ resources: resourceArns,
67
65
  });
68
66
  }
69
67
  /**
@@ -74,7 +72,7 @@ export class IamManager {
74
72
  return new PolicyStatement({
75
73
  actions: ['lambda:InvokeFunction'],
76
74
  effect: Effect.ALLOW,
77
- resources: resourceArns ?? ['*'],
75
+ resources: resourceArns,
78
76
  });
79
77
  }
80
78
  /**
@@ -98,7 +96,7 @@ export class IamManager {
98
96
  'appconfig:ListDeployments',
99
97
  ],
100
98
  effect: Effect.ALLOW,
101
- resources: resourceArns ?? ['*'],
99
+ resources: resourceArns,
102
100
  });
103
101
  }
104
102
  /**
@@ -109,7 +107,7 @@ export class IamManager {
109
107
  return new PolicyStatement({
110
108
  actions: ['appconfig:GetLatestConfiguration', 'appconfig:StartConfigurationSession'],
111
109
  effect: Effect.ALLOW,
112
- resources: resourceArns ?? ['*'],
110
+ resources: resourceArns,
113
111
  });
114
112
  }
115
113
  /**
@@ -120,7 +118,7 @@ export class IamManager {
120
118
  return new PolicyStatement({
121
119
  actions: ['xray:PutTraceSegments', 'xray:PutTelemetryRecords'],
122
120
  effect: Effect.ALLOW,
123
- resources: resourceArns ?? ['*'],
121
+ resources: resourceArns,
124
122
  });
125
123
  }
126
124
  /**
@@ -131,7 +129,7 @@ export class IamManager {
131
129
  return new PolicyStatement({
132
130
  actions: ['kms:Decrypt'],
133
131
  effect: Effect.ALLOW,
134
- resources: resourceArns ?? ['*'],
132
+ resources: resourceArns,
135
133
  });
136
134
  }
137
135
  /**
@@ -154,7 +152,7 @@ export class IamManager {
154
152
  return new PolicyStatement({
155
153
  actions: ['s3:ListAllMyBuckets'],
156
154
  effect: Effect.ALLOW,
157
- resources: resourceArns ?? ['*'],
155
+ resources: resourceArns,
158
156
  });
159
157
  }
160
158
  /**
@@ -167,6 +165,7 @@ export class IamManager {
167
165
  return new PolicyStatement({
168
166
  actions: ['s3:GetObject', 's3:GetObjectAcl'],
169
167
  effect: Effect.ALLOW,
168
+ /* defaults to the supplied bucket's objects - already scoped, not a wildcard */
170
169
  resources: resourceArns ?? [bucket.arnForObjects(`*`)],
171
170
  });
172
171
  }
@@ -180,6 +179,7 @@ export class IamManager {
180
179
  return new PolicyStatement({
181
180
  actions: ['s3:DeleteObject'],
182
181
  effect: Effect.ALLOW,
182
+ /* defaults to the supplied bucket's objects - already scoped, not a wildcard */
183
183
  resources: resourceArns ?? [bucket.arnForObjects(`*`)],
184
184
  });
185
185
  }
@@ -193,6 +193,7 @@ export class IamManager {
193
193
  return new PolicyStatement({
194
194
  actions: ['s3:PutObject', 's3:PutObjectAcl'],
195
195
  effect: Effect.ALLOW,
196
+ /* defaults to the supplied bucket's objects - already scoped, not a wildcard */
196
197
  resources: resourceArns ?? [bucket.arnForObjects(`*`)],
197
198
  });
198
199
  }
@@ -204,7 +205,7 @@ export class IamManager {
204
205
  return new PolicyStatement({
205
206
  actions: ['iam:PassRole'],
206
207
  effect: Effect.ALLOW,
207
- resources: resourceArns ?? ['*'],
208
+ resources: resourceArns,
208
209
  });
209
210
  }
210
211
  /**
@@ -215,7 +216,7 @@ export class IamManager {
215
216
  return new PolicyStatement({
216
217
  actions: ['cloudfront:GetInvalidation', 'cloudfront:CreateInvalidation'],
217
218
  effect: Effect.ALLOW,
218
- resources: resourceArns ?? ['*'],
219
+ resources: resourceArns,
219
220
  });
220
221
  }
221
222
  /**
@@ -226,7 +227,7 @@ export class IamManager {
226
227
  return new PolicyStatement({
227
228
  actions: ['elasticfilesystem:*'],
228
229
  effect: Effect.ALLOW,
229
- resources: resourceArns ?? ['*'],
230
+ resources: resourceArns,
230
231
  });
231
232
  }
232
233
  /**
@@ -250,7 +251,7 @@ export class IamManager {
250
251
  actions: ['iam:PassRole'],
251
252
  conditions: { StringLike: { 'iam:PassedToService': 'ecs-tasks.amazonaws.com' } },
252
253
  effect: Effect.ALLOW,
253
- resources: resourceArns ?? ['*'],
254
+ resources: resourceArns,
254
255
  });
255
256
  }
256
257
  /**
@@ -293,7 +294,7 @@ export class IamManager {
293
294
  return new PolicyStatement({
294
295
  actions: ['logs:CreateLogStream'],
295
296
  effect: Effect.ALLOW,
296
- resources: resourceArns ?? ['*'],
297
+ resources: resourceArns,
297
298
  });
298
299
  }
299
300
  /**
@@ -321,7 +322,7 @@ export class IamManager {
321
322
  return new PolicyStatement({
322
323
  actions: ['logs:PutLogEvents'],
323
324
  effect: Effect.ALLOW,
324
- resources: resourceArns ?? ['*'],
325
+ resources: resourceArns,
325
326
  });
326
327
  }
327
328
  /**
@@ -341,7 +342,7 @@ export class IamManager {
341
342
  'dynamodb:BatchGetItem',
342
343
  ],
343
344
  effect: Effect.ALLOW,
344
- resources: resourceArns ?? ['*'],
345
+ resources: resourceArns,
345
346
  });
346
347
  }
347
348
  /**
@@ -352,7 +353,7 @@ export class IamManager {
352
353
  return new PolicyStatement({
353
354
  actions: ['dynamodb:BatchWriteItem', 'dynamodb:DeleteItem', 'dynamodb:PutItem', 'dynamodb:UpdateItem'],
354
355
  effect: Effect.ALLOW,
355
- resources: resourceArns ?? ['*'],
356
+ resources: resourceArns,
356
357
  });
357
358
  }
358
359
  /**
@@ -363,19 +364,20 @@ export class IamManager {
363
364
  return new PolicyStatement({
364
365
  actions: ['dynamodb:DescribeStream', 'dynamodb:GetRecords', 'dynamodb:GetShardIterator', 'dynamodb:ListStreams'],
365
366
  effect: Effect.ALLOW,
366
- resources: resourceArns ?? ['*'],
367
+ resources: resourceArns,
367
368
  });
368
369
  }
369
370
  /**
370
371
  * @summary Method to create iam policy to invalidate cloudfront cache
371
- * @param resourceArns list of ARNs to allow access to
372
+ * @param distributionArns CloudFront distribution ARNs to allow invalidation against
373
+ * @param logGroupArns CloudWatch log group ARNs the CodeBuild project writes to
372
374
  */
373
- createPolicyForCloudfrontInvalidation(resourceArns) {
375
+ createPolicyForCloudfrontInvalidation(distributionArns, logGroupArns) {
374
376
  return new PolicyDocument({
375
377
  statements: [
376
- this.statementForCreateAnyLogStream(),
377
- this.statementForPutAnyLogEvent(),
378
- this.statementForCloudfrontInvalidation(),
378
+ this.statementForCreateAnyLogStream(logGroupArns),
379
+ this.statementForPutAnyLogEvent(logGroupArns),
380
+ this.statementForCloudfrontInvalidation(distributionArns),
379
381
  new PolicyStatement({
380
382
  actions: [
381
383
  'ecr:GetDownloadUrlForLayer',
@@ -384,7 +386,9 @@ export class IamManager {
384
386
  'ecr:GetAuthorizationToken',
385
387
  ],
386
388
  effect: Effect.ALLOW,
387
- resources: resourceArns ?? ['*'],
389
+ /* ecr:GetAuthorizationToken does not support resource-level IAM and must
390
+ use Resource:* per AWS docs; the other ECR actions inherit the same. */
391
+ resources: ['*'],
388
392
  }),
389
393
  ],
390
394
  });
@@ -418,12 +422,14 @@ export class IamManager {
418
422
  * @summary Method to create iam role to invalidate cloudfront cache
419
423
  * @param id scoped id of the resource
420
424
  * @param scope scope in which this resource is defined
425
+ * @param distributionArns CloudFront distribution ARNs to allow invalidation against
426
+ * @param logGroupArns CloudWatch log group ARNs the CodeBuild project writes to
421
427
  */
422
- createRoleForCloudfrontInvalidation(id, scope) {
428
+ createRoleForCloudfrontInvalidation(id, scope, distributionArns, logGroupArns) {
423
429
  return new Role(scope, `${id}-install-deps-project-role`, {
424
430
  assumedBy: new ServicePrincipal('codebuild.amazonaws.com'),
425
431
  inlinePolicies: {
426
- codeBuildPolicy: this.createPolicyForCloudfrontInvalidation(),
432
+ codeBuildPolicy: this.createPolicyForCloudfrontInvalidation(distributionArns, logGroupArns),
427
433
  },
428
434
  roleName: scope.resourceNameFormatter.format(`${id}-cf-invalidation`, scope.props.resourceNameOptions?.iam),
429
435
  });
@@ -463,7 +469,13 @@ export class IamManager {
463
469
  */
464
470
  createRoleForEcsEvent(id, scope, cluster, task) {
465
471
  const policy = new PolicyDocument({
466
- statements: [this.statementForRunEcsTask(scope, cluster, task), this.statementForEcsPassRole()],
472
+ statements: [
473
+ this.statementForRunEcsTask(scope, cluster, task),
474
+ /* iam:PassRole condition (PassedToService=ecs-tasks) already limits which roles
475
+ the EventBridge target can pass; resource scope kept wildcard to allow any
476
+ ECS task role the consumer wires up */
477
+ this.statementForEcsPassRole(['*']),
478
+ ],
467
479
  });
468
480
  const role = new Role(scope, `${id}`, {
469
481
  assumedBy: new ServicePrincipal('events.amazonaws.com'),
@@ -506,7 +518,9 @@ export class IamManager {
506
518
  const role = new Role(scope, `${id}`, {
507
519
  assumedBy: servicePrincipal ?? new ServicePrincipal('lambda.amazonaws.com'),
508
520
  description: `Role for ${id} Lambda function`,
509
- inlinePolicies: { policy },
521
+ /* skip the inline policy when empty - CDK rejects inlinePolicies entries
522
+ without statements */
523
+ inlinePolicies: policy.isEmpty ? undefined : { policy },
510
524
  managedPolicies: [
511
525
  ManagedPolicy.fromManagedPolicyArn(scope, `${id}-AWSLambdaBasicExecutionRole`, 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'),
512
526
  ],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradientedge/cdk-utils-aws",
3
- "version": "2.17.0",
3
+ "version": "2.19.0",
4
4
  "description": "AWS CDK utilities for @gradientedge/cdk-utils",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -14,17 +14,17 @@
14
14
  "dist/src/"
15
15
  ],
16
16
  "dependencies": {
17
- "@aws-sdk/client-secrets-manager": "3.1060.0",
18
- "@aws-sdk/credential-providers": "3.1060.0",
19
- "@aws-sdk/types": "3.973.10",
17
+ "@aws-sdk/client-secrets-manager": "3.1064.0",
18
+ "@aws-sdk/credential-providers": "3.1064.0",
19
+ "@aws-sdk/types": "3.973.12",
20
20
  "@types/lodash": "4.17.24",
21
21
  "app-root-path": "3.1.0",
22
- "aws-cdk-lib": "2.257.0",
22
+ "aws-cdk-lib": "2.258.1",
23
23
  "constructs": "10.6.0",
24
24
  "lodash": "4.18.1",
25
25
  "moment": "2.30.1",
26
26
  "uuid": "14.0.0",
27
- "@gradientedge/cdk-utils-common": "2.10.0"
27
+ "@gradientedge/cdk-utils-common": "2.11.0"
28
28
  },
29
29
  "keywords": [
30
30
  "gradientedge",