-
Notifications
You must be signed in to change notification settings - Fork 4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(events): add target to make AWS API calls (#3720)
Add a AwsApi rule target to make AWS API calls. Comparable to the AwsCustomResource in terms of API and IAM permissions. Closes #2538
- Loading branch information
Showing
14 changed files
with
861 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,3 +15,5 @@ coverage | |
.LAST_PACKAGE | ||
*.snk | ||
.cdk.staging | ||
|
||
lib/sdk-api-metadata.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
20 changes: 20 additions & 0 deletions
20
packages/@aws-cdk/aws-events-targets/lib/aws-api-handler/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
// tslint:disable:no-console | ||
import AWS = require('aws-sdk'); | ||
import { AwsApiProps } from '../aws-api'; | ||
|
||
export async function handler(event: AwsApiProps) { | ||
console.log('Event: %j', event); | ||
console.log('AWS SDK VERSION: ' + (AWS as any).VERSION); | ||
|
||
const awsService = new (AWS as any)[event.service](event.apiVersion && { apiVersion: event.apiVersion }); | ||
|
||
try { | ||
const response = await awsService[event.action](event.parameters).promise(); | ||
console.log('Response: %j', response); | ||
} catch (e) { | ||
console.log(e); | ||
if (!event.catchErrorPattern || !new RegExp(event.catchErrorPattern).test(e.code)) { | ||
throw e; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import events = require('@aws-cdk/aws-events'); | ||
import iam = require('@aws-cdk/aws-iam'); | ||
import lambda = require('@aws-cdk/aws-lambda'); | ||
import path = require('path'); | ||
import metadata = require('./sdk-api-metadata.json'); | ||
import { addLambdaPermission } from './util'; | ||
|
||
/** | ||
* AWS SDK service metadata. | ||
*/ | ||
export type AwsSdkMetadata = {[key: string]: any}; | ||
|
||
const awsSdkMetadata: AwsSdkMetadata = metadata; | ||
|
||
export interface AwsApiProps { | ||
/** | ||
* The service to call | ||
* | ||
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html | ||
*/ | ||
readonly service: string; | ||
|
||
/** | ||
* The service action to call | ||
* | ||
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html | ||
*/ | ||
readonly action: string; | ||
|
||
/** | ||
* The parameters for the service action | ||
* | ||
* @see https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/index.html | ||
* | ||
* @default - no parameters | ||
*/ | ||
readonly parameters?: any; | ||
|
||
/** | ||
* The regex pattern to use to catch API errors. The `code` property of the | ||
* `Error` object will be tested against this pattern. If there is a match an | ||
* error will not be thrown. | ||
* | ||
* @default - do not catch errors | ||
*/ | ||
readonly catchErrorPattern?: string; | ||
|
||
/** | ||
* API version to use for the service | ||
* | ||
* @see https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/locking-api-versions.html | ||
* @default - use latest available API version | ||
*/ | ||
readonly apiVersion?: string; | ||
|
||
/** | ||
* The IAM policy statement to allow the API call. Use only if | ||
* resource restriction is needed. | ||
* | ||
* @default - extract the permission from the API call | ||
*/ | ||
readonly policyStatement?: iam.PolicyStatement; | ||
} | ||
|
||
/** | ||
* Use an AWS Lambda function that makes API calls as an event rule target. | ||
*/ | ||
export class AwsApi implements events.IRuleTarget { | ||
constructor(private readonly props: AwsApiProps) {} | ||
|
||
/** | ||
* Returns a RuleTarget that can be used to trigger this AwsApi as a | ||
* result from a CloudWatch event. | ||
*/ | ||
public bind(rule: events.IRule, id?: string): events.RuleTargetConfig { | ||
const handler = new lambda.SingletonFunction(rule as events.Rule, `${rule.node.id}${id}Handler`, { | ||
code: lambda.Code.fromAsset(path.join(__dirname, 'aws-api-handler')), | ||
runtime: lambda.Runtime.NODEJS_10_X, | ||
handler: 'index.handler', | ||
uuid: 'b4cf1abd-4e4f-4bc6-9944-1af7ccd9ec37', | ||
lambdaPurpose: 'AWS', | ||
}); | ||
|
||
if (this.props.policyStatement) { | ||
handler.addToRolePolicy(this.props.policyStatement); | ||
} else { | ||
handler.addToRolePolicy(new iam.PolicyStatement({ | ||
actions: [awsSdkToIamAction(this.props.service, this.props.action)], | ||
resources: ['*'] | ||
})); | ||
} | ||
|
||
// Allow handler to be called from rule | ||
addLambdaPermission(rule, handler); | ||
|
||
return { | ||
id: '', | ||
arn: handler.functionArn, | ||
input: events.RuleTargetInput.fromObject(this.props), | ||
targetResource: handler, | ||
}; | ||
} | ||
} | ||
|
||
/** | ||
* Transform SDK service/action to IAM action using metadata from aws-sdk module. | ||
*/ | ||
function awsSdkToIamAction(service: string, action: string): string { | ||
const srv = service.toLowerCase(); | ||
const iamService = awsSdkMetadata[srv].prefix || srv; | ||
const iamAction = action.charAt(0).toUpperCase() + action.slice(1); | ||
return `${iamService}:${iamAction}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.