
複数環境デプロイとは
複数環境デプロイとは、アプリケーションを本番環境にリリースする前に、開発環境やステージング環境など複数の異なる環境に段階的にデプロイする手法です。
代表的な環境構成
| 環境 | 用途 |
|---|---|
| 開発環境(Development) | 開発中の機能テスト、動作確認 |
| ステージング環境(Staging) | 本番環境と同等の構成での統合テスト |
| 本番環境(Production) | エンドユーザーが利用する実稼働環境 |
なぜ複数環境が必要か
- リスク低減:本番環境に影響を与える前に、バグや設定ミスを検出できる
- 品質保証:本番相当環境で動作確認やパフォーマンステストを実施できる
- 段階的なリリース:小さな変更から始めて、徐々に本番環境へ展開できる
- 並行開発の実現:複数の機能を異なる環境で同時に開発・テストできる
CodePipelineでの実現方法
CodePipelineでは、パイプライン内に複数のデプロイステージを設定し、各環境への自動デプロイと承認フローを組み合わせることで、安全で効率的な複数環境デプロイを実現します。
環境分離戦略
複数環境を構築する際、環境をどのように分離するかは重要な設計判断です。主な分離戦略として、AWSアカウントレベルでの分離とリージョンレベルでの分離があります。
アカウント分離(推奨)
概要
開発環境、ステージング環境、本番環境をそれぞれ別のAWSアカウントに配置する方法です。
メリット
- セキュリティの強化: 環境間で完全にIAM権限が分離される
- 請求の分離: 環境ごとのコストを明確に追跡できる
- リソース制限の回避: 各アカウントでサービスクォータが独立
- 障害の影響範囲限定: 開発環境のミスが本番環境に影響しない
デメリット
- 管理の複雑性: 複数アカウントの管理が必要
- クロスアカウント設定: IAMロールやS3アクセスの設定が複雑
- 初期コスト: 複数アカウントの初期セットアップに時間がかかる
適用ケース
- エンタープライズ環境
- 厳格なセキュリティ要件がある場合
- 複数チームでの開発
リージョン分離
概要
同一AWSアカウント内で、異なるリージョンに環境を配置する方法です。
メリット
- 管理がシンプル: 単一アカウントで完結
- リソース共有が容易: IAMロールやセキュリティグループの共有が簡単
- 低コスト: アカウント管理のオーバーヘッドが少ない
デメリット
- セキュリティリスク: IAM権限の誤設定で環境間の影響が発生しうる
- リソース競合: サービスクォータを環境間で共有
- 請求の分離困難: タグベースでのコスト配分が必要
適用ケース
- 小規模プロジェクト
- 開発初期段階
- セキュリティ要件が緩やかな場合
命名規則
リソース命名パターン
{プロジェクト名}-{環境名}-{リソースタイプ}-{用途}
具体例
| リソース | 用途 |
|---|---|
| myapp-dev-pipeline | 開発環境のパイプライン |
| myapp-stg-codebuild-api | ステージング環境のCodeBuildプロジェクト(API用) |
| myapp-prd-ecs-cluster | 本番環境のECSクラスター |
| myapp-dev-s3-artifacts | 開発環境のアーティファクトS3バケット |
環境名の標準化
| 環境 | 略称 | フル名称 |
|---|---|---|
| 開発環境 | dev | development |
| ステージング環境 | stg | staging |
| 本番環境 | prd | production |
タグ戦略
| タグキー | 説明 | 例 |
|---|---|---|
| Environment | 環境識別 | dev, stg prd |
| Project | プロジェクト名 | myapp |
| ManagedBy | 管理方法 | terraform cloudformation manual |
| CostCenter | コストセンター | engineering marketing |
タグ適用例
Resources:
MyPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: myapp-dev-pipeline
Tags:
- Key: Environment
Value: dev
- Key: Project
Value: myapp
- Key: ManagedBy
Value: cloudformation
- Key: CostCenter
Value: engineering
タグによるコスト配分
# タグベースのコストレポート取得
aws ce get-cost-and-usage \
--time-period Start=2024-01-01,End=2024-01-31 \
--granularity MONTHLY \
--metrics BlendedCost \
--group-by Type=TAG,Key=Environment
パイプライン設計パターン
複数環境デプロイを実現するパイプラインの設計パターンには、主に2つのアプローチがあります。

