Skip to content

Commit bb96621

Browse files
authored
feat(logs): custom Role for Kinesis destination (#13553)
* [x] Testing - Unit test added. * [x] Docs - __jsdocs__: All public APIs documented - __README__: README and/or documentation topic updated When creating a logs destination, an optional `role` can be passed to be assumed when writing logs in the destination. Closes #7661. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent d19e538 commit bb96621

File tree

3 files changed

+75
-3
lines changed

3 files changed

+75
-3
lines changed

packages/@aws-cdk/aws-logs-destinations/README.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@
99

1010
<!--END STABILITY BANNER-->
1111

12-
A short description here.
12+
This library contains destinations for AWS CloudWatch Logs SubscriptionFilters. You
13+
can send log data to Kinesis Streams or Lambda Functions.
14+
15+
See the documentation of the `logs` module for more information.

packages/@aws-cdk/aws-logs-destinations/lib/kinesis.ts

+19-2
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,35 @@ import * as kinesis from '@aws-cdk/aws-kinesis';
33
import * as logs from '@aws-cdk/aws-logs';
44
import { Construct } from '@aws-cdk/core';
55

6+
/**
7+
* Customize the Kinesis Logs Destination
8+
*/
9+
export interface KinesisDestinationProps {
10+
/**
11+
* The role to assume to write log events to the destination
12+
*
13+
* @default - A new Role is created
14+
*/
15+
readonly role?: iam.IRole;
16+
}
17+
618
/**
719
* Use a Kinesis stream as the destination for a log subscription
820
*/
921
export class KinesisDestination implements logs.ILogSubscriptionDestination {
10-
constructor(private readonly stream: kinesis.IStream) {
22+
/**
23+
* @param stream The Kinesis stream to use as destination
24+
* @param props The Kinesis Destination properties
25+
*
26+
*/
27+
constructor(private readonly stream: kinesis.IStream, private readonly props: KinesisDestinationProps = {}) {
1128
}
1229

1330
public bind(scope: Construct, _sourceLogGroup: logs.ILogGroup): logs.LogSubscriptionDestinationConfig {
1431
// Following example from https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html#DestinationKinesisExample
1532
// Create a role to be assumed by CWL that can write to this stream and pass itself.
1633
const id = 'CloudWatchLogsCanPutRecords';
17-
const role = scope.node.tryFindChild(id) as iam.IRole || new iam.Role(scope, id, {
34+
const role = this.props.role ?? scope.node.tryFindChild(id) as iam.IRole ?? new iam.Role(scope, id, {
1835
assumedBy: new iam.ServicePrincipal('logs.amazonaws.com'),
1936
});
2037
this.stream.grantWrite(role);

packages/@aws-cdk/aws-logs-destinations/test/kinesis.test.ts

+52
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Template } from '@aws-cdk/assertions';
2+
import * as iam from '@aws-cdk/aws-iam';
23
import * as kinesis from '@aws-cdk/aws-kinesis';
34
import * as logs from '@aws-cdk/aws-logs';
45
import * as cdk from '@aws-cdk/core';
@@ -136,3 +137,54 @@ test('stream can be subscription destination twice, without duplicating permissi
136137
},
137138
});
138139
});
140+
141+
test('an existing IAM role can be passed to new destination instance instead of auto-created ', ()=> {
142+
// GIVEN
143+
const stack = new cdk.Stack();
144+
const stream = new kinesis.Stream(stack, 'MyStream');
145+
const logGroup = new logs.LogGroup(stack, 'LogGroup');
146+
147+
const importedRole = iam.Role.fromRoleArn(stack, 'ImportedRole', 'arn:aws:iam::123456789012:role/ImportedRoleKinesisDestinationTest');
148+
149+
const kinesisDestination = new dests.KinesisDestination(stream, { role: importedRole });
150+
151+
new logs.SubscriptionFilter(logGroup, 'MySubscriptionFilter', {
152+
logGroup: logGroup,
153+
destination: kinesisDestination,
154+
filterPattern: logs.FilterPattern.allEvents(),
155+
});
156+
157+
// THEN
158+
const template = Template.fromStack(stack);
159+
template.resourceCountIs('AWS::IAM::Role', 0);
160+
template.hasResourceProperties('AWS::Logs::SubscriptionFilter', {
161+
RoleArn: importedRole.roleArn,
162+
});
163+
});
164+
165+
test('creates a new IAM Role if not passed on new destination instance', ()=> {
166+
// GIVEN
167+
const stack = new cdk.Stack();
168+
const stream = new kinesis.Stream(stack, 'MyStream');
169+
const logGroup = new logs.LogGroup(stack, 'LogGroup');
170+
171+
const kinesisDestination = new dests.KinesisDestination(stream);
172+
173+
new logs.SubscriptionFilter(logGroup, 'MySubscriptionFilter', {
174+
logGroup: logGroup,
175+
destination: kinesisDestination,
176+
filterPattern: logs.FilterPattern.allEvents(),
177+
});
178+
179+
// THEN
180+
const template = Template.fromStack(stack);
181+
template.resourceCountIs('AWS::IAM::Role', 1);
182+
template.hasResourceProperties('AWS::Logs::SubscriptionFilter', {
183+
RoleArn: {
184+
'Fn::GetAtt': [
185+
'LogGroupMySubscriptionFilterCloudWatchLogsCanPutRecords9112BD02',
186+
'Arn',
187+
],
188+
},
189+
});
190+
});

0 commit comments

Comments
 (0)