AWS CDKでパラメーターストア (SecureString) を参照するときはfromSecureStringParameterAttributesを使う
AWSで環境変数をSystems Managerのパラメータストアに保存して、EC2やLambdaから参照する場面は多くあります。
そういったとき、AWS CDKではこんなコード(EC2インスタンスを作り、既存のパラメータストアのRead権限を付与する例です)を書きますが、
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as ssm from 'aws-cdk-lib/aws-ssm'; export class ExampleStack extends Construct { constructor(scope: Construct, id: string, props: {}) { super(scope, id); const instance = new ec2.Instance(this, 'Instance', {/* 略 */}); const param = ssm.StringParameter.fromStringParameterAttributes(this, 'Param', { parameterName: '/example/param', }); param.grantRead(instance); // 以下略
パラメータの種類がSecureStringの場合、cdk diff
は問題ないのですが cdk deploy
をすると……
ExampleStack: deploying... [1/1] ExampleStack: creating CloudFormation changeset... ❌ ExampleStack failed: ValidationError: Parameters [/example/param] referenced by template have types not supported by CloudFormation.
“referenced by template have types not supported by CloudFormatin” という何のことだか分かりづらいエラーが発生します。
原因と修正
パラメータストアの「安全な文字列」(SecureString) は暗号化されているため、通常の文字列のパラメータとは扱い方が違います。例えば、通常の文字列のパラメータストアは param.stringValue
としてCDK (CFn)の中で文字列を参照できますが、SecureStringだとデプロイ時にエラーとなります。
参照するときに使う関数も異なり、fromStringParameterAttributes関数やfromStringParameterName関数ではなく、fromSecureStringParameterAttributes関数を使う必要があります。
そのため上のコードは、
import * as cdk from 'aws-cdk-lib'; import { Construct } from 'constructs'; import * as ec2 from 'aws-cdk-lib/aws-ec2'; import * as ssm from 'aws-cdk-lib/aws-ssm'; export class ExampleStack extends Construct { constructor(scope: Construct, id: string, props: {}) { super(scope, id); const instance = new ec2.Instance(this, 'Instance', {/* 略 */}); const param = ssm.StringParameter.fromSecureStringParameterAttributes(this, 'Param', { parameterName: '/example/param', }); param.grantRead(instance); // 以下略
とする必要がありました。
最後に
見返すとすごく単純な話ですが、何となくコーディングしていると関数名の “Secure” を見落としまってデプロイ時にエラーが出るという落とし穴の紹介でした。
ちなみにですが、APIキーやパスワードなどの文字列の保管には、Systems ManagerのパラメータストアではなくAWS Secretsを使った方がいいかもしれません。1つのパラメータをJSONで保管できたり、CDKでも参照が柔軟( hogeSecret.unsafeUnwrap()
で直接文字列を参照できるなど)になります。