Lambda から Secrets Manager のシークレットを取得する方法 ── ソースコードにパスワードを書かない

目次

概要

データベースのユーザー名とパスワードを、アプリケーションのソースコードや設定ファイルに直接書いてしまうことがあります。動きはしますが、リポジトリを見られる人には誰にでもパスワードが見え、パスワードを変えるたびにコードを書き換えてデプロイし直す必要があります。

AWS Secrets Manager に認証情報を保存しておけば、アプリケーションは実行時に API(GetSecretValue)で値を取りに行くだけで済みます。コードに残るのはシークレットの名前だけです。さらに Secrets Manager には、保存した認証情報を定期的に変えるローテーションの仕組みがあります。

この記事では、認証情報の置き場所の選択肢(ソースコード、環境変数、Parameter Store、Secrets Manager)を比べたうえで、Lambda から Secrets Manager のシークレットを取得するコードと、そのために必要な実行ロールの権限を整理します。実践では、権限が無いと取得に失敗することを確かめてから、実行ロールに権限を足して取得できるようにします。

Lambda はシークレット名だけを持ち、実行ロールの権限で Secrets Manager から値を取る
Lambda はシークレット名だけを持ち、実行ロールの権限で Secrets Manager から値を取る
クラウドおさる

倉庫の合言葉を巻物に書いて持ち歩くと、落としたときに猿山じゅうに知れ渡るでござる。合言葉は長老の金庫に預けて、必要なときだけ聞きに行く。今日はその「聞きに行く」部分を作るでござるよ。

この記事のメリット

  • 認証情報をソースコード・環境変数・Parameter Store・Secrets Manager に置いた場合の違いを説明できるようになる
  • Lambda から GetSecretValue でシークレットを取得するコードを書けるようになる
  • シークレットの取得に必要な実行ロールの権限(secretsmanager:GetSecretValue)を設定できるようになる
  • 「自動ローテーションが必要なら Secrets Manager」という使い分けを判断できるようになる

執筆者とキャラクター紹介

執筆者:土肥(とひ)

株式会社ジェニュインの代表であり元エンジニア。これまでオンプレミスと AWS 環境のインフラ業務を担当。AWS 認定資格の学習で得た知識を、ハンズオンとともに解説するのが得意。直近では新人の教育も行っており、これから技術を学ぶ方が納得できる解説を心がけています。基礎編・Cloud Practitioner の記事では、解説役としても登場します。

土肥

クラウドおさる

クラウドおさる

はじめましてでござる。弊猿はクラウドおさる。IT インフラが異常に発達した猿山から、雲に乗って地上の AWS を学びに降りてきたのでござる。

クラウドおさる

基礎編や Cloud Practitioner の記事では、とひさんに素朴な疑問をぶつける役でござるな。Security - Specialty などの記事では、要所でワンポイントや注意点をひとこと添えるでござる。

クラウドおさる

猿山にもデータセンターや監視当番があって、地上で起きることはだいたい猿山にも同じ仕組みがあるのでござる。例え話がつい猿山に寄るのは、弊猿の癖でござる。

技術解説

認証情報の置き場所の比較

置き場所中身を見られる人変えるときの作業自動ローテーション
ソースコードリポジトリを読める全員コードを書き換えて再デプロイできない
環境変数(Lambda・EC2・AMI など)関数やインスタンスの設定を見られる人設定を書き換えて再デプロイ・再起動できない
Systems Manager Parameter Store(SecureString)パラメータの読み取り権限を持つ人パラメータを更新組み込みの仕組みは無い
AWS Secrets Managerシークレットの読み取り権限を持つ人シークレットを更新できる(RDS などとの統合、または Lambda によるローテーション)

「安全に保管する」だけなら Parameter Store の SecureString でも KMS で暗号化して保管できます。「自動でローテーションする」まで求められる場合は Secrets Manager を選びます。Secrets Manager は、Amazon RDS・Amazon Redshift・Amazon DocumentDB などの認証情報について、ローテーションの仕組みをあらかじめ用意しています。

クラウドおさる

「環境変数に入れたから安全」と思いがちでござるが、関数の設定を見られる人には丸見えで、変えるには関数を更新するしかないのでござる。ローテーションまで求められたら Secrets Manager、と覚えておくでござるぞ。

アプリケーションからの取得

アプリケーションは、SDK の GetSecretValue でシークレットを取得します。Python(boto3)なら次のようになります。

import json
import boto3

client = boto3.client("secretsmanager")
resp = client.get_secret_value(SecretId="dva-lab/db-credentials")
secret = json.loads(resp["SecretString"])   # {"username": "...", "password": "...", ...}

コードに書くのはシークレットの名前(または ARN)だけです。名前も環境変数で渡せば、環境ごとに別のシークレットを指せます。ローテーションでパスワードが変わっても、アプリケーションは次に取得したときに新しい値を受け取るので、コードの変更は要りません。

