こんにちは!インフラやクラウドのセキュリティを担当していると、「APIキーって、どうやって安全に管理すればいいの?」という質問を本当によく受けます。特に、新人のIT担当者さんや、これから開発を始める方にとっては、聞き慣れない用語ばかりで不安になりますよね。
大丈夫です。今回は、API GatewayにおけるAPIキーの管理と、安全なローテーション(定期的な交換)の仕組みについて、身近な例えを交えながら一歩ずつ優しく紐解いていきましょう!
—
1. 家の鍵で例える「APIキー」の正体
まずは、APIキーがどんな役割を持っているのか、私たちの日常生活に置き換えて考えてみましょう。
想像してみてください。あなたは「大切なデータが保管されている自分専用の倉庫(API)」を持っています。この倉庫に行くためのドアには鍵穴がついていますよね。このドアを開けるための「合鍵」こそが、APIキーなんです。
もし、この合鍵をそこらへんの道端にポロっと落としたり、誰でも見られるSNSに写真を載せたりしたらどうなるでしょうか?
そう、悪意を持った泥棒(攻撃者)がその鍵を拾って、あなたの大切な倉庫に勝手に入り込み、中身を盗み見たり、ぐちゃぐちゃに荒らしたりしてしまいますよね。
APIの世界でもまったく同じことが起きます。プログラムの中でAPIキーをそのままベタ書き(ハードコード)して、GitHubなどの公開リポジトリにうっかりアップロードしてしまう事故が後を絶ちません。攻撃者は常にインターネット上のそうした「うっかり」を自動ツールで巡回して探しています。一度キーがバレると、不正なリクエストを大量に送り込まれて、法外なクラウドの利用請求を請求される……なんていう悪夢のような事態につながるのです。
だからこそ、「鍵を安全にしまう場所」と「定期的に鍵を新しくする仕組み(ローテーション)」が必要になります。
—
2. 金庫(Secrets Manager)に鍵を預ける理由
「じゃあ、その合鍵をどこに保管すればいいの?」という疑問がわきますよね。
ソースコードの中に直接書いてはいけないとなると、次に思いつくのはサーバーの設定ファイルでしょうか? でも、それも権限管理を間違えると危険です。ここで登場するのが、クラウドサービスが提供している Secrets Manager(シークレットマネージャー) という強力な仕組みです。
Secrets Managerは、いわば「銀行の厳重な貸金庫」だと思ってください。
アプリケーション(プログラム)は、普段は合鍵を持たず、必要な時だけ専用の暗号化された通信を使って、この貸金庫からキーを安全に取り出して使います。これなら、もしアプリケーションのソースコードが万が一見られても、肝心の合鍵は貸金庫の中にあるため、無事に難を逃れることができます。
—
3. 定期的な鍵の交換(ローテーション)が最強の防犯になる理由
「でも、一度貸金庫に入れたなら、もうずっと同じ鍵でいいのでは?」と思いますよね。
実は、ここにセキュリティの大きな罠があります。
どれだけ厳重に管理していても、目に見えないところでキーが漏洩してしまうリスクはゼロにはなりません。例えば、従業員のパソコンがマルウェアに感染したり、古いログファイルにキーがうっかり残っていたり……。
そこで重要になるのが 「APIキーのローテーション(定期的な交換)」 です。
これは、家の防犯に例えるなら「定期的に鍵の交換をする」のと同じです。
たとえ万が一、古い鍵がどこかに漏洩していたとしても、30日や90日といった短いスパンで新しい鍵に自動で交換していれば、古い鍵は「すでに使えない古い鉄くず」になっているため、泥棒の侵入を防ぐことができます。
—
4. 実践!AWS API GatewayとSecrets Managerの連携イメージ
ここからは、実務でどのようにこの仕組みを構築するのか、具体的なイメージを見ていきましょう。
今回は、API Gatewayで受け取ったリクエストを検証するLambda(サーバーレス関数)から、Secrets Managerに保存された最新のAPIキーを安全に取得するPythonのコード例をご紹介します。
import os
import boto3
from botocore.exceptions import ClientError
# AWSのSecrets Managerクライアントを初期化します
# (インフラの権限設定により、この関数にはシークレットを読む最小限の権限が与えられています)
client = boto3.client('secretsmanager')
def get_secret_api_key():
secret_name = "prod/app/apikey" # 貸金庫に登録されているキーの名前
try:
# 貸金庫(Secrets Manager)から安全にキーを取り出します
response = client.get_secret_value(SecretId=secret_name)
# シークレットがプレーンテキストかJSON形式かによって取得方法を調整します
if 'SecretString' in response:
return response['SecretString']
else:
# バイナリの場合はデコード処理を行います
return response['SecretBinary']
except ClientError as e:
# 万が一、貸金庫へのアクセスに失敗した時のエラーハンドリング
print(f"シークレットの取得に失敗しました: {e}")
raise e
def lambda_handler(event, context):
"""
API Gatewayからのリクエストを処理するメインの関数です
"""
# クライアントから送られてきたリクエストヘッダーからAPIキーを取得します
# (ここでは例として `x-api-key` ヘッダーを想定しています)
headers = event.get('headers', {})
client_provided_key = headers.get('x-api-key')
# 貸金庫から最新の正しいAPIキーを安全に呼び出します
valid_api_key = get_secret_api_key()
# クライアントのキーと、正しいキーを安全に比較します
if client_provided_key == valid_api_key:
return {
'statusCode': 200,
'body': '認証成功!安全なデータをお返しします。'
}
else:
return {
'statusCode': 401,
'body': '認証失敗:有効なAPIキーではありません。'
}
コードのポイント
1. コードに直書きしない: ソースコード内には、シークレットの名前(prod/app/apikey)だけを指定し、実際のキー文字列は一切書いていません。
2. 動的な取得: リクエストが来るたび、あるいは適切なキャッシュ時間を挟みながら、Secrets Managerから最新のキーを参照します。これにより、ローテーションが行われてもシステムを止めることなくスムーズに切り替えることができます。
—
5. 現場のホワイトハッカーから一言
APIキーの管理とローテーションは、最初は少しの手間に感じるかもしれません。「動いているんだから変えなくてもいいのでは?」と思うこともあるでしょう。
しかし、セキュリティインシデントの多くは、こうした「ちょっとした油断」や「古い鍵の放置」から発生します。今回ご紹介したように、APIキーを「貸金庫(Secrets Manager)」に預け、定期的に「鍵の交換(ローテーション)」を行う文化をチームに根付かせることで、システムの堅牢性は劇的に向上します。
一歩ずつ、できるところから安全な仕組みを取り入れていきましょう。あなたのインフラストラクチャが、強固な防犯壁で守られることを応援しています!
コメント