Applicable when
- Custom Token Authorization scheme is to be used to enforce control access on your REST API using AWS API Gateway through CDK.
Implementation
1. Create REST API service (typically in your REST API stack)
import { RestApi } from "@aws-cdk/aws-apigateway";
const api = new RestApi(this, "rest-api", {
// config goes here...
});
2. Create your lambda function that will handle your custom authorization
import { APIGatewayAuthorizerResult, APIGatewayTokenAuthorizerEvent, PolicyDocument } from 'aws-lambda';
import { Log } from '../shared/util/logging';
export async function handler(event: APIGatewayTokenAuthorizerEvent): Promise<APIGatewayAuthorizerResult> {
const token = event.authorizationToken;
const policyDocument: PolicyDocument = {
Version: '2012-10-17',
Statement: [
{
Action: 'execute-api:Invoke',
Effect: token === process.env.MAINTENANCE_API_KEY ? 'Allow' : 'Deny',
Resource: 'arn:aws:execute-api:us-east-1:*:*',
},
],
};
Log.debug(policyDocument, token);
return {
policyDocument,
principalId: 'apigateway.amazonaws.com',
};
}
3. Define your Maintenance API Key in secrets manager and provide it as an env variable to your lambda function during deployment
const apiAuthLambda = this.createLambda('api-authorizer/handler.handler', LambdaName.ApiAuthorizer);
public createLambda(lambdaHandlerPath: string, name: LambdaName): LambdaFunction {
this.lambdas[name] = new LambdaFunction(this, lambdaName, {
// lambda config goes here...
environment: {
// other env variables here...
MAINTENANCE_API_KEY: this.secret.credentials.secretValueFromJson(SecretPropertyName.MaintenanceAPIKey).toString(),
},
});
return this.lambdas[name];
}
Note that you can have any form of custom authorization as per your choosing. In this example, we choose a statically defined Maintenance API key (hardcoded in secrets manager) and we allow any REST API call made with this authorizationToken.
4. Create authorizer role with lambda invocation permissions
import { PolicyDocument, Role, ServicePrincipal } from '@aws-cdk/aws-iam';
import { BackendStack } from '../stack/backend.stack';
import { withEnv } from '../util/const';
export function getAuthorizerRole(scope: BackendStack): Role {
const authorizerRoleName = withEnv('authorizer-role');
return new Role(scope, authorizerRoleName, {
roleName: authorizerRoleName,
assumedBy: new ServicePrincipal('apigateway.amazonaws.com'),
inlinePolicies: {
allowLambdaInvocation: PolicyDocument.fromJson({
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['lambda:InvokeFunction', 'lambda:InvokeAsync'],
Resource: `arn:aws:lambda:${scope.region}:${scope.account}:function:*`,
},
],
}),
},
});
}
5. Create api authorizer in your REST API stack
const apiAuthorizerName = withEnv('api-authorizer');
const apiAuthorizer = new CfnAuthorizer(this, apiAuthorizerName, {
restApiId: this.api.restApiId,
type: 'TOKEN',
name: apiAuthorizerName,
authorizerUri: `arn:aws:apigateway:us-east-1:lambda:path/2015-03-31/functions/${apiAuthLambda.functionArn}/invocations`,
identitySource: 'method.request.header.Api-Key',
authorizerCredentials: authorizerRole.roleArn,
});
Note that identitySource determines which parameter from your request is used to authorize the API call. In the above example, we are looking for a "Api-Key" property in header.
6. Attach authorizer to your REST API method
const method = api.root.getResource(resourceName).addMethod(verb, new LambdaIntegration(lambdaFunction, { proxy: true }), {
...methodOptions,
authorizationType: AuthorizationType.CUSTOM,
});
const resource = method.node.findChild('Resource');
const logicalId = apiAuthorizer.logicalId;
(resource as CfnResource).addPropertyOverride('AuthorizationType', AuthorizationType.CUSTOM);
(resource as CfnResource).addPropertyOverride('AuthorizerId', { Ref: logicalId });
Once you deploy your environment, you will see the authorization scheme set to custom for your REST API methods on the API Gateway console as follows:
You will also see that your created authorizers will be visible under authorizers tab:
Note that if you have followed the code snippets above you will see only one "api-authorizer". The above image is for a use case where it had 2 authorizers.
Invocations made via the API Gateway test dashboard bypass custom authorization (meaning all calls are automatically valid).
So, you can use the "Test" button on your "Test Authorizer" dialog to quickly test if it works as expected.
Or use POSTMAN to test if your calls work with right control access:
Comments
1 comment
Can yoy please provide code for this.
Please sign in to leave a comment.