とある事情で AアカウントにあるCodeCommitリポジトリを、BアカウントのCodePipelineで取得する必要がありました。
その際いくつかハマったのでメモとして残しておきます。
CodePipelineのRole
CodePipelineには、StageごとにRoleを指定する機能があります。
これは、CodePipelineが動作中に、指定されたRoleに AssumeRole してくれる機能です。
そのためCodePipelineのRoleのポリシーに、 sts:AssumeRole
を追加しておく必要があります。
CodeCommit
CodeCommitにはリソースベースのポリシーがありません。
そのため、今回はAアカウントに CodeCommitRoleを作成し、そのロールに以下の権限を付けてあります。
Effect: Allow
Action:
- codecommit:Get*
- codecommit:GitPull
- codecommit:UploadArchive
- codecommit:CancelUploadArchive
Resource:
- !Ref CodeCommitRepositoryARN
その上で、AssumeRolePolicyとして、BアカウントからのAssumeRoleを許可しました。
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
AWS: "<Bアカウント>"
Action:
- 'sts:AssumeRole'
これだけでは動かない
しかし、残念ながらこれでは動きません。
Bアカウントのパイプラインは、CodeCommitRoleにAssumeRoleしているため、パイプラインのアーティファクトストア(BアカウントのS3)にCodeCommitから取得したソースコードをs3にPutすることができないのです。
そのため、CodeCommitRoleにs3へのPut権限を付ける必要があります。
Effect: Allow
Action:
- s3:PutObject
- s3:PutObjectAcl
Resource:
- !Sub "arn:aws:s3:::${バケットのプレフィックス}-*/*"
※ バケットはCloudFormationで作成しているので、プレフィックスを固定にしています。
無事にPutできた
s3に無事にPutすることができるようになりました。
しかし、Objectをダウンロードしようとすると、復号に失敗するエラーが発生します。
これは、CodeCommitRoleがs3へPutする際に、AアカウントのKMSキーを使って暗号化してs3にPutするために発生しています(おそらく)
KMSで暗号化
それを回避するためにCodePipelineのArtifactStoreの設定で、KMSを明示するようにしました。
(aws/s3 のKMSキーを使用しようとして、それぞれのアカウントにデフォルトで存在するため、それが使用されてしまったという理解をしています)
これはBアカウントで作成するリソースです。
ArtifactStore:
Type: S3
Location: !Ref ArtifactBucket
EncryptionKey:
Type: KMS
Id: !GetAtt BucketEncryptionKey.Arn
KMSのキーポリシーには、Aアカウントが使用できるようにする必要があります
BucketEncryptionKey:
Type: AWS::KMS::Key
Properties:
KeyPolicy:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
Action:
- 'kms:*'
- Effect: Allow
Principal:
AWS: "Aアカウント"
Action:
- 'kms:Encrypt'
- 'kms:Decrypt'
- 'kms:ReEncrypt*'
- 'kms:GenerateDataKey'
- 'kms:DescribeKey'
Resource:
- '*'
そして、CodeCommitRoleにこのKeyを使用できるようにします。
- Effect: Allow
Action:
- 'kms:Encrypt'
- 'kms:Decrypt'
- 'kms:ReEncrypt*'
- 'kms:GenerateDataKey'
- 'kms:DescribeKey'
Resource:
- !Ref BucketEncryptionKeyARN
こうすることで無事BアカウントのCodePipelineがAアカウントのCodeCommitを取得できるようになりました。
まとめ
クロスアカウントでCodePipelineからCodeCommitのリポジトリを使用する方法を考えました。
クロスアカウントは何をやるにしても大変なのでやらないで済むに越したことはないなと思いました。