ようへいの日々精進XP

よかろうもん

(ショロカレアップデート) Amazon Managed Policy をコンテナインスタンスに付与しておく方が色々と幸せになれたので追記します

この記事はショロカレで書いた記事の中で検証した内容を再構成してお送り致します。

tl;dr

inokara.hateblo.jp

の中で ECS のコンテナインスタンスに付ける IAM role ポリシーの JSON を以下のように terraform 内で直接記載していた。

# 
# Create IAM role Policy
#
resource "aws_iam_role_policy" "ecs_iam_role" {
    name = "ecs_iam_role"
    role = "${aws_iam_role.ecs_iam_role.id}"
    policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
         "ecs:RegisterContainerInstance",
         "ecs:DeregisterContainerInstance",
         "ecs:DiscoverPollEndpoint",
         "ecs:Submit*",
         "ecs:Poll",
         "ecs:StartTask",
         "ecs:StartTelemetrySession"
      ],
      "Effect": "Allow",
      "Resource": "*"
    },
    {
       "Effect": "Allow",
       "Action": [
           "ecr:BatchCheckLayerAvailability",
           "ecr:BatchGetImage",
           "ecr:GetDownloadUrlForLayer",
           "ecr:GetAuthorizationToken"
       ],
       "Resource": "*"
     }
  ]
}
EOF
}

記事を読んで下さった @riywo さんから以下のような助言を頂いたので、Amazon Managed Policy を付与する方法に変えて試してみることにした。

IAM Policyですが、TerraformにInlineで直書きするよりも、AWS Managed PolicyをRoleにattachしておいた方が、今回の様なサービス側での変更に自動で追従できるので便利だと思います。

@riywo さん、本当に有難うございます!


メモ

引き続き、教材は...

github.com

を使う。

構成も terraform 一発で...

f:id:inokara:20151223024101p:plain

が出来る。

まずは Amazon Managed Policy とは

マネジメントコンソールを日本語表示していると「管理ポリシー」という名前になっているので、一瞬だけ「?」となってしまったが、 Amazon Managed Policy とは...

docs.aws.amazon.com

上記のドキュメントを拝借すると以下のように書かれている。

AWS 管理ポリシーは、多くの一般的ユースケースでアクセス権限を提供できるように設計されています。たとえば、管理者用(すべてのアクセス)、パワーユーザー用(IAM を除くすべてのアクセス)、および AWS サービスへのその他のさまざまなレベルアクセス用の一般的なアクセス権限を定義する AWS 管理ポリシーが用意されています。AWS 管理ポリシーでは、ポリシーを自身で記述する場合よりも適切なアクセス権限をユーザー、グループ、およびロールにより簡単に割り当てられます。

ざっくりで恐縮だが、「AWS 側でアクセスレベルに応じていい感じで見繕ったポリシー集」という認識。そして、Amazon Managed Policy の特徴として...

AWS 管理ポリシーで定義したアクセス権限は変更できません。AWS により、AWS 管理ポリシーで定義されたアクセス権限は不定期に更新されます。

上記のように AWS 側で新しいサービスや機能が追加されるとポリシーも更新されるという点。例えば、今回の ECR が利用出来るようになった時点で、元々は ECS のみのポリシーしかアタッチされていなかった Managed Policy に対して、ECR の各種リソースにアクセス出来るポリシーが追加されたりするということである。

具体的な例だと...

  • AmazonEC2ContainerServiceforEC2Role

上記のポリシーは従来は以下のようなポリシーとなっていた。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:CreateCluster",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Poll",
        "ecs:RegisterContainerInstance",
        "ecs:StartTelemetrySession",
        "ecs:Submit*"
      ],
      "Resource": "*"
    }
  ]
}

が、ECR が利用出来るようになってからは以下のように更新されている。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:CreateCluster",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Poll",
        "ecs:RegisterContainerInstance",
        "ecs:StartTelemetrySession",
        "ecs:Submit*",
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage"
      ],
      "Resource": "*"
    }
  ]
}

この変更の履歴については各ポリシーの「ポリシーのバージョン」で確認することが出来る。(この「ポリシーのバージョン」についても @riywo さんに教えて頂いた。感謝!)

