本番環境の所有権は誰のものか?環境間における特権境界の重要性

あなたのチームの開発者が、設定ファイルを少し変更したとします。ステージング環境を更新するつもりでしたが、誤って本番環境に対してコマンドを実行してしまいました。5分後、ユーザーからエラー報告が相次ぎます。チームは何が起きたのか、誰が変更したのか、どうやって元に戻すのかを必死に調べます。一方、問題を引き起こした開発者は、そもそも本番環境に触れる権限があったのかどうかも確信が持てません。

このシナリオは、ほとんどのチームが認めたくないほど頻繁に発生します。悪意や能力不足が原因ではありません。環境の間に境界が欠けていることが問題なのです。全員が開発、ステージング、本番に対して同じアクセス権を持っていると、システムは意図的な変更とミスを区別できません。

ユニバーサルアクセスの問題点

多くのチームはシンプルな設定から始めます。全員にすべてへのアクセス権を与えるのです。開発者はステージングや本番、あるいは他のチームの開発環境も変更できます。最初は実用的に感じられます。権限を待つ必要もなければ、修正をデプロイするために誰かに助けを求める必要もありません。

しかし、このアプローチには2つの問題があります。第一に、説明責任が曖昧になります。本番で何かが壊れ、全員がアクセス権を持っていた場合、根本原因の特定に時間がかかります。誰がどのマシンから、いつ、どのコマンドを実行したかを確認しなければなりません。第二に、ミスの影響範囲が広がります。フィーチャーブランチで作業中の開発者が、誤って本番デプロイをトリガーする可能性があります。設定ファイルのタイプミスが、何百ものユーザーが依存するサービスをダウンさせるかもしれません。

解決策は、誰も作業できなくなるほど厳しくロックダウンすることではありません。環境間に明確な特権境界を設けることです。

特権境界とは何か

特権境界とは、各環境で誰が何をできるかを明確に分離することです。これは単にツールの権限設定だけの問題ではありません。ステートバックエンド、リポジトリ、パイプライン設定の構造化の仕方に関わります。

例えば、本番環境のステートファイルは開発環境のステートファイルとは異なる場所に置くべきです。Terraformを使用している場合、本番ステートバックエンドは、より厳格なIAMポリシーを持つ別のS3バケットにすることができます。チーム内のごく一部のメンバーだけがそのバケットにアクセスできます。開発ステートバックエンドは、チーム全員が読み書きできる共有バケットでも構いません。

ここでの原則は最小権限です。すべての人またはシステムは、自分の仕事を遂行するために必要なアクセス権のみを持ちます。開発者は開発環境へのフルアクセスを必要とするかもしれません。本番で何が動いているかを把握するために、本番ステートへの読み取り専用アクセスが必要かもしれません。しかし、本番環境に変更を加える必要がある場合、その変更はより正式なプロセス、すなわち他のチームメンバーによるレビューを受けたプルリクエスト、または承認を必要とするパイプラインを経由する必要があります。

所有権が境界を具体化する

特権境界は、各環境に明確な所有者がいる場合に最も効果的に機能します。所有者とは、その環境で何か問題が発生した場合に責任を負う人物またはチームです。所有権は支配することではなく、説明責任を負うことです。

実際には、所有権は次のようになることがよくあります。

  • プラットフォームエンジニアリングチームが本番環境を所有します。安定性、パフォーマンス、セキュリティに責任を持ちます。
  • アプリケーション開発チームがステージング環境を所有します。本番デプロイをリクエストする前に、変更を検証するために使用します。
  • 個々の開発者は、自分自身の開発環境を所有します。自由に壊したり、再構築したり、実験したりできます。

この分割は、開発者が本番環境に触れてはいけないという意味ではありません。本番環境に触れる場合、本番環境の所有者を巻き込んだプロセスに従うということです。所有者が変更をレビューし、リスクを理解し、デプロイを承認または却下します。

特権境界を実際に実装する方法

特権境界は、リポジトリ構造、パイプライン設定、ステートバックエンドの3つの場所に現れます。

リポジトリ構造

境界を強制する最も簡単な方法は、ディレクトリ構造とブランチ保護です。本番環境の設定は、別のディレクトリ、あるいは別のリポジトリに置くことができます。同じリポジトリ内にある場合、本番環境のディレクトリは保護されるべきです。特定のチームメンバーのみがそこに変更をプッシュできます。本番環境の設定を変更するプルリクエストには、本番環境の所有者による承認が必要です。

次のフローチャートは、誰が変更を行い、どの環境を対象とするかに基づいて、変更要求が特権境界をどのように通過するかを示しています。

