LoginSignup
2
0

More than 3 years have passed since last update.

Asume Roleを使って何も権限を持たないIAMユーザに一時的なCredentialを払い出す

Last updated at Posted at 2019-05-25

Asume Roleを使って何も権限を持たないIAMユーザに一時的なCredentialを払い出す方法について記載しています。

1. IAMユーザ Aliceの作成

何も権限を持たないAliceを作成する。

aws iam create-user --user-name Alice

2. AliceのCredential確認

aws iam create-access-key --user-name Alice

{
    "AccessKey": {
        "UserName": "Alice",
        "AccessKeyId": "XXXXXXXXXXX",
        "Status": "Active",
        "SecretAccessKey": "XXXXXXXXXXX",
        "CreateDate": "2019-05-25T07:20:17Z"
    }
}

AccessKeyIdSecretAccessKey~/.aws/credentialsに設定する。

~/.aws/credentials
[default]
aws_access_key_id = XXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXX

3. Aliceに一時的に付与したいロールを作成する

example-roleという名前でロールを定義し、以下アタッチする。

  • 信頼関係
  • ポリシー

ここで定義するexample-roleがIAMユーザAliceに一時的に付与したいロールになる

信頼関係を定義したexample-role-trust-policy.jsonを作成する。

example-role-trust-policy.json
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Principal": { "AWS": "arn:aws:iam::123456789010:user/Alice" },
        "Action": "sts:AssumeRole"
    }
}

example-roleを作成して、信頼関係とポリシー(今回はAmazonS3ReadOnlyAccess)をアタッチする。

# ロールの作成
aws iam create-role --role-name example-role --assume-role-policy-document file://./example-role-trust-policy.json
# 作成したロールにポリシーをアタッチ
aws iam attach-role-policy --role-name example-role --policy-arn "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
# 作成されたロールにアタッチされたポリシーを確認
aws iam list-attached-role-policies --role-name example-role

{
    "AttachedPolicies": [
        {
            "PolicyName": "AmazonS3ReadOnlyAccess",
            "PolicyArn": "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess"
        }
    ]
}

3. Aliceが一時的に利用できるCredentialsを払い出す

以下のような定義ファイルをjson形式で作成して、

temp-role.json
{
    "RoleArn": "arn:aws:iam::123456789010:role/example-role",
    "RoleSessionName": "AWSCLI-Session",
    "DurationSeconds": 3600
}

コマンドを実行します。

aws sts assume-role --cli-input-json file://./temp-role.json

{
    "Credentials": {
        "AccessKeyId": "ASIA3BHYW2I5DZ5TWSNA",
        "SecretAccessKey": "L7BrCaaqMw6OehjKYfal+VKu3AyOiVBGBA7KaVNP",
        "SessionToken": "FQoGZXIvYXdzEPH//////////wEaDEtezAAgPx3oBVJ3USLyAU+f9XPlKMhq/vAxHUD70Mr9+NybYsujRibsl8V4kU3RcWHOZ4W65ELtKvS80dGlBp95oNgAGu6MUtvIT6gSBLBkymyiEuxYeaxzeXj1JV8NffOl8n0oOC1QrIXaJTdDjb//A6vpXiwIJQV7UonBnbADY4fgA8aMw4TfRQyOUIbt1dmdadaBnBYLoV52DBKTtfKR821zasyLMv4773T2OtUR+ZPh7B12A2qvggENtrYQL1JZXOOb65NdIoKNwZD4zA5OtXsC204xsB3/TP3JIeaw9gAlp1hFx3vqzT/N3mbGABA2xu5WMcRjMFHMp8dN8bHJKMHbo+cF",
        "Expiration": "2019-05-25T08:24:49Z"
    },
    "AssumedRoleUser": {
        "AssumedRoleId": "AROA3BHYW2I5O46TBXOWN:AWSCLI-Session",
        "Arn": "arn:aws:sts:: 123456789010:assumed-role/example-role/AWSCLI-Session"
    }
}

Credentialsが利用できるか確認する

上記で払い出されたアクセスキー、シークレットキー、セッショントークンをここでは環境変数にセットします。

export AWS_ACCESS_KEY_ID="ASIA3BHYW2I5DZ5TWSNA"
export AWS_SECRET_ACCESS_KEY="L7BrCaaqMw6OehjKYfal+VKu3AyOiVBGBA7KaVNP"
export AWS_SESSION_TOKEN="FQoGZXIvYXdzEPH//////////wEaDEtezAAgPx3oBVJ3USLyAU+f9XPlKMhq/vAxHUD70Mr9+NybYsujRibsl8V4kU3RcWHOZ4W65ELtKvS80dGlBp95oNgAGu6MUtvIT6gSBLBkymyiEuxYeaxzeXj1JV8NffOl8n0oOC1QrIXaJTdDjb//A6vpXiwIJQV7UonBnbADY4fgA8aMw4TfRQyOUIbt1dmdadaBnBYLoV52DBKTtfKR821zasyLMv4773T2OtUR+ZPh7B12A2qvggENtrYQL1JZXOOb65NdIoKNwZD4zA5OtXsC204xsB3/TP3JIeaw9gAlp1hFx3vqzT/N3mbGABA2xu5WMcRjMFHMp8dN8bHJKMHbo+cF"

以下のコマンドでS3に対してReadOnlyなアクセスができていればOKです。

# これはOK
aws s3 ls
aws s3 cp s3://任意のバケット名 .
# これはNG
aws s3 cp testfile s3://任意のバケット名

おまけ - AssumeRoleを使ってマネジメントコンソールのURLを発行する

AssumeRoleで一時的な権限を持つユーザに対してマネジメントコンソールにログインするためのURLを発行するプログラムをGoで書いてみました。

