woshidan's blog

そんなことよりコードにダイブ。

IAMのロール、EC2インスタンスやECSのタスクに対するロールについてメモ

今日はIAMのロールについて復習しようと思います。

TL;DR

  • 特別な作業をする時だけふだん使わない権限を一時的に使いたいときは、IAMロールの出番
  • IAMロールの使い方
    • IAMロール自体を作成し、
    • 誰がそのロールを利用できるのか、を記述した信頼ポリシー
    • 「~~をするためにxxが必要なんですが」)を記述したポリシーをアクセス権限ポリシー をロールにアタッチした上で
    • 許可されたユーザーやサービス(EC2, ECS, EMRなど)がAssumeRole APIにリクエストを投げて成功すると、一時的にロールに付与したアクセス権限ポリシーを持っているようにAPIを叩ける
  • IAMロールの使い所
    • 一時的に強い権限をユーザーに付与する、外部のユーザーに組織内のリソースへアクセス権限を与える、EC2インスタンス上のアプリケーションやECSのタスクに権限を付与する etc.
  • EC2インスタンス上のアプリケーションに権限を付与する場合はさらにIAMインスタンスプロファイルを用いてロールをインスタンスにアタッチする
  • ECSのタスクに権限を付与する場合は、作成したロールのARNをタスク定義のパラメータ(タスクロール: taskRoleArn)に指定する

IAMのロールに関する用語や使い方の確認

IAMはざっくり言うと、権限を管理する単位としてIAMユーザーというアカウントを用意して、IAMユーザーやIAMユーザーが所属するIAMグループ*1AWSのリソースへのアクセス権限を表すIAMポリシーをアタッチして権限を付与する、という感じのWebサービスです。

IAMユーザーというと聞きなれないですが、新しいチームに所属したときにAWSアカウントの管理者から「アカウント作成したよ」と渡される認証情報はIAMユーザーの認証情報ですね。

さて、この一度作成したAWSアカウントをしょっちゅう作り変える、という話も聞きませんし、コード管理しているとはいえしょっちゅうポリシーを変更して違う権限を付与するようにすると、「できると思っていたことができない」となって作業効率が落ちてしまいます。

なので、特別な作業をする時だけふだん使わない権限を一時的に使える仕組みがあると便利ですね。

そういうときは、IAMロールを作成して、IAMロールに特別な作業のための権限を記述したポリシーをアタッチします。

次に、誰がそのロールを利用できるのか、を記述した信頼ポリシーをたとえば、

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Principal": { "AWS": "arn:aws:iam::AWS-account-ID:user/user-name" },
    "Resource": "arn:aws:iam::ACCOUNT-ID-WITHOUT-HYPHENS:role/Test*"
  }
}

のように定義して*2作成したロールに付与すると、必要なときにAssumeRole APIを利用して*3そのロールを引き受ける*4ことで、一時的にふだん利用しているアカウントのものとは異なる権限が一時的に利用できるようになります。

また、「誰がそのロールを利用できるのか」を記述した信頼ポリシーに対して、一時的に付与したい実際やりたい作業のためのアクセス権限(「~~をするためにxxが必要なんですが」)を記述したポリシーをアクセス権限ポリシーと呼びます。

EC2インスタンス上で動くアプリケーションのための権限付与のためにIAMロールを利用する

このIAMロールは、EC2インスタンスの上でアプリケーションを動かす際の権限の付与にも利用できます*5

どういうことかというと、たとえば、IAMロールを利用しない場合、EC2インスタンス専用のIAMユーザーを用意して、EC2インスタンス上の設定ファイルにはそのユーザーの認証情報を書き込む、といった方法が考えられるんですが、認証情報を管理者以外がsshして見るかもしれないような場所におきたくないですよね。

IAMロールを利用して権限を付与する場合、EC2インスタンスの起動設定にアプリケーションで利用するロールを指定するだけでそのロールに付与されたポリシーに沿った権限がEC2インスタンスのアプリケーションから利用できるようになります。

ただし、EC2インスタンスがロールを利用する場合は、アクセス権限ポリシーの書き方はユーザーがロールを利用する場合と同じなのですが、信頼ポリシーの書き方がユーザーの場合と少し変わっていて、ロールを引き受けるリクエストを投げるのがEC2インスタンス=EC2のサービスだということで、

{
    "Version": "2012-10-17",
    "Statement": {
        "Sid": "TrustPolicyStatementThatAllowsEC2ServiceToAssumeTheAttachedRole",
        "Effect": "Allow",
        "Principal": { "Service": "ec2.amazonaws.com" },
       "Action": "sts:AssumeRole"
    }
}   

