Site icon Mr. 沙先生

一條龍佈署 CI/CD 從 Travis 到 CodeDeploy 的 On-Premises (IAM Role/STS)

之前寫過 CodeDeploy 在 EC2 的應用,然後終於可以來寫 CodeDeploy 在 On-Premises 也就是在 非EC2 的主機佈署,

 

On-Premises 與 EC2 不同的地方在於 AWS 不認得你的 On-Premises Server,AWS 不可能知道你家的 Server 在哪裡吧 !!,基於 AWS 雲的概念是 IP 不是一個可以作為依據的資訊,所以也不會用 IP 來鎖 (用企業的方式思考,一家公司只有一個 Public IP 怎麼佈署萬台 Server ?)

 

由於之前沒有涉獵 AWS 太深,這次重新深入了解 AWS 後踩了非常多的坑 ..   但也了解 AWS 的強大

 

對於非 AWS 的第三方驗證可以採用 Security Token Service (STS) 來取得暫時授權,通常 STS 會和 IAM Role 並用,而 CodeDeploy On-Premises 這篇我採用的就是 AssumeRole 這個 API

 

要用 CodeDeploy 的 On-Premises 官方有提供幾種選擇

 

在這篇我選擇用 register-on-premises-instance(IAM Role) 來建立 CodeDeploy On-Premises。

 

關係架構圖

 

如果你的 On-Premises 環境沒有辦法直接對外訪問 or 必須使用 Proxy,那你必須先確認以下環境資訊。

 

環境

 

在進行 CodeDeploy On-Premises 之前必須先確認你的網路環境允許連上以下 AWS 服務

 

必要條件

用來建立以下服務的 IAM User 必須擁有以下權限

Attach

AWSCodeDeployFullAccess

lnline

iam:CreateAccessKey,
iam:CreateUser,
iam:DeleteAccessKey,
iam:DeleteUser,
iam:DeleteUserPolicy,
iam:ListAccessKeys,
iam:ListUserPolicies,
iam:PutUserPolicy,
iam:GetUser

此安裝將會建立以下 AWS 服務

 

全程將使用 AWS command line 建立,將不會有 Web cosole 的執行過程

 

 

開始建立 CodeDeploy On-Premises (IAM Role/STS)

或者你可以用 shazi7804/codedeploy-permissions-onpremises 進行自動佈署。

 

Step 1: 建立 S3 bucket

$ aws s3api create-bucket --bucket codedeploy-project --region ap-northeast-1

 

確認可以訪問

$ aws s3 ls project

 

Step 2: 建立 IAM User for Travis CI

建立 IAM User

$ aws iam create-user --user-name travisci-project

 

Attach Policy – AWSCodeDeployDeployerAccess

$ aws attach-user-policy --user-name travisci-project --policy-arn arn:aws:iam::aws:policy/AWSCodeDeployDeployerAccess

 

lnline Policy – 授與 bucket name 為 codedeploy-project 有權限

