konokenj.cdk-api-mcp-server 0.50.0__py3-none-any.whl → 0.52.0__py3-none-any.whl
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.
Potentially problematic release.
This version of konokenj.cdk-api-mcp-server might be problematic. Click here for more details.
- cdk_api_mcp_server/__about__.py +1 -1
- cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-bedrock-agentcore-alpha/README.md +327 -5
- cdk_api_mcp_server/resources/aws-cdk/constructs/@aws-cdk/aws-msk-alpha/README.md +30 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigateway/README.md +9 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigateway/integ.spec-restapi.ts +1 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2/README.md +93 -81
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-apigatewayv2/integ.stage.ts +20 -4
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-codepipeline-actions/integ.pipeline-elastic-beanstalk-deploy.ts +4 -1
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/README.md +53 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.dynamodb.add-to-resource-policy.ts +80 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.dynamodb.policy.ts +21 -1
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-ec2/integ.vpc-flow-logs.ts +4 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-elasticloadbalancingv2/README.md +34 -4
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-elasticloadbalancingv2/integ.nlb.security-group.ts +70 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events-targets/README.md +22 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events-targets/integ.firehose-delivery-stream.ts +51 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-iam/integ.managed-policy.ts +9 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-iam/integ.policy.ts +9 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-kinesisfirehose/README.md +60 -3
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-kinesisfirehose/integ.cloudwatch-logs-processors.ts +45 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-lambda/integ.runtime.fromasset.ts +19 -4
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-lambda/integ.runtime.inlinecode.ts +7 -0
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/cx-api/FEATURE_FLAGS.md +32 -13
- {konokenj_cdk_api_mcp_server-0.50.0.dist-info → konokenj_cdk_api_mcp_server-0.52.0.dist-info}/METADATA +2 -2
- {konokenj_cdk_api_mcp_server-0.50.0.dist-info → konokenj_cdk_api_mcp_server-0.52.0.dist-info}/RECORD +28 -25
- cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-events-targets/integ.kinesis-firehose-stream.ts +0 -33
- {konokenj_cdk_api_mcp_server-0.50.0.dist-info → konokenj_cdk_api_mcp_server-0.52.0.dist-info}/WHEEL +0 -0
- {konokenj_cdk_api_mcp_server-0.50.0.dist-info → konokenj_cdk_api_mcp_server-0.52.0.dist-info}/entry_points.txt +0 -0
- {konokenj_cdk_api_mcp_server-0.50.0.dist-info → konokenj_cdk_api_mcp_server-0.52.0.dist-info}/licenses/LICENSE.txt +0 -0
|
@@ -5,7 +5,7 @@ import * as iam from 'aws-cdk-lib/aws-iam';
|
|
|
5
5
|
import { IManagedPolicy, ManagedPolicyReference } from 'aws-cdk-lib/aws-iam';
|
|
6
6
|
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
7
7
|
import * as deploy from 'aws-cdk-lib/aws-s3-deployment';
|
|
8
|
-
import { App, Fn, RemovalPolicy, Stack, UnscopedValidationError } from 'aws-cdk-lib';
|
|
8
|
+
import { App, Fn, RemovalPolicy, ResourceEnvironment, Stack, UnscopedValidationError } from 'aws-cdk-lib';
|
|
9
9
|
import * as integ from '@aws-cdk/integ-tests-alpha';
|
|
10
10
|
import * as cpactions from 'aws-cdk-lib/aws-codepipeline-actions';
|
|
11
11
|
import { Node } from 'constructs';
|
|
@@ -56,6 +56,9 @@ function makePolicy(arn: string): IManagedPolicy {
|
|
|
56
56
|
get node(): Node {
|
|
57
57
|
throw new UnscopedValidationError('The result of fromAwsManagedPolicyName can not be used in this API');
|
|
58
58
|
},
|
|
59
|
+
get env(): ResourceEnvironment {
|
|
60
|
+
throw new UnscopedValidationError('The result of fromAwsManagedPolicyName can not be used in this API');
|
|
61
|
+
},
|
|
59
62
|
};
|
|
60
63
|
}
|
|
61
64
|
|
|
@@ -816,6 +816,59 @@ Using `resourcePolicy` you can add a [resource policy](https://docs.aws.amazon.c
|
|
|
816
816
|
});
|
|
817
817
|
```
|
|
818
818
|
|
|
819
|
+
### Adding Resource Policy Statements Dynamically
|
|
820
|
+
|
|
821
|
+
You can also add resource policy statements to a table after it's created using the `addToResourcePolicy` method. Following the same pattern as KMS, resource policies use wildcard resources to avoid circular dependencies:
|
|
822
|
+
|
|
823
|
+
```ts
|
|
824
|
+
const table = new dynamodb.TableV2(this, 'Table', {
|
|
825
|
+
partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
|
|
826
|
+
});
|
|
827
|
+
|
|
828
|
+
// Standard resource policy (recommended approach)
|
|
829
|
+
table.addToResourcePolicy(new iam.PolicyStatement({
|
|
830
|
+
actions: ['dynamodb:GetItem', 'dynamodb:PutItem', 'dynamodb:Query'],
|
|
831
|
+
principals: [new iam.AccountRootPrincipal()],
|
|
832
|
+
resources: ['*'], // Wildcard avoids circular dependency - same pattern as KMS
|
|
833
|
+
}));
|
|
834
|
+
|
|
835
|
+
// Allow specific service access
|
|
836
|
+
table.addToResourcePolicy(new iam.PolicyStatement({
|
|
837
|
+
actions: ['dynamodb:Query'],
|
|
838
|
+
principals: [new iam.ServicePrincipal('lambda.amazonaws.com')],
|
|
839
|
+
resources: ['*'],
|
|
840
|
+
}));
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
#### Scoped Resource Policies (Advanced)
|
|
844
|
+
|
|
845
|
+
For scoped resource policies that reference specific table ARNs, you must specify an explicit table name:
|
|
846
|
+
|
|
847
|
+
```ts
|
|
848
|
+
import { Fn } from 'aws-cdk-lib';
|
|
849
|
+
|
|
850
|
+
// Table with explicit name enables scoped resource policies
|
|
851
|
+
const table = new dynamodb.TableV2(this, 'Table', {
|
|
852
|
+
tableName: 'my-explicit-table-name', // Required for scoped resources
|
|
853
|
+
partitionKey: { name: 'pk', type: dynamodb.AttributeType.STRING },
|
|
854
|
+
});
|
|
855
|
+
|
|
856
|
+
// Now you can use scoped resources
|
|
857
|
+
table.addToResourcePolicy(new iam.PolicyStatement({
|
|
858
|
+
actions: ['dynamodb:GetItem'],
|
|
859
|
+
principals: [new iam.AccountRootPrincipal()],
|
|
860
|
+
resources: [
|
|
861
|
+
Fn.sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/my-explicit-table-name'),
|
|
862
|
+
Fn.sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/my-explicit-table-name/index/*'),
|
|
863
|
+
],
|
|
864
|
+
}));
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
**Important Limitations:**
|
|
868
|
+
- **Auto-generated table names**: Must use `resources: ['*']` to avoid circular dependencies
|
|
869
|
+
- **Explicit table names**: Enable scoped resources but lose CDK's automatic naming benefits
|
|
870
|
+
- **CloudFormation constraint**: Resource policies cannot reference the resource they're attached to during creation
|
|
871
|
+
|
|
819
872
|
TableV2 doesn’t support creating a replica and adding a resource-based policy to that replica in the same stack update in Regions other than the Region where you deploy the stack update.
|
|
820
873
|
To incorporate a resource-based policy into a replica, you'll need to initially deploy the replica without the policy, followed by a subsequent update to include the desired policy.
|
|
821
874
|
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration test for DynamoDB Table.addToResourcePolicy() method
|
|
3
|
+
*
|
|
4
|
+
* This test validates the fix for issue #35062: "(aws-dynamodb): `addToResourcePolicy` has no effect"
|
|
5
|
+
*
|
|
6
|
+
* WHAT WE'RE TESTING:
|
|
7
|
+
* - The addToResourcePolicy() method was broken - it had "no effect" when called
|
|
8
|
+
* - Resource policies weren't being added to the CloudFormation template
|
|
9
|
+
* - This created a security gap where developers thought they were securing tables but policies weren't applied
|
|
10
|
+
*
|
|
11
|
+
* TEST VALIDATION:
|
|
12
|
+
* 1. Creates DynamoDB tables with different resource policy configurations
|
|
13
|
+
* 2. Tests both wildcard resources (for auto-generated names) and scoped resources (for explicit names)
|
|
14
|
+
* 3. Verifies policies get added to CloudFormation templates with correct structure
|
|
15
|
+
* 4. Ensures both patterns work without circular dependencies
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/aws/aws-cdk/issues/35062
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { App, Fn, RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib';
|
|
21
|
+
import { Construct } from 'constructs';
|
|
22
|
+
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
|
|
23
|
+
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
24
|
+
import { IntegTest } from '@aws-cdk/integ-tests-alpha';
|
|
25
|
+
|
|
26
|
+
export class TestStack extends Stack {
|
|
27
|
+
public readonly wildcardTable: dynamodb.Table;
|
|
28
|
+
public readonly scopedTable: dynamodb.Table;
|
|
29
|
+
|
|
30
|
+
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
31
|
+
super(scope, id, props);
|
|
32
|
+
|
|
33
|
+
// TEST 1: Table with wildcard resource policy (auto-generated name)
|
|
34
|
+
// This is the standard pattern to avoid circular dependencies
|
|
35
|
+
this.wildcardTable = new dynamodb.Table(this, 'WildcardTable', {
|
|
36
|
+
partitionKey: {
|
|
37
|
+
name: 'id',
|
|
38
|
+
type: dynamodb.AttributeType.STRING,
|
|
39
|
+
},
|
|
40
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Add resource policy with wildcard resources
|
|
44
|
+
this.wildcardTable.addToResourcePolicy(new iam.PolicyStatement({
|
|
45
|
+
actions: ['dynamodb:GetItem', 'dynamodb:PutItem', 'dynamodb:Query'],
|
|
46
|
+
principals: [new iam.AccountRootPrincipal()],
|
|
47
|
+
resources: ['*'], // Use wildcard to avoid circular dependency - standard pattern for resource policies
|
|
48
|
+
}));
|
|
49
|
+
|
|
50
|
+
// TEST 2: Table with scoped resource policy (explicit table name)
|
|
51
|
+
// This demonstrates how to use scoped resources when table name is known at synthesis time
|
|
52
|
+
this.scopedTable = new dynamodb.Table(this, 'ScopedTable', {
|
|
53
|
+
tableName: 'my-explicit-scoped-table', // Explicit name enables scoped ARN construction
|
|
54
|
+
partitionKey: {
|
|
55
|
+
name: 'id',
|
|
56
|
+
type: dynamodb.AttributeType.STRING,
|
|
57
|
+
},
|
|
58
|
+
removalPolicy: RemovalPolicy.DESTROY,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// Add resource policy with properly scoped resource using explicit table name
|
|
62
|
+
// This works because table name is known at synthesis time (no circular dependency)
|
|
63
|
+
this.scopedTable.addToResourcePolicy(new iam.PolicyStatement({
|
|
64
|
+
actions: ['dynamodb:GetItem', 'dynamodb:Query'],
|
|
65
|
+
principals: [new iam.AccountRootPrincipal()],
|
|
66
|
+
// Use CloudFormation intrinsic function to construct table ARN with known table name
|
|
67
|
+
resources: [Fn.sub('arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/my-explicit-scoped-table')],
|
|
68
|
+
}));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Test Setup
|
|
73
|
+
const app = new App();
|
|
74
|
+
const stack = new TestStack(app, 'add-to-resource-policy-test-stack');
|
|
75
|
+
|
|
76
|
+
// Integration Test Configuration
|
|
77
|
+
new IntegTest(app, 'add-to-resource-policy-integ-test', {
|
|
78
|
+
testCases: [stack],
|
|
79
|
+
});
|
|
80
|
+
|
cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-dynamodb/integ.dynamodb.policy.ts
CHANGED
|
@@ -38,7 +38,27 @@ export class TestStack extends Stack {
|
|
|
38
38
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
// IMPORTANT: Cross-account grants with auto-generated table names create circular dependencies
|
|
42
|
+
//
|
|
43
|
+
// WHY NOT this.tableTwo.grantReadData(new iam.AccountPrincipal('123456789012'))?
|
|
44
|
+
// - Cross-account principals cannot have policies attached to them
|
|
45
|
+
// - Grant falls back to adding a resource policy to the table
|
|
46
|
+
// - Resource policy tries to reference this.tableArn (the table's own ARN)
|
|
47
|
+
// - This creates a circular dependency: Table → ResourcePolicy → Table ARN → Table
|
|
48
|
+
// - CloudFormation fails with "Circular dependency between resources"
|
|
49
|
+
//
|
|
50
|
+
// SOLUTIONS:
|
|
51
|
+
// 1. Use addToResourcePolicy with wildcard resources (this approach)
|
|
52
|
+
// 2. Use explicit table names: tableName: 'my-table-name' (enables scoped resources)
|
|
53
|
+
// 3. Use same-account principals (grants go to principal policy, not resource policy)
|
|
54
|
+
//
|
|
55
|
+
this.tableTwo.addToResourcePolicy(new iam.PolicyStatement({
|
|
56
|
+
actions: ['dynamodb:*'],
|
|
57
|
+
// we need a valid account for cross-account principal otherwise it won't deploy
|
|
58
|
+
// this account is from fact-table.ts
|
|
59
|
+
principals: [new iam.AccountPrincipal('127311923021')],
|
|
60
|
+
resources: ['*'], // Wildcard avoids circular dependency - same pattern as KMS
|
|
61
|
+
}));
|
|
42
62
|
}
|
|
43
63
|
}
|
|
44
64
|
|
|
@@ -72,6 +72,10 @@ class TestStack extends Stack {
|
|
|
72
72
|
destination: FlowLogDestination.toS3(),
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
vpc.addFlowLog('FlowLogsCloudwatch', {
|
|
76
|
+
destination: FlowLogDestination.toCloudWatchLogs(),
|
|
77
|
+
});
|
|
78
|
+
|
|
75
79
|
const bucket = new s3.Bucket(this, 'Bucket', {
|
|
76
80
|
removalPolicy: RemovalPolicy.DESTROY,
|
|
77
81
|
autoDeleteObjects: true,
|
cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-elasticloadbalancingv2/README.md
CHANGED
|
@@ -338,17 +338,13 @@ Balancers:
|
|
|
338
338
|
```ts
|
|
339
339
|
declare const vpc: ec2.Vpc;
|
|
340
340
|
declare const asg: autoscaling.AutoScalingGroup;
|
|
341
|
-
declare const sg1: ec2.ISecurityGroup;
|
|
342
|
-
declare const sg2: ec2.ISecurityGroup;
|
|
343
341
|
|
|
344
342
|
// Create the load balancer in a VPC. 'internetFacing' is 'false'
|
|
345
343
|
// by default, which creates an internal load balancer.
|
|
346
344
|
const lb = new elbv2.NetworkLoadBalancer(this, 'LB', {
|
|
347
345
|
vpc,
|
|
348
346
|
internetFacing: true,
|
|
349
|
-
securityGroups: [sg1],
|
|
350
347
|
});
|
|
351
|
-
lb.addSecurityGroup(sg2);
|
|
352
348
|
|
|
353
349
|
// Add a listener on a particular port.
|
|
354
350
|
const listener = lb.addListener('Listener', {
|
|
@@ -362,6 +358,40 @@ listener.addTargets('AppFleet', {
|
|
|
362
358
|
});
|
|
363
359
|
```
|
|
364
360
|
|
|
361
|
+
### Security Groups for Network Load Balancer
|
|
362
|
+
|
|
363
|
+
By default, Network Load Balancers (NLB) have a security group associated with them.
|
|
364
|
+
This is controlled by the feature flag `@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault`.
|
|
365
|
+
When this flag is enabled (the default for new projects), a security group will be automatically created and attached to the NLB unless you explicitly provide your own security groups via the `securityGroups` property.
|
|
366
|
+
|
|
367
|
+
If you wish to create an NLB without any security groups, you can set the `disableSecurityGroups` property to `true`. When this property is set, no security group will be associated with the NLB, regardless of the feature flag.
|
|
368
|
+
|
|
369
|
+
```ts
|
|
370
|
+
declare const vpc: ec2.IVpc;
|
|
371
|
+
|
|
372
|
+
const nlb = new elbv2.NetworkLoadBalancer(this, 'LB', {
|
|
373
|
+
vpc,
|
|
374
|
+
// To disable security groups for this NLB
|
|
375
|
+
disableSecurityGroups: true,
|
|
376
|
+
});
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
If you want to use your own security groups, provide them via the `securityGroups` property:
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
declare const vpc: ec2.IVpc;
|
|
383
|
+
declare const sg1: ec2.ISecurityGroup;
|
|
384
|
+
declare const sg2: ec2.ISecurityGroup;
|
|
385
|
+
|
|
386
|
+
const nlb = new elbv2.NetworkLoadBalancer(this, 'LB', {
|
|
387
|
+
vpc,
|
|
388
|
+
// Provide your own security groups
|
|
389
|
+
securityGroups: [sg1],
|
|
390
|
+
});
|
|
391
|
+
// Add another security group to the NLB
|
|
392
|
+
nlb.addSecurityGroup(sg2);
|
|
393
|
+
```
|
|
394
|
+
|
|
365
395
|
### Enforce security group inbound rules on PrivateLink traffic for a Network Load Balancer
|
|
366
396
|
|
|
367
397
|
You can indicate whether to evaluate inbound security group rules for traffic
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { ExpectedResult, IntegTest, Match } from '@aws-cdk/integ-tests-alpha';
|
|
2
|
+
import { Stack, aws_ec2 as ec2, aws_elasticloadbalancingv2 as elbv2, App } from 'aws-cdk-lib';
|
|
3
|
+
import { Construct } from 'constructs';
|
|
4
|
+
|
|
5
|
+
class TestStack extends Stack {
|
|
6
|
+
public readonly lbWithSg: elbv2.NetworkLoadBalancer;
|
|
7
|
+
public readonly lbWithSg2: elbv2.NetworkLoadBalancer;
|
|
8
|
+
public readonly lbWithoutSg: elbv2.NetworkLoadBalancer;
|
|
9
|
+
|
|
10
|
+
constructor(scope: Construct, id: string) {
|
|
11
|
+
super(scope, id);
|
|
12
|
+
|
|
13
|
+
const vpc = new ec2.Vpc(this, 'Stack', {
|
|
14
|
+
maxAzs: 1,
|
|
15
|
+
natGateways: 0,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
this.lbWithSg = new elbv2.NetworkLoadBalancer(this, 'NlbWithSecurityGroup', {
|
|
19
|
+
vpc,
|
|
20
|
+
});
|
|
21
|
+
this.lbWithSg2 = new elbv2.NetworkLoadBalancer(this, 'NlbWithSecurityGroup2', {
|
|
22
|
+
vpc,
|
|
23
|
+
securityGroups: [new ec2.SecurityGroup(this, 'SecurityGroup', {
|
|
24
|
+
vpc,
|
|
25
|
+
allowAllOutbound: true,
|
|
26
|
+
})],
|
|
27
|
+
});
|
|
28
|
+
this.lbWithSg.connections.allowTo(this.lbWithSg2, ec2.Port.tcp(1229));
|
|
29
|
+
this.lbWithoutSg = new elbv2.NetworkLoadBalancer(this, 'NlbWithoutSecurityGroup', {
|
|
30
|
+
vpc,
|
|
31
|
+
disableSecurityGroups: true,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const app = new App({
|
|
37
|
+
postCliContext: {
|
|
38
|
+
'@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault': true,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const stack = new TestStack(app, 'NlbSecurityGroupStack');
|
|
42
|
+
const integ = new IntegTest(app, 'NlbSecurityGroupInteg', {
|
|
43
|
+
testCases: [stack],
|
|
44
|
+
});
|
|
45
|
+
integ.assertions.awsApiCall('elastic-load-balancing-v2', 'describeLoadBalancers', {
|
|
46
|
+
LoadBalancerArns: [
|
|
47
|
+
stack.lbWithSg.loadBalancerArn,
|
|
48
|
+
stack.lbWithSg2.loadBalancerArn,
|
|
49
|
+
stack.lbWithoutSg.loadBalancerArn,
|
|
50
|
+
],
|
|
51
|
+
}).expect(ExpectedResult.objectLike({
|
|
52
|
+
LoadBalancers: [
|
|
53
|
+
Match.objectLike({
|
|
54
|
+
LoadBalancerArn: stack.lbWithSg.loadBalancerArn,
|
|
55
|
+
SecurityGroups: Match.arrayWith([
|
|
56
|
+
Match.stringLikeRegexp('sg-[0-9a-f]{8,17}'),
|
|
57
|
+
]),
|
|
58
|
+
}),
|
|
59
|
+
Match.objectLike({
|
|
60
|
+
LoadBalancerArn: stack.lbWithSg2.loadBalancerArn,
|
|
61
|
+
SecurityGroups: Match.arrayWith([
|
|
62
|
+
Match.stringLikeRegexp('sg-[0-9a-f]{8,17}'),
|
|
63
|
+
]),
|
|
64
|
+
}),
|
|
65
|
+
Match.objectLike({
|
|
66
|
+
LoadBalancerArn: stack.lbWithoutSg.loadBalancerArn,
|
|
67
|
+
SecurityGroups: undefined,
|
|
68
|
+
}),
|
|
69
|
+
],
|
|
70
|
+
}));
|
|
@@ -19,6 +19,7 @@ Currently supported are:
|
|
|
19
19
|
- [Invoke an API Destination](#invoke-an-api-destination)
|
|
20
20
|
- [Invoke an AppSync GraphQL API](#invoke-an-appsync-graphql-api)
|
|
21
21
|
- [Put an event on an EventBridge bus](#put-an-event-on-an-eventbridge-bus)
|
|
22
|
+
- [Put an event on a Firehose delivery stream](#put-an-event-on-a-firehose-delivery-stream)
|
|
22
23
|
- [Run an ECS Task](#run-an-ecs-task)
|
|
23
24
|
- [Tagging Tasks](#tagging-tasks)
|
|
24
25
|
- [Launch type for ECS Task](#launch-type-for-ecs-task)
|
|
@@ -528,6 +529,27 @@ rule.addTarget(new targets.EventBus(
|
|
|
528
529
|
));
|
|
529
530
|
```
|
|
530
531
|
|
|
532
|
+
## Put an event on a Firehose delivery stream
|
|
533
|
+
|
|
534
|
+
Use the `FirehoseDeliveryStream` target to put event to an Amazon Data Firehose delivery stream.
|
|
535
|
+
|
|
536
|
+
The code snippet below creates the scheduled event rule that put events to an Amazon Data Firehose delivery stream.
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
import * as firehose from 'aws-cdk-lib/aws-kinesisfirehose';
|
|
540
|
+
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
541
|
+
|
|
542
|
+
declare const bucket: s3.Bucket;
|
|
543
|
+
const stream = new firehose.DeliveryStream(this, 'DeliveryStream', {
|
|
544
|
+
destination: new firehose.S3Bucket(bucket),
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
const rule = new events.Rule(this, 'Rule', {
|
|
548
|
+
schedule: events.Schedule.expression('rate(1 minute)'),
|
|
549
|
+
});
|
|
550
|
+
rule.addTarget(new targets.FirehoseDeliveryStream(stream));
|
|
551
|
+
```
|
|
552
|
+
|
|
531
553
|
## Run an ECS Task
|
|
532
554
|
|
|
533
555
|
Use the `EcsTask` target to run an ECS Task.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as events from 'aws-cdk-lib/aws-events';
|
|
2
|
+
import * as firehose from 'aws-cdk-lib/aws-kinesisfirehose';
|
|
3
|
+
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
4
|
+
import * as cdk from 'aws-cdk-lib';
|
|
5
|
+
import * as targets from 'aws-cdk-lib/aws-events-targets';
|
|
6
|
+
import { IntegTest, ExpectedResult, AwsApiCall } from '@aws-cdk/integ-tests-alpha';
|
|
7
|
+
|
|
8
|
+
// ---------------------------------
|
|
9
|
+
// Define a rule that triggers a put to a Firehose delivery stream every 1min.
|
|
10
|
+
|
|
11
|
+
const app = new cdk.App();
|
|
12
|
+
|
|
13
|
+
const stack = new cdk.Stack(app, 'aws-cdk-firehose-event-target');
|
|
14
|
+
|
|
15
|
+
const bucket = new s3.Bucket(stack, 'firehose-bucket', {
|
|
16
|
+
autoDeleteObjects: true,
|
|
17
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
18
|
+
});
|
|
19
|
+
const deliveryStream = new firehose.DeliveryStream(stack, 'MyDeliveryStream', {
|
|
20
|
+
destination: new firehose.S3Bucket(bucket, {
|
|
21
|
+
bufferingInterval: cdk.Duration.seconds(30),
|
|
22
|
+
}),
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const event = new events.Rule(stack, 'EveryMinute', {
|
|
26
|
+
schedule: events.Schedule.rate(cdk.Duration.minutes(1)),
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
event.addTarget(new targets.FirehoseDeliveryStream(deliveryStream));
|
|
30
|
+
|
|
31
|
+
const testCase = new IntegTest(app, 'firehose-event-target-integ', {
|
|
32
|
+
testCases: [stack],
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const s3ApiCall = testCase.assertions.awsApiCall('S3', 'listObjectsV2', {
|
|
36
|
+
Bucket: bucket.bucketName,
|
|
37
|
+
MaxKeys: 1,
|
|
38
|
+
}).expect(ExpectedResult.objectLike({
|
|
39
|
+
KeyCount: 1,
|
|
40
|
+
})).waitForAssertions({
|
|
41
|
+
interval: cdk.Duration.seconds(30),
|
|
42
|
+
totalTimeout: cdk.Duration.minutes(10),
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
if (s3ApiCall instanceof AwsApiCall) {
|
|
46
|
+
s3ApiCall.waiterProvider?.addToRolePolicy({
|
|
47
|
+
Effect: 'Allow',
|
|
48
|
+
Action: ['s3:GetObject', 's3:ListBucket'],
|
|
49
|
+
Resource: ['*'],
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { App, Stack } from 'aws-cdk-lib';
|
|
2
2
|
import { IntegTest } from '@aws-cdk/integ-tests-alpha';
|
|
3
3
|
import { AccountRootPrincipal, Grant, ManagedPolicy, PolicyStatement, Role, User } from 'aws-cdk-lib/aws-iam';
|
|
4
|
+
import * as lambda from 'aws-cdk-lib/aws-lambda';
|
|
4
5
|
|
|
5
6
|
const app = new App();
|
|
6
7
|
|
|
@@ -34,6 +35,14 @@ policy.attachToRole(role);
|
|
|
34
35
|
const importedRole = Role.fromRoleArn(stack, 'ImportedRole', role.roleArn);
|
|
35
36
|
policy.attachToRole(importedRole);
|
|
36
37
|
|
|
38
|
+
// Can be passed to grantInvoke, see https://github.com/aws/aws-cdk/issues/32980
|
|
39
|
+
const func = new lambda.Function(stack, 'Function', {
|
|
40
|
+
runtime: lambda.Runtime.NODEJS_LATEST,
|
|
41
|
+
handler: 'index.handler',
|
|
42
|
+
code: lambda.Code.fromInline('export const handler = async () => null'),
|
|
43
|
+
});
|
|
44
|
+
func.grantInvoke(policy);
|
|
45
|
+
|
|
37
46
|
new IntegTest(app, 'ManagedPolicyInteg', {
|
|
38
47
|
testCases: [stack],
|
|
39
48
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { App, Stack } from 'aws-cdk-lib';
|
|
2
2
|
import { IntegTest } from '@aws-cdk/integ-tests-alpha';
|
|
3
3
|
import { AccountRootPrincipal, Grant, Policy, PolicyStatement, Role, User } from 'aws-cdk-lib/aws-iam';
|
|
4
|
+
import * as lambda from 'aws-cdk-lib/aws-lambda';
|
|
4
5
|
|
|
5
6
|
const app = new App();
|
|
6
7
|
|
|
@@ -21,6 +22,14 @@ role.grantAssumeRole(user);
|
|
|
21
22
|
|
|
22
23
|
Grant.addToPrincipal({ actions: ['iam:*'], resourceArns: [role.roleArn], grantee: policy2 });
|
|
23
24
|
|
|
25
|
+
// Can be passed to grantInvoke, see https://github.com/aws/aws-cdk/issues/32980
|
|
26
|
+
const func = new lambda.Function(stack, 'Function', {
|
|
27
|
+
runtime: lambda.Runtime.NODEJS_LATEST,
|
|
28
|
+
handler: 'index.handler',
|
|
29
|
+
code: lambda.Code.fromInline('export const handler = async () => null'),
|
|
30
|
+
});
|
|
31
|
+
func.grantInvoke(policy);
|
|
32
|
+
|
|
24
33
|
new IntegTest(app, 'PolicyInteg', {
|
|
25
34
|
testCases: [stack],
|
|
26
35
|
});
|
|
@@ -483,8 +483,11 @@ Data can be transformed before being delivered to destinations. There are two ty
|
|
|
483
483
|
data processing for delivery streams: record transformation with AWS Lambda, and record
|
|
484
484
|
format conversion using a schema stored in an AWS Glue table. If both types of data
|
|
485
485
|
processing are configured, then the Lambda transformation is performed first. By default,
|
|
486
|
-
no data processing occurs.
|
|
487
|
-
|
|
486
|
+
no data processing occurs.
|
|
487
|
+
|
|
488
|
+
This construct library currently only supports data
|
|
489
|
+
transformation with AWS Lambda and some built-in data processors.
|
|
490
|
+
See [#15501](https://github.com/aws/aws-cdk/issues/15501)
|
|
488
491
|
to track the status of adding support for record format conversion.
|
|
489
492
|
|
|
490
493
|
### Data transformation with AWS Lambda
|
|
@@ -520,7 +523,7 @@ const lambdaProcessor = new firehose.LambdaFunctionProcessor(lambdaFunction, {
|
|
|
520
523
|
});
|
|
521
524
|
declare const bucket: s3.Bucket;
|
|
522
525
|
const s3Destination = new firehose.S3Bucket(bucket, {
|
|
523
|
-
|
|
526
|
+
processors: [lambdaProcessor],
|
|
524
527
|
});
|
|
525
528
|
new firehose.DeliveryStream(this, 'Delivery Stream', {
|
|
526
529
|
destination: s3Destination,
|
|
@@ -532,6 +535,60 @@ new firehose.DeliveryStream(this, 'Delivery Stream', {
|
|
|
532
535
|
See: [Data Transformation](https://docs.aws.amazon.com/firehose/latest/dev/data-transformation.html)
|
|
533
536
|
in the *Amazon Data Firehose Developer Guide*.
|
|
534
537
|
|
|
538
|
+
### Add a new line delimiter when delivering data to Amazon S3
|
|
539
|
+
|
|
540
|
+
You can specify the `AppendDelimiterToRecordProcessor` built-in processor to add a new line delimiter between records in objects that are delivered to Amazon S3. This can be helpful for parsing objects in Amazon S3.
|
|
541
|
+
For details, see [Use Amazon S3 bucket prefix to deliver data](https://docs.aws.amazon.com/firehose/latest/dev/dynamic-partitioning-s3bucketprefix.html).
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
declare const bucket: s3.Bucket;
|
|
545
|
+
const s3Destination = new firehose.S3Bucket(bucket, {
|
|
546
|
+
processors: [
|
|
547
|
+
new firehose.AppendDelimiterToRecordProcessor(),
|
|
548
|
+
],
|
|
549
|
+
});
|
|
550
|
+
new firehose.DeliveryStream(this, 'Delivery Stream', {
|
|
551
|
+
destination: s3Destination,
|
|
552
|
+
});
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
### Decompress and extract message of CloudWatch Logs
|
|
556
|
+
|
|
557
|
+
CloudWatch Logs events are sent to Firehose in compressed gzip format. If you want to deliver decompressed log events to Firehose destinations, you can use the `DecompressionProcessor` to automatically decompress CloudWatch Logs.
|
|
558
|
+
For details, see [Send CloudWatch Logs to Firehose](https://docs.aws.amazon.com/firehose/latest/dev/writing-with-cloudwatch-logs.html).
|
|
559
|
+
|
|
560
|
+
You may also needed to specify `AppendDelimiterToRecordProcessor`
|
|
561
|
+
because decompressed log events record has no trailing newline.
|
|
562
|
+
|
|
563
|
+
```ts
|
|
564
|
+
declare const bucket: s3.Bucket;
|
|
565
|
+
const s3Destination = new firehose.S3Bucket(bucket, {
|
|
566
|
+
processors: [
|
|
567
|
+
new firehose.DecompressionProcessor(),
|
|
568
|
+
new firehose.AppendDelimiterToRecordProcessor(),
|
|
569
|
+
],
|
|
570
|
+
});
|
|
571
|
+
new firehose.DeliveryStream(this, 'Delivery Stream', {
|
|
572
|
+
destination: s3Destination,
|
|
573
|
+
});
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
When you enable decompression, you have the option to also enable message extraction. When using message extraction, Firehose filters out all metadata, such as owner, loggroup, logstream, and others from the decompressed CloudWatch Logs records and delivers only the content inside the message fields.
|
|
577
|
+
|
|
578
|
+
```ts
|
|
579
|
+
declare const bucket: s3.Bucket;
|
|
580
|
+
const s3Destination = new firehose.S3Bucket(bucket, {
|
|
581
|
+
processors: [
|
|
582
|
+
new firehose.DecompressionProcessor(),
|
|
583
|
+
new firehose.CloudWatchLogProcessor({ dataMessageExtraction: true }),
|
|
584
|
+
],
|
|
585
|
+
});
|
|
586
|
+
new firehose.DeliveryStream(this, 'Delivery Stream', {
|
|
587
|
+
destination: s3Destination,
|
|
588
|
+
});
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
|
|
535
592
|
## Specifying an IAM role
|
|
536
593
|
|
|
537
594
|
The DeliveryStream class automatically creates IAM service roles with all the minimum
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
import * as firehose from 'aws-cdk-lib/aws-kinesisfirehose';
|
|
4
|
+
import * as lambdanodejs from 'aws-cdk-lib/aws-lambda-nodejs';
|
|
5
|
+
import * as s3 from 'aws-cdk-lib/aws-s3';
|
|
6
|
+
import * as cdk from 'aws-cdk-lib';
|
|
7
|
+
import { IntegTest } from '@aws-cdk/integ-tests-alpha';
|
|
8
|
+
|
|
9
|
+
const app = new cdk.App();
|
|
10
|
+
|
|
11
|
+
const stack = new cdk.Stack(app, 'firehose-delivery-stream-cloudwatch-logs-processors');
|
|
12
|
+
|
|
13
|
+
const bucket = new s3.Bucket(stack, 'DestinationBucket', {
|
|
14
|
+
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
|
15
|
+
autoDeleteObjects: true,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const dataProcessorFunction = new lambdanodejs.NodejsFunction(stack, 'DataProcessorFunction', {
|
|
19
|
+
entry: path.join(__dirname, 'lambda-data-processor.js'),
|
|
20
|
+
timeout: cdk.Duration.minutes(1),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
new firehose.DeliveryStream(stack, 'DecompressCloudWatchLogsEntry', {
|
|
24
|
+
destination: new firehose.S3Bucket(bucket, {
|
|
25
|
+
processors: [
|
|
26
|
+
new firehose.DecompressionProcessor(),
|
|
27
|
+
new firehose.AppendDelimiterToRecordProcessor(),
|
|
28
|
+
new firehose.LambdaFunctionProcessor(dataProcessorFunction),
|
|
29
|
+
],
|
|
30
|
+
}),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
new firehose.DeliveryStream(stack, 'ExtractCloudWatchLogsEntry', {
|
|
34
|
+
destination: new firehose.S3Bucket(bucket, {
|
|
35
|
+
processors: [
|
|
36
|
+
new firehose.DecompressionProcessor(),
|
|
37
|
+
new firehose.CloudWatchLogProcessor({ dataMessageExtraction: true }),
|
|
38
|
+
new firehose.LambdaFunctionProcessor(dataProcessorFunction),
|
|
39
|
+
],
|
|
40
|
+
}),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
new IntegTest(app, 'integ-tests', {
|
|
44
|
+
testCases: [stack],
|
|
45
|
+
});
|
cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-lambda/integ.runtime.fromasset.ts
CHANGED
|
@@ -10,20 +10,35 @@ const app = new App({
|
|
|
10
10
|
});
|
|
11
11
|
const stack = new Stack(app, 'aws-cdk-lambda-runtime-fromasset');
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const lambdaFunctionJava21 = new Function(stack, 'MyFunctionJava21', {
|
|
14
14
|
runtime: Runtime.JAVA_21,
|
|
15
15
|
handler: 'com.mycompany.app.LambdaMethodHandler::handleRequest',
|
|
16
16
|
code: Code.fromAsset(path.join(__dirname, 'my-app-1.0-SNAPSHOT.zip')),
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
+
const lambdaFunctionJava25 = new Function(stack, 'MyFunctionJava25', {
|
|
20
|
+
runtime: Runtime.JAVA_25,
|
|
21
|
+
handler: 'com.mycompany.app.LambdaMethodHandler::handleRequest',
|
|
22
|
+
code: Code.fromAsset(path.join(__dirname, 'my-app-1.0-SNAPSHOT.zip')),
|
|
23
|
+
});
|
|
24
|
+
|
|
19
25
|
const integTest = new integ.IntegTest(app, 'Integ', { testCases: [stack] });
|
|
20
26
|
|
|
21
|
-
const
|
|
22
|
-
functionName:
|
|
27
|
+
const invokeJava21 = integTest.assertions.invokeFunction({
|
|
28
|
+
functionName: lambdaFunctionJava21.functionName,
|
|
29
|
+
payload: '123',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
invokeJava21.expect(integ.ExpectedResult.objectLike({
|
|
33
|
+
Payload: '"123"',
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const invokeJava25 = integTest.assertions.invokeFunction({
|
|
37
|
+
functionName: lambdaFunctionJava25.functionName,
|
|
23
38
|
payload: '123',
|
|
24
39
|
});
|
|
25
40
|
|
|
26
|
-
|
|
41
|
+
invokeJava25.expect(integ.ExpectedResult.objectLike({
|
|
27
42
|
Payload: '"123"',
|
|
28
43
|
}));
|
|
29
44
|
|
cdk_api_mcp_server/resources/aws-cdk/constructs/aws-cdk-lib/aws-lambda/integ.runtime.inlinecode.ts
CHANGED
|
@@ -55,6 +55,13 @@ const python313 = new Function(stack, 'PYTHON_3_13', {
|
|
|
55
55
|
});
|
|
56
56
|
new CfnOutput(stack, 'PYTHON_3_13-functionName', { value: python313.functionName });
|
|
57
57
|
|
|
58
|
+
const python314 = new Function(stack, 'PYTHON_3_14', {
|
|
59
|
+
code: new InlineCode('def handler(event, context):\n return "success"'),
|
|
60
|
+
handler: 'index.handler',
|
|
61
|
+
runtime: Runtime.PYTHON_3_14,
|
|
62
|
+
});
|
|
63
|
+
new CfnOutput(stack, 'PYTHON_3_14-functionName', { value: python314.functionName });
|
|
64
|
+
|
|
58
65
|
const node20xfn = new Function(stack, 'NODEJS_20_X', {
|
|
59
66
|
code: new InlineCode('exports.handler = async function(event) { return "success" }'),
|
|
60
67
|
handler: 'index.handler',
|