パスワードを変えるとき:直書きは再デプロイ、Secrets Manager は取得し直すだけ
パスワードを変えるとき:直書きは再デプロイ、Secrets Manager は取得し直すだけ

取得に必要な権限

Lambda 関数が AWS のサービスを呼ぶときの権限は、実行ロールで決まります。シークレットを取得するには、実行ロールに次の権限が必要です。

権限必要になる場面
secretsmanager:GetSecretValueシークレットの値を取得する
kms:Decryptシークレットをカスタマー管理キーで暗号化している場合(AWS マネージドキー aws/secretsmanager なら不要)

権限が無いと、GetSecretValue は AccessDeniedException を返します。リソースは * ではなく、取得するシークレットの ARN に絞ります。

呼び出すたびに取りに行かない工夫

GetSecretValue は API 呼び出しごとに料金がかかり、呼び出しの分だけ処理も遅くなります。Lambda では、関数の外側(初期化時)で取得して実行環境の中で使い回したり、AWS Parameters and Secrets Lambda Extension を使って取得した値をキャッシュしたりする方法があります。

クラウドおさる

合言葉は金庫から聞いてきて、しばらくは覚えておくのでござる。毎回長老を起こしに行っていたら、長老も弊猿もくたびれるでござるな。

新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

実践

ハンズオンガイド7 ステップ画面 5 枚

コンソールの横に開いて、チェックしながら進めましょう。

ガイドを開く

別タブで開きます。チェックはこのブラウザに保存されます。

Lambda 関数 dva-secret-lab-fn は、環境変数 SECRET_ID に入っている名前のシークレットを取得して、ユーザー名・ホスト名・パスワードの文字数を返します(パスワードそのものは返しません)。まずシークレットを作り、権限が無い状態で呼び出して失敗することを確かめてから、実行ロールに権限を足します。

前提条件

  • リージョン: ap-northeast-1(東京)
  • 以下のリソースが作成済みであること

まだ用意していない場合は、「作り方の参考」の記事の手順で作れます。リソース名は、この記事の名前に読み替えてください。

リソース種別リソース名内容作り方の参考
Lambda 関数dva-secret-lab-fnPython 3.13。環境変数 SECRET_ID = dva-lab/db-credentials。上の「アプリケーションからの取得」と同じ処理で、取得したシークレットからユーザー名・ホスト名・パスワードの文字数を返すAWS Lambda で関数を作成しイベント駆動で実行する
IAM ロールdva-secret-lab-role上の関数の実行ロール。CloudWatch Logs への出力(AWSLambdaBasicExecutionRole)だけを許可―

作成するリソース一覧

リソース種別リソース名用途
シークレットdva-lab/db-credentialsデータベースの認証情報(ハンズオン用のダミー)
インラインポリシーdva-secret-lab-get-secret実行ロールにシークレットの取得を許可する

手順 1: シークレットを作る

AWS マネジメントコンソールにログインし、リージョンが ap-northeast-1(東京)であることを確認します。上部の検索バーに Secrets Manager と入力し、「Secrets Manager」を選択します。

「新しいシークレットを保存する」をクリックし、以下を設定します。

  • シークレットのタイプ: 「その他のシークレットのタイプ」
  • キー/値のペア: 「行を追加」で次の 4 行を入力
  • username: app_user
  • password: Handson-Passw0rd-2026(ハンズオン用のダミー)
  • host: db.example.internal
  • port: 3306
  • 暗号化キー: aws/secretsmanager(デフォルト)
シークレットのタイプとキー/値のペアを入力した画面
シークレットのタイプとキー/値のペアを入力した画面

「次」をクリックし、シークレットの名前に dva-lab/db-credentials と入力して「次」をクリックします。ローテーションの設定はデフォルト(無効)のまま「次」をクリックし、レビュー画面で「保存」をクリックします。

手順 2: 権限が無い状態で関数を呼び出す

上部の検索バーに Lambda と入力し、「Lambda」を選択します。関数の一覧から dva-secret-lab-fn を開き、「テスト」タブを選択します。イベント名に empty と入力し、イベント JSON は {} のまま「テスト」をクリックします。

実行結果は「実行中の関数: 失敗」になります。その下の「詳細」を開くと、Response の errorMessage に AccessDeniedException と、実行ロール dva-secret-lab-role が secretsmanager:GetSecretValue を実行する権限を持っていない旨が表示されます。

テストの実行結果(AccessDeniedException が表示されている状態)
テストの実行結果(AccessDeniedException が表示されている状態)
クラウドおさる

シークレットはちゃんとあるのに、関数の背負っている役目(実行ロール)に「金庫を開けてよい」と書いていないので断られたのでござるな。

手順 3: 実行ロールに取得の権限を足す

関数の画面の「設定」タブ →「アクセス権限」を選択し、「実行ロール」のロール名 dva-secret-lab-role をクリックします。IAM コンソールでロールが開きます。

