プログラミング初心者がアーキテクトっぽく語る

見苦しい記事も多数あるとは思いますが訂正しつつブログと共に成長していければと思います

APIキーの保管

Web APIを叩くにはAPIキー、シークレット、Credentialが必要だ。

こういった情報をどのように管理すべきだろうか。

ハードコードすると変更するのが大変だ。ソフトコードすると少し変更しやすくなるがそれでもビルドが必要になってしまう。それにソフトコードもハードコードもGitにPushすると多くの人に見られてしまう。

暗号化すれば安全だろうか?では復号鍵はどう管理すればよいのだろう?

考え始めると深い。実際のところすべての状況に適した回答は存在しない。ケースバイケースで考えていくしかないのだ。

今回はAPIキー管理の考え方について述べる。


Web APIキーの考慮点

環境によって異なる

一般的には開発環境と商用環境ではキーが異なる。環境によって容易にキーを切り替え可能でなければならない。

定期的変更が必要

一般的にキーは使っている期間が短いほど流出するリスクも流出した後のリスクも低くなる。このためキーの変更(ローテーション)が容易に可能でなければならない。

数が多い

Web APIを利用するシステムでは複数のサービスが存在することが一般的だ。サービスの数が多いシステムでは多数のキーを安全かつ効率的に取り扱える管理性が重要となる。

Gitに注意

キーがGitにPushされないよう注意を払わなくてはいけない。GitHubに対してはハッカーが常にキー情報のスクレーピングを行っていると言われている。AWSのキーを含むコードをGitHubのPublic RepositoryにPushしたら15分ほどで仮想マイニング用のインスタンスが立ち上がったという話がQiitaで紹介されていた。

Private Repositoryは安全かいうとそうとも言い切れない。Private RepositoryにはCredentialが含まれている可能性があるためハッカーが積極的に攻撃する対象となっているからだ。

パスワードに過度に依存しない

パスワードは正しく運用されれば安全だが、現実としては正しく運用されずセキュリティホール化することが多い。パスワードへ過度に依存せず、Multi Factor AuthenticationやSSOの利用も検討することも重要だ。

まとめ

つまりAPIキー管理には以下の3点が重要ということになる。

  1. 交換容易性
  2. 秘匿性
    • Git超注意!!!
  3. 管理性

管理方式

以下に主なキーの管理方式を紹介する。

1. コードに平文で書く

  • シンプルだが安全でない
  • 開発者に知られてしまう
  • GitにPushすると多くの人に見られてしまう
  • キーを変更する場合、コードを変更しなくてはならない
    • ローテーションが容易ではない
  • 単体試験コードなどを除けばNG

2. コードに暗号化して書く

  • 平文より安全だが復号鍵の管理が必要なので完全な解決にはならない
  • 復号鍵がRepositoryに含まれていた場合、多くの人に知られてしまう
  • ローテーションが容易ではない

3. 環境変数に書く

  • 12 factor appで推奨されている方式
  • コードに記載されないので開発者からは見えない
  • 環境ごとにキーを切り替えやすい
  • GitにPushされるリスクが少ない
  • Production環境にアクセスできる人間はキーを閲覧できる可能性があることに注意が必要

4. データベースに保管する

  • 集中管理できるので複数のキーがある場合の管理性が高い
  • ローテーションが容易
  • データベースのCredentialの管理が必要なので完全な解決にはならない

5. キー/シークレットの管理サービスを使う

  • キー管理専用なのでデータベースより扱いやすい
  • ローテーションが容易
  • サービスによってはサービスのCredentialの管理が必要になることがある
  • Identify basedな管理方式は大規模環境では管理負荷が高くなる傾向がある
  • サービス例
    • AWS Key Management Service
    • AWS Secrets Manager
    • Azure Key Vault
    • Google Cloud KMS

6. コンテナに注入する

  • DockerやKubernetesにはSensitiveな情報をvolumeのような形でコンテナに注入する技術がある
    • Kubernetes Secret
    • Docker secrets(Swamでのみ利用可能)
  • 環境変数よりも覗きにくいためコンテナ環境ではこちらの方が好まれる傾向がある
  • 現時点ではローテーションが容易でない

