まずは前提知識から
登場人物を整理します。
Secrets Manager とは
用語メモ:Secrets Manager とは?
データベースのパスワードや API キーといった「秘密の文字列」を、コードに直書きせず安全に保管・取り出しできる AWS のサービスです。アプリは必要なときにここから取り出します。
ローテーションとは
用語メモ:ローテーションとは?
パスワードを定期的に新しいものへ作り替える仕組みです。たとえば「30 日ごとに自動でパスワードを変える」設定にしておけば、万一漏れても古いパスワードはすぐ使えなくなります。
このパスワードの作り替え作業を、AWS は 小さなプログラム(Lambda 関数) に自動でやらせます。これが本記事の主役「ローテーション Lambda」です。
用語メモ:Lambda とは?
サーバーを自分で用意しなくても、書いたプログラムを必要なときだけ実行してくれる AWS のサービスです。
用語メモ:ランタイム とは?
プログラムを動かす言語と、そのバージョンのことです。このローテーション Lambda は Python などのプログラミング言語で書かれていて、python3.10やpython3.12のように「Python の何番か」が決まっています。これが「ランタイム」です。
この記事が解決したいこと(ひとことで)
「Lambda の画面でランタイムを 3.12 にポチッと変えるだけ」では壊れます。 なぜ壊れるのか、どう直すのかが本記事のテーマです。
ランタイム(Python のバージョン)と、そのプログラムが使う部品(依存ライブラリ)はセット。バージョンだけを変えると部品が合わなくなって動かない。
いちばん大事な勘違い:これは「自分の」Lambda
ローテーションを有効にすると、Python 製のローテーション Lambda があなたのアカウントの中に自動で作られます。「AWS が用意してくれたもの」に見えますが、実体は あなたが所有する普通の Lambda 関数です。
たとえ:宅配便の「置き配ボックス」
宅配業者(AWS)が玄関先にボックスを設置してくれた状態をイメージしてください。設置はしてくれたけれど、ボックス自体はあなたの家の持ち物です。古くなったら交換するのもあなたの役目。AWS が勝手に新品へ取り替えてくれるわけではありません。
つまり ランタイムを新しくする責任はユーザー側にある、というのが出発点です。放っておくと古い Python のまま残ります。
中身をツリーで見ると、こうなっています(いまは「セットになっている」とだけ分かれば OK)。
- ローテーション Lambda(あなたの持ち物)
- プログラム本体(Python のコード)
- 依存ライブラリ(データベースに繋ぐための部品)
- ネイティブの部品(
.soという拡張子のファイル)← Python のバージョンに合わせて作られている
- ネイティブの部品(
- ランタイム設定(
python3.10など)← 上の.soと合っていないと読み込みに失敗する
なぜ「ランタイムだけ変える」と壊れるのか
ここが本記事の核心です。
ローテーション Lambda には、データベースに繋ぐための部品として .so(読み方:エスオー)というファイルが同梱されています。
用語メモ:
.so(共有オブジェクト)とは?
Python のコードから呼び出す「機械語で書かれた部品」です。データベース接続のような重い処理は、速くするためにこうしたネイティブ部品を使います。
この .so は 「Python 3.10 用」「Python 3.12 用」のように、特定の Python バージョン専用に作られています。
たとえ:充電ケーブルの規格
Python のバージョンを変えるのは、スマホを別の機種に替えるようなもの。本体(コード)を替えたのに古いケーブル(.so)を挿そうとしても、端子が合わず充電できません。「ケーブルだけ古いまま」だと動かないのと同じです。
だから、Lambda の画面で ランタイムの数字だけ 3.10 → 3.12 に書き換えると、同梱の .so が合わなくなって読み込みに失敗します。コードは Python でも、その下の部品がバージョンに固定されているためです。
「自分は何もしていないのに突然失敗し始めた」場合
古い Python バージョンは AWS によって廃止されることがあります。そのとき Lambda 側でランタイムだけが自動で新しい Python に引き上げられることがあり、すると コードと .so は古いまま なので、ある日突然失敗します。これが次のエラーの典型です。
-
Unable to import module 'lambda_function'(モジュールを読み込めません) -
pg module not found(PostgreSQL のドライバが見つかりません)
どちらも「Python と同梱部品(
.so)が合っていない」サインです。エラー文言は怖く見えますが、意味は「部品の規格が合わずプログラムを起動できなかった」ということです。
失敗したらどう見分ける?(とっかかり)
詳細版では細かい切り分け表がありますが、初級者はまず「本当に失敗しているか」と「それはランタイムのせいか」の 2 点を見れば十分です。
| 見るところ | 何が分かるか |
|---|---|
CloudTrail に RotationFailed イベント |
ローテーションが実際に失敗した、という確かな証拠 |
CloudWatch Logs に Unable to import module / pg module not found
|
ランタイムと .so の不一致が原因(=この記事の対象) |
Logs が Found credentials in environment variables の後で無音 |
ネットワーク(接続先に届いていない)の問題。ランタイムとは別物 |
用語メモ:CloudTrail / CloudWatch Logs とは?
CloudTrail は「AWS 上で誰が何をしたか」の操作記録、CloudWatch Logs は「プログラムが出した実行ログ」です。前者で「失敗した事実」、後者で「失敗の中身」を確認します。
ここで大事な注意が 1 つ。
Found credentials in environment variablesの後で止まっているのを「ランタイムの問題」と間違えないこと。 これは接続先(Secrets Manager)に届いていないネットワークの問題で、ランタイムを更新しても直りません。
また、 「ローテーション失敗専用の CloudWatch メトリクスは存在しません」。「専用の失敗カウンターがあるはず」と思ってアラームを組むと検知漏れになります。失敗の監視は CloudTrail の RotationFailed と Lambda の Errors を組み合わせて行います(ここは今は「専用メトリクスは無い」とだけ覚えれば OK)。
直し方は「作り方」で変わる(眺めるだけで OK)
正しい直し方は、その Lambda がどうやって作られたかで枝分かれします。
| 作られ方 | ざっくりした直し方 |
|---|---|
| コンソール(画面)で有効化 | 古い関数は手で直せないので、新しい関数を作り直すのが正攻法 |
CloudFormation(新しい指定 2024-09-16) |
ランタイムは指定せず、テンプレートそのままで更新すると AWS が最新版を入れてくれる |
CloudFormation(古い指定 2020-07-23) |
まず新しい指定への移行が推奨。デフォルトは Python 3.10 |
| SAR で導入 | SAR アプリのバージョンを上げて更新する |
| CDK で作成 | CDK を v2.258.0 以降に上げて再デプロイすると Python 3.12 になる |
| 自作(カスタム) | 自分で部品とランタイムを更新する |
用語メモ:CloudFormation / SAR / CDK とは?
どれも「AWS リソースを手作業ではなくコードや設定で作る」仕組みです。作った方法によって「更新の入り口」が変わるため、まずどれで作ったかを特定するのが直す第一歩になります。
いちばんの落とし穴
注意点を 1 つだけ持ち帰ってください。
- 新しい指定
AWS::SecretsManager-2024-09-16を使う場合は、Runtime(ランタイム)を自分で指定してはいけません。AWS が最新版を配り直す仕組みと食い違って壊れる恐れがあるためです。 -
Runtimeを自分で指定してよいのは、古い2020-07-23を使っていて、かつ同梱コード・.soが Python 3.10 と合わない、という条件をどちらも満たすときだけです。
出典
AWS::SecretsManager::RotationSchedule HostedRotationLambda - CloudFormation Template Reference
切り分けの全体像(簡略図)
切り分けフローを 3 ステップへ絞ったものです。
古い関数には別の注意もある
2021 年 12 月より前に作られたローテーション Lambda は、新しい認証方式(scram-sha-256)や暗号化通信(SSL/TLS)に対応していないテンプレートのことがあります。この場合はランタイム更新だけでは足りず、作り直しが必要になることがあります。
まとめ
- ローテーション Lambda は「AWS が作ってくれた自分の持ち物」。更新する責任はユーザー側にある。
-
ランタイム(Python のバージョン)と部品(
.so)はセット。バージョンだけを手で変えると部品が合わず壊れる。 - 「突然失敗し始めた」場合は、ランタイムだけ自動で上がって部品が古いまま、というパターンを疑う。
- 失敗の確認は CloudTrail
RotationFailed+ CloudWatch Logs。専用の失敗メトリクスは無い。 - 直し方は「どう作ったか」で枝分かれする。まず作り方を特定するのが第一歩。
もっと深く知りたくなったら、正しい更新手順・検証用の構成までを扱った詳細版へどうぞ。