[https://twitter.com/wand_ta/status/1239684609480130562:embed]
-
いただいた意見
- ローカル開発に特定クラウドのIAMの仕組み自体をあまり使いたくない
- ベンダー依存がきつい
- それは確かにそのとおり
- だが、ローカルでも一応IAM Roleによる認証認可ができるのでその練習をしてみる
- アカウント間の権限委譲の正しいやり方もこれ
やりたいこと
- 本番環境ではEC2にデプロイして、EC2にIAM Roleをアタッチしたい
- ローカル開発環境でも同じIAM Roleで権限付与を行いたい
- しかしローカル開発環境はEC2ではないので、「IAM Roleをアタッチする」ことができない
-
ので以下のようにする
- ローカル開発用IAM Userを作成する
- ローカル開発環境に、1.で作成したIAM Userのクレデンシャルを配置する
- 1.で作成したIAM Userに、IAM Roleの権限を委譲する
AWS STS
- Security Token Service
- 公式
- 一時的に認証トークンを払い出したりするやつ
AssumeRole
- IAM RoleとSTSの認証トークンを使って、IAM User/GroupまたはAWSのサービスに権限を委譲する機能
試す
構築
[https://github.com/wand2016/iam-assumerole-sample:embed:cite]
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を許可する
- プライベートS3バケット
terraform apply
...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
eample_iam_role_arn = arn:aws:iam::xxxxxxxxxx: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": "xxxxxxxxxx",
"Arn": "arn:aws:iam::xxxxxxxxxx: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::xxxxxxxxxx:role/role_s3_putobject_for_ec2" \
--role-session-name AWSCLI-Session
{
"Credentials": {
"AccessKeyId": "xxxxxxxxxx",
"SecretAccessKey": "xxxxxxxxxx",
"SessionToken": "FwoGZXIvYXdzEAMaDPinCoHBc3kWUfSFNCKyAf3FBuNx+VF387AMZP7AWCDsl1ADA3WvTHaNxNPV//chdBh0lVqN7yY81HExdt0GhF0Q7hAPSCunCSss0yyurqmlwP3ZEexPcW/advuvJg5ocNeCE8U32uk8LjbZQ51LzJPXTvu6wE75Qnza1R2pP2XVRORGHEQN2XICEjkjuhxhHamkC+cZP2QwR/WJz2z6pvd0qvkzYRUStWyVfmvMrzvnKDqbdVg/5zjdDnFJQAsOSoso6tDO8wUyLRyeC4aC47KlpyILKp8B57hqASZcLiRe6fdC4hTlhKfNXdrcMnpxYX5L+mxYRg==",
"Expiration": "2020-03-19T18:14:18Z"
},
"AssumedRoleUser": {
"AssumedRoleId": "AROAZM6KJ4NKAXJMITDJV:AWSCLI-Session",
"Arn": "arn:aws:sts::xxxxxxxxxx:assumed-role/role_s3_putobject_for_ec2/AWSCLI-Session"
}
}
-
この認証情報を使う
- aws configureまたは環境変数等
export AWS_ACCESS_KEY_ID=xxxxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxx
export AWS_SESSION_TOKEN=xxxxxxxxxx
- 再度、自分が誰だか確認する
aws sts get-caller-identity
{
"UserId": "AROAZM6KJ4NKAXJMITDJV:AWSCLI-Session",
"Account": xxxxxxxxxx,
"Arn": "arn:aws:sts::xxxxxxxxxx: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アカウント管理下のリソースにアクセスしたいときの正しい方法はこれ