お知らせ

APIキーをバックエンドでセキュアに保持する

APIキーをバックエンドでセキュアに保持する

概要

外部APIのAPIキーを保持する、マルチテナント型SaaSを開発されている方も多数いらっしゃるかと思います。
バックエンドとしてAPIキーをどのように保持すべきか?考えてみました。

設計方針

設計方針としては、以下になるかと思います。

  1. シークレットは「読み取り専用」に絞る
    • APIキーは書き換えや参照が頻繁に行われるものではありません。アプリケーションから必要に応じて「読む」だけでよいので、データベースやファイルに平文で置かず、読み取り専用の仕組みを用意します。
    • 平文配置した瞬間に、鍵は暴かれるリスクが高まります。どれほどセキュアなサーバーでも、不慮のミスや権限の漏れはゼロにはできません。だからこそ、「読むためには真正性を示し、限定的にしか触れられない場所に格納する」ことが大前提です。
  2. テナントごとに「分離」を徹底する
    • マルチテナント環境では、A社のAPIキーをB社から参照されてはいけません。
    • テナントIDをベースに「名前空間」を分ける、あるいはテナントごとに別のシークレットストアを使うなど、キーの保存先を論理的・物理的に分離しましょう。
  3. 暗号化キー(KMS)は別管理
    • シークレットそのものを暗号化して保存する場合、暗号化/復号の鍵(KMSキー)はアプリケーションサーバーとは別の場所で管理します。
    • クラウド利用なら「AWS KMS」「Azure Key Vault」「GCP Cloud KMS」といったマネージドKMSを活用し、何があっても平文の鍵が流出しない構造を作ります。
  4. アクセス権限は「最小権限」に絞る
    • アプリケーション本体(バックエンド)がシークレットを取りに行く際は、「読む権限」しか与えないIAMロール/サービスプリンシパルを用意します。
    • 本番とは別の環境(ステージング・開発)を用意するなら、それぞれに異なるキーを発行し、本番のキーには一切触れられないようにします。
  5. 監査ログを有効化する
    • 誰がいつ、どのテナントのどのシークレットにアクセスしたのかを必ずログに残す。
    • もし不正にアクセスを試みる攻撃者がいても、ログをたどることで侵入経路や責任所在を明確にできます。
  6. 可能であれば、定期ローテーションを組み込む
    • 「一度発行したAPIキーはずっと使い続ける」運用は危険です。
    • 毎月または四半期に一度、(あるいはテナントの要望に応じて)自動的に新鍵に切り替える仕組みを用意しましょう。
    • ローテーションといっても面倒ではありません。秘密情報の扱いを自動化し、心にゆとりを持った運用を実現しましょう。

2. 具体的な実装パターン例

ここでは代表的な3つのアプローチを示します。どれもメリット・デメリットがありますので、自社の運用規模やクラウドサービスの採用状況に合わせて選択してください。

2.1. クラウドシークレットマネージャ(AWS Secrets Managerなど)の活用

構成イメージ

┌───────────────────┐
│  クラウドKMS/KV   │   ← APIキーを暗号化して保管。例: AWS Secrets Manager 、
│(AWS Secrets      │      Azure Key Vault、GCP Secret Manager 等
│ Manager など)    │
└───────────────────┘
           ↑
           │(暗号化/復号リクエスト)
           │
┌───────────────────┐
│   バックエンド     │   ← シークレットを読む専用のIAMロールを付与
│  (APIサーバー等)   │
│                   │
└───────────────────┘
  1. テナントごとにシークレットを作成する
    • 例えば AWS Secrets Manager なら、シークレット名を /saas/myapp/tenant-{tenant_id}/external-api-key のように命名します。
    • Azure Key Vault も同様に「VaultName/tenant-{tenant_id}-api-key」という形で分ければよいでしょう。
  2. 読み取りはSDK経由で行う
    • バックエンドからはAWS SDK(Java/Python/Node.js など)や Azure SDK を通して「SecretId(名前)」を指定して暗号化済みのAPIキーを取り出す。
    • SDK呼び出しの際、実行環境のInstance Profile や Service Principal に「読み取り権限」だけを与えることで、不正な書き換えや作成を防ぎます。
  3. ローテーション機能を自動化
    • AWS Secrets Manager には「自動ローテーション機能」があり、Lambda関数を組み合わせれば数分で新鍵発行→置き換え→デプロイ完了までを自動化可能です。
    • ローテーションの度にテナントオーナーにアラートを送りたい場合は、SNS やメール連携を活用するとよいでしょう。
  4. メリット
    • マネージドサービスなのでオンプレでVaultを立てる手間が不要
    • KMSキーやアクセス権周りをクラウドベンダーが管理してくれる安心感
    • 監査ログやローテーション機能がデフォルトで使える
  5. デメリット・懸念点
    • クラウドベンダーのサービスロックインを招きやすい
    • コストがテナント数×シークレット数でかさむ可能性がある
    • クラウド側の障害が直撃すると、一時的にAPIキー取得自体ができなくなるリスクがある

実装ポイント(AWS例)

1. IAMロール作成
   - 名前: MyApp-SecretReaderRole
   - ポリシー例 (JSON抜粋):
     {
       "Version": "2012-10-17",
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
             "secretsmanager:GetSecretValue"
           ],
           "Resource": [
             "arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:/saas/myapp/tenant-*/external-api-key-*"
           ]
         }
       ]
     }

2. シークレット作成
   AWS CLI:
   $ aws secretsmanager create-secret \
       --name "/saas/myapp/tenant-1001/external-api-key" \
       --description "テナントID=1001向けの外部APIキー" \
       --secret-string '{"api_key":"YOUR_API_KEY_HERE\