Skip to content

Commit b5ccabf

Browse files
authored
Merge branch 'master' into merge-back/1.139.0
2 parents 9578a49 + c016a9f commit b5ccabf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+380
-207
lines changed

buildspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ phases:
2727
- /bin/bash ./scripts/transform.sh
2828
post_build:
2929
commands:
30+
# Short-circuit: Don't run pack if the above build failed.
31+
- '[[ "$CODEBUILD_BUILD_SUCCEEDING" -eq 1 ]] || exit 1'
3032
- "[ -f .BUILD_COMPLETED ] && /bin/bash ./pack.sh"
3133
- /bin/bash ./scripts/cache-store.sh
3234
artifacts:

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,8 @@
123123
"aws-cdk-lib/@balena/dockerignore/**",
124124
"aws-cdk-lib/case",
125125
"aws-cdk-lib/case/**",
126-
"aws-cdk-lib/colors",
127-
"aws-cdk-lib/colors/**",
126+
"aws-cdk-lib/chalk",
127+
"aws-cdk-lib/chalk/**",
128128
"aws-cdk-lib/diff",
129129
"aws-cdk-lib/diff/**",
130130
"aws-cdk-lib/fast-deep-equal",
@@ -151,8 +151,8 @@
151151
"monocdk/@balena/dockerignore/**",
152152
"monocdk/case",
153153
"monocdk/case/**",
154-
"monocdk/colors",
155-
"monocdk/colors/**",
154+
"monocdk/chalk",
155+
"monocdk/chalk/**",
156156
"monocdk/diff",
157157
"monocdk/diff/**",
158158
"monocdk/fast-deep-equal",
@@ -180,4 +180,4 @@
180180
"dependencies": {
181181
"string-width": "^4.2.3"
182182
}
183-
}
183+
}

packages/@aws-cdk/aws-apigatewayv2/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,3 +426,17 @@ webSocketApi.grantManageConnections(lambda);
426426
API Gateway supports multiple mechanisms for [controlling and managing access to a WebSocket API](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-websocket-api-control-access.html) through authorizers.
427427