$ tee travisci-project-lnline.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1487528506000",
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::codedeploy-project/*"
            ]
        }
    ]
}
EOF
$ aws iam put-user-policy --user-name travisci-project --policy-name travisci-project-lnline.json
$ rm travisci-project-lnline.json

 

Step 3: 建立 IAM User for On-Premises

給 On-Premises 的 IAM User 可以共用,所以一個 AWS account 僅需要一個。

$ aws iam create-user --user-name codedeploy-onpremises

 

lnline sts-AssumeRole

$ tee codedeploy-onpremises-lnline.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole"
            ],
            "Resource": "arn:aws:iam::012345678:role/Role-onpremises"
        }
    ]
}
EOF
$ aws iam put-user-policy --user-name codedeploy-onpremises --policy-name role-codedeploy-onpremises --policy-document file://codedeploy-onpremises-lnline.json
$ rm codedeploy-onpremises-lnline.json

 

Step 4: 建立 IAM Role for On-Premises

給 On-Premises 的 IAM Role 可以共用,所以一個 AWS account 僅需要一個。

trust policy 給 AWS IAM root

$ tee role-onpremises-trust.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Principal": {"AWS": "arn:aws:iam::0123456789:root"},
    "Action": "sts:AssumeRole"
  }
}
EOF
$ aws iam create-role --role-name Role-onpremises --assume-role-policy-document file://role-onpremises-trust.json
$ rm role-onpremises-trust.json

 

給予 S3 權限,並且 bucket name 一樣鎖在 codedeploy-*

$ tee role-onpremises-policy.json <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::codedeploy-*"
        }
    ]
}
EOF
$ aws iam put-role-policy --role-name Role-onpremises --policy-name role-onpremises-policy --policy-document file://role-onpremises-policy.json

 

Create Role Profile

$ aws iam create-instance-profile --instance-profile-name Role-onpremises-profile

 

把 Role 和 Profile 關聯起來

$ aws iam add-role-to-instance-profile --role-name Role-onpremises --instance-profile-name  Role-onpremises-profile

 

Step 5: 建立 IAM Role for CodeDeploy

給 CodeDeploy Server 的 IAM Role 一個 AWS account 僅需要一個。

$ tee role-codedeploy-trust.json <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "codedeploy.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
$ aws iam create-role --role-name Role-CodeDeploy --assume-role-policy-document file://role-codedeploy-trust.json
$ rm role-codedeploy-trust.json

 

Attach policy

$ aws iam attach-role-policy --role-name Role-CodeDeploy --policy-arn arn:aws:iam::aws:policy/service-role/AWSCodeDeployRole

 

Create Profile

$ aws iam create-instance-profile --instance-profile-name Role_CodeDeploy-Profile

 

把 Role 和 Profile 關聯起來

$ aws iam add-role-to-instance-profile --role-name Role-CodeDeploy --instance-profile-name Role_CodeDeploy-Profile

 

Step 6: 建立 CodeDeploy

Create application

$ aws deploy create-application --application-name project --region ap-northeast-1

 

Create deployment_group (prod)

$ aws deploy create-deployment-group \
           --application-name project \
           --deployment-config-name CodeDeployDefault.AllAtOnce \
           --deployment-group-name prod \
           --service-role-arn arn:aws:iam::0123456789:role/Role-CodeDeploy \
           --region ap-northeast-1

 

Step 7: 註冊 CodeDeploy On-Premises

利用 Step4 建立的 IAM Role 去產生 sts session

$ aws sts assume-role --role-arn arn:aws:iam::0123456789:role/Role-onpremises --role-session-name project-session-server01

 

將產生的 sts session 去註冊 On-Premises instance

$ aws deploy register-on-premises-instance --instance-name project-server01 --iam-session-arn arn:aws:sts::0123456789:assumed-role/Role-onpremises/project-session-server01

 

替註冊的 On-Premises instance 加入 tags:Key=project,Values=project-server01

$ aws deploy add-tags-to-on-premises-instances --instance-names project-server01 --tags Key=project,Values=project-server01

 

在 On-Premises Server 安裝 CodeDeploy

以下步驟皆在 On-Premises Server 下進行操作 或者你可以用 shazi7804/codedeploy-session-helper 進行自動佈署。

Step 1: 設定 Proxy

如果你的 On-Premises 不允許直接訪問外部網路,需要另外設定 Proxy,因為安裝 CodeDeploy 必須對外訪問。

建議先把他寫到 /etc/environment,否則在接下來的 sudo 會無法使用 export 環境變數

 

Step 2: 安裝 aws cli

$ sudo apt-get install -y wget unzip
$ cd /tmp
$ wget https://s3.amazonaws.com/aws-cli/awscli-bundle.zip
$ unzip awscli-bundle.zip
$ cd awscli-bundle
$ sudo chmod +x install
$ sudo ./install -i /usr/local/aws -b /usr/local/bin/aws

 

確認版本為最新的 aws cli

$ aws --version

 

在 On-Premises 必須取得 #Step 3: “建立 IAM User for On-Premises” 的 Access Key/ Secret Access Key,並且登記在 On-Premises Server 的 aws cli

$ aws configure

 

Step 3: 安裝 CodeDeploy agent

$ sudo apt-get install -y ruby
$ wget https://aws-codedeploy-ap-northeast-1.s3.amazonaws.com/latest/install
$ sudo chmod +x install
$ sudo ./install auto

install 有支援 proxy 參數,可以用 –proxy 解決

 

驗證服務正在使用

$ ps ax | grep codedeploy
codedeploy-agent: master 19248
codedeploy-agent: InstanceAgent::Plugins::CodeDeployPlugin::CommandPoller of master 19248

 

Step 4: 設定檔 codedeploy.onpremises.yml & codedeployagent.yml

建立 CodeDeploy On-Premises 需要使用的設定檔

$ sudo tee /etc/codedeploy-agent/conf/codedeploy.onpremises.yml <<EOF
---
iam_session_arn: arn:aws:sts::0123456789:assumed-role/Role-onpremises/project-session-server01
aws_credentials_file: /etc/codedeploy-agent/conf/credentials
region: ap-northeast-1
EOF

 

在 codedeployagent.yml 把 proxy 參數加入,讓 codedeploy agent 可以用 proxy 去更新

:proxy_uri: http://proxy.com:3128

 

重新啟動 CodeDeploy agent 把 proxy 的設定參數吃進去

$ sudo service codedeploy-agent restart

 

Step 5: 建立 sts 臨時認證檔 credentials

將 #Step 6: “建立 CodeDeploy” 中建立的 sts 認證資訊寫入 /etc/codedeploy-agent/conf/credentials

$ tee /etc/codedeploy-agent/conf/credentials <<EOF
[default]
aws_access_key_id = $sts_access_key_id
aws_secret_access_key = $sts_secret_access_key
aws_session_token = $sts_session_token
EOF

 

在 CodeDeploy 中決定 deploy 的 On-Premises instance tags

CodeDeploy 中的 deployment_group tags 必須和 On-Premises instance tags 符合才會進行 CodeDeploy。

你可以透過 Web cosole 在 CodeDeploy/Application/deployment_group/Search by tags 進行設定 tags,tags type 必須是 On-premises-instance

或是使用 awscli “更新” tags,此設定會直接覆蓋現有 tags,若有多筆 tags 可以用 json 或是多個 –on-premises-instance-tag-filters 來指定 tag

$ aws deploy update-deployment-group \
                       --application-name project \
                       --current-deployment-group-name master \
                       --on-premises-instance-tag-filters Key=Name,Value=project-server01,Type=KEY_AND_VALUE

或是用 json 更新 tags

$ tee multi_tags.json <<EOF
[
  {
    "Key": "project",
    "Value": "server01",
    "Type": "KEY_AND_VALUE"
  },
  {
    "Key": "project",
    "Value": "server02",
    "Type": "KEY_AND_VALUE"
  }
]
EOF
$ aws deploy update-deployment-group \
                       --application-name project \
                       --current-deployment-group-name prod \
                       --on-premises-instance-tag-filters file://multi_tags.json

 

驗證

正常運作時 access codedeploy 的 log。

$ less /var/log/aws/codedeploy-agent/codedeploy-agent.log

2017-03-06 00:03:13 INFO  [codedeploy-agent(19252)]: Version file found in /opt/codedeploy-agent/.version.
2017-03-06 00:04:14 INFO  [codedeploy-agent(19252)]: [Aws::CodeDeployCommand::Client 200 61.019261 0 retries] poll_host_command(host_identifier:"arn:aws:sts::0123456789:assumed-role/Role-onpremises/project-session-server01")

收到 codedeploy 的 access log 狀態為 200

[codedeploy-agent(...)]: [Aws::CodeDeployCommand::Client 200 ....

 

Note

 

Reference

CodeDeploy: deployment-config

Exit mobile version