勉強日記

チラ裏

IAM UserにIAM Roleの権限を委譲する (AssumeRole)


  • いただいた意見
    • ローカル開発に特定クラウドのIAMの仕組み自体をあまり使いたくない
    • ベンダー依存がきつい
  • それは確かにそのとおり
  • だが、ローカルでも一応IAM Roleによる認証認可ができるのでその練習をしてみる
  • アカウント間の権限委譲の正しいやり方もこれ

やりたいこと

  • 本番環境ではEC2にデプロイして、EC2にIAM Roleをアタッチしたい
  • ローカル開発環境でも同じIAM Roleで権限付与を行いたい
  • しかしローカル開発環境はEC2ではないので、「IAM Roleをアタッチする」ことができない
  • ので以下のようにする
    1. ローカル開発用IAM Userを作成する
    2. ローカル開発環境に、1.で作成したIAM Userのクレデンシャルを配置する
    3. 1.で作成したIAM Userに、IAM Roleの権限を委譲する

AWS STS

  • Security Token Service
  • 公式
  • 一時的に認証トークンを払い出したりするやつ

AssumeRole

  • IAM RoleとSTSの認証トークンを使って、IAM User/GroupまたはAWSのサービスに権限を委譲する機能

試す

構築

github.com

AWSのリソースはterraformで構築・破棄する

IAM Role

variable "name" {}
variable "policy" {}
variable "service_identifier" {}
variable "iam_identifier" {}

resource "aws_iam_role" "default" {
  name = var.name
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

data "aws_iam_policy_document" "assume_role" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "Service"
      identifiers = [var.service_identifier]
    }
    principals {
      type = "AWS"
      identifiers = [var.iam_identifier]
    }
  }
}

resource "aws_iam_policy" "default" {
  name = var.name
  policy = var.policy
}

resource "aws_iam_role_policy_attachment" "default" {
  role = aws_iam_role.default.name
  policy_arn = aws_iam_policy.default.arn
}

output "iam_role_arn" {
  value = aws_iam_role.default.arn
}

output "iam_role_name" {
  value = aws_iam_role.default.name
}
  • 肝となるのはIAM RoleのIAM Policy部分
    • IAM Role側で「あなたには権限を委譲できますよ」と許可する
data "aws_iam_policy_document" "assume_role" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type = "Service"
      identifiers = [var.service_identifier]
    }
    principals {
      type = "AWS"
      identifiers = [var.iam_identifier]
    }
  }
}
    principals {
      type = "Service"
      identifiers = [var.service_identifier]
    }
  • 指定のAWSのサービスにAssumeRoleできるようする
    • 「EC2にIAM Roleをアタッチする」時などに使うやつ
    • AWSコンソール上でIAM Roleを作るとき、「何にアタッチする用か」選ばされますよね
    principals {
      type = "AWS"
      identifiers = [var.iam_identifier]
    }
  • 指定のIAM User/IAM GroupにAssumeRoleできるようにする

IAM User, S3 Bucket

# ローカル開発で使うユーザー
# このユーザーに権限を付与する
resource "aws_iam_user" "example" {
  name = "localuser"
  path = "/personal/"

  tags = {
    Name = "example for AssumeRole"
  }
}

# EC2からS3へアクセスするためにIAM Role
# 本番環境ではEC2にアタッチする
# ローカル環境ではIAMユーザーにAssumeする
module "role_s3_putobject_for_ec2" {
  source = "./iam_role"
  name = "role_s3_putobject_for_ec2"
  service_identifier = "ec2.amazonaws.com"
  iam_identifier = aws_iam_user.example.arn
  policy = data.aws_iam_policy_document.example.json
}

data "aws_iam_policy_document" "example" {
  statement {
    actions = [
      "s3:PutObject"
    ]

    resources = [
      "${aws_s3_bucket.example.arn}/*",
    ]
  }

  statement {
    actions = [
      "sts:*"
    ]
    resources = [
      "*",
    ]
  }
}


# 検証用プライベートバケット
resource "aws_s3_bucket" "example" {
  bucket = "my-assumerole-example"
  acl    = "private"

  tags = {
    Name = "example"
  }
}

output "example_s3_bucket_arn" {
  value = aws_s3_bucket.example.arn
}

output "eample_iam_role_arn" {
  value = module.role_s3_putobject_for_ec2.iam_role_arn
}
  • 作るもの
    • プライベートS3バケット my-assumerole-example
    • IAM User localuser
      • ローカル開発用の、開発者個人のIAM User
      • このユーザ自身はバケットにPutObjectできない
    • IAM Role role_s3_putobject_for_ec2
      • このロールだけがバケットにPutObjectできる
      • localuserへのAssumeRoleを許可する