のように、「誰がそのロールを利用できるのか」の「誰が」の部分を指定する Principal*6 の値が、

  • キーが "Service"
  • 値が "ec2.amazonaws.com"

となっています*7

EC2で何か具体的なアプリケーションの利用例、、ではないですが、具体例として

場合のTerraformの設定ファイルでも眺めてしめます。

具体例: EC2インスタンスをECSのコンテナインスタンスとして動かすための権限を付与する

refs:

// 信頼ポリシーをロールに付与
resource "aws_iam_role" "ec2_instance_role" {
  name = "ec2_instance_role"
  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
       "Action": "sts:AssumeRole",
       "Principal": {
         "Service": "ec2.amazonaws.com"
        },
        "Effect": "Allow",
        "Sid": ""
    }
    ]
}
EOF
}
// アクセス権限ポリシー
resource "aws_iam_policy" "ecs_container_instance_policy" {
  name = "ecs_container_instance_policy"
  path = "/"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "ecs:CreateCluster",
        "ecs:DeregisterContainerInstance",
        "ecs:DiscoverPollEndpoint",
        "ecs:Poll",
        "ecs:RegisterContainerInstance",
        "ecs:StartTelemetrySession",
        "ecs:UpdateContainerInstancesState",
        "ecs:Submit*",
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:BatchGetImage",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "*"
    }
  ]
}
EOF
}
// 信頼ポリシーが付与されているロールにさらにアクセス権限ポリシーを付与
resource "aws_iam_role_policy_attachment" "ecs_container_instance_policy_attachment" {
  role       = "${aws_iam_role.ec2_instance_role.name}"
  policy_arn = "${aws_iam_policy.ecs_container_instance_policy.arn}"
}
// EC2インスタンスにはインスタンスプロファイルを利用してロールをアタッチ
resource "aws_iam_instance_profile" "ecs_container_instance_profile" {
  name = "ecs_container_instance_profile"
  role = "${aws_iam_role.ec2_instance_role.name}"
}
resource "aws_instance" "ecs_container_instance" {
  ...
  iam_instance_profile = "${aws_iam_instance_profile.ecs_container_instance_profile.name}"
}

具体例: ECS上で動くタスクにタスクロールを付与する

refs:

// タスクに付与する信頼ポリシーのプリンシパルは ecs-tasks.amazonaws.com
resource "aws_iam_role" "task_role" {
  name = "task_role"
  assume_role_policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": [
    {
       "Action": "sts:AssumeRole",
       "Principal": {
         "Service": "ecs-tasks.amazonaws.com"
        },
        "Effect": "Allow",
        "Sid": ""
    }
    ]
}
EOF
}
// たとえばタスクにS3のListXxx APIへのリクエストを許可するアクセス権限ポリシーを書いてみる
resource "aws_iam_policy" "task_role_policy" {
  name = "task_role_policy"
  path = "/"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:List*",
      ],
      "Resource": "*"
    }
  ]
}
EOF
}
// 信頼ポリシーが付与されているロールにさらにアクセス権限ポリシーを付与
resource "aws_iam_role_policy_attachment" "task_role_policy_attachment" {
  role       = "${aws_iam_role.task_role.name}"
  policy_arn = "${aws_iam_policy.task_role_policy.arn}"
}
// タスク定義を書く時 TaskRole として先ほど作成したロールを指定する
resource "aws_ecs_task_definition" "ecs_task" {
  family = "ecs_task"
  task_role_arn = "${aws_iam_role.task_role.arn}"
  container_definitions = <<DEFINITION
[
  {
    "essential": true,
    "image": "nginx:latest",
    "memoryReservation": 512,
    "name": "nginx"
  }
]
DEFINITION
}

思ったよりまとまらなかった...。現場からは以上です。

*1:IAMユーザーやIAMグループ, IAMロールなどの違いについてはこちら https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id.html

*2:詳細 https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html

*3:AssumeRole APIを利用する場合の詳細は https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_switch-role-api.html 他。CLIの場合はsource_profileにロールを引き受ける権限があるプロファイル、role_arnに引きうけたいロールのARNを指定したプロファイルを作成する https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_switch-role-cli.html

*4:ロールをアタッチされて権限を切り替えることと同じくらいの意味で「ロールを引き受ける」という言葉を使うみたいです https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_terms-and-concepts.html など。なお、ロールを引き受けている間は、元のアクセス権限は利用できません

*5:外部アカウントのユーザーへのアクセス許可など、もっと他のユースケースについては https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_common-scenarios.html など

*6:IAMユーザー、IAMグループ、IAMロールといったIAMポリシーがアタッチされる対象をIAMの用語で「プリンシパル」といいます

*7:https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_use_passrole.html