main.go
package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/url"
    "strconv"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/sts"
)

func main() {
    flag.Parse()
    arn := flag.Arg(0)
    sessionName := flag.Arg(1)
    durationSeconds, _ := strconv.Atoi(flag.Arg(2))

    fmt.Println(getManagementConsoleURL(
        createSTSClient(), arn, sessionName, int64(durationSeconds)))
}

// マネジメントコンソールにログインするための一時的なURLを取得する
func getManagementConsoleURL(stsClient *sts.STS, arn string, sessionName string, durationSeconds int64) string {
    issUserURL := "https://www.google.com"
    consoleURL := "https://ap-northeast-1.console.aws.amazon.com/console/home?region=ap-northeast-1"
    signIUnURL := "https://signin.aws.amazon.com/federation"

    signInToken, err := getSignInToken(stsClient, arn, sessionName, durationSeconds)
    if err != nil {
        log.Fatalln(err)
    }
    return signIUnURL + "?Action=login" + "&SigninToken=" + url.QueryEscape(signInToken.Value) + "&Issuser=" + url.QueryEscape(issUserURL) + "&Destination=" + url.QueryEscape(consoleURL)

}

// マネジメントコンソールにサインインするためのトークンを取得する
func getSignInToken(stsClient *sts.STS, arn string, sessionName string, durationSeconds int64) (*TemporarySigninToken, error) {
    input := sts.AssumeRoleInput{
        DurationSeconds: aws.Int64(3600),
        RoleArn:         aws.String(arn),
        RoleSessionName: aws.String(sessionName),
    }

    output, err := stsClient.AssumeRole(&input)
    if err != nil {
        log.Fatalln(err)
    }

    sessionModel := SessionModel{
        *output.Credentials.AccessKeyId,
        *output.Credentials.SecretAccessKey,
        *output.Credentials.SessionToken,
    }

    jsonByte, _ := json.Marshal(sessionModel)
    siginInTokenUrl := fmt.Sprintf("https://signin.aws.amazon.com/federation?Action=getSigninToken&SessionType=json&Session=%s", url.QueryEscape(string(jsonByte)))
    res, err := http.Get(siginInTokenUrl)

    if err != nil {
        return nil, err
    }

    body, err := ioutil.ReadAll(res.Body)

    if err != nil {
        return nil, err
    }

    var temporarySigninToken TemporarySigninToken
    err = json.Unmarshal(body, &temporarySigninToken)

    if err != nil {
        return nil, err
    }

    return &temporarySigninToken, nil
}

func createSTSClient() *sts.STS {
    return sts.New(createSession())
}

func createSession() *session.Session {
    session, err := session.NewSession(&aws.Config{Region: aws.String("ap-northeast-1")})

    if err != nil {
        log.Fatal("Error creating session", err)
    }
    return session
}

type SessionModel struct {
    SessionId    string `json:"sessionId"`
    SessionKey   string `json:"sessionKey"`
    SessionToken string `json:"sessionToken"`
}

type TemporarySigninToken struct {
    Value string `json:"SigninToken"`
}

実行すると、URLが払い出されます。
第一引数はRoleのARN, 第二引数はセッションの名前、第三引数は有効期限(秒)になっています。

$ go run main.go arn:aws:iam::123456789010:role/example-role MgtConsoleSession 3600
https://signin.aws.amazon.com/federation?Action=login&SigninToken=n_H5deaNtwwnre19CLEg6vJ29tLRgJIf7dgxeRKy_03fKgZ2BZHjKn2Rgv9p6dQCcgTTtP58Ue0jA44DGXkNj4w91rwPfCiORzeqJkAARK_t5RPo_1aEnwSn2AHKtZIe63EUTSy1u8ekEDMlHwtZBqTi70fkZGw1z2LN3KEu2U_mobOc7NS_Ny0AKAzGV-JgAGRi4CH0ldE0CD_Wn05TlFTCAiTvVAtxI4wJHiYiUhdzvwGJZEfBt4GK2eXmCmXQDJj6TTyzBijM_jhZnFBCBOEh3srIalboDhckmPkYCrulcZXFieNZx0F4NTeT61vZ5X6hglsqZ8wqXf2t0YIBMqBVt-LULSd9whfj69d2uH6vBBw41a60S4TJD3BHNBROPvwRuIxlFEX9KcPEYUA5Y251kOak5irio8hEXtEJ0ZgCQ7SWybZ2yMzoUelAFpuzIsN2a07xDdDL5VhOIPAImTQFikU8l34GL6hnVGxjrJb0a65adu7OsA4aHj5uM_B2xkh14gvB_WV6hGr9ju7n42MudvlNJcSqAmpWDZX73a4IP-8UkXXTlkxbpUv92j1PRn4gHOUW0GCa3hQXS4q0t99uD98n9jY72QZO-Yq6QI02P2vx2s1SZ5fHHjstUIZUurrhZ8zbvsqcLELPddUj9YHzaTrGv6w-mNocQwcBpckkq7Hrvu9EEiC2AAVzc75oJ90wZ2BPoPcer0cbbO6vHduWuH8I61uy3qnbyzTfwnPlyB9Ij5EVpgP20HtZ_4ZYzinShmJKkqvis2w8MIuLTE8X5VYOWFZwdL-VxUUsDQ8rUNYmpYHXpI87rVm7zOiCMYJA5pn8UYU8fctnJq19mUNxdI1qKrL1-AqKDtAxY241gyPL-72J0ufvvB04qdFD61f8mRoOpx3uSqa7plzE0gsF&Issuser=https%3A%2F%2Fwww.google.com&Destination=https%3A%2F%2Fap-northeast-1.console.aws.amazon.com%2Fconsole%2Fhome%3Fregion%3Dap-northeast-1
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0