terraform apply
...

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

eample_iam_role_arn = arn:aws:iam::646279979860:role/role_s3_putobject_for_ec2
example_s3_bucket_arn = arn:aws:s3:::my-assumerole-example
  • このIAMロールのARNとS3バケットのARNは後で使う

AssumeRole前、S3にPutObjectできないことを確認する

  • localuserで認証が通っていることを確認
aws sts get-caller-identity
{
    "UserId": "AIDAZM6KJ4NKJ77M676ZG",
    "Account": "646279979860",
    "Arn": "arn:aws:iam::646279979860:user/personal/localuser"
}
  • PutObjectを試みてみる
touch hoge
aws s3 cp hoge s3://my-assumerole-example/hoge
upload failed: ./hoge to s3://my-assumerole-example/hoge An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
  • プライベートバケット、かつ明示的に許可されていないのでAccess Denied

AssumeRoleし、S3にPutObjectできることを確認する

  • aws sts assume-roleを実行すると、一時的な認証情報が払い出される
aws sts assume-role --role-arn "arn:aws:iam::646279979860:role/role_s3_putobject_for_ec2" \
  --role-session-name AWSCLI-Session
{
    "Credentials": {
        "AccessKeyId": "ASIAZM6KJ4NKJY3HJR4W",
        "SecretAccessKey": "okAlfJWJiYsgFZHswW7vVvxiyP+dtWuuFjT9mKYm",
        "SessionToken": "FwoGZXIvYXdzEAMaDPinCoHBc3kWUfSFNCKyAf3FBuNx+VF387AMZP7AWCDsl1ADA3WvTHaNxNPV//chdBh0lVqN7yY81HExdt0GhF0Q7hAPSCunCSss0yyurqmlwP3ZEexPcW/advuvJg5ocNeCE8U32uk8LjbZQ51LzJPXTvu6wE75Qnza1R2pP2XVRORGHEQN2XICEjkjuhxhHamkC+cZP2QwR/WJz2z6pvd0qvkzYRUStWyVfmvMrzvnKDqbdVg/5zjdDnFJQAsOSoso6tDO8wUyLRyeC4aC47KlpyILKp8B57hqASZcLiRe6fdC4hTlhKfNXdrcMnpxYX5L+mxYRg==",
        "Expiration": "2020-03-19T18:14:18Z"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "AROAZM6KJ4NKAXJMITDJV:AWSCLI-Session",
        "Arn": "arn:aws:sts::646279979860:assumed-role/role_s3_putobject_for_ec2/AWSCLI-Session"
    }
}
export AWS_ACCESS_KEY_ID=ASIAZM6KJ4NKJY3HJR4W
export AWS_SECRET_ACCESS_KEY=okAlfJWJiYsgFZHswW7vVvxiyP+dtWuuFjT9mKYm
export AWS_SESSION_TOKEN=FwoGZXIvYXdzEAMaDPinCoHBc3kWUfSFNCKyAf3FBuNx+VF387AMZP7AWCDsl1ADA3WvTHaNxNPV//chdBh0lVqN7yY81HExdt0GhF0Q7hAPSCunCSss0yyurqmlwP3ZEexPcW/advuvJg5ocNeCE8U32uk8LjbZQ51LzJPXTvu6wE75Qnza1R2pP2XVRORGHEQN2XICEjkjuhxhHamkC+cZP2QwR/WJz2z6pvd0qvkzYRUStWyVfmvMrzvnKDqbdVg/5zjdDnFJQAsOSoso6tDO8wUyLRyeC4aC47KlpyILKp8B57hqASZcLiRe6fdC4hTlhKfNXdrcMnpxYX5L+mxYRg==
  • 再度、自分が誰だか確認する
aws sts get-caller-identity
{
    "UserId": "AROAZM6KJ4NKAXJMITDJV:AWSCLI-Session",
    "Account": "646279979860",
    "Arn": "arn:aws:sts::646279979860:assumed-role/role_s3_putobject_for_ec2/AWSCLI-Session"
}
  • 一時的なユーザ情報になった
  • 再度PutObjectを試してみる
aws s3 cp hoge s3://my-assumerole-example/hoge
upload: ./hoge to s3://my-assumerole-example/hoge
  • 成功した!

まとめ

  • IAM UserにIAM RoleをAssumeRoleできた
    • EC2環境とローカル開発環境の差異を小さくできる
    • 他人のAWSアカウント管理下のリソースにアクセスしたいときの正しい方法はこれ