본문 바로가기

클라우드/Public Cloud(Naver, Amazon)

타 계정 간 codepipeline 연동

Account A, Account B가 있다. Account A에 code pipeline이 있고, Account B에 리소스가 있다.

Account A의 pipeline을 통해 Account B의 리소스에 배포를 진행한다. 사전조건은 Account A에 일단 잘 동작하는 codepipeline이 존재함을 확인하고 진행한다.

사전 준비 사항 : AWS KMS 암호화 키 생성 (ACCOUNT A)

고객 관리형 키는 모든 AWS KMS 키와 마찬가지로 리전에 따라 다릅니다. 파이프라인이 생성된 동일한 리전에서 고객 관리형 AWS KMS 키를 생성해야 합니다

키 생성 클릭 후 키 유형은 대칭으로 생성 후 별칭 입력

키 관리 권한을 정의할 USER을 입력, 임의로 아무나 입력

이 키를 사용할 수 있는 권한을 정의해야한다. 기존에 존재하는 codepipeline과 coudebuild role을 선택한다. 이 두 서비스가 kms를 사용할 권한을 가지고 있어야 한다.

그 후 다른 계정 추가에서 ACCOUNT B의 ACCOUNT id를 입력하고 추가한다.

—> 이후 아티팩트가 담길 S3가 KMS 암호화 되는데 ACCOUNT B에서 이 아티팩트 S3에 접근해야 되기 떄문에

(생성완료!)

Account A

1단계 : 계정 정책 및 역할 설정

ACCOUNT B에게 build의 아티팩트가 담긴 s3에 권한을 부여해야 한다.

S3 버킷 정책 추가

빨간색 부분을 바꿔주면 된다. S3 : 아티팩트가 담길 S3 버킷 이름, ACCOUNT B의 ACCOUNT ID

ex) S3 : arn:aws:s3:::duckaccount-test/ , Account : "arn:aws:iam::ACCOUNTID:root

{
  "Version": "2012-10-17",
  "Id": "SSEAndSSLPolicy",
  "Statement": [
	{
  	"Sid": "DenyUnEncryptedObjectUploads",
	  "Effect": "Deny",
	  "Principal": "*",
	  "Action": "s3:PutObject",
	  "Resource": "**arn:aws:s3:::codepipeline-us-east-2-1234567890/***",
	  "Condition": {
		"StringNotEquals": {
		"s3:x-amz-server-side-encryption": "aws:kms"
		}
	   }
	 },
	{
	  "Sid": "DenyInsecureConnections",
	  "Effect": "Deny",
	  "Principal": "*",
	  "Action": "s3:*",
	  "Resource": "**arn:aws:s3:::codepipeline-us-east-2-1234567890/***",
	  "Condition": {
		"Bool": {
	  		"aws:SecureTransport": false
			}
		}
	  },
	{
	  "Sid": "",
	  "Effect": "Allow",
	  "Principal": {
		"AWS": "arn:aws:iam::**012ID_ACCOUNT_B:root**"
		},
	  "Action": [
            "s3:Get*",
            "s3:Put*"
        ],
	  "Resource": "**arn:aws:s3:::codepipeline-us-east-2-1234567890/***"
	},
	{
	  "Sid": "",
	  "Effect": "Allow",
	  "Principal": {
	      "AWS": "arn:aws:iam::**012ID_ACCOUNT_B:root**"
			},
	  "Action": "s3:ListBucket",
  	"Resource": "**arn:aws:s3:::codepipeline-us-east-2-1234567890**"
	}
   ]
}

수정 후 대입한 후 s3 버킷 정책 저장한다.

 

추가적으로 Account A에 codepipeline에 Assume role을 추가하여야 한다. codepipe role에 들어가서 인라인 정책 추가를 클릭한다.

json 탭을 클릭하여 ACCOUNT B의 역할을 수임하도록 허용 합니다.

{
   "Version": "2012-10-17",
   "Statement": {
       "Effect": "Allow",
       "Action": "sts:AssumeRole",
       "Resource": [
           "**arn:aws:iam::012ID_ACCOUNT_B:role/***"
       ]
   }
 }

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": [
         "**arn:aws:s3:::codepipeline-us-east-2-1234567890/***"
       ]
     },
     {
       "Effect": "Allow",
       "Action": [
         "s3:ListBucket"
       ],
       "Resource": [
         "**arn:aws:s3:::codepipeline-us-east-2-1234567890**"
       ]
     }
   ]
 }

