開発者が知るべきCI/CDの権限管理ベストプラクティス
CI/CD (Continuous Integration/Continuous Delivery) パイプラインは、現代のソフトウェア開発において不可欠な要素となっています。コードの自動ビルド、テスト、デプロイメントを効率的に行うことで、開発速度を大幅に向上させることができます。しかし、この自動化されたプロセスが、意図せず機密データへの広範なアクセス権を持つことになり、セキュリティリスクの温床となるケースも少なくありません。
開発者にとって、CI/CDパイプラインは自分が書いたコードを本番環境へ届けるための重要な「手」です。この「手」にどのような権限を与えるべきか、そしてその権限をどのように管理するべきかを理解することは、安全なシステム構築において極めて重要です。
この記事では、CI/CDパイプラインにおける権限管理の重要性を再確認し、開発者が実践すべき具体的なベストプラクティスについて解説します。
CI/CDパイプラインがアクセスするものと潜在的なリスク
CI/CDパイプラインは、その役割を果たすために様々なリソースにアクセスする必要があります。代表的なものとしては以下のようなものがあります。
- コードリポジトリ: ソースコードの取得。書き込み権限が必要な場合も。
- アーティファクトリポジトリ: ビルド済み成果物(JAR, WAR, Dockerイメージなど)の保存や取得。
- コンテナレジストリ: Dockerイメージのビルドとプッシュ、あるいはプル。
- クラウドプロバイダのリソース:
- データベース: データのマイグレーション実行、テストデータの投入。
- ストレージ: S3バケットへのファイルのアップロード/ダウンロード。
- コンピュートサービス: 仮想マシンやコンテナインスタンスへのデプロイ、設定変更。
- ネットワークリソース: ロードバランサーやセキュリティグループの設定変更。
- シークレット管理サービス: データベース認証情報、APIキーなどの取得。
- 外部サービス/API: 通知サービス、監視サービス、他のマイクロサービスなどとの連携。
これらのリソースへのアクセス権限が不適切に管理されている場合、以下のようなリスクが発生します。
- 情報漏洩: 機密性の高い設定情報やデータがパイプラインのログや環境変数から漏洩する。
- 不正変更/破壊: パイプラインが侵害された際に、本番環境のデータが改ざんされたり、システムが破壊されたりする。
- 権限昇格: パイプライン経由で、本来持っていないはずのシステム全体への広範なアクセス権を取得される。
- サービス停止: 不適切な設定変更やデプロイにより、サービスが停止する。
これらのリスクを低減するためには、CI/CDパイプラインに付与する権限を慎重に設計・管理する必要があります。
CI/CD権限管理の基本原則
CI/CDパイプラインの権限管理においても、一般的なセキュリティの基本原則が適用されます。
- 最小権限の原則 (Principle of Least Privilege): パイプラインが必要とする最小限の権限のみを付与します。特定のジョブやステップを実行するために必要な権限だけを持つように設計します。例えば、ビルドジョブにはコードの読み取りとアーティファクトの書き込み権限のみを与え、デプロイジョブにのみターゲット環境へのデプロイ権限を与えるといった考え方です。
- 職務分離の原則 (Separation of Duties): 可能であれば、異なる役割を持つ操作(例:ビルドとデプロイ、開発環境へのデプロイと本番環境へのデプロイ)には、それぞれ異なる権限セットを持つ異なる主体(ユーザー、サービスアカウント、ロールなど)を割り当てます。これにより、一つのアカウントが侵害された場合の影響範囲を限定できます。
- 秘密情報の管理: データベースのパスワードやAPIキーなどの機密情報は、コードや設定ファイルに直接埋め込まず、専用のシークレット管理ツール(AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, HashiCorp Vaultなど)で安全に管理し、パイプライン実行時に必要な権限を持つ主体のみが取得できるようにします。
実践的な権限設計と実装方法
これらの原則に基づき、具体的なCI/CDツールやクラウド環境でどのように権限を設計・実装していくかを見ていきます。
1. パイプライン実行主体の特定と管理
CI/CDパイプラインは、何らかの実行主体(ユーザーアカウント、サービスアカウント、IAMロールなど)として動作します。この実行主体こそが、パイプラインが付与された権限を持つことになります。
多くのCI/CDプラットフォームやクラウドサービスは、パイプラインのために専用のIDを作成・割り当てる機能を提供しています。
- AWS: AWS IAMロールを利用します。CI/CDツール(例: AWS CodeBuild, AWS CodePipeline, Jenkins on EC2)に特定のIAMロールを割り当て、そのロールに必要な権限ポリシーをアタッチします。別のAWSアカウントやサービスにアクセスする場合は、IAMロールのAssumeRole機能を活用します。
- Azure: マネージドIDまたはサービスプリンシパルを利用します。Azure DevOps PipelinesやGitHub ActionsからAzureリソースにアクセスする際に、認証情報漏洩のリスクを減らすマネージドID(Azureリソースの場合)や、より細かく権限管理が可能なサービスプリンシパルを使用します。
- GCP: サービスアカウントを利用します。Cloud BuildなどのGCPサービスや、外部CIツールからGCPリソースにアクセスする際に、特定の権限を持つサービスアカウントキーを付与します。キーの管理には注意が必要です。ワークロードID連携(Workload Identity Federation)を利用すると、外部IDプロバイダ(GitHub Actionsなど)からGCPサービスアカウントを直接操作できるようになり、キー管理が不要になります。
- GitHub Actions/GitLab CI/CircleCIなど: クラウドプロバイダのサービスプリンシパルやIAMロール、サービスアカウントキーなどを利用するか、CIプラットフォームが提供する独自のシークレット管理機能と連携します。GitHub ActionsではOpenID Connect (OIDC) を使用してAWS, Azure, GCPなどのクラウドプロバイダと連携し、長期的な認証情報(アクセスキーなど)を使わずに一時的な認証情報でアクセスする仕組みが推奨されています。
重要なのは、長期的な静的認証情報(アクセスキーやパスワード)を可能な限り使用しないことです。一時的な認証情報や、マネージドID、OIDC連携などを積極的に活用しましょう。
2. 環境とステップに応じた権限の分離
多くの場合、CI/CDパイプラインは開発、ステージング、本番といった複数の環境に対してデプロイを行います。それぞれの環境で必要な権限は異なるはずです。
- 環境ごとの分離:
- 開発環境:比較的緩やかな権限。
- ステージング環境:本番に近い環境へのアクセス権限。
- 本番環境:最も厳格な権限。変更を加える操作(デプロイ、データ更新など)は最小限に絞り、多くの場合、承認プロセスを伴います。
- 環境ごとに異なるIAMロール、サービスプリンシパル、あるいはサービスアカウントを割り当て、それぞれに異なる権限ポリシーを適用します。
- パイプラインステップごとの分離:
- ビルドステップ:コードリポジトリ読み取り、アーティファクトリポジトリ書き込みなどの権限。
- テストステップ:データベース読み取り(テストデータ)、外部API読み取りなどの権限。本番データへのアクセスは原則禁止。
- デプロイステップ:ターゲット環境へのデプロイに必要な権限(例: EC2へのSSH、S3へのファイルアップロード、Kubernetes APIへのアクセス)。
- ロールアウトステップ:デプロイ後の健全性チェックやトラフィック切り替えに必要な権限。
- 可能であれば、パイプライン内の各ステップを異なる権限主体で実行するように設計します。例えば、ビルドはビルド専用の権限を持つサービスアカウント、デプロイはデプロイ専用の権限を持つサービスアカウントが行うといった粒度で分けます。これはCI/CDプラットフォームの機能に依存しますが、AWS CodeBuildなどではビルドプロジェクトごとにIAMロールを指定できます。
3. シークレット管理ツールとの連携
データベース認証情報、APIキー、秘密鍵などのシークレットは、コードや環境変数に直接書き込むべきではありません。必ず専用のシークレット管理ツールを利用し、パイプライン実行時にツールから取得するようにします。
CI/CDパイプラインの実行主体(IAMロールなど)には、必要なシークレット管理ツールから特定のシークレットを読み取るための最小限の権限のみを付与します。
例えば、AWS Secrets Managerを利用する場合、デプロイ用IAMロールには以下のようなポリシーをアタッチします。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:REGION:ACCOUNT_ID:secret:my-app-prod-db-credentials-??????"
}
]
}
これにより、このIAMロールを持つパイプラインは指定されたシークレットのみを読み取ることができ、他のシークレットにはアクセスできません。
4. 承認プロセスとの連携
特に本番環境へのデプロイなど、リスクの高い操作については、自動化だけでなく手動による承認プロセスを組み合わせることが一般的です。承認プロセスは、特定の権限を持つユーザーやグループが行うように設定します。
CI/CDプラットフォームによっては、承認ステップをワークフローに組み込む機能があります。この機能を利用することで、承認権限を持つ特定のユーザーが承認を行うまで次のステップ(例:本番デプロイ)に進まないように制御できます。
5. パイプライン定義ファイルの権限管理
CI/CDパイプラインの定義ファイル(例: .github/workflows/*.yml
, .gitlab-ci.yml
, buildspec.yml
など)は、パイプラインの動作そのものを決定するものであり、実行主体の権限を悪用するような記述が紛れ込むリスクがあります。
これらの定義ファイル自体も、他のソースコードと同様にバージョン管理システムで管理し、コードレビュープロセスを経て変更をマージするようにします。これにより、意図しない、あるいは悪意のある権限悪用につながる記述がパイプラインに導入されるリスクを低減できます。
特に、パイプライン定義ファイルからアクセスできる変数やシークレットの範囲を制限する設定(例: GitHub Actionsの環境ごとのシークレットと変数、Branch protection rules)を活用することが重要です。
まとめ
CI/CDパイプラインは、開発効率を高める強力なツールである一方、不適切な権限管理は重大なセキュリティリスクを招きます。開発者として、自身が利用・管理するCI/CDパイプラインの権限設定には十分な注意を払い、以下の点を実践することが推奨されます。
- 最小権限の原則に基づき、各パイプライン、各ステップに必要な最小限の権限のみを付与する。
- 環境ごとに権限を分離し、特に本番環境へのアクセスは厳格に管理する。
- シークレット管理ツールを必ず利用し、機密情報のハードコーディングを避ける。パイプラインにはシークレットツールへのアクセス権限のみを与える。
- 一時的な認証情報や、マネージドID、OIDC連携など、安全な認証方法を積極的に利用する。
- パイプライン定義ファイルの変更もコードレビュー対象とし、安全性を確保する。
- 必要に応じて承認プロセスを導入し、リスクの高い操作を保護する。
これらのプラクティスを実践することで、開発速度を維持しながら、よりセキュアなCI/CDパイプラインを構築し、システム全体のセキュリティレベルを向上させることができます。権限管理は一度設定すれば終わりではなく、システムの変更や追加に合わせて継続的に見直し、改善していくことが重要です。