[Node.js] AWSアカウント内にデプロイされているS3イベントトリガーのLambda関数を列挙するスクリプト

2022.05.02

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

広島吉川です。

[Node.js] AWSアカウント内にデプロイされているCloudWatch EventsトリガーのLambda関数を列挙するスクリプト | DevelopersIO

先日のこちらの記事の続編として、今回はS3イベントトリガーのLambda関数一覧を取得してみたいと思います。

環境

  • node 16.13.0
  • npm 8.1.4
  • typescript 3.9.7
  • aws-cdk 2.20.0
  • aws-cdk-lib 2.20.0
  • constructs 10.0.115
  • @aws-sdk/* 3.67.0
  • markdown-table 3.0.2

S3イベントトリガーのLambda関数を準備

import * as cdk from 'aws-cdk-lib'
import { Construct } from 'constructs'

export class AwsPlaygroundStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    // Lambda関数
    for (let i = 0; i < 30; i++) {
      new cdk.aws_lambda.Function(this, `sampleFn${i}`, {
        functionName: `sampleFn${i}`,
        runtime: cdk.aws_lambda.Runtime.NODEJS_14_X,
        code: cdk.aws_lambda.AssetCode.fromInline(
          `export const handler = () => console.log('Hello lambda.')`
        ),
        handler: 'handler',
      })
    }

    // S3イベントトリガーのLambda関数
    for (let i = 0; i < 10; i++) {
      const lambdaFn = new cdk.aws_lambda.Function(this, `sampleBatchFn${i}`, {
        functionName: `sampleBatchFn${i}`,
        runtime: cdk.aws_lambda.Runtime.NODEJS_14_X,
        code: cdk.aws_lambda.AssetCode.fromInline(
          `export const handler = () => console.log('Hello lambda.')`
        ),
        handler: 'handler',
      })
      const s3Bucket = new cdk.aws_s3.Bucket(this, `s3Bucket${i}`, {
        removalPolicy: cdk.RemovalPolicy.DESTROY,
      })
      lambdaFn.addEventSource(
        new cdk.aws_lambda_event_sources.S3EventSource(s3Bucket, {
          events: [cdk.aws_s3.EventType.OBJECT_CREATED],
        })
      )
    }
  }
}

上のCDKコードで

  • トリガーなしのLambda関数 30個
  • S3イベントトリガーのLambda関数 10個

を準備しました。

AWS SDKでS3バケットに紐づくLambda関数を取得

S3クライアントの getBucketNotificationConfiguration() を使うことでバケットに紐づくLambda関数を取得できるようです。

import { S3 } from '@aws-sdk/client-s3'

const region = 'ap-northeast-3' // 大阪リージョン
const s3 = new S3({ region })

;(async () => {
  const output = await s3.getBucketNotificationConfiguration({
    Bucket: 'S3_BUCKET_NAME',
  })
  console.log(output.LambdaFunctionConfigurations)
})()

出力は以下となります。

[
  {
    Id: 'XXXXXXXXXXXXXXXXXXXX',
    LambdaFunctionArn: 'arn:aws:lambda:ap-northeast-3:AWS_ACCOUNT_ID:function:sampleBatchFn6',
    Events: [ 's3:ObjectCreated:*' ],
    Filter: undefined
  }

注意点として、S3クライアントを new する際に渡す region と取得対象のS3バケットのリージョンは一致させるようにしましょう。不一致の場合、下記のエラーが発生するようです。

PermanentRedirect: The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.

S3イベントをトリガーとしているLambda関数一覧を取得

では、

  • すべてのS3バケット一覧を取得
  • 大阪リージョンにあるバケット一覧に絞り込む
  • 各バケットに紐づくLambda関数を確認する

という方針でS3イベントトリガーのLambda関数ARN一覧を取得するコードを書いていきます。

import { S3 } from '@aws-sdk/client-s3'

const region = 'ap-northeast-3' // 大阪リージョン
const s3 = new S3({ region })

;(async () => {
  const listBucketsOutput = await s3.listBuckets({})

  // 全バケット名を取得
  const bucketNames = listBucketsOutput.Buckets!.map((bucket) => bucket.Name!)

  // 大阪リージョンのバケットに絞り込む
  const filteredBucketNames = (
    await Promise.all(
      bucketNames.map(async (bucketName) => {
        const getBucketLocationOutput = await s3.getBucketLocation({
          Bucket: bucketName,
        })
        if (getBucketLocationOutput.LocationConstraint !== region) {
          return undefined
        }

        return bucketName
      })
    )
  ).filter((bucketName) => bucketName != null) as string[]

  const result: {
    bucketName: string
    lambdaFnArns: string[]
  }[] = (
    await Promise.all(
      filteredBucketNames!.map(async (bucketName) => {
        const getBucketNotificationConfigurationOutput =
          await s3.getBucketNotificationConfiguration({
            Bucket: bucketName,
          })
        return {
          bucketName,
          lambdaFnArns:
            getBucketNotificationConfigurationOutput.LambdaFunctionConfigurations?.map(
              (lambdaFunctionConfiguration) =>
                lambdaFunctionConfiguration.LambdaFunctionArn!
            ) ?? [],
        }
      })
    )
  ).filter((item) => item.lambdaFnArns.length > 0) // 紐づくLambda関数が1つ以上あるバケットに絞り込む
  console.log(result)
})()

出力は以下のようになります。

[
  {
    bucketName: 'S3_BUCKET_NAME_0'
    lambdaFnArns: [
      'arn:aws:lambda:ap-northeast-3:AWS_ACCOUNT_ID:function:sampleBatchFn0'
    ]
  },
  {
    bucketName: 'S3_BUCKET_NAME_1',
    lambdaFnArns: [
      'arn:aws:lambda:ap-northeast-3:AWS_ACCOUNT_ID:function:sampleBatchFn1'
    ]
  },
  {
    bucketName: 'S3_BUCKET_NAME_2',
    lambdaFnArns: [
      'arn:aws:lambda:ap-northeast-3:AWS_ACCOUNT_ID:function:sampleBatchFn2'
    ]
  },
  "...(以下省略)..."
]

参考