概要
AWS Lambdaを使用せずにEventBridge + SNSでECRイメージスキャン結果のメール通知を行うCDKサンプルコード(TypeScript)を紹介します。
フィルター範囲
severityはECRイメージスキャンで定義されている重要度レベルを示しており、重要度は以下の通りです。
- UNDEFINED
- CRITICAL
- HIGH
- MEDIUM
- LOW
- INFORMATIONAL
本記事の例では重要度HIGH以上を通知対象としています。
ファイル構成
ファイル構成は以下です。
- bin/
- main.ts
- lib/
- ImageScan/
- ImageScanStack.ts
- ImageScan/
サンプルコード
bin/main.ts
bin/main.ts
#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { Environment } from 'aws-cdk-lib';
import { ImageScanStack } from '../lib/ImageScan/ImageScanStack';
if (process.env['NODE_ENV'] == null || process.env['NODE_ENV'] === '') {
throw new Error('NODE_ENV is not set');
}
if (process.env['AWS_PROFILE'] == null || process.env['AWS_PROFILE'] === '') {
throw new Error('AWS_PROFILE is not set');
}
const app = new cdk.App();
const env: Environment = {
account: '<AWSアカウント番号>',
region: '<AWSリージョン>',
};
new ImageScanStack(app, {
env: env,
});
lib/ImageScan/ImageScanStack.ts
lib/ImageScan/ImageScanStack.ts
import * as cdk from 'aws-cdk-lib';
import { Rule } from 'aws-cdk-lib/aws-events';
import { Topic } from 'aws-cdk-lib/aws-sns';
import { EmailSubscription } from 'aws-cdk-lib/aws-sns-subscriptions';
import { SnsTopic } from 'aws-cdk-lib/aws-events-targets';
import { Construct } from 'constructs';
/**
* 構築プロパティ。
*/
export interface ImageScanProps extends cdk.StackProps {}
export class ImageScanStack extends cdk.Stack {
private readonly _props: ImageScanProps;
constructor(scope: Construct, props: ImageScanProps) {
super(scope);
// SNSアラートトピック作成
const snsTopic = new Topic(this, 'SNSTopic', {
displayName: 'ImageScanResultAlert',
topicName: 'ImageScanResultTopic',
});
snsTopic.addSubscription(new EmailSubscription('user@example.com'));
// イメージスキャン結果通知イベント作成
const imageScanResultEvent = new Rule(this, 'ImageScanResultEvent', {
ruleName: 'ImageScanResultEvent',
description: 'ECR Image Scan Result Alert for ExampleRepositoryName',
eventPattern: {
source: ['aws.ecr'],
detailType: ['ECR Image Scan'],
detail: {
'repository-name': ['ExampleRepositoryName'], // イメージスキャン対象のリポジトリ名
'scan-status': ['COMPLETE'],
'finding-severity-counts': {
$or: [
// 重要度HIGH以上のみ通知するようにフィルタリング
{
CRITICAL: [{ numeric: ['>', 0] }],
},
{
HIGH: [{ numeric: ['>', 0] }],
},
],
},
},
},
});
// ターゲット追加
imageScanResultEvent.addTarget(new SnsTopic(snsTopic));
}
}
メール通知の発砲
重要度HIGH以上のイメージがプッシュされた際に以下のような内容のメール通知が発砲されます。
{"version":"0","id":"93d88051-2270-f8b7-ad0b-efea5b962e2b","detail-type":"ECR Image Scan","source":"aws.ecr","account":"<AWSアカウント番号>","time":"2023-06-24T02:00:00Z","region":"<AWSリージョン>","resources":["arn:aws:ecr:<AWSリージョン>:<AWSアカウント番号>:repository/ExampleRepositoryName"],"detail":{"scan-status":"COMPLETE","repository-name":"ExampleRepositoryName","image-digest":"sha256:b8a5bc211d11fa35c0074cfc64cb8f783356eeda0f242017e1e7efcd562a38d4","image-tags":["e7e685b","latest"],"finding-severity-counts":{"HIGH":9,"MEDIUM":0,"INFORMATIONAL":44,"LOW":0}}}
メールの本文は改行されていないJSONでそのまま出力されるため、必要に応じてEventBridgeの入力トランスフォーマー等で整形して下さい。