Skip to content

Commit 2e73226

Browse files
committed
feat(apigatewayv2): add role support for lambda authorizers
1 parent effa46d commit 2e73226

File tree

6 files changed

+95
-1
lines changed

6 files changed

+95
-1
lines changed

packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-authorizers/test/http/integ.lambda.js.snapshot/AuthorizerInteg.template.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,23 @@
5353
"authfunctionServiceRoleFCB72198"
5454
]
5555
},
56+
"AuthRole900B840B": {
57+
"Type": "AWS::IAM::Role",
58+
"Properties": {
59+
"AssumeRolePolicyDocument": {
60+
"Statement": [
61+
{
62+
"Action": "sts:AssumeRole",
63+
"Effect": "Allow",
64+
"Principal": {
65+
"Service": "apigateway.amazonaws.com"
66+
}
67+
}
68+
],
69+
"Version": "2012-10-17"
70+
}
71+
}
72+
},
5673
"MyHttpApi8AEAAC21": {
5774
"Type": "AWS::ApiGatewayV2::Api",
5875
"Properties": {
@@ -153,6 +170,12 @@
153170
"ApiId": {
154171
"Ref": "MyHttpApi8AEAAC21"
155172
},
173+
"AuthorizerCredentialsArn": {
174+
"Fn::GetAtt": [
175+
"AuthRole900B840B",
176+
"Arn"
177+
]
178+
},
156179
"AuthorizerPayloadFormatVersion": "2.0",
157180
"AuthorizerResultTtlInSeconds": 300,
158181
"AuthorizerType": "REQUEST",

packages/@aws-cdk-testing/framework-integ/test/aws-apigatewayv2-authorizers/test/http/integ.lambda.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { HttpLambdaIntegration } from 'aws-cdk-lib/aws-apigatewayv2-integrations
44
import * as lambda from 'aws-cdk-lib/aws-lambda';
55
import { App, Stack, CfnOutput } from 'aws-cdk-lib';
66
import { HttpLambdaAuthorizer, HttpLambdaResponseType } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';
7+
import { Role, ServicePrincipal } from 'aws-cdk-lib/aws-iam';
78

89
/*
910
* Stack verification steps:
@@ -25,10 +26,15 @@ const authHandler = new lambda.Function(stack, 'auth-function', {
2526
code: lambda.Code.fromAsset(path.join(__dirname, '..', 'auth-handler'), { exclude: ['*.ts'] }),
2627
});
2728

29+
const authRole = new Role(stack, 'AuthRole', {
30+
assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),
31+
});
32+
2833
const authorizer = new HttpLambdaAuthorizer('LambdaAuthorizer', authHandler, {
2934
authorizerName: 'my-simple-authorizer',
3035
identitySource: ['$request.header.X-API-Key'],
3136
responseTypes: [HttpLambdaResponseType.SIMPLE],
37+
role: authRole,
3238
});
3339

3440
const defaultAuthorizer = new HttpLambdaAuthorizer('LambdaDefaultAuthorizer', authHandler, {

packages/aws-cdk-lib/aws-apigatewayv2-authorizers/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ Lambda authorizers use a Lambda function to control access to your HTTP API. Whe
167167

168168
Lambda authorizers depending on their response, fall into either two types - Simple or IAM. You can learn about differences [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html#http-api-lambda-authorizer.payload-format-response).
169169

170+
If the Lambda function is in another account, you need to provide an IAM role to the authorizer that has permission to invoke the Lambda function.
170171

171172
```ts
172173
import { HttpLambdaAuthorizer, HttpLambdaResponseType } from 'aws-cdk-lib/aws-apigatewayv2-authorizers';

packages/aws-cdk-lib/aws-apigatewayv2-authorizers/lib/http/lambda.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
AuthorizerPayloadVersion,
88
IHttpApi,
99
} from '../../../aws-apigatewayv2';
10-
import { ServicePrincipal } from '../../../aws-iam';
10+
import { ServicePrincipal, IRole } from '../../../aws-iam';
1111
import { IFunction } from '../../../aws-lambda';
1212
import { Stack, Duration, Names } from '../../../core';
1313
import { UnscopedValidationError, ValidationError } from '../../../core/lib/errors';
@@ -60,6 +60,15 @@ export interface HttpLambdaAuthorizerProps {
6060
* @default [HttpLambdaResponseType.IAM]
6161
*/
6262
readonly responseTypes?: HttpLambdaResponseType[];
63+
64+
/**
65+
* The IAM role that the API Gateway service assumes while invoking the authorizer.
66+
*
67+
* Supported only for REQUEST authorizers.
68+
*
69+
* @default - No role
70+
*/
71+
readonly role?: IRole;
6372
}
6473

6574
/**
@@ -119,6 +128,7 @@ export class HttpLambdaAuthorizer implements IHttpRouteAuthorizer {
119128
payloadFormatVersion: enableSimpleResponses ? AuthorizerPayloadVersion.VERSION_2_0 : AuthorizerPayloadVersion.VERSION_1_0,
120129
authorizerUri: lambdaAuthorizerArn(this.handler),
121130
resultsCacheTtl: this.props.resultsCacheTtl ?? Duration.minutes(5),
131+
role: this.props.role,
122132
});
123133

124134
this.handler.addPermission(`${Names.nodeUniqueId(this.authorizer.node)}-Permission`, {

packages/aws-cdk-lib/aws-apigatewayv2-authorizers/test/http/lambda.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DummyRouteIntegration } from './integration';
33
import { Duration, Stack } from '../../..';
44
import { Match, Template } from '../../../assertions';
55
import { HttpApi } from '../../../aws-apigatewayv2';
6+
import { Role, ServicePrincipal } from '../../../aws-iam';
67
import { Code, Function } from '../../../aws-lambda';
78
import * as lambda from '../../../aws-lambda';
89

@@ -36,6 +37,7 @@ describe('HttpLambdaAuthorizer', () => {
3637
IdentitySource: [
3738
'$request.header.Authorization',
3839
],
40+
AuthorizerCredentialsArn: Match.absent(),
3941
});
4042

4143
Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Route', {
@@ -200,4 +202,41 @@ describe('HttpLambdaAuthorizer', () => {
200202
// THEN
201203
expect(t).toThrow(Error);
202204
});
205+
206+
test('should use role when role is provided', () => {
207+
// GIVEN
208+
const stack = new Stack();
209+
const api = new HttpApi(stack, 'HttpApi');
210+
const role = new Role(stack, 'Role', { assumedBy: new ServicePrincipal('apigateway.amazonaws.com') });
211+
212+
const handler = new Function(stack, 'auth-function', {
213+
runtime: lambda.Runtime.NODEJS_LATEST,
214+
code: Code.fromInline('exports.handler = () => {return true}'),
215+
handler: 'index.handler',
216+
});
217+
218+
const authorizer = new HttpLambdaAuthorizer('BooksAuthorizer', handler, {
219+
responseTypes: [HttpLambdaResponseType.SIMPLE],
220+
role,
221+
});
222+
223+
// WHEN
224+
api.addRoutes({
225+
integration: new DummyRouteIntegration(),
226+
path: '/books',
227+
authorizer,
228+
});
229+
230+
// THEN
231+
Template.fromStack(stack).hasResourceProperties('AWS::ApiGatewayV2::Authorizer', {
232+
AuthorizerPayloadFormatVersion: '2.0',
233+
EnableSimpleResponses: true,
234+
AuthorizerCredentialsArn: {
235+
'Fn::GetAtt': [
236+
'Role1ABCC5F0',
237+
'Arn',
238+
],
239+
},
240+
});
241+
});
203242
});

packages/aws-cdk-lib/aws-apigatewayv2/lib/http/authorizer.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Construct } from 'constructs';
22
import { IHttpApi } from './api';
33
import { IHttpRoute } from './route';
44
import { CfnAuthorizer } from '.././index';
5+
import { IRole } from '../../../aws-iam';
56
import { Duration, Resource } from '../../../core';
67
import { ValidationError } from '../../../core/lib/errors';
78
import { addConstructMetadata } from '../../../core/lib/metadata-resource';
@@ -104,6 +105,15 @@ export interface HttpAuthorizerProps {
104105
* @default - API Gateway will not cache authorizer responses
105106
*/
106107
readonly resultsCacheTtl?: Duration;
108+
109+
/**
110+
* The IAM role that the API Gateway service assumes while invoking the authorizer.
111+
*
112+
* Supported only for REQUEST authorizers.
113+
*
114+
* @default - No role
115+
*/
116+
readonly role?: IRole;
107117
}
108118

109119
/**
@@ -178,6 +188,10 @@ export class HttpAuthorizer extends Resource implements IHttpAuthorizer {
178188
throw new ValidationError('authorizerUri is mandatory for Lambda authorizers', scope);
179189
}
180190

191+
if (props.type !== HttpAuthorizerType.LAMBDA && props.role) {
192+
throw new ValidationError('role is supported only for Lambda authorizers', scope);
193+
}
194+
181195
/**
182196
* This check is required because Cloudformation will fail stack creation if this property
183197
* is set for the JWT authorizer. AuthorizerPayloadFormatVersion can only be set for REQUEST authorizer
@@ -199,6 +213,7 @@ export class HttpAuthorizer extends Resource implements IHttpAuthorizer {
199213
authorizerPayloadFormatVersion,
200214
authorizerUri: props.authorizerUri,
201215
authorizerResultTtlInSeconds: props.resultsCacheTtl?.toSeconds(),
216+
authorizerCredentialsArn: props.role?.roleArn,
202217
});
203218

204219
this.authorizerId = resource.ref;

0 commit comments

Comments
 (0)