stsを使ってクロスアカウントアクセスしてみる

##はじめに

AWS環境でアカウントをまたいで2パターンあります。
リソースポリシーで別アカウントに対して直接アクセスを許可する
STSを使ってAssumeRoleする

基本的にリソースポリシーを使うほうがお手軽ですが、すべてのAWSサービスがサポートしているわけではなりません。
例えばAWS IoTでは使用できません。そういった場合は、AssumeRoleできるように構成する必要があります。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_compare-resource-policies.html

##リソースポリシー

####サポートしているものの例
Amazon S3 バケット 
Amazon Simple Notification Service (Amazon SNS) トピック 
Amazon Simple Queue Service (Amazon SQS) キュー
ECR　リポジトリポリシー
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/set-repository-policy.html
API Gatewayリソースポリシー
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-resource-policies.html
CodeCommit
https://docs.aws.amazon.com/ja_jp/codecommit/latest/userguide/auth-and-access-control-iam-access-control-identity-based.html

##AssumeRoleする際の流れ
クロスアカウント→アカウントA
クロスアカウント先→アカウントB

###前準備
アカウントBで対象のリソースにアクセス権限を持ったIAMロールを作成する
アカウントBでアカウントAのIAMロールやIAMユーザに対して、AssumeRole出来る権限を付与する
アカウントAでAssumeRole出来る権限を付与する

###処理の流れ
アカウントAで認証
アカウントAでAssumeRole
アカウントAでアカウントBのリソースを操作する

##AWS CLIを使って試してみます

###アカウントBでの作業
####アカウントBでIAMロールを作成する
信頼関係でアカウントAを指定する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/78184/c5e30a89-86ae-c931-3f6e-002ee512a1b0.png)

IoT操作に必要な権限が記述されたIAMポリシーを作成したIAMロールに付与する

###アカウントAでの作業
IAMポリシー作成

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "sts:AssumeRole"
            ],
            "Effect": "Allow",
            "Resource": [ "arn:aws:iam::アカウントB:role/IAMロール名" ]
        }
    ]
}
```

IAMユーザを作成してIAMポリシーをアタッチする
アクセスキー、シークレットアクセスキーを作成する

swtichというプロファイルでアクセスキー、シークレットアクセスキーを登録する

```
$ emacs .aws/credentials
[switch]
aws_access_key_id = <アクセスキー>
aws_secret_access_key = <シークレットアクセスキー>
```

AssumeRoleする先のIAMロールのARNと元になるプロファイルを指定する

```
$ emacs .aws/config [profile target]
role_arn = arn:aws:iam::<アカウントB>:role/<IAMロール>
source_profile = switch
```

アカウントBのIoTコンソールでtopic/testをサブスクライブする
![image.png](https://qiita-image-store.s3.amazonaws.com/0/78184/72168f6f-1f51-f8d9-4929-4833b27a575c.png)

topic/testに対してPublishする

```
$  aws --profile target --region ap-northeast-1 iot-data publish --topic topic/test --qos 1 --payload "publish from cli"
```

アカウントBのIoTコンソールでメッセージが表示されていることを確認する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/78184/79b412bd-e849-f17b-f9ac-0e947686ade7.png)

##node.jsで試す

```
npm init
npm install aws-sdk --save
npm install aws-iot-device-sdk --save
```

```javascript
var AWS = require('aws-sdk');
var awsIot = require('aws-iot-device-sdk'); 

var params = {
    RoleArn: '<アカウントBのIAMロールのARN>',
    RoleSessionName: 'test'

};

AWS.config.update({
    accessKeyId: "<アカウントAのアクセスキー>",
    secretAccessKey: "<アカウントAのシークレットアクセスキー>",
    region: "ap-northeast-1"
});

var topic = 'topic/test';
var sts = new AWS.STS();


sts.assumeRole(params, function (err, data) {
	if (err)
	    console.log(err, err.stack);
	else
	    var device = awsIot.device({
		    region: 'ap-northeast-1',
		    host: 'a2f3k5gm6f35cb-ats.iot.ap-northeast-1.amazonaws.com',
		    protocol: 'wss',
		    accessKeyId: data.Credentials.AccessKeyId,
		    secretKey: data.Credentials.SecretAccessKey,
		    sessionToken: data.Credentials.SessionToken,
		    clientId: '12345'

		});

	device.publish(topic, JSON.stringify({"message": "message from other AWS account"}));
});
```

```
$ npm start

> cross@1.0.0 start /Users/Work/cross
> node test.js
```

アカウントBのIoTコンソールにメッセージが出力されることを確認する
![image.png](https://qiita-image-store.s3.amazonaws.com/0/78184/dd6ca32d-9ee7-dd72-c898-f9222b35ce78.png)

##約束
投稿内容は私個人の意見であり、所属企業・部門見解を代表するものではありません。