【小ネタ】AWS CDK で既存のリソースから Construct を取得する

2020.05.18

概要

AWS CDK で既存のリソースから Construct を取得したい要件があると思います。例えば、すでにAWSに手動で構築してあるリソースや、別スタックでデプロイされているリソースなどです。CDK では便利な grant* のメソッドがあり、これを使うことで面倒なIAMロール作成の手間を省くことができます。既存のリソースから grant* のメソッドを使って、IAM ロールを作成したい要件もあるかと思います。 この記事では、別スタックでデプロイされている DynamoDB の ARN を取得し、別スタックから Lambda の環境変数にテーブル名を設定、さらに DynamoDB へのアクセス権限を付与する IAM ロールの設定を行うためのソースサンプルを記述します。

環境

cdk --version                                                                                                                                                                                           [cm-sato]  月  5/18 18:50:32 2020
1.39.0 (build 5d727c1)

DynamoDB スタック

以下のようなDynamoDBスタックを作成します。今回は sampleTable というテーブルを作成しています。また、別のスタックで参照するために、ARN名をパラメーターストアに格納しています。

lin/dynamodb-stack.ts

import * as cdk from '@aws-cdk/core';
import { Table, BillingMode, AttributeType } from '@aws-cdk/aws-dynamodb';
import { StringParameter } from '@aws-cdk/aws-ssm';

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

    // The code that defines your stack goes here
    const sampleTable = new Table(this, 'sampleTable', {
      billingMode: BillingMode.PAY_PER_REQUEST,
      partitionKey: {
          type: AttributeType.STRING,
          name: 'id',
      },
    });

    // テーブルARNをパラメータストアに登録する
    new StringParameter(this, 'SampleTableArn', {
      parameterName: 'SampleTableArn',
      stringValue: sampleTable.tableArn,
    });
  }
}

Lambda スタック

次に、Lambda 用のスタックを作成します。ここで、既存のリソースから Construct を取得します。CDK では既存のリソースから取得するために、from*Arnメソッドが用意されています。 上記の DynamoDB スタックは先にデプロイされていることが前提となります。ここでは、パラメータストアから DynamoDB の Arn を取得し、そこから DynamoDB の Consturuct を取得しています。

lib/lambda-stack.ts

import * as cdk from '@aws-cdk/core';
import { Function, Code, Runtime } from '@aws-cdk/aws-lambda';
import { StringParameter } from '@aws-cdk/aws-ssm';
import { Table } from '@aws-cdk/aws-dynamodb';

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

    // パラメータストアから値を取得する
    const tableArn = StringParameter.valueForStringParameter(this, 'SampleTableArn');

    // 既存のテーブルを取得する
    const sampleTable = Table.fromTableArn(this, 'fromSampleTable', tableArn);

    const sampleFn = new Function(this, 'SampleFn', {
      code: Code.fromAsset('../handlers'),
      handler: 'sample.handler',
      runtime: Runtime.NODEJS_12_X,
      environment: {
        // 既存のテーブル情報からLambdaの環境変数にテーブル名を登録する
        SampleTableName: sampleTable.tableName
      }
    });

    // 既存のテーブル情報からIAMロールを作成しLambda関数に設定する
    sampleTable.grantFullAccess(sampleFn);
  }
}

デプロイ

bin/sample-stack.ts

#!/usr/bin/env node
import 'source-map-support/register';
import * as cdk from '@aws-cdk/core';
import { DynamoDBStack } from '../lib/dynamodb-stack';
import { LambdaStack } from '../lib/lambda-stack';

const app = new cdk.App();
new DynamoDBStack(app, 'DynamoDBStack');
new LambdaStack(app, 'LambdaStack');
cdk deploy DynamoDBStack
cdk deploy LambdaStack

まとめ

小ネタ的な記事でした。CDK でスタックを分割する場合に、クロススタック参照にしてしまうと、スタック間が密結合になってしまい、参照元のスタックを更新できなくなるなどの問題があります。その解決策としてパラメーターストアと from*Arn のメソッドを使って、スタック間を疎結合にするというような用途で使えると思います。