📚

AWS SDK Go(v1)でクロスアカウントアクセス

2023/03/14に公開

概要

複数のAWSアカウントを用途に応じ、分けて運用することはよくあると思います。
この際、LambdaやECSなどAWS SDKやAWS CLIを使ったのプログラムから別アカウントのリソースへクロスアカウントアクセスすることがあると思いますが、その場合にはSTSを利用して一時的なセキュリティ認証情報を取得し、アクセスを行います。
今回は、その方法をまとめています。

環境

golang : 1.20.1
aws-sdk-go : v1.44.219

IAM Role設定

今回は、CloudWatch Logsのロググループ一覧を取得できるようにするケースを例にしています。

権限の委任元(=アクセスされる側)のアカウントでの作業(1/2)

許可するポリシーの作成

インラインポリシーでも良いですが、管理上ポリシーを作成します。
以下では、権限の委任元のアカウントのロググループ全体をDescribeできる権限を与えていますが、必要に応じて特定のロググループへ制限するようにしてください。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "logs:DescribeLogGroups",
            "Resource": "arn:aws:logs:*:<委任元のAccountID>:log-group:*"
        }
    ]
}

委任するロールの作成

上記で作成したポリシーをアタッチしつつ、委任先のアカウントを信頼されたエンティティとして指定し、IAM Roleを作成します。
Management Consoleから作成すると、信頼ポリシーは以下のようになっているはずです。しかし、このままだと、委任先のどのユーザー/ロールでもこのポリシーを引き受けることができてしまうので、後ほど編集します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<委任先のAccountID>:root"
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}

権限の委任先(=アクセスする側)のアカウントでの作業

ポリシーの作成

先ほど委任元で作成したロールを引き受けるポリシーを作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::<委任元のAccountID>:role/<委任元で作成したロール名>"
        }
    ]
}

権限を引き受けるロールの作成

作成したポリシーをアタッチしつつ、権限を利用するサービス/ユーザーに応じてロールを作成します。
作成したロールのArnを次で使うため、メモしてください。

権限の委任元(=アクセスされる側)のアカウントでの作業(2/2)

委任先でAssume Roleできるロールやユーザーを制限するため、信頼ポリシーを更新します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::<委任先のAccountID>:user/<ユーザー名>",
                    "arn:aws:iam::<委任先のAccountID>:role/<ロール名>"
                ]
            },
            "Action": "sts:AssumeRole",
            "Condition": {}
        }
    ]
}

サンプルコード

package main

import (
	"fmt"
	"os"

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

func main() {

	var (
		region        string = "ap-northeast-1"
		assumeRoleArn string = "arn:aws:iam::<委任先のAccountID>:role/<ロール名>"
	)

	sess := session.Must(session.NewSessionWithOptions(session.Options{
		SharedConfigState: session.SharedConfigEnable,
	}))
	assumeRoler := sts.New(sess)
	creds := stscreds.NewCredentialsWithClient(assumeRoler, assumeRoleArn)

	svc := cloudwatchlogs.New(sess, aws.NewConfig().WithRegion(region).WithCredentials(creds))

	logGroupsList, err := svc.DescribeLogGroups(&cloudwatchlogs.DescribeLogGroupsInput{})

	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}

	fmt.Println(logGroupsList)
}

肝となるのはここの箇所で、STSで認証情報を取得している部分となります。

assumeRoler := sts.New(sess)
creds := stscreds.NewCredentialsWithClient(assumeRoler, assumeRoleArn)

参考リンク

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_credentials_temp_request.html
https://docs.aws.amazon.com/sdk-for-go/api/aws/credentials/stscreds/

Discussion