0. 개요
이번 포스팅에서는 Account A, Account B가 존재하고, Account A의 codepipeline을 통해 Account B의 리소스에 배포하는 환경 구축을 구축해보도록 하겠습니다. 부가적으로 S3를 KMS로 암호화하여 보안적인 부분도 고려했습니다.사전에 Account A에 제대로 동작하는 Codepipeline이 구성이 되었다고 가정하였습니다. 구성을 그림으로 보여드리겠습니다.
1. 환경 구축(Account A)
- AWS KMS 암호화 키 생성
고객 관리형 키는 모든 AWS KMS 키와 마찬가지로 리전에 따라 다릅니다. 파이프라인이 생성된 동일한 리전에서 고객 관리형 AWS KMS 키를 생성해야 합니다.
키 생성 클릭 후 키 유형은 대칭으로 선택 후 별칭을 입력합니다.
이 키를 사용할 수 있는 권한을 정의해야 합니다. 기존에 존재하는 codepipeline과 coudebuild role을 선택합니다. 이 두 서비스가 kms를 사용할 권한을 가지고 있어야 합니다.
다른 계정 추가에서 ACCOUNT B의 ACCOUNT id를 입력하고 추가합니다.이후에 아티팩트가 담길 S3가 KMS 암호화 되는데 ACCOUNT B에서 이 아티팩트 S3에 접근해야 되기 떄문입니다.
생성이 완료가 되었습니다.
- IAM 계정 정책 및 역할 설정을 진행해야 합니다.
ACCOUNT B에게 build의 아티팩트가 담긴 s3에 권한을 부여해야 합니다. S3 버킷 정책 추가 빨간색 부분을 바꿔주면 됩니다. 수정 후 대입한 후 버킷 정책을 저장합니다.
S3 : 아티팩트가 담길 S3 버킷 이름, ACCOUNT B의 ACCOUNT ID
{
"Version": "2012-10-17",
"Id": "SSEAndSSLPolicy",
"Statement": [
{
"Sid": "DenyUnEncryptedObjectUploads",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:PutObject",
"Resource": <strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:s3:::codepipeline-us-east-2-1234567890/***"</span></strong>,
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": "aws:kms"
}
}
},
{
"Sid": "DenyInsecureConnections",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": <strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:s3:::codepipeline-us-east-2-1234567890/***",</span></strong>
"Condition": {
"Bool": {
"aws:SecureTransport": false
}
}
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<strong><span class="has-inline-color has-vivid-red-color">**012ID_ACCOUNT_B:root**"</span></strong>
},
"Action": [
"s3:Get*",
"s3:Put*"
],
"Resource": <strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:s3:::codepipeline-us-east-2-1234567890/***"</span></strong>
},
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::<strong><span class="has-inline-color has-vivid-red-color">**012ID_ACCOUNT_B:root**</span></strong>"
},
"Action": "s3:ListBucket",
"Resource": <strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:s3:::codepipeline-us-east-2-1234567890**"</span></strong>
}
]
}
JSON추가적으로 Account A에 codepipeline에 Assume role을 추가하여야 합니다. codepipe role에 들어가서 인라인 정책 추가를 클릭합니다.
json 탭을 클릭하여 ACCOUNT B의 역할을 수임하도록 허용합니다. (빨간색 부분을 수정합니다.)
{
"Version": "2012-10-17",
"Statement": {
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": [
<span class="has-inline-color has-vivid-red-color"><strong>"**arn:aws:iam::012ID_ACCOUNT_B:role/***"</strong></span>
]
}
}
JSON2. 환경 구축(Account B)
ACCOUNT B에 codedeploy를 당할 리소스에 역할에 추가를 해야 합니다. 기존에는 AmazonEC2RoleforAWSCodeDeploy, AmazonS3FullAccess만 존재하면 리소스 배포가 되었지만 타 계정연동 이기 떄문에 인라인 정책 2개를 추가해야 합니다.
인라인 정책 1
—> ACCOUNT A 파이프라인의 아티팩트가 저장되는 S3버킷에 대한 액세스 권한을 부여해야 한다.
s3 arn : ACCOUNT A의 아티팩트 S3
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:Get*"
],
"Resource": [
<strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:s3:::codepipeline-us-east-2-1234567890/***"</span></strong>
]
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
<strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:s3:::codepipeline-us-east-2-1234567890**"</span></strong>
]
}
]
}
JSON인라인 정책 2
—> kms에 대한 권한도 있어야 s3에 접근할 수 있습니다.
ACCOUNT A의 KMS의 ARN을 입력합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"kms:DescribeKey",
"kms:GenerateDataKey*",
"kms:Encrypt",
"kms:ReEncrypt*",
"kms:Decrypt"
],
"Resource": [
<strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:kms:us-east-1:012ID_ACCOUNT_A:key/2222222-3333333-4444-556677EXAMPLE**"</span></strong>
]
}
]
}
JSONACCOUNT B의 크로스 어카운트(교차 계정 역할)을 구성해야 합니다.
- iam 역할 생성 >>> 신뢰할 수 있는 계정 ACCOUNT A 입력 >>> S3readonly 정책 추가 >>> 생성
여기서 역시 인라인 정책 2개를 추가해야 합니다.
인라인 정책 1
—> ACCOUNT A가 Account B의 deploy할 수 있는 권한을 줍니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codedeploy:CreateDeployment",
"codedeploy:GetDeployment",
"codedeploy:GetDeploymentConfig",
"codedeploy:GetApplicationRevision",
"codedeploy:RegisterApplicationRevision"
],
"Resource": "*"
}
]
}
JSON인라인 정책 2
—> Account A의 아티팩트 S3를 검색하고 출력을 넣을 수 있도록 허용합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject*",
"s3:PutObject",
"s3:PutObjectAcl",
"codecommit:ListBranches",
"codecommit:ListRepositories"
],
"Resource": [
<span class="has-inline-color has-vivid-red-color"><strong>"**arn:aws:s3:::codepipeline-us-east-2-1234567890/**</strong></span><strong><span class="has-inline-color has-vivid-red-color">*"</span></strong>
]
}
]
}
JSON3. PIPELINE 설정
그렇지만 pipeline 편집은 AWS 콘솔을 사용하여 다른 계정과 연결된 리소스를 사용하는 파이프라인을 생성하거나 편집할 수 없습니다. 그러므로 AWS CLI를 이용하였습니다. (AWS codepipeline role을 주고 ec2 한대를 생성하여서 진행)
파이프라인의 이름을 입력하면 그 파이프라인의 이름의 현재 구성이 pipeline.json의 형식으로 파일이 생성됩니다.
aws codepipeline get-pipeline –name MyFirstPipeline >pipeline.json
{
"pipeline": {
"roleArn": "arn:aws:iam::311724524637:role/service-role/AWSCodePipelineServiceRole-ap-northeast-2-account-test-pipeline",
"stages": [
{
"name": "Source",
"actions": [
{
"inputArtifacts": [],
"name": "Source",
"region": "ap-northeast-2",
"namespace": "SourceVariables",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"version": "1",
"provider": "CodeCommit"
},
"outputArtifacts": [
{
"name": "SourceArtifact"
}
],
"configuration": {
"OutputArtifactFormat": "CODE_ZIP",
"PollForSourceChanges": "false",
"BranchName": "master",
"RepositoryName": "account-test"
},
"runOrder": 1
}
]
},
{
"name": "Build",
"actions": [
{
"inputArtifacts": [
{
"name": "SourceArtifact"
}
],
"name": "Build",
"region": "ap-northeast-2",
"namespace": "BuildVariables",
"actionTypeId": {
"category": "Build",
"owner": "AWS",
"version": "1",
"provider": "CodeBuild"
},
"outputArtifacts": [
{
"name": "BuildArtifact"
}
],
"configuration": {
"ProjectName": "account-test-build"
},
"runOrder": 1
}
]
},
{
"name": "Deploy",
"actions": [
{
"inputArtifacts": [
{
"name": "BuildArtifact"
}
],
"name": "Deploy",
"region": "ap-northeast-2",
"namespace": "DeployVariables",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"version": "1",
"provider": "CodeDeploy"
},
"outputArtifacts": [],
"configuration": {
"ApplicationName": "test",
"DeploymentGroupName": "account-test"
},
"runOrder": 1
}
]
}
],
"artifactStore": {
"type": "S3",
"location": "codepipeline-ap-northeast-2-800634835495"
},
"name": "account-test-pipeline",
"version": 1
}
}
JSON기존 구성에 artifactStore 부분에 encryptionKey, ID 및 유형 정보를 추가합니다. location이 S3 버킷이름이고 id는 Account A의 kms arn입니다.
"artifactStore”: {
"location": "codepipeline-us-east-2-1234567890",
"type": "S3",
"encryptionKey": {
"id": "arn:aws:kms:us-east-1:012ID_ACCOUNT_A:key/2222222-3333333-4444-556677EXAMPLE",
"type": "KMS"
}
},
JSONDEPLOY 부분에 Account B의 codedeploy를 사용하기 위해 json 수정을 진행합니다. 어플리케이션 이름과 배포 그룹이름을 Account B의 내용으로 바꿉니다. role은 ACCOUNT B의 crossaccount role로 바꿔줍니다. 사전에 ACCOUNT B에 codedeploy 리소스는 생성되어 있어야 합니다. (리소스 + codedeploy 자체(어플리케이션, 배포그룹))
{
"name": "Staging",
"actions": [
{
"inputArtifacts": [
{
"name": "MyAppBuild"
}
],
"name": <strong><span class="has-inline-color has-vivid-red-color">"**ExternalDeploy**"</span></strong>,
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"version": "1",
"provider": "CodeDeploy"
},
"outputArtifacts": [],
"configuration": {
"ApplicationName": <strong><span class="has-inline-color has-vivid-red-color">"**AccountBApplicationName**"</span></strong>,
"DeploymentGroupName": <strong><span class="has-inline-color has-vivid-red-color">"**AccountBApplicationGroupName**"</span></strong>
},
"runOrder": 1,
"roleArn": <strong><span class="has-inline-color has-vivid-red-color">"**arn:aws:iam::012ID_ACCOUNT_B:role/CrossAccount_Role**"</span></strong>
}
]
}
JSONupdate-pipeline 명령 metadata이 파일 을 사용할 수 있도록 파일 에서 행을 제거해야 합니다.
"metadata": {
"pipelineArn": "arn:aws:codepipeline:region:account-ID:pipeline-name",
"created": "date",
"updated": "date"
}
JSON설정값을 바꾼 후 파이프라인 업데이트를 하면 파이프라인이 업데이트 됩니다.
aws codepipeline update-pipeline –cli-input-json file://pipeline.json
파이프라인을 실행합니다.
aws codepipeline start-pipeline-execution –name MyFirstPipeline
모든 설정이 완료되었고 해당 파이프라인 실행하게 되면 Account A의 ci/cd를 거쳐 Account B의 codedeploy를 통해 배포가 됩니다. 이렇게 kms를 통한 타 계정 ci/cd배포 hand-on을 마치겠습니다.
SA 최덕진