f:id:inokara:20151225084651p:plain

Version 3 が最新で上述のように ECR に関するポリシーが追加されていることになる。

ということで...terraform のテンプレートを書き換える

terraform のテンプレートを以下のように書き換えて apply してみた。

$ cat iam.tf 
#
# Create IAM Instance Profile
#
resource "aws_iam_instance_profile" "ecs_iam_role" {
    name = "ecs_iam_role"
    roles = ["${aws_iam_role.ecs_iam_role.name}"]
}

#
# Create IAM role
#
resource "aws_iam_role" "ecs_iam_role" {
    name = "ecs_iam_role"
    assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "ec2.amazonaws.com"
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

#
# Attach Managed Policy
#
resource "aws_iam_policy_attachment" "ecs-role-attach" {
    name = "ecs-role-attach"
    roles = ["${aws_iam_role.ecs_iam_role.name}"]
    policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role"
}

aws_iam_policy_attachment というリソースを使うことで、Managed Policy を IAM role に付与することが出来た。

apply

以下のように terraform apply を実行する。

$ make tf-apply

(snip)

Outputs:

  EC2 IP address   = xx.xxx.xx.xxx
  EC2 Instance ID  = i-xxxxxxx
  ECS Cluster Name = oreno-cluster

既に ECR に push 済みのイメージを利用している。

確認

$ aws ecs list-clusters
{
    "clusterArns": [
        "arn:aws:ecs:us-east-1:xxxxxxxxxxxxxxx:cluster/oreno-cluster"
    ]
}
  • task-definition
$ aws ecs describe-task-definition --task-definition sample01
{
    "taskDefinition": {
        "status": "ACTIVE", 
        "family": "sample01", 
        "volumes": [], 
        "taskDefinitionArn": "arn:aws:ecs:us-east-1:xxxxxxxxxxxxxxxx:task-definition/sample01:5", 
        "containerDefinitions": [
            {
                "environment": [], 
                "name": "oreno-jenkins", 
                "mountPoints": [], 
                "image": "xxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo", 
                "cpu": 0, 
                "portMappings": [
                    {
                        "protocol": "tcp", 
                        "containerPort": 8080, 
                        "hostPort": 8080
                    }
                ], 
                "command": [], 
                "memory": 256, 
                "essential": true, 
                "volumesFrom": []
            }
        ], 
        "revision": 5
    }
}
  • コンテナイメージを Serverspec で
$ rake spec:ecs
/usr/local/bin/ruby -I/usr/local/lib/ruby/gems/2.1.0/gems/rspec-support-3.3.0/lib:/usr/local/lib/ruby/gems/2.1.0/gems/rspec-core-3.3.2/lib /usr/local/lib/ruby/gems/2.1.0/gems/rspec-core-3.3.2/exe/rspec --pattern spec/ecs/\*_spec.rb

Docker image "xxxxxxxxxxxxxxxxxxxxx.dkr.ecr.us-east-1.amazonaws.com/oreno-docker-repo"
  should exist

Finished in 9.79 seconds (files took 0.63187 seconds to load)
1 example, 0 failures
  • 実際に Jenkins コンテナにアクセスする
$ curl -s xx.xxx.xx.xx:8080/api/json | jq .
{
  "views": [
    {
      "url": "http://xx.xxx.xx.xx:8080/",
      "name": "All"
    }
  ],
  "useSecurity": false,
  "useCrumbs": false,
  "unlabeledLoad": {},
  "slaveAgentPort": 0,
  "quietingDown": false,
  "primaryView": {
    "url": "http://xx.xxx.xx.xx:8080/",
    "name": "All"
  },
  "assignedLabels": [
    {}
  ],
  "mode": "NORMAL",
  "nodeDescription": "the master Jenkins node",
  "nodeName": "",
  "numExecutors": 2,
  "description": null,
  "jobs": [],
  "overallLoad": {}
}

OK!


以上

Managed Policy

を使うことで terraform テンプレートを簡潔に書くことが出来るようになったのと、今後の機能追加等にも自動で追随出来るようになって管理のコストも抑えられそう!

まだまだ

勉強が必要な初老丸でした!