「許可を追加」→「インラインポリシーを作成」を選択します。ポリシーエディタで「JSON」を選び、次のポリシーを入力します。Resource は、手順 1 で作ったシークレットの ARN(Secrets Manager のシークレットの詳細画面で確認できます)に置き換えます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:ap-northeast-1:<アカウントID>:secret:dva-lab/db-credentials-XXXXXX"
        }
    ]
}
インラインポリシーの JSON を入力した画面
インラインポリシーの JSON を入力した画面

「次へ」をクリックし、ポリシー名に dva-secret-lab-get-secret と入力して「ポリシーの作成」をクリックします。ロールの「許可ポリシー」に dva-secret-lab-get-secret が追加されたことを確認します。

手順 4: もう一度呼び出す

Lambda コンソールに戻り、dva-secret-lab-fn の「テスト」タブで、もう一度「テスト」をクリックします。今度は成功し、username に app_user、host に db.example.internal、password_length にパスワードの文字数、version_id に取得したシークレットのバージョン ID が返ります(結果は「詳細」を開くと見られます)。

テストの実行結果(シークレットの取得に成功した状態)
テストの実行結果(シークレットの取得に成功した状態)

関数のコードと環境変数には、パスワードはどこにも書かれていません。関数は実行のたびに、Secrets Manager から値を取りに行っています。

手順 5: ローテーションの設定画面を確かめる

Secrets Manager のコンソールで dva-lab/db-credentials を開き、「ローテーション」タブを選択して「ローテーションを編集」をクリックします。「ローテーション設定を編集する」ダイアログが開き、「自動ローテーション」をオンにすると、ローテーションのスケジュールと、ローテーションを行う Lambda 関数を指定する欄が表示されます。今回のシークレットは「その他のシークレットのタイプ」なので、パスワードを変える処理(Lambda 関数)を自分で用意する必要があります。RDS などのデータベースのタイプを選んだシークレットでは、AWS が用意したローテーションの仕組みを使えます。

ローテーションの編集画面(自動ローテーションのスケジュールと Lambda 関数の指定)
ローテーションの編集画面(自動ローテーションのスケジュールと Lambda 関数の指定)

ここでは設定を保存せずに「Cancel」をクリックします。RDS の認証情報を実際にローテーションする流れは、Secrets ManagerによるECSコンテナの認証情報管理と自動ローテーション で扱っています。

クラウドおさる

アプリは名前だけ知っていて、中身は金庫番(Secrets Manager)が管理する。だから合言葉を変えても、アプリは書き換えずに済むのでござる。

まとめ

要件選ぶもの
認証情報をコードに書かずに安全に保管するParameter Store の SecureString、または Secrets Manager
さらに自動でローテーションするSecrets Manager
Lambda から取得できるようにする実行ロールに secretsmanager:GetSecretValue(カスタマー管理キーなら kms:Decrypt も)
  • ソースコードや環境変数に入れた認証情報は、見られる範囲が広く、変えるたびに再デプロイが要る
  • Secrets Manager に保存すれば、アプリケーションは GetSecretValue で実行時に取得し、コードにはシークレットの名前だけが残る
  • 取得の権限は Lambda の実行ロールで与える。権限が無いと AccessDeniedException になる
  • 自動ローテーションは Secrets Manager の機能。RDS などには組み込みの仕組みがあり、その他のシークレットはローテーション用の Lambda 関数を用意する
  • 呼び出しのたびに取得しないよう、初期化時に取得して使い回すか、Parameters and Secrets Lambda Extension でキャッシュする

参照先

キャリア相談
クラウドおさる

独学の先に、AWS の仕事がある ── ジュニアおさるのキャリア相談

CLF には受かったけれど、次に何をすればいいのか分からない。独学で AWS を学ぶジュニアおさるの相談に、株式会社ジェニュイン代表の土肥が答えています。

  • ✓資格はゴールか、CLF の次に何から手を付けるか
  • ✓EC2 の次に作ってみる構成と、IaC・コスト管理
  • ✓実務経験ゼロでも、面接で話せる「これまで」の作り方
新卒・未経験の方へ
クラウドおさる

AWS を仕事にしたい方へ ── 新卒・未経験から

この記事を書いているのは、AWS の設計・構築を仕事にしている現役エンジニアです。運営元の株式会社ジェニュインでは、新卒・未経験の方も募集しています。異業種や文系からインフラエンジニアになり活躍しているメンバーもいます。

  • ✓システム開発・WEB エンジニア / インフラ構築などの職種で、未経験から応募できます
  • ✓未経験から入社した社員の声を含む社員アンケートを掲載
  • ✓応募フォームから 1 分で応募できます

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社ジェニュイン(https://genuine-pt.jp)の代表取締役.

2018年〜インフラエンジニアとしてキャリアをスタートし、オンプレミスのネットワーク・サーバ環境で3年半、クラウド環境で4年半の8年間エンジニアとして従事。
2021年に佐藤氏の創業した株式会社Luxyを引き継ぎ、代表に就任。
その後アガルートグループ内の株式会社ジェニュインと合併。
合併後同社代表に就任。

目次