⭕️

イラストで理解するAssumeRoleの疑問

2023/06/29に公開

はじめに

先日IAMロールについての記事を書いていた際に、AsumeRoleについて調べていました。
調べれば調べるほど、あれ?ここどうなってるんだろう?と疑問が湧いてきたので一つずつ解決していきます。
少し長いですが、よければ気になったところだけでも見てってください。

概要図

まずは以前の記事で書いたIAMロールを使った一時認証の図です。

用語

では、いくつか用語があるのでなんとなく理解していきましょう。

STS

Security Token Service(STS)
これは一時的な認証情報を発行してくれるサービスです。

AssumeRole

Assumeとは「引き受ける」みたいな意味です。
Assume Role、つまりIAM RoleをAssume(引き受ける)するということです。

AssumeRoleというRoleが存在している訳ではありません。(コレ重要)
AssumeRoleはユーザーがSTSに対して、ロールを借して!ってお願いする行為です。

一時的な認証情報

一時的な認証情報とは先ほどからSTSが出してきているものです。

一時認証情報はアクセスID、シークレットキーを持っています。
なんだかIAMユーザーと似てますね。
以下はAWSの公式ドキュメントの引用です。

AWS Security Token Service (AWS STS) を使用して、AWS リソースへのアクセスをコントロールできる一時的セキュリティ認証情報を持つ、信頼されたユーザーを作成および提供することができます。

ここから分かるように、STSによって発行されるのは一時的なユーザーと考えていいでしょう。
(私が)何となく理解しやすいので、今回は認証情報が書かれたカードとします。

疑問点

少し前置きが長くなりましたが、
ここからは私が感じた疑問点を解決していきます。

誰でもAssumeRoleできるの?

できません。
当然ですが、AssumeRoleを行うには条件があります。

条件は、
使いたいRole(正確にはSTS)に対してAssumeRoleができるポリシーを持っていることです。
例えば以下のようなポリシーです。

dev-userにアタッチされたポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::123456789:role/dev-role"
        }
    ]
}

このポリシーでは
Resource:アカウントID:123456789が所有しているdev-roleというロールを借りたいので
Action:stsに対してAssumeRole(dev-roleを貸して)ができる
ということを定義しています。
対象のロールを借りたいユーザーに、このポリシーをアタッチします。

AssumeRoleを行うためのポリシーはリソースに対してもアタッチすることができます。
例えば、Lambdaを作成すると自動的にアタッチされるロールの信頼ポリシーは以下のようになっています。

Lambdaにアタッチされたロールの信頼ポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "Service": "lambda.amazonaws.com"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

普段あまり意識していませんが、リソースから別のリソースを操作する場合は
裏でAssumeRoleが動いています。

どうやってAssumeRoleするの?

では、どのようにSTSへAssumeRoleのリクエスト送れば良いのでしょうか?
AssumeRoleしたいと独り言を呟いても認証情報はもらえません。

一般的な方法としては
「AWS CLI」「SDK」が使われます。

試しに、AWS CLIを使ってリクエストしてみます。
ちなみに、このリクエストができるのは、先ほどのAssumeRoleができる条件を満たしたユーザーです。

$ aws sts assume-role --role-arn arn:aws:iam::123456789:role/dev-role --role-session-name dev-session --profile dev-user
#output(値は適当です。)
{
    "Credentials": {
        "AccessKeyId": "1234567890ASDFGHJKL",
        "SecretAccessKey": "1234567890asdfghjkl",
        "SessionToken": "1234567890asdfghjkl1234567890asdfghjkl...",
        "Expiration": "2023-00-00T00:00:00+00:00"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "QWERTYUIO1234567890:dev-session",
        "Arn": "arn:aws:sts::123456789:assumed-role/dev-role/dev-session"
    }
}

ちゃんとリクエストが通りましたね。

では、AssumeRole APIの内容を分解してみます。
今回は以下の条件でリクエストを行いました。
借りたいRole名:dev-role
Roleを借りるユーザー:dev-user
セッション名:dev-session

セッション名は、一時認証情報が書かれたカードの名前です。
セッション名があることで、どのセッションで操作を行なったか?というログが残ります。

次に、AssumeRoleのレスポンスを確認すると、発行された一時認証の情報が返ってきてますね。
これを環境変数やcredentialsに登録することで、一時認証を使ってロールを借りることができます。

後ほど、実際に一時認証を使ってロールの権限内の操作をしてみます。

aws cliでリクエストを行うには何が必要?

少し本題から逸れますが、aws cliを使うには既存ユーザーのprofileを登録しておく必要があります。

今回リクエストを行ったdev-userは、事前に作成したdev-userを使用しています。
aws cliの場合、dev-userの情報を~/.aws/credentialsに設定します。

credentials
[dev-user]
aws_access_key_id = AAAAAAAAAAAAAAAAA
aws_secret_access_key = BBBBBBBBBBBBBBBBB
config
[profile dev-user]
region = ap-northeast-1
output = json

