認証情報の「終身刑」を終わらせろ:なぜ固定アクセスキーがインシデントの温床になるのか
現場でインシデント対応をしていると、溜息が出るほど繰り返される光景がある。「環境変数にハードコードされた AWS_ACCESS_KEY_ID と AWS_SECRET_ACCESS_KEY」だ。
エンジニアの君たちが便利さゆえに放置しているその長期認証情報は、攻撃者にとっての「金の卵を産むガチョウ」だ。一度流出すれば、たとえサーバーが破棄されても、ログが消されても、そのキーがローテーション(無効化)されない限り、攻撃者は永久に君たちのクラウド環境へバックドアを通し続ける。
今回は、この「認証の終身刑」を廃止し、STS(Security Token Service)を用いた一時的なセッション管理へ移行する実務的な話をしよう。
—
1. なぜ「固定キー」は即座に無効化できないのか
攻撃者が君たちのサーバーの .env や ~/.aws/credentials を奪取したとき、彼らは決して派手な破壊活動はしない。「静かに権限昇格し、バックアップを暗号化し、最後に踏み台として利用する」のが定石だ。
固定キーの最大の問題は、「いつ盗まれたか特定できない」ことにある。一度漏洩したキーを止めるには、全システムを停止してキーを再発行しなければならない。これに対し、STSによる一時認証は、「最大でも数時間で自動的に無効化される」という最強の防御策だ。万が一漏洩しても、攻撃者がアクセス権を得られる時間は限定的で、かつ漏洩元を追跡できる猶予が生まれる。
—
2. STSを活用した「ロールベース」の自動認証フロー(Python実装)
AWS SDKを使っているなら、手動でキーを管理するコードは今すぐ捨ててほしい。EC2やEKSを使っているなら、IAMロールをインスタンス/Podに付与するだけで、SDKが自動的にSTS経由で一時トークンを取得・更新してくれる。
もし、どうしても外部サービスや別の役割が必要な場合は、AssumeRole を使い、有効期限(DurationSeconds)を短く制限したトークンを発行するのが鉄則だ。
実装例:STSを用いたセッション生成(Python + Boto3)
import boto3
from datetime import datetime, timezone
def get_temporary_credentials(role_arn, session_name="AppSession"):
"""
指定されたロールのSTS一時認証情報を取得する
"""
sts_client = boto3.client('sts')
# セッションの有効期限を最小限の1時間に設定(デフォルト1時間)
assumed_role = sts_client.assume_role(
RoleArn=role_arn,
RoleSessionName=session_name,
DurationSeconds=3600
)
creds = assumed_role['Credentials']
# セッション情報を返却。これ以降、この一時キーを使って他リソースへアクセスする
return {
'aws_access_key_id': creds['AccessKeyId'],
'aws_secret_access_key': creds['SecretAccessKey'],
'aws_session_token': creds['SessionToken'],
'expiration': creds['Expiration']
}
# 使用例
# 開発者はこの一時キーを使い捨て、メモリ上にのみ保持すること
temp_creds = get_temporary_credentials("arn:aws:iam::123456789012:role/ReadOnlyAccess")
print(f"セッション有効期限: {temp_creds['expiration']}")
—
3. インフラ側で絶対にやるべき「IAMポリシーの絞り込み」
STSを使うといっても、そのロール自体が強すぎる権限(AdministratorAccessなど)を持っていれば本末転倒だ。STSを利用する際は、「そのアプリが絶対に必要とする最小限の権限」のみを付与したロールを用意せよ。
例えば、S3の特定のバケットにしかアクセスできないロールを作る場合、以下のような Inline Policy を適用する。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::my-secure-bucket-name/*"
}
]
}
ここで重要なのは、「IAMロールのセッション名(SessionName)をログに記録する」ことだ。CloudTrailには誰がどのロールで何をしたか記録される。AssumeRole の際のセッション名を一意にすることで、インシデント発生時のフォレンジック(追跡)が劇的に楽になる。
—
4. 現場のエンジニアへ:明日からのチェックリスト
1. 環境変数の棚卸し: サーバー上の .env や config.php に ACCESS_KEY という文字列がないか grep をかけろ。もしあれば、即座に削除し、IAMロールへの移行計画を立てろ。
2. SDKのデフォルト挙動を信じろ: 多くのエンジニアが「AWS環境なのにわざわざキーを渡す」無駄な実装をしている。SDKのデフォルト(認証情報プロバイダーチェーン)に任せれば、自動的にSTSトークンをリフレッシュしてくれる。
3. セッション期限の意識: DurationSeconds を長く設定する誘惑に駆られるな。1時間で十分だ。短ければ短いほど、攻撃者の攻撃窓(Attack Window)は狭まる。
最後に
セキュリティとは、「何もしないこと」ではなく「攻撃者が利益を得るコストを、彼らが諦めるレベルまで引き上げること」だ。固定キーを使うのは、家の鍵を玄関マットの下に置いているのと同じこと。
STSへの移行は、少しの設計変更で済む。だが、その「少し」が、君たちの会社を壊滅的なインシデントから救う最後の砦になる。今日、デプロイが終わったら、真っ先にIAMロールの設定を見直してくれ。それがプロの仕事だ。
コメント