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