428428
These authorizers can be found in the [APIGatewayV2-Authorizers](https://docs.aws.amazon.com/cdk/api/latest/docs/aws-apigatewayv2-authorizers-readme.html) constructs library.
429+
430+
### API Keys
431+
432+
Websocket APIs also support usage of API Keys. An API Key is a key that is used to grant access to an API. These are useful for controlling and tracking access to an API, when used together with [usage plans](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-api-usage-plans.html). These together allow you to configure controls around API access such as quotas and throttling, along with per-API Key metrics on usage.
433+
434+
To require an API Key when accessing the Websocket API:
435+
436+
```ts
437+
const webSocketApi = new WebSocketApi(stack, 'mywsapi',{
438+
apiKeySelectionExpression: WebSocketApiKeySelectionExpression.HEADER_X_API_KEY,
439+
});
440+
...
441+
```
442+

packages/@aws-cdk/aws-apigatewayv2/lib/websocket/api.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,29 @@ import { WebSocketRoute, WebSocketRouteOptions } from './route';
1212
export interface IWebSocketApi extends IApi {
1313
}
1414

15+
/**
16+
* Represents the currently available API Key Selection Expressions
17+
*/
18+
export class WebSocketApiKeySelectionExpression {
19+
20+
/**
21+
* The API will extract the key value from the `x-api-key` header in the user request.
22+
*/
23+
public static readonly HEADER_X_API_KEY = new WebSocketApiKeySelectionExpression('$request.header.x-api-key');
24+
25+
/**
26+
* The API will extract the key value from the `usageIdentifierKey` attribute in the `context` map,
27+
* returned by the Lambda Authorizer.
28+
* See https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-lambda-authorizer-output.html
29+
*/
30+
public static readonly AUTHORIZER_USAGE_IDENTIFIER_KEY = new WebSocketApiKeySelectionExpression('$context.authorizer.usageIdentifierKey');
31+
32+
/**
33+
* @param customApiKeySelector The expression used by API Gateway
34+
*/
35+
public constructor(public readonly customApiKeySelector: string) {}
36+
}
37+
1538
/**
1639
* Props for WebSocket API
1740
*/
@@ -22,6 +45,12 @@ export interface WebSocketApiProps {
2245
*/
2346
readonly apiName?: string;
2447

48+
/**
49+
* An API key selection expression. Providing this option will require an API Key be provided to access the API.
50+
* @default - Key is not required to access these APIs
51+
*/
52+
readonly apiKeySelectionExpression?: WebSocketApiKeySelectionExpression
53+
2554
/**
2655
* The description of the API.
2756
* @default - none
@@ -76,6 +105,7 @@ export class WebSocketApi extends ApiBase implements IWebSocketApi {
76105

77106
const resource = new CfnApi(this, 'Resource', {
78107
name: this.webSocketApiName,
108+
apiKeySelectionExpression: props?.apiKeySelectionExpression?.customApiKeySelector,
79109
protocolType: 'WEBSOCKET',
80110
description: props?.description,
81111
routeSelectionExpression: props?.routeSelectionExpression ?? '$request.body.action',

packages/@aws-cdk/aws-apigatewayv2/lib/websocket/route.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ export interface WebSocketRouteProps extends WebSocketRouteOptions {
5252
* The key to this route.
5353
*/
5454
readonly routeKey: string;
55+
56+
/**
57+
* Whether the route requires an API Key to be provided
58+
* @default false
59+
*/
60+
readonly apiKeyRequired?: boolean;
5561
}
5662

5763
/**
@@ -91,6 +97,7 @@ export class WebSocketRoute extends Resource implements IWebSocketRoute {
9197

9298
const route = new CfnRoute(this, 'Resource', {
9399
apiId: props.webSocketApi.apiId,
100+
apiKeyRequired: props.apiKeyRequired,
94101
routeKey: props.routeKey,
95102
target: `integrations/${config.integrationId}`,
96103
authorizerId: authBindResult.authorizerId,

packages/@aws-cdk/aws-apigatewayv2/test/websocket/api.test.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import { Match, Template } from '@aws-cdk/assertions';
22
import { User } from '@aws-cdk/aws-iam';
33
import { Stack } from '@aws-cdk/core';
44
import {
5-
WebSocketRouteIntegration, WebSocketApi, WebSocketIntegrationType,
6-
WebSocketRouteIntegrationBindOptions, WebSocketRouteIntegrationConfig,
5+
WebSocketRouteIntegration,
6+
WebSocketApi,
7+
WebSocketApiKeySelectionExpression,
8+
WebSocketIntegrationType,
9+
WebSocketRouteIntegrationBindOptions,
10+
WebSocketRouteIntegrationConfig,
711
} from '../../lib';
812

913
describe('WebSocketApi', () => {
@@ -25,6 +29,27 @@ describe('WebSocketApi', () => {
2529
Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Integration', 0);
2630
});
2731

32+
test('apiKeySelectionExpression: given a value', () => {
33+
// GIVEN
34+
const stack = new Stack();
35+
36+
// WHEN
37+
new WebSocketApi(stack, 'api', {
38+
apiKeySelectionExpression: WebSocketApiKeySelectionExpression.AUTHORIZER_USAGE_IDENTIFIER_KEY,
39+
});
40+
41+
// THEN
42+
Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Api', {
43+
ApiKeySelectionExpression: '$context.authorizer.usageIdentifierKey',
44+
Name: 'api',
45+
ProtocolType: 'WEBSOCKET',
46+
});
47+
48+
Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Stage', 0);
49+
Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Route', 0);
50+
Template.fromStack(stack).resourceCountIs('AWS::ApiGatewayV2::Integration', 0);
51+
});
52+
2853
test('addRoute: adds a route with passed key', () => {
2954
// GIVEN
3055
const stack = new Stack();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"Resources": {
3+
"MyWebsocketApiEBAC53DF": {
4+
"Type": "AWS::ApiGatewayV2::Api",
5+
"Properties": {
6+
"ApiKeySelectionExpression": "$request.header.x-api-key",
7+
"Name": "MyWebsocketApi",
8+
"ProtocolType": "WEBSOCKET",
9+
"RouteSelectionExpression": "$request.body.action"
10+
}
11+
}
12+
}
13+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env node
2+
import * as cdk from '@aws-cdk/core';
3+
import * as apigw from '../../lib';
4+
import { WebSocketApiKeySelectionExpression } from '../../lib';
5+
6+
const app = new cdk.App();
7+
8+
const stack = new cdk.Stack(app, 'aws-cdk-aws-apigatewayv2-websockets');
9+
10+
new apigw.WebSocketApi(stack, 'MyWebsocketApi', {
11+
apiKeySelectionExpression: WebSocketApiKeySelectionExpression.HEADER_X_API_KEY,
12+
});
13+
14+
app.synth();

packages/@aws-cdk/aws-apigatewayv2/test/websocket/route.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,45 @@ describe('WebSocketRoute', () => {
4242
});
4343
});
4444

45+
test('Api Key is required for route when apiKeyIsRequired is true', () => {
46+
// GIVEN
47+
const stack = new Stack();
48+
const webSocketApi = new WebSocketApi(stack, 'Api');
49+
50+
// WHEN
51+
new WebSocketRoute(stack, 'Route', {
52+
webSocketApi,
53+
integration: new DummyIntegration(),
54+
routeKey: 'message',
55+
apiKeyRequired: true,
56+
});
57+
58+
// THEN
59+
Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Route', {
60+
ApiId: stack.resolve(webSocketApi.apiId),
61+
ApiKeyRequired: true,
62+
RouteKey: 'message',
63+
Target: {
64+
'Fn::Join': [
65+
'',
66+
[
67+
'integrations/',
68+
{
69+
Ref: 'RouteDummyIntegrationE40E82B4',
70+
},
71+
],
72+
],
73+
},
74+
});
75+
76+
Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Integration', {
77+
ApiId: stack.resolve(webSocketApi.apiId),
78+
IntegrationType: 'AWS_PROXY',
79+
IntegrationUri: 'some-uri',
80+
});
81+
});
82+
83+
4584
test('integration cannot be used across WebSocketApis', () => {
4685
// GIVEN
4786
const integration = new DummyIntegration();

packages/@aws-cdk/aws-cloudtrail/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@
8686
"@aws-cdk/pkglint": "0.0.0",
8787
"@types/jest": "^27.4.0",
8888
"aws-sdk": "^2.848.0",
89-
"colors": "1.4.0",
9089
"jest": "^27.4.7"
9190
},
9291
"dependencies": {

packages/@aws-cdk/aws-iot-actions/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,9 +189,9 @@ const stream = new firehose.DeliveryStream(this, 'MyStream', {
189189
const topicRule = new iot.TopicRule(this, 'TopicRule', {
190190
sql: iot.IotSql.fromStringAsVer20160323("SELECT * FROM 'device/+/data'"),
191191
actions: [
192-
new actions.FirehoseStreamAction(stream, {
192+
new actions.FirehosePutRecordAction(stream, {
193193
batchMode: true,
194-
recordSeparator: actions.FirehoseStreamRecordSeparator.NEWLINE,
194+
recordSeparator: actions.FirehoseRecordSeparator.NEWLINE,
195195
}),
196196
],
197197
});

packages/@aws-cdk/aws-iot-actions/lib/firehose-stream-action.ts renamed to packages/@aws-cdk/aws-iot-actions/lib/firehose-put-record-action.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { singletonActionRole } from './private/role';
77
/**
88
* Record Separator to be used to separate records.
99
*/
10-
export enum FirehoseStreamRecordSeparator {
10+
export enum FirehoseRecordSeparator {
1111
/**
1212
* Separate by a new line
1313
*/
@@ -32,7 +32,7 @@ export enum FirehoseStreamRecordSeparator {
3232
/**
3333
* Configuration properties of an action for the Kinesis Data Firehose stream.
3434
*/
35-
export interface FirehoseStreamActionProps extends CommonActionProps {
35+
export interface FirehosePutRecordActionProps extends CommonActionProps {
3636
/**
3737
* Whether to deliver the Kinesis Data Firehose stream as a batch by using `PutRecordBatch`.
3838
* When batchMode is true and the rule's SQL statement evaluates to an Array, each Array
@@ -48,14 +48,14 @@ export interface FirehoseStreamActionProps extends CommonActionProps {
4848
*
4949
* @default - none -- the stream does not use a separator
5050
*/
51-
readonly recordSeparator?: FirehoseStreamRecordSeparator;
51+
readonly recordSeparator?: FirehoseRecordSeparator;
5252
}
5353

5454

5555
/**
5656
* The action to put the record from an MQTT message to the Kinesis Data Firehose stream.
5757
*/
58-
export class FirehoseStreamAction implements iot.IAction {
58+
export class FirehosePutRecordAction implements iot.IAction {
5959
private readonly batchMode?: boolean;
6060
private readonly recordSeparator?: string;
6161
private readonly role?: iam.IRole;
@@ -64,7 +64,7 @@ export class FirehoseStreamAction implements iot.IAction {
6464
* @param stream The Kinesis Data Firehose stream to which to put records.
6565
* @param props Optional properties to not use default
6666
*/
67-
constructor(private readonly stream: firehose.IDeliveryStream, props: FirehoseStreamActionProps = {}) {
67+
constructor(private readonly stream: firehose.IDeliveryStream, props: FirehosePutRecordActionProps = {}) {
6868
this.batchMode = props.batchMode;
6969
this.recordSeparator = props.recordSeparator;
7070
this.role = props.role;

packages/@aws-cdk/aws-iot-actions/lib/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ export * from './cloudwatch-logs-action';
22
export * from './cloudwatch-put-metric-action';
33
export * from './cloudwatch-set-alarm-state-action';
44
export * from './common-action-props';
5-
export * from './firehose-stream-action';
5+
export * from './firehose-put-record-action';
66
export * from './lambda-function-action';
77
export * from './s3-put-object-action';
88
export * from './sqs-queue-action';
9-

packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/firehose-stream-action.test.ts renamed to packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/firehose-put-record-action.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ test('Default firehose stream action', () => {
1515

1616
// WHEN
1717
topicRule.addAction(
18-
new actions.FirehoseStreamAction(stream),
18+
new actions.FirehosePutRecordAction(stream),
1919
);
2020

2121
// THEN
@@ -77,7 +77,7 @@ test('can set batchMode', () => {
7777

7878
// WHEN
7979
topicRule.addAction(
80-
new actions.FirehoseStreamAction(stream, { batchMode: true }),
80+
new actions.FirehosePutRecordAction(stream, { batchMode: true }),
8181
);
8282

8383
// THEN
@@ -100,7 +100,7 @@ test('can set separotor', () => {
100100

101101
// WHEN
102102
topicRule.addAction(
103-
new actions.FirehoseStreamAction(stream, { recordSeparator: actions.FirehoseStreamRecordSeparator.NEWLINE }),
103+
new actions.FirehosePutRecordAction(stream, { recordSeparator: actions.FirehoseRecordSeparator.NEWLINE }),
104104
);
105105

106106
// THEN
@@ -124,7 +124,7 @@ test('can set role', () => {
124124

125125
// WHEN
126126
topicRule.addAction(
127-
new actions.FirehoseStreamAction(stream, { role }),
127+
new actions.FirehosePutRecordAction(stream, { role }),
128128
);
129129

130130
// THEN

packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-stream-action.ts renamed to packages/@aws-cdk/aws-iot-actions/test/kinesis-firehose/integ.firehose-put-record-action.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ class TestStack extends cdk.Stack {
2525
destinations: [new destinations.S3Bucket(bucket)],
2626
});
2727
topicRule.addAction(
28-
new actions.FirehoseStreamAction(stream, {
28+
new actions.FirehosePutRecordAction(stream, {
2929
batchMode: true,
30-
recordSeparator: actions.FirehoseStreamRecordSeparator.NEWLINE,
30+
recordSeparator: actions.FirehoseRecordSeparator.NEWLINE,
3131
}),
3232
);
3333
}

packages/@aws-cdk/cloudformation-diff/lib/format-table.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import * as colors from 'colors/safe';
1+
import * as chalk from 'chalk';
22
import * as stringWidth from 'string-width';
33
import * as table from 'table';
44

@@ -93,7 +93,7 @@ function sum(xs: number[]): number {
9393
}
9494

9595
// What color the table is going to be
96-
const tableColor = colors.gray;
96+
const tableColor = chalk.gray;
9797

9898
// Unicode table characters with a color
9999
const TABLE_BORDER_CHARACTERS = {

0 commit comments

Comments
 (0)