Ccmmutty logo
Commutty IT
4
6 min read

AWS CDKでLambdaの環境変数と付き合う方法

https://cdn.magicode.io/media/notebox/2a68562c-fdf9-43fa-a2dd-54c6a3365eaa.jpeg
実は結構色々な選択肢があるのですが、今回は一番シンプルな方法を説明します。

結論編

AWS CDKでLambdaで環境変数を扱う場合、ハードコードできないものはSecrets ManagerとParameter Storeを使う。
Parameter Storeで通常の情報を管理し、Secrets Managerで秘匿情報を管理する。

アーキテクチャ

AWS CDKからCloudFormationに対して、クラウド内でSecrets ManagerやParameter Storeを参照するように指示する。

1. Parameter Storeの設定

  • AWS Management ConsoleからSystems Managerを開く(スクリーンショット1)
  • 画面内で、Parameter Storeの管理画面に遷移する
    • Systems Managerサービスのフィーチャーのため、Systems Managerの画面の左のメニューから探す
  • create parameterボタンから、パラメータを作成する(スクリーンショット2)
    • 秘匿情報はSecrets Managerに保存するため、こちらには保存しない。

2. Secrets Managerの設定

  • AWS Management ConsoleからSecrets Managerを開く
  • Step1でOther type of secretを選択し、plaintextタブを選んで値を入力する(スクリーンショット1)
  • Step2でこのSecretに名前をつける(スクリーンショット2)
  • Step3はそのまま次へ進む

3. AWS CDKコード(TypeScript、v1)

const someHandler = new lambda.Function(this, 'someHandler', {
  runtime: lambda.Runtime.NODEJS_16_X,
  code: lambda.Code.fromAsset('../backend/dist/handler'),
  environment: {
    SOME_ENV_VAR: 'hard-coded',
    ENVIRONMENT:
        // Parameter Store
        ssm.StringParameter.fromStringParameterAttributes(this, 'SomeHandlerParam1', {
          parameterName: 'someApp/backend/ENVIRONMENT'
        }).stringValue,
    SOME_CREDENTIAL:
        // Secrets Manager
        secretsmanager.Secret.fromSecretNameV2(this, 'SomeHandlerParam2', 'someApp/backend/credentials')
          .secretValue.toString()
  },
  handler: 'handler.handler',
  memorySize: 1024
})
※動作するプロダクションコードを上記スクリーンショットに合わせて手直ししております。もしスクリーンショットとの矛盾に気づかれましたら、ご指摘ください。

注意点

1. 設計について

CDKを実行しているマシン上で、実際のSecrets ManagerやParameter Store上の値を取得しようとすることは望ましくない。
このようにしてLambdaに環境変数を設定すると、CloudFormationテンプレート上に値が出てしまい、CloudFormationを参照できるIAMはそうした値を知ることができてしまい、セキュリティリスクにつながる。(公式より)
この記事で説明しているコードは、望ましい設計となっている。先述のアーキテクチャ図にあるとおり、CloudFormationの動的参照機能を活用しており、ローカルマシン上で値を取得しないためである。

2. Secrets Managerの費用について

  • Secrets Managerは1パラメータあたり0.4USD/月 + 少々(リクエスト分)かかる。
  • 費用対策として、同一アプリケーションで秘匿したい値が複数ある場合は、それらをJSONとして設定することが可能。以下のようなコードにすることで、シークレットの値をJSONとして扱い、キーを指定して値を抽出することが可能。
secretsmanager.Secret.fromSecretNameV2(this, 'SomeHandlerParam2', 'someApp/backend/credentials')
              .secretValueFromJson('someKey').toString()

3. 環境変数の変更について

Parameter StoreやSecrets Manager上で環境変数を変更しても、Lambdaに反映されるわけではない点は注意が必要である。 少々手間だが、以下2点の方法で環境変数を変更可能である。
  • 方法1. Parameter StoreやSecrets Manager上で値を更新して、同じ値をLambdaに手動で入れる
  • 方法2. Parameter StoreやSecrets Manager上で値を更新して、再度CDKのデプロイを走らせる。
    • cdk deployは生成されたCloudFormationテンプレートに差分が違いがないとデプロイされないことに注意。-fオプションをつけることで強制的にデプロイが可能。

背景説明編

背景

設定値の取り扱いとして、望ましくないパターンが次の2パターンである。
  1. AWS CDKのコードにベタ書きしてしまう
  2. AWS CDKをデプロイして、後からAWS Management ConsoleなどでLambdaの環境変数を手動で変更する
1.は自明として、2.のパターンについて解説する。
AWS CDKでLambdaをデプロイしたときの挙動は、環境変数は全て削除され、設定し直されるイメージになる。
つまり、
  • 既存のLambdaの環境変数の値を手動で変えても、デプロイのたびに上書きされる だけでなく、
  • CDK上に定義されていないLambdaの環境変数を手動で追加しても、デプロイのたびに抹消される ということである。
したがって、ハードコードできない環境変数は、全てParameter StoreやSecrets Managerに保存し、CloudFormationの動的参照でデプロイ時にLambdaに設定する必要がある。

サービスの使い分け

Secrets Managerのシークレットは、AWS上で暗号化されてストレージに保存される。
AWS CDKはParameter Storeの暗号化機能に対応していないため、秘匿情報はSecrets Managerに保存する必要がある。(2022年7月時点)

詳細

Parameter StoreにもSecureStringという機能があり、値を暗号化してAWS上に保存することができる。
しかし、CloudFormationは、Lambdaの環境変数としてParameter StoreのSecureStringを動的参照指定できない。(ごく僅かなサービスしか対応していない
したがって、AWS CDKでLambdaの環境変数に設定したい秘匿情報を保存するためには、Parameter Storeを利用することができない。

秘匿情報かどうかの判断

AWS CDKを使うにあたって、Parameter StoreとSecrets Managerのセキュリティに関する違いは、AWSのストレージ上に値が暗号化された状態で保存されるかどうかである。
この記事では、ストレージ上に暗号化されるべき値を秘匿情報と表現している。
AWSのストレージ上に値が暗号化されずに保存される状況が「セキュアでない」かどうかは、組織のポリシーの依るところが大きいと考える。
例えばクレデンシャルなどの情報も暗号化されて保存される必要がなければ、全てParamter Storeに保存しても問題ない。

追伸

認証周りが億劫で、LambdaにデプロイしているWebアプリにFirebase Authenticationを導入しました。(フロントエンドNuxt3 SSR on Lambda、バックエンドExpress on Lambda)
バックエンドでアクセストークンをverifyするために、Firebaseサービスアカウントのキーを環境変数に設定しようとしたところ、デプロイのたびにバックエンドが壊れて困ったので、この記事を書きました。
今までDynamoDBのテーブルや、CORS設定のためのフロントエンドのドメインなど、AWS CDK上で解決できる値が多かったので、初めて困ったかもしれません。
調べているうちにLambdaに環境変数を動的に設定する様々な方法と、そのメリデメに詳しくなってしまったので、(ニッチですが)どこかで記事にするかもしれません。

Discussion

コメントにはログインが必要です。