単一パイプライン・複数環境
1つのパイプライン内に複数環境へのデプロイステージを順次配置する方法です。
メリット
- 一貫性の保証: 同一のアーティファクトが全環境にデプロイされる
- 管理がシンプル: パイプラインが1つで済む
- 進捗の可視化: 全環境のデプロイ状況を一元管理できる
- 自動的な段階デプロイ: 前段階が成功した場合のみ次の環境へ進む
デメリット
- 柔軟性の低下: 特定環境のみの再デプロイが難しい
- パイプラインの肥大化: 環境が増えるとステージ数が多くなる
- 並行デプロイ不可: 複数環境への同時デプロイができない
適用ケース
- 環境間で厳密な整合性が必要な場合
- リリースプロセスが定型化されている場合
- 小〜中規模プロジェクト
CloudFormation実装例
Resources:
MultiEnvPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: myapp-multi-env-pipeline
RoleArn: !GetAtt CodePipelineServiceRole.Arn
ArtifactStore:
Type: S3
Location: !Ref ArtifactStoreBucket
Stages:
# ソースステージ
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: myapp-repo
BranchName: main
OutputArtifacts:
- Name: SourceOutput
# ビルドステージ
- Name: Build
Actions:
- Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CodeBuildProject
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
# 開発環境デプロイ
- Name: DeployToDev
Actions:
- Name: DeployDevAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: myapp-dev-stack
TemplatePath: BuildOutput::template.yaml
ParameterOverrides: !Sub |
{
"Environment": "dev"
}
Capabilities: CAPABILITY_IAM
RoleArn: !GetAtt CloudFormationRole.Arn
InputArtifacts:
- Name: BuildOutput
# ステージング環境デプロイ
- Name: DeployToStaging
Actions:
- Name: DeployStagingAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: myapp-stg-stack
TemplatePath: BuildOutput::template.yaml
ParameterOverrides: !Sub |
{
"Environment": "stg"
}
Capabilities: CAPABILITY_IAM
RoleArn: !GetAtt CloudFormationRole.Arn
InputArtifacts:
- Name: BuildOutput
# 本番環境承認
- Name: ApprovalForProduction
Actions:
- Name: ManualApproval
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
Configuration:
CustomData: "本番環境へのデプロイを承認してください"
# 本番環境デプロイ
- Name: DeployToProduction
Actions:
- Name: DeployProductionAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: myapp-prd-stack
TemplatePath: BuildOutput::template.yaml
ParameterOverrides: !Sub |
{
"Environment": "prd"
}
Capabilities: CAPABILITY_IAM
RoleArn: !GetAtt CloudFormationRole.Arn
InputArtifacts:
- Name: BuildOutput
環境ごとの個別パイプライン
各環境に対して独立したパイプラインを構築する方法です。
メリット
- 柔軟性が高い: 環境ごとに異なる設定やプロセスを適用可能
- 並行実行: 複数環境への同時デプロイが可能
- 独立性: 特定環境のパイプライン変更が他環境に影響しない
- ブランチ戦略との統合: 環境ごとに異なるブランチをソースにできる
デメリット
- 管理の複雑性: 複数のパイプラインを個別に管理する必要がある
- 一貫性の課題: 異なるアーティファクトが各環境にデプロイされる可能性
- 設定の重複: 共通設定を複数パイプラインで維持する必要がある
適用ケース
- 大規模プロジェクト
- 環境ごとに異なるデプロイプロセスが必要な場合
- ブランチ戦略(Git Flow等)と統合する場合
- 複数チームでの開発
CloudFormation実装例(開発環境パイプライン)
Resources:
DevPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: myapp-dev-pipeline
RoleArn: !GetAtt CodePipelineServiceRole.Arn
ArtifactStore:
Type: S3
Location: !Ref ArtifactStoreBucket
Stages:
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: myapp-repo
BranchName: develop # 開発ブランチ
OutputArtifacts:
- Name: SourceOutput
- Name: Build
Actions:
- Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref DevCodeBuildProject
EnvironmentVariables: !Sub |
[
{"name": "ENVIRONMENT", "value": "dev"}
]
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
- Name: Deploy
Actions:
- Name: DeployAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: 1
Configuration:
ClusterName: myapp-dev-cluster
ServiceName: myapp-dev-service
FileName: imagedefinitions.json
InputArtifacts:
- Name: BuildOutput
CloudFormation実装例(本番環境パイプライン)
Resources:
ProductionPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: myapp-prd-pipeline
RoleArn: !GetAtt CodePipelineServiceRole.Arn
ArtifactStore:
Type: S3
Location: !Ref ArtifactStoreBucket
Stages:
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: myapp-repo
BranchName: main # 本番ブランチ
OutputArtifacts:
- Name: SourceOutput
- Name: Build
Actions:
- Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref PrdCodeBuildProject
EnvironmentVariables: !Sub |
[
{"name": "ENVIRONMENT", "value": "prd"}
]
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
- Name: Approval
Actions:
- Name: ManualApproval
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
Configuration:
CustomData: "本番環境へのデプロイを承認してください"
NotificationArn: !Ref ApprovalSNSTopic
- Name: Deploy
Actions:
- Name: DeployAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: ECS
Version: 1
Configuration:
ClusterName: myapp-prd-cluster
ServiceName: myapp-prd-service
FileName: imagedefinitions.json
InputArtifacts:
- Name: BuildOutput
承認フローの実装
本番環境へのデプロイ前に人間による承認を必要とすることで、意図しないリリースを防ぎます。
Manual Approval の設定
CodePipelineのManual Approvalアクションを使用して、パイプラインの実行を一時停止し、承認者による手動承認を待ちます。
CloudFormation実装例
Resources:
ApprovalStage:
Type: AWS::CodePipeline::Pipeline
Properties:
Stages:
- Name: ApprovalStage
Actions:
- Name: ManualApprovalAction
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
Configuration:
# 承認者へのメッセージ
CustomData: |
本番環境へのデプロイを承認してください。
変更内容: アプリケーションバージョン v2.3.1
デプロイ予定時刻: 2024-01-15 18:00 JST
# SNSトピックARN(承認通知用)
NotificationArn: !Ref ApprovalNotificationTopic
# 外部リンク(レビュー資料など)
ExternalEntityLink: https://example.com/release-notes/v2.3.1
AWS CLI実装例
# パイプラインの承認待ち状態を確認
aws codepipeline get-pipeline-state \
--name myapp-prd-pipeline
# 承認を実行
aws codepipeline put-approval-result \
--pipeline-name myapp-prd-pipeline \
--stage-name ApprovalStage \
--action-name ManualApprovalAction \
--result summary="承認します",status=Approved \
--token
# 却下を実行
aws codepipeline put-approval-result \
--pipeline-name myapp-prd-pipeline \
--stage-name ApprovalStage \
--action-name ManualApprovalAction \
--result summary="変更内容に問題があるため却下",status=Rejected \
--token
承認タイムアウト設定
Manual Approvalアクションには、デフォルトで7日間のタイムアウトがあります。この期間内に承認または却下されない場合、アクションは自動的に失敗します。
- タイムアウト期間は変更できません(固定で7日間)
- タイムアウト後は、パイプラインを再実行する必要があります
- 長期休暇などを考慮してリリース計画を立てる
承認権限の設定
承認を実行できるユーザーを制限するには、IAMポリシーを使用します。
# IAMポリシー例
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codepipeline:GetPipelineState",
"codepipeline:PutApprovalResult"
],
"Resource": "arn:aws:codepipeline:ap-northeast-1:123456789012:myapp-prd-pipeline"
}
]
}
SNS通知の設定
承認が必要になったタイミングで、関係者に自動通知を送ります。
CloudFormation実装例
# SNSトピックの作成例
Resources:
ApprovalNotificationTopic:
Type: AWS::SNS::Topic
Properties:
TopicName: myapp-approval-notifications
DisplayName: "MyApp 本番デプロイ承認通知"
Subscriptions:
- Protocol: email
Endpoint: devops-team@example.com
- Protocol: email
Endpoint: release-manager@example.com
ApprovalNotificationTopicPolicy:
Type: AWS::SNS::TopicPolicy
Properties:
Topics:
- !Ref ApprovalNotificationTopic
PolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action:
- SNS:Publish
Resource: !Ref ApprovalNotificationTopic
通知メール内容
件名: APPROVAL NEEDED: myapp-prd-pipeline
本文:
Pipeline myapp-prd-pipeline requires approval.
Stage: ApprovalStage
Action: ManualApprovalAction
Custom Data:
本番環境へのデプロイを承認してください。
変更内容: アプリケーションバージョン v2.3.1
デプロイ予定時刻: 2024-01-15 18:00 JST
Approve or reject: https://console.aws.amazon.com/codesuite/codepipeline/pipelines/myapp-prd-pipeline/view
パラメータ管理
複数環境デプロイでは、環境ごとに異なるパラメータ(データベース接続先、APIエンドポイント、リソース設定など)を管理する必要があります。
Parameter Store の活用
環境固有の設定値を安全に保存・管理するためのサービスです。
パラメータの階層構造
環境ごとにパラメータを階層化して管理します。
/myapp/dev/db/host → dev-db.example.com
/myapp/dev/db/port → 3306
/myapp/dev/api/endpoint → https://api-dev.example.com
/myapp/stg/db/host → stg-db.example.com
/myapp/stg/db/port → 3306
/myapp/stg/api/endpoint → https://api-stg.example.com
/myapp/prd/db/host → prd-db.example.com
/myapp/prd/db/port → 3306
/myapp/prd/api/endpoint → https://api.example.com
パラメータの作成
# 開発環境のパラメータ
aws ssm put-parameter \
--name "/myapp/dev/db/host" \
--value "dev-db.example.com" \
--type String \
--tags "Key=Environment,Value=dev" "Key=Project,Value=myapp"
# 本番環境のパラメータ(SecureString)
aws ssm put-parameter \
--name "/myapp/prd/db/password" \
--value "SecurePassword123!" \
--type SecureString \
--key-id alias/aws/ssm \
--tags "Key=Environment,Value=prd" "Key=Project,Value=myapp"
CloudFormation実装例
Resources:
DevDatabaseHost:
Type: AWS::SSM::Parameter
Properties:
Name: /myapp/dev/db/host
Type: String
Value: dev-db.example.com
Tags:
Environment: dev
Project: myapp
DevDatabasePassword:
Type: AWS::SSM::Parameter
Properties:
Name: /myapp/dev/db/password
Type: SecureString
Value: !Ref DevDBPassword # CloudFormationパラメータから取得
Tags:
Environment: dev
Project: myapp
パラメータの取得
# 単一パラメータの取得
aws ssm get-parameter \
--name "/myapp/dev/db/host" \
--query "Parameter.Value" \
--output text
# SecureStringの取得(復号化)
aws ssm get-parameter \
--name "/myapp/prd/db/password" \
--with-decryption \
--query "Parameter.Value" \
--output text
# パスベースで複数パラメータを一括取得
aws ssm get-parameters-by-path \
--path "/myapp/dev/" \
--recursive \
--with-decryption
アプリケーションからの取得(Python Boto3)
import boto3
ssm = boto3.client('ssm', region_name='ap-northeast-1')
# 単一パラメータ取得
response = ssm.get_parameter(
Name='/myapp/dev/db/host'
)
db_host = response['Parameter']['Value']
# SecureString取得
response = ssm.get_parameter(
Name='/myapp/dev/db/password',
WithDecryption=True
)
db_password = response['Parameter']['Value']
# 複数パラメータ一括取得
response = ssm.get_parameters_by_path(
Path='/myapp/dev/',
Recursive=True,
WithDecryption=True
)
params = {p['Name']: p['Value'] for p in response['Parameters']}
パラメータアクセスのIAMポリシー
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:GetParameter",
"ssm:GetParameters",
"ssm:GetParametersByPath"
],
"Resource": [
"arn:aws:ssm:ap-northeast-1:123456789012:parameter/myapp/dev/*"
]
},
{
"Effect": "Allow",
"Action": [
"kms:Decrypt"
],
"Resource": "arn:aws:kms:ap-northeast-1:123456789012:key/your-kms-key-id"
}
]
}
環境変数の注入
Parameter Storeの値を、デプロイプロセスやアプリケーション実行時に環境変数として注入します。
CodeBuildでの環境変数注入
# buildspec.ymlでの実装
version: 0.2
env:
parameter-store:
DB_HOST: /myapp/${ENVIRONMENT}/db/host
DB_PORT: /myapp/${ENVIRONMENT}/db/port
DB_NAME: /myapp/${ENVIRONMENT}/db/name
DB_PASSWORD: /myapp/${ENVIRONMENT}/db/password
API_ENDPOINT: /myapp/${ENVIRONMENT}/api/endpoint
phases:
pre_build:
commands:
- echo "環境: $ENVIRONMENT"
- echo "データベースホスト: $DB_HOST"
build:
commands:
- echo "アプリケーションをビルド"
- docker build -t myapp:latest \
--build-arg DB_HOST=$DB_HOST \
--build-arg DB_PORT=$DB_PORT \
--build-arg DB_NAME=$DB_NAME \
--build-arg API_ENDPOINT=$API_ENDPOINT \
.
CodeBuildプロジェクトでの環境変数設定
Resources:
CodeBuildProject:
Type: AWS::CodeBuild::Project
Properties:
Name: myapp-build
Environment:
Type: LINUX_CONTAINER
ComputeType: BUILD_GENERAL1_SMALL
Image: aws/codebuild/standard:7.0
EnvironmentVariables:
- Name: ENVIRONMENT
Value: dev
Type: PLAINTEXT
ServiceRole: !GetAtt CodeBuildRole.Arn
CodePipelineからの環境変数上書き
- Name: Build
Actions:
- Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CodeBuildProject
EnvironmentVariables: !Sub |
[
{
"name": "ENVIRONMENT",
"value": "prd",
"type": "PLAINTEXT"
}
]
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
CloudFormationでの環境変数注入
Parameters:
Environment:
Type: String
AllowedValues:
- dev
- stg
- prd
Resources:
LambdaFunction:
Type: AWS::Lambda::Function
Properties:
FunctionName: !Sub myapp-${Environment}-function
Environment:
Variables:
DB_HOST: !Sub '{{resolve:ssm:/myapp/${Environment}/db/host}}'
DB_PORT: !Sub '{{resolve:ssm:/myapp/${Environment}/db/port}}'
DB_PASSWORD: !Sub '{{resolve:ssm-secure:/myapp/${Environment}/db/password}}'
API_ENDPOINT: !Sub '{{resolve:ssm:/myapp/${Environment}/api/endpoint}}'
動的参照の種類
| 参照タイプ | 構文 | 用途 |
|---|---|---|
| ssm | '{{resolve:ssm:parameter-name}}' | String型パラメータ |
| ssm-secure | '{{resolve:ssm-secure:parameter-name}}' | SecureString型パラメータ |
| secretsmanager | '{{resolve:secretsmanager:secret-id}}` | Secrets Managerのシークレット |
ECSタスク定義での環境変数注入
# タスク定義(CloudFormation)
Resources:
TaskDefinition:
Type: AWS::ECS::TaskDefinition
Properties:
Family: !Sub myapp-${Environment}
ContainerDefinitions:
- Name: app
Image: !Sub ${AWS::AccountId}.dkr.ecr.ap-northeast-1.amazonaws.com/myapp:latest
Environment:
- Name: ENVIRONMENT
Value: !Ref Environment
Secrets:
- Name: DB_HOST
ValueFrom: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/myapp/${Environment}/db/host
- Name: DB_PASSWORD
ValueFrom: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/myapp/${Environment}/db/password
- Name: API_ENDPOINT
ValueFrom: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/myapp/${Environment}/api/endpoint
必要なIAMポリシー(ECSタスクロール)
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters",
"secretsmanager:GetSecretValue"
],
"Resource": [
"arn:aws:ssm:ap-northeast-1:123456789012:parameter/myapp/*",
"arn:aws:secretsmanager:ap-northeast-1:123456789012:secret:myapp/*"
]
},
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:ap-northeast-1:123456789012:key/your-kms-key-id"
}
]
}
クロスアカウントデプロイ
IAM ロール設定
デプロイ先アカウントでのロール作成
各環境アカウント(開発/ステージング/本番)で、ツールアカウントから AssumeRole できるロールを作成します。
Parameters:
ToolAccountId:
Type: String
Description: ツールアカウントのAWSアカウントID
Default: "123456789012"
Resources:
# クロスアカウントデプロイ用ロール
CrossAccountDeployRole:
Type: AWS::IAM::Role
Properties:
RoleName: CrossAccountDeployRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${ToolAccountId}:root
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/PowerUserAccess
Policies:
- PolicyName: DeployPermissions
PolicyDocument:
Version: 2012-10-17
Statement:
# CloudFormationの権限
- Effect: Allow
Action:
- cloudformation:*
Resource: "*"
# ECSの権限
- Effect: Allow
Action:
- ecs:*
- ecr:*
Resource: "*"
# S3アーティファクトアクセス
- Effect: Allow
Action:
- s3:GetObject
- s3:GetObjectVersion
Resource:
- !Sub arn:aws:s3:::tool-account-artifacts/*
# KMS復号化権限
- Effect: Allow
Action:
- kms:Decrypt
- kms:DescribeKey
Resource: !Sub arn:aws:kms:ap-northeast-1:${ToolAccountId}:key/*
# CloudFormation実行用ロール(CrossAccountDeployRoleから利用)
CloudFormationExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: CloudFormationExecutionRole
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: cloudformation.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/PowerUserAccess
Outputs:
CrossAccountDeployRoleArn:
Value: !GetAtt CrossAccountDeployRole.Arn
Export:
Name: CrossAccountDeployRoleArn
ツールアカウントでのパイプライン設定
# CloudFormation実装例(ツールアカウント)
Parameters:
DevAccountId:
Type: String
Default: "111111111111"
StagingAccountId:
Type: String
Default: "222222222222"
ProductionAccountId:
Type: String
Default: "333333333333"
Resources:
# CodePipelineサービスロール
CodePipelineServiceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service: codepipeline.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CodePipelinePolicy
PolicyDocument:
Version: 2012-10-17
Statement:
# クロスアカウントロールのAssumeRole権限
- Effect: Allow
Action: sts:AssumeRole
Resource:
- !Sub arn:aws:iam::${DevAccountId}:role/CrossAccountDeployRole
- !Sub arn:aws:iam::${StagingAccountId}:role/CrossAccountDeployRole
- !Sub arn:aws:iam::${ProductionAccountId}:role/CrossAccountDeployRole
# S3アーティファクトアクセス
- Effect: Allow
Action:
- s3:GetObject
- s3:PutObject
Resource:
- !Sub ${ArtifactBucket.Arn}/*
# その他のCodePipeline権限
- Effect: Allow
Action:
- codecommit:GetBranch
- codecommit:GetCommit
- codebuild:StartBuild
- codebuild:BatchGetBuilds
Resource: "*"
# パイプライン定義
CrossAccountPipeline:
Type: AWS::CodePipeline::Pipeline
Properties:
Name: cross-account-pipeline
RoleArn: !GetAtt CodePipelineServiceRole.Arn
ArtifactStore:
Type: S3
Location: !Ref ArtifactBucket
EncryptionKey:
Id: !GetAtt ArtifactKMSKey.Arn
Type: KMS
Stages:
# ソースステージ
- Name: Source
Actions:
- Name: SourceAction
ActionTypeId:
Category: Source
Owner: AWS
Provider: CodeCommit
Version: 1
Configuration:
RepositoryName: myapp-repo
BranchName: main
OutputArtifacts:
- Name: SourceOutput
# ビルドステージ
- Name: Build
Actions:
- Name: BuildAction
ActionTypeId:
Category: Build
Owner: AWS
Provider: CodeBuild
Version: 1
Configuration:
ProjectName: !Ref CodeBuildProject
InputArtifacts:
- Name: SourceOutput
OutputArtifacts:
- Name: BuildOutput
# 開発環境デプロイ(クロスアカウント)
- Name: DeployToDev
Actions:
- Name: DeployDevAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: myapp-dev-stack
TemplatePath: BuildOutput::template.yaml
RoleArn: !Sub arn:aws:iam::${DevAccountId}:role/CloudFormationExecutionRole
Capabilities: CAPABILITY_IAM
InputArtifacts:
- Name: BuildOutput
RoleArn: !Sub arn:aws:iam::${DevAccountId}:role/CrossAccountDeployRole
# 本番環境デプロイ(クロスアカウント + 承認)
- Name: ApprovalForProduction
Actions:
- Name: ManualApproval
ActionTypeId:
Category: Approval
Owner: AWS
Provider: Manual
Version: 1
- Name: DeployToProduction
Actions:
- Name: DeployProductionAction
ActionTypeId:
Category: Deploy
Owner: AWS
Provider: CloudFormation
Version: 1
Configuration:
ActionMode: CREATE_UPDATE
StackName: myapp-prd-stack
TemplatePath: BuildOutput::template.yaml
RoleArn: !Sub arn:aws:iam::${ProductionAccountId}:role/CloudFormationExecutionRole
Capabilities: CAPABILITY_IAM
InputArtifacts:
- Name: BuildOutput
RoleArn: !Sub arn:aws:iam::${ProductionAccountId}:role/CrossAccountDeployRole
S3/KMS アクセス設定
クロスアカウントデプロイでは、ツールアカウントのS3バケット(アーティファクト格納先)に他アカウントからアクセスする必要があります。
S3バケットポリシー
# CloudFormation実装例
Resources:
ArtifactBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: myapp-cross-account-artifacts
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: aws:kms
KMSMasterKeyID: !GetAtt ArtifactKMSKey.Arn
ArtifactBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref ArtifactBucket
PolicyDocument:
Version: 2012-10-17
Statement:
# デプロイ先アカウントからの読み取り許可
- Sid: AllowCrossAccountRead
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${DevAccountId}:role/CrossAccountDeployRole
- !Sub arn:aws:iam::${StagingAccountId}:role/CrossAccountDeployRole
- !Sub arn:aws:iam::${ProductionAccountId}:role/CrossAccountDeployRole
Action:
- s3:GetObject
- s3:GetObjectVersion
Resource: !Sub ${ArtifactBucket.Arn}/*
# CodePipelineからの読み書き許可
- Sid: AllowCodePipeline
Effect: Allow
Principal:
AWS: !GetAtt CodePipelineServiceRole.Arn
Action:
- s3:PutObject
- s3:GetObject
Resource: !Sub ${ArtifactBucket.Arn}/*
KMSキーポリシー
S3バケットが暗号化されている場合、デプロイ先アカウントがKMSキーにアクセスできる必要があります。
# CloudFormation実装例
Resources:
ArtifactKMSKey:
Type: AWS::KMS::Key
Properties:
Description: KMS key for cross-account artifact encryption
KeyPolicy:
Version: 2012-10-17
Statement:
# ルートアカウント(ツールアカウント)の管理者権限
- Sid: Enable IAM User Permissions
Effect: Allow
Principal:
AWS: !Sub arn:aws:iam::${AWS::AccountId}:root
Action: kms:*
Resource: "*"
# CodePipelineの暗号化・復号化権限
- Sid: Allow CodePipeline to use the key
Effect: Allow
Principal:
AWS: !GetAtt CodePipelineServiceRole.Arn
Action:
- kms:Decrypt
- kms:Encrypt
- kms:GenerateDataKey
Resource: "*"
# デプロイ先アカウントの復号化権限
- Sid: Allow cross-account decrypt
Effect: Allow
Principal:
AWS:
- !Sub arn:aws:iam::${DevAccountId}:role/CrossAccountDeployRole
- !Sub arn:aws:iam::${StagingAccountId}:role/CrossAccountDeployRole
- !Sub arn:aws:iam::${ProductionAccountId}:role/CrossAccountDeployRole
Action:
- kms:Decrypt
- kms:DescribeKey
Resource: "*"
ArtifactKMSKeyAlias:
Type: AWS::KMS::Alias
Properties:
AliasName: alias/artifact-bucket-key
TargetKeyId: !Ref ArtifactKMSKey