인라인 정책 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": [
           "**arn:aws:kms:us-east-1:012ID_ACCOUNT_A:key/2222222-3333333-4444-556677EXAMPLE**"
          ]
      }
   ]
}

 

ACCOUNT 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": "*"
    }
  ]
}

인라인 정책 2

—> Account A의 아티팩트 S3를 검색하고 출력을 넣을 수 있도록 허용한다.

{
   "Version": "2012-10-17",
   "Statement": [
     {
       "Effect": "Allow",
       "Action": [
         "s3:GetObject*",
         "s3:PutObject",
         "s3:PutObjectAcl",
         "codecommit:ListBranches",
         "codecommit:ListRepositories"                
       ],
       "Resource": [
         "**arn:aws:s3:::codepipeline-us-east-2-1234567890/***"
       ]
     }
   ]
}

 

이러면 위의 기초 권한 세팅은 완료된다. pipeline 편집만 진행하면 된다.

그렇지만 pipeline 편집은 AWS 콘솔을 사용하여 다른 계정과 연결된 리소스를 사용하는 파이프라인을 생성하거나 편집할 수 없습니다. 그러므로 AWSCLI를 이용하였습니다.

AWS codepipeline role을 주고 ec2 한대를 생성하여서 진행하였다.

파이프라인의 이름을 입력하면 그 파이프라인의 이름의 현재 구성이 pipeline.json의 형식으로 파일이 생성된다.

aws codepipeline get-pipeline --name MyFirstPipeline >pipeline.json

{
    "pipeline": {
        "roleArn": "arn:aws:iam::accountid: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
    }
}

기존에 구성에 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"
    }
  },

DEPLOY 부분에 Account B의 codedeploy를 사용하기 위해 json 수정을 진행한다.

어플리케이션 이름과 배포 그룹이름을 Account B의 내용으로 바꾼다.

role은 ACCOUNT B의 crossaccount role로 바꿔준다. 사전에 ACCOUNT B에 codedeploy 리소스는 생성되어 있어야 한다. (리소스 + codedeploy 자체(어플리케이션, 배포그룹))

,
            {
                "name": "Staging",
                "actions": [
                    {
                        "inputArtifacts": [
                            {
                                "name": "MyAppBuild"
                            }
                        ],
                        "name": "**ExternalDeploy**",
                        "actionTypeId": {
                            "category": "Deploy",
                            "owner": "AWS",
                            "version": "1",
                            "provider": "CodeDeploy"
                        },
                        "outputArtifacts": [],
                        "configuration": {
                            "ApplicationName": "**AccountBApplicationName**",
                            "DeploymentGroupName": "**AccountBApplicationGroupName**"
                        },
                        "runOrder": 1,
                        "roleArn": "**arn:aws:iam::012ID_ACCOUNT_B:role/CrossAccount_Role**"
                    }
                ]
            }

update-pipeline 명령 metadata이 파일 을 사용할 수 있도록 파일 에서 행을 제거해야 합니다.

삭제~~~~~

"metadata": {  
  "pipelineArn": "arn:aws:codepipeline:region:account-ID:pipeline-name",
  "created": "date",
  "updated": "date"
  }

해당 설정값을 바꾼 후 파이프라인 업데이트를 하면 파이프라인이 업데이트 된다.

aws codepipeline update-pipeline --cli-input-json file://pipeline.json

파이프라인을 실행한다.

aws codepipeline start-pipeline-execution --name MyFirstPipeline

ACCOUNT A의 codecommit build를 거쳐 Account B의 codedeploy를 통해 배포된다.

 

 

********* 이슈 **************

codebuild에 s3 권한이 없다는 이슈가 있어서 iam role에 s3:GetObject"를 추가했다. + kms의 역할에 codebuild 추가했다.

보안상 문제되지 않는다면 KMS 암호화를 사용하지 않고 진행해도 될 것 같다.