CDP Advent Calendar 2012の18日目を担当させていただく横倉です。
”別のAWSアカウントとの共有はIAMで賢く行なう” を詳細にした内容になります。
AWSを安全に共有するパターンです。 元ネタ
Delegating API Access to AWS Services Using IAM Roles
解決したい課題
AWSアカウントは、自分のAWSリソースであれば、問題なく自由にアクセスして操作することができます。
しかし、別のAWSアカウントのリソースにアクセスしたいとなったら、IAMユーザーを作成してもらい、IAMユーザーのログイン情報、またはアクセスキー、シークレットアクセスキーなどを送ってもらう必要がありました。
この場合はIAMユーザーのログイン情報、またはアクセスキー、シークレットキーをアカウント所有者の間で直接やり取りする必要があります。
社内などの内部でのやり取りであれば管理は容易かもしれません。
しかし、外部と連携する場合、アカウント情報の流出というリスクがある為、厳重な管理のもとIAMユーザーの定期的な再発行など、管理コストが高くなってしまうのが必然です。
解決方法
IAMのRole機能を利用することで、外部AWSアカウントのIAMユーザーに対してアクセス許可することができます。
その為、AWSのリソースを共有するのにIAMユーザーをやり取りすることが不要になります。
イメージとしては、プライベートAMIを特定のAWSアカウントに共有する作業に似ています。
AWSリソースへのアクセスポリシーを特定のAWSアカウントに共有する作業になります。
例として、別アカウントのSQSにアクセスするまでを2ステップでご紹介します。
- 1 信用するアカウント(piyo@example.com)
AWSのSQSへのアクセスを許可するIAM Roleを作成
- 2 信用されたアカウント(hoge@example.com)
hoge@example.comがメインアカウントのIAMユーザーにポリシーを設定
1 信用するアカウント(piyo@example.com)
AWSのSQSへのアクセスを許可するIAM Roleを作成
piyo@example.comのアカウントでManagement Console のIAMコンソールからRolesリンクを開き、”Create New Role”をクリック、作成するRoleの名前を入力します。
”Roles for Cross-Account Access”にチェックを入れる。
共有したいAWSアカウントのIDを入力します。
共有するポリシーを選択します。ここではSQSにアクセスできるように”Amazon SQS Full Access”を選択します。
ポリシー内容の確認後、作成するRoleの確認画面で問題なければCreate Roleをクリックします。
作成したRoleから、ARN(Amazon Resource Name)を確認します。
※ 後ほど、信用されたアカウントでポリシー作成する際に指定するものになります

2 信用されたアカウント(hoge@example.com)
hoge@example.comがメインアカウントのIAMユーザーにポリシーを設定
hoge@example.comのアカウントでManagement Console のIAMコンソールより、UsersリンクよりIAMユーザーを選択します。
※ 事前にIAMユーザーの作成が必要になりますので、そちらは別途ご確認ください。
IAMユーザーを選択した状態で、Permissionsより”Attach User Policy”をクリック
Custom Policy を選択します。
Policy Nameを入力し、ActionとResourceを入力します。
Action にはsts:AssumeRoleと記入し、Resourceには先程作成したRoleのARN(Amazon Resource Name)を入力します。
IAMユーザーはRoleにアクセスするのに、AWS STS(Security Token Service)というサービスを利用します。
※ AWS Security Token Service
- ・IAMユーザーが一時的にAWSアカウントに対して限られた権限を要求できるサービス
- ・AssumeRoleはIAMユーザーしか使えず、AWSアカウントでは利用不可
対象のIAMユーザーにポリシーがアタッチされていることを確認してください。

SQSにアクセスする方法
AWS Java SDKを使ったサンプルコードを記載します。
import com.amazonaws.*;
import com.amazonaws.services.sqs.*;
import com.amazonaws.services.securitytoken.*;
import com.amazonaws.services.securitytoken.model.*;
import com.amazonaws.auth.*;
public class AssumeRoleDemo {
private static final String ROLE_ARN =
"arn:aws:iam::111122223333:role/SQS-Access-Role-for-hoge";
private static AWSCredentials longTermCredentials_;
private static void init() throws Exception {
// acquire long term credentials from the properties file
longTermCredentials_ = new PropertiesCredentials(AssumeRoleDemo.class.getResourceAsStream("AwsCredentials.properties"));
}
public static void main(final String[] args) throws Exception {
init();
// AWS Security Token Service (STS) AssumeRole APIを利用して、piyo@example.comのSQSにアクセスするため認証する
AWSSecurityTokenServiceClient stsClient = new
AWSSecurityTokenServiceClient(longTermCredentials_);
AssumeRoleRequest assumeRequest = new AssumeRoleRequest()
.withRoleArn(ROLE_ARN)
.withDurationSeconds(3600)
.withRoleSessionName("demo");
AssumeRoleResult assumeResult =
stsClient.assumeRole(assumeRequest);
// AssumeRoleは一時的なアクセス情報をIAMのRoleに割り当てます。
BasicSessionCredentials temporaryCredentials =
new BasicSessionCredentials(
assumeResult.getCredentials().getAccessKeyId(),
assumeResult.getCredentials().getSecretAccessKey(),
assumeResult.getCredentials().getSessionToken());
AmazonSQS sqs = new AmazonSQSClient(temporaryCredentials);
//東京リージョンを選択
sqs.setEndpoint("sqs.ap-northeast-1.amazonaws.com");
System.out.println("===========================================");
System.out.println("Getting Started with Amazon SQS");
System.out.println("===========================================n");
try {
// List queues
System.out.println("Listing all queues in your account.n");
for (String queueUrl : sqs.listQueues().getQueueUrls()) {
System.out.println(" QueueUrl: " + queueUrl);
}
System.out.println();
} catch (AmazonServiceException ase) {
System.out.println("Caught an AmazonServiceException, which means your request made it " +
"to Amazon SQS, but was rejected with an error response for some reason.");
System.out.println("Error Message: " + ase.getMessage());
System.out.println("HTTP Status Code: " + ase.getStatusCode());
System.out.println("AWS Error Code: " + ase.getErrorCode());
System.out.println("Error Type: " + ase.getErrorType());
System.out.println("Request ID: " + ase.getRequestId());
} catch (AmazonClientException ace) {
System.out.println("Caught an AmazonClientException, which means the client encountered " +
"a serious internal problem while trying to communicate with SQS, such as not " +
"being able to access the network.");
System.out.println("Error Message: " + ace.getMessage());
}
}
}
まとめ
運用を考えたセキュリティ設計もクラウドならではであり、様々なパターンができると思います。
そんな中で、今回の様な安全なリソース共有方法は今後のAWSの更なる可能性を感じますね。
参考
Delegating API Access to AWS Services Using IAM Roles
AWS Identity and Access Management