Role名とアカウントIDが分かればAssumeRoleができる?

できません。
Roleとアカウント名が分かっていても、Role側でAssumeRoleが許可されている必要があります。
では、どのようにIAM Roleで許可をするのでしょうか?

IAM Roleには2種類のポリシーが割り当てられます。

  • アイデンティティベースのポリシー
  • 信頼ポリシー

このうちの「信頼ポリシー」にAssumeRoleをしたいユーザー(dev-user)を登録します。

図にするとこんな感じです。

IAM Roleでは、
「自分を借りる対象」と「自分が操作できる対象」
を定義することができます。

この「自分を借りる対象」に登録されていないユーザー(またはリソース)は
AssumeRoleを行なうことができません。

今回のIAM Roleの信頼ポリシーはこちらです。

dev-roleの信頼ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789:user/dev-user"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

アイデンティティベースのポリシーにはS3のバケット一覧を取得できる権限を与えています。

dev-roleのアイデンティティポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "s3:ListAllMyBuckets",
            "Resource": "*"
        }
    ]
}

次は一時認証を使ってこのロールの権限内でS3バケットの一覧を取得してみます。

一時認証でリソースを操作してみる

先ほどの一時認証情報を使ってS3を操作してみます。
では、認証情報を~/.aws/credentialsに登録します。

credentials
[dev-session]
aws_access_key_id = 1234567890ASDFGHJKL
aws_secret_access_key = 1234567890asdfghjkl
aws_session_token = 1234567890asdfghjkl1234567890asdfghjkl.....
config
[profile dev-session]
region = ap-northeast-1
output = json

profileの登録ができたのでdev-sessionを使ってS3バケットの一覧を取得してみます。

$ aws s3 ls --profile dev-session
#output
2023-00-00 12:14:19 testbucket1
2023-00-00 18:37:28 testbucket2
2023-00-00 15:26:56 testbucket3

おお!ちゃんとAssumeRoleできました!

念のためdev-roleで許可されていない操作も試してみます。
dev-roleで許可されていないDynamoDBのテーブル一覧を取得してみます。

$ aws dynamodb list-tables --profile dev-session
An error occurred (AccessDeniedException) when calling the ListTables operation: User: arn:aws:sts::194641379830:assumed-role/dev-role/dev-session is not authorized to perform: dynamodb:ListTables on resource: arn:aws:dynamodb:ap-northeast-1:194641379830:table/* because no identity-based policy allows the dynamodb:ListTables action

ちゃんと拒否されました。
権限がない!と言われています。

次に
AssumeRoleを行ったdev-userには直接S3を操作するポリシーはアタッチしていません。
一応、それも確認しておきましょう。

$ aws s3 ls --profile dev-user
#output
An error occurred (AccessDenied) when calling the ListBuckets operation: Access Denied

アクセスが拒否されましたね。
これは、dev-user自身にはS3を操作する権限がないためです。

最後に
AssumeRoleのデフォルトの時間である1時間が経過して、一時認証の期限が切れたことも確認してみます。

$ aws s3 ls --profile dev-session
#output
An error occurred (ExpiredToken) when calling the ListBuckets operation: The provided token has expired.

ちゃんと期限が切れているというエラーが返ってきました。

これで以下のことがわかりました。

  • dev-userは直接S3バケットを見ることはできない
  • dev-userにはdev-roleをAssumeRoleできる権限がある
  • dev-roleにはS3を操作する権限と、dev-userからのAssumeRoleを許可する権限がある
  • AssumeRoleすることで、一時的にdev-roleの権限を借りることができる。

全体を図にまとめるとこんな感じです。

ううっ、ややこしい...

ちょっと気になったところ

最後に少し気になった部分を一つ。
STSより発行された一時認証情報とIAM Roleがどのように紐づけられているのかが気になりました。

明示的に紐付けを行なっていなかったので、恐らく内部的に紐づいているのかな?と感じました。
AssumeRoleAPIに対するレスポンスでassume-role/dev-role/dev-sessionとなっているのでここで紐づいているのだとは思いますが。

    "AssumedRoleUser": {
        "AssumedRoleId": "QWERTYUIO1234567890:dev-session",
        "Arn": "arn:aws:sts::123456789:assumed-role/dev-role/dev-session"
    }

そもそも、Roleを指定してAssumeRoleをしているので気にする部分でもないかもしれませんが...

まとめ

AssumeRoleという存在はなんとなく横目に感じていましたが、触ってみると思っていた以上に大事な存在でした。
これで1週間はAssumeRoleのことを忘れずにいられると思います。

今回はユーザーからAssumeRoleを行いましたが、普段私たちが使っている時は
リソースが別のリソースを操作する際に使われることの方が圧倒的に多いと思います。

参考資料

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp.html
https://dev.classmethod.jp/articles/jaws-ug-cli-sts-handson/

GitHubで編集を提案

Discussion