flowchart TD A[変更要求] --> B{誰が変更するのか?} B -->|開発者| C{対象環境は?} B -->|運用/管理者| D{対象環境は?} C -->|開発/ステージング| E[PRを作成] C -->|本番| F[ブロック - 所有者にエスカレーション] D -->|開発/ステージング| G[PRを作成] D -->|本番| H[所有者レビュー付きでPRを作成] E --> I[プランステップ] G --> I H --> J[プランステップ + 所有者承認] I --> K[開発/ステージングに適用] J --> L[本番に適用]

パイプライン設定

CI/CDパイプラインは、境界が運用可能になる場所です。本番環境のパイプラインは、特定の条件が満たされた場合にのみ実行されるべきです。例えば、保護されたブランチからのみトリガーされるようにします。指定された担当者による手動承認を必要とするようにします。開発パイプラインではスキップされる追加の検証ステップを実行するようにします。

さらに進んでいるチームもあります。本番パイプラインが、本番ステートバックエンドにアクセスできる特定のCI/CDランナーからのみ実行されるように設定します。開発者はローカルマシンから本番パイプラインを実行できません。なぜなら、ローカルマシンには必要な認証情報がないからです。

ステートバックエンド

ステートバックエンドは、Infrastructure as Codeツールが環境の現在の状態を保存する場所です。Terraformを使用している場合、本番環境のステートファイルは、厳格なアクセス制御を持つ別のバックエンドに置くべきです。そのバックエンドのIAMポリシーは、個々の開発者アカウントではなく、本番パイプラインからのみ操作を許可するようにします。

例えば、本番ステートバックエンドに次のようなポリシーを設定できます。「CI/CDサービスアカウントのみがこのステートファイルに書き込める。それ以外の全員は読み取りのみ可能。」これにより、開発者が誤って本番環境に対してTerraformコマンドを実行しても、ステートロックを取得できないためコマンドは失敗します。

以下は、開発ステートファイルへの書き込みアクセスのみを許可し、本番ステートファイルへの書き込みアクセスを拒否することで、この境界を強制するTerraform IAMポリシーです。

data "aws_iam_policy_document" "state_access" {
  statement {
    sid    = "AllowDevWrite"
    effect = "Allow"
    actions = [
      "s3:PutObject",
      "s3:GetObject",
      "s3:DeleteObject"
    ]
    resources = [
      "arn:aws:s3:::my-tf-state-bucket/env:/dev/*"
    ]
  }

  statement {
    sid    = "DenyProdWrite"
    effect = "Deny"
    actions = [
      "s3:PutObject",
      "s3:DeleteObject"
    ]
    resources = [
      "arn:aws:s3:::my-tf-state-bucket/env:/prod/*"
    ]
  }
}

境界は不信の表れではない

特権境界に抵抗を示すチームもあります。それは不信の表れだと感じるからです。「私たちは優秀な人材を雇っている。なぜ本番環境へのアクセスを信頼できないのか?」

この捉え方は本質を見失っています。特権境界は信頼の問題ではありません。明確さと説明責任の問題です。全員がすべてにアクセスできる場合、何かが壊れたときに誰に連絡すればよいか誰もわかりません。境界が明確であれば、チームは各環境を誰が所有し、どのプロセスに従うべきかを正確に把握できます。

境界はまた、ミスを犯した人を守ります。無制限のアクセス権を持っていたために誤って本番環境を壊してしまった開発者は、ひどく落ち込みます。また、全員がインシデントを調査している間、チームの時間を浪費することになります。明確な境界があれば、同じ開発者でも、変更が本番に到達する前に止められていたでしょう。システムがミスをキャッチするのであって、個人を責めるのではないのです。

特権境界設定のためのクイックチェックリスト

現在の設定を見直す場合、以下を確認してください。

  • 本番ステートバックエンドは開発用やステージング用から分離されていますか?
  • 開発者は自分のラップトップから本番ステートに書き込めますか?
  • 本番パイプラインは手動承認を必要としますか?
  • 各環境に明確な所有者はいますか?
  • 本番環境の設定変更は、デプロイ前に所有者によってレビューされますか?

これらのチェックは網羅的ではありませんが、本番インシデントにつながる最も一般的なギャップをカバーしています。

次のステップ

特権境界と所有権を確立したら、次の課題はインフラストラクチャの状態を正確に保つことです。時には、Infrastructure as Codeツールの外部で変更が発生することがあります。誰かがクラウドコンソールから直接サーバー設定を変更する。チームメンバーがインシデント対応中に手動でホットフィックスを適用する。これらの変更は、ステートと現実の間にドリフトを生み出します。ドリフトはインフラストラクチャの信頼性を損ない、将来の変更を予測不可能にします。これは別途掘り下げる価値のあるトピックですが、今のところ重要なのは、まず明確な境界を確立することです。境界がなければ、ドリフトの検出と修正ははるかに困難になります。