7. API Gatewayを使う

  • Secret管理機能があるAPI Gatewayを使う
  • 処理の流れ
    • アプリケーションはAPI GatewayにRequestを送る
    • API GatewayはアプリケーションをIdentity Basedで認証
    • API GatewayはRequestにCredentialを付与してサービスに転送する
  • アプリケーションのコードからCredentialを排除できることがメリット
  • Cloud Providerが提供している
  • Cloud Providerが提供する仕組みによっては複雑になる

考察

1. 鍵の鍵の管理

上述の方式2,4,5ではキー自体は安全にすることはできるが新たな鍵やCredentialの管理が発生してしまい堂々巡りである。

ではこれらの方式は使えないのかというとそうではない。新たな鍵やCrendentialの管理が安全にできれば問題ない。

具体的にどうすればよいのか。一番よいのはそれら鍵やCredentialをcodebaseの一部として持たないことである。ユーザ入力として受け取る、環境変数にするなどの方法が考えられる。


2. 環境変数で扱うときの検討

方式3で取り上げた環境変数に書く方式はTwelve App Factorで推奨されているので採用例も多い。

しかしただ環境変数にしただけでは意味がない。適切に行えば問題ないが注意事項が多いので避けられることもある。

環境変数定義ファイルの扱いに注意

まず注意すべきは環境変数を定義したファイルの取り扱いだ。

この方式を採用した場合当然、環境ごとの環境変数を定義したファイルを作成するだろう。これをそのままGitにPushしては意味がない。Git以外の文書管理サービス上に厳格なアクセス権を設定して保管しなくてはならない。

どうしてもGitで管理したい場合はAWS KMWなどを利用して暗号化して別のRepositoryにPushするとよいだろう。Private Repositoryだからと言って平文のままPushするのは危険だ。

Twelve Factor Appはリリースの流れを「ビルド→リリース→実行」と定義しており、環境変数定義ファイルはリリース工程でバイナリとバンドルされる。このリリース工程においてしかるべき権限を持った人間のみがファイルを取り扱うようにすることも重要である。

CI/CD環境のアクセス権に注意

もし「ビルド→リリース→実行」の一連の流れをCI/CDで自動化する場合はCI/CD環境のアクセス権に注意が必要だ。さもなければPipelineの内容からファイルのアクセス情報が盗まれ、ファイルを盗難、改ざんされてしまうかもしれない。

本番環境のアクセス権に注意

もう一つ注意すべきは本番環境へのアクセスだ。

本番環境にルートアクセスできる人間は環境変数を表示できる。

他ユーザがps -ewwで環境変数を表示できるかもしれない。

障害発生時の解析情報として環境変数を出力するソフトウェアは多い。ログからキーが盗まれる可能性がある。

Dockerイメージのビルドに注意

Dockerイメージのレイヤ情報に環境変数が含まれていた場合には閲覧されるかもしれない。Dockerfileの記述に注意する。困難な状況ではmulti stage buildも効果的だ。

子プロセスに注意

環境変数は子プロセスにも引き継がれる。Third Party製ツールやユーザプログラムを子プロセスで実行するとキーが盗まれる危険がある。


3. キー管理のCloudサービス

Cloudサービスの内容は色々ある。

AWS KMSとGoogle Cloud KWSは方式2においてキーの暗号化に使用した暗号鍵を安全に管理するための仕組みだ。なお方式2はいくら安全になってもローテーションに課題があるので利用しない方がよいだろう。AWS KMSとGoogle Cloud KWSを使うのであれば方式3の環境変数を暗号化する場合などがよいと考える。

AWS Secrets ManagerやAzure Key Vaultはキー自体を管理するサービスだ。方式4のクラウド版と言えるだろう。

それぞれのCloudサービスについては以下の記事で簡単に紹介している。

architecting.hateblo.jp