STS(Security Token Service)を使ってアカウント間のリソースを共有する

# はじめに

AというAWSアカウントのリソースをBという第三者のアカウントで扱いたい場合があります。
例えば情報システム部門Bがユーザ部門Aのバックアップ、監視などをSDKを使って扱う場合などが考えられます。

AアカウントでB用のIAMユーザを作成して、グループに所属させ、必要な権限を付与して、アクセスキー・シークレットアクセスキーを付与して、、とすればやりたいことは実現できますが、めんどくさいですね。

管理上にも問題があって、AWSではIAMユーザのアクセスキー・シークレットアクセスキーの定期的な変更を推奨していますが、Aアカウントでアクセスキーの変更を行った場合、Bのプログラム（や設定ファイルなど）に影響があるのもいただけません。

そこで登場するのがロールとSTS(Security Token Service)です。

ロールとSTSを利用することでアカウントとポリシーが分離できるため、定期的なアクセスキーの変更はBだけでよくなりますので、管理上も容易になります。

ロールの付与はインスタンスにだけ利用すると勘違いしている人もいますが、インスタンスに付与するロールも内部ではSTSを利用しています。

ここでは他アカウントのEC2インスタンスの一覧を取得するのをSTSを使って実装してみます。

# リソースを公開する側の設定（Aアカウント側）

## ロールの設定

1. ロール名を入力
![image](https://qiita-image-store.s3.amazonaws.com/0/57686/67b33fab-d3ca-2f6a-14ac-abbf3ddbb3fb.png)

2. Provide access between AWS accounts you own を選択

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/c42247e6-48b3-214d-cd93-6049394c1650.png)

3.BのアカウントIDを入力します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/2489e945-f0f7-ec56-5aa4-ecc1e54186fb.png)

4.EC2 Full Accessを選択します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/b707eb7a-47d2-de40-da71-7bf9aaf8025e.png)

5.ロールを作成します。作成されたロールのarnはコピーしておいてください。

# リソースを扱う側の設定(Bアカウント側）

1.IAMユーザを作成します。STSはルートアカウントでは利用できないので必ず別にユーザを作成してください。
2.1で作成したユーザの画面で「AttachUserPolicy」を選択します。
3.CustomPolicyを選択します。

![image](https://qiita-image-store.s3.amazonaws.com/0/57686/fb643440-dc72-0f68-0275-da528c6ac74f.png)

4.ポリシーを登録します。
![image](https://qiita-image-store.s3.amazonaws.com/0/57686/90314457-6ceb-ed68-2da9-4e90d4657642.png)

```
{
  "Statement": [{
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::xxxxxxxxxxxxxx:role/EC2FullAccessRole"
  }]
}
```

5.ポリシーが登録されていることを確認します。

これで、BのIAMユーザでAのEC2の操作をなんでもできるような設定が完了しました。

# EC2のインスタンス一覧の取得をSTSを使って実装する。

ソースを見たほうが早いと思うのでとりあえず貼ります。

``` Ec2InstanceListUseSTS
package aws.ec2.sts;

import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.AmazonEC2Client;
import com.amazonaws.services.ec2.model.DescribeTagsRequest;
import com.amazonaws.services.ec2.model.DescribeTagsResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.TagDescription;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
import com.amazonaws.services.securitytoken.model.AssumeRoleResult;

public class Ec2InstanceListUseSTS {

	/** Aのリソースにアクセスするためのロールの*/
	private static final String ARN = "arn:aws:iam::xxxxxxxxxxxx:role/EC2FullAccessRole";

	public static void main(String[] args) {

		// BアカウントのProviderを取得する。
		AWSCredentialsProvider provider = new ProfileCredentialsProvider(
				"uzr_api");
		
		// STSサービスを利用するためのClientを取得します。
		AWSSecurityTokenServiceClient client = new AWSSecurityTokenServiceClient(
				provider.getCredentials());
		AssumeRoleRequest request = new AssumeRoleRequest().withRoleArn(ARN)
				.withDurationSeconds(3600)
				.withRoleSessionName("EC2FullAccess_uzr_session");

		AssumeRoleResult result = client.assumeRole(request);

		// Aアカウントのリソースにアクセスするための一時的な認証情報を取得します。
		BasicSessionCredentials tempCredential = new BasicSessionCredentials(
				result.getCredentials().getAccessKeyId(), 
				result.getCredentials().getSecretAccessKey(),
				result.getCredentials().getSessionToken());

		// 一時的な認証情報を使って、EC2のインスタンス一覧のタグ名を取得します。
		AmazonEC2 ec2 = new AmazonEC2Client(tempCredential);
		ec2.setRegion(Region.getRegion(Regions.AP_NORTHEAST_1));

		DescribeTagsRequest describeTagRequest = new DescribeTagsRequest()
				.withFilters(new Filter().withName("resource-type").withValues(
						"instance"));

		DescribeTagsResult tagsResult = ec2.describeTags(describeTagRequest);

		for (TagDescription description : tagsResult.getTags()) {
			System.out.println(description.getKey() + " : "
					+ description.getValue());
		}

	}

}

```

下記のSTSで認証情報を取得するときには、相手側のARNと有効期限、セッション名が必須です。
言うまでもなく、有効期限については短ければ短いほどセキュリティ的には強固になります。

# まとめ

STSを使ってリソースをセキュアに扱う方法を紹介しましたが、STSは他にもFacebookやAmazonの認証を利用することもできます。
それはまた今度。