クロスアカウントなAWS CLI処理でハマった話

2015.08.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

クロスアカウントなAWSコマンド処理でハマった話

はじめに

こんにちは、川原です。

ご存知の通り(?)、弊社では数多くのお客様のAWS環境を構築・運用しています。 そのため、管理するAWSアカウントもかなりの数になっており、弊社の社員一人一人がログインするAWS環境の数(≒AWSアカウントの数)もそれなりの数になっています。 そのような場合、AWS環境毎に作業者用のIAMユーザーを作成していては、アカウントIDとパスワードの管理が煩雑になることは想像に難くありません(ある人が数十数百のAWSアカウントの環境をさわっている場面を想像して頂ければよいかと)。

そこで活用するのが、IAMユーザーのクロスアカウントスイッチ機能です。 この機能の詳細はこのブログ を見て頂ければと思いますが、簡単に述べると、「1つのIAMユーザーで複数のAWSアカウントにログインできるようにする」というものです。

今回は、AWSコマンドラインインターフェイス(AWS CLI)で、クロスアカウントスイッチ相当の操作を行おうとしてハマった事象と、その解消方法についてお話したいと思います。

どんな事にハマったの?

まず、前提ですが、下記の通りです。

前提

下記のAWSアカウントが存在。

  • AWSアカウント: hoge
  • AWSアカウント: foo

それぞれのAWSアカウント上に下記ユーザー、ロールが存在。

  • hoge上のIAMユーザー: user-kawahara
  • foo上のIAMロール: role-kawahara

そして、hoge上のuser-kawaharaは、fooのrole-kawaharaにスイッチロールできるように設定してあり、AWSマネジメントコンソールで動作確認済の状態。 イメージ的には下記のような感じになっている状態です。

mod_2015-08-12_23_15_39

やりたかったこと

これは単純で、foo上のS3バケット配下のオブジェクトを参照するってことです。ただし、AWSアカウントfoo上に、私はIAMユーザーを持っていません。保持しているのはfoo上のIAMロールrole-kawaharaからassumeされたhoge上のuser-kawaharaというIAMユーザーです(わかりづらい日本語ですが、上記前提の通りです)。

もし、foo上にIAMユーザー"user-kunio"が存在しており、そのユーザーのアクセスキ ーとシークレットキーが存在していたとしたら、こんな感じのコマンドを発行したかったです。

$cat ~/.aws/credecials
[user-kunio] #これはfoo上のuser-kunioのクレデンシャル(でも実際には無い)
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY

$aws --profile user-kunio s3 ls s3://YOUR_BUCKET_NAME

発生事象

上記のようなAWSアカウト跨がった操作をコマンドベースで行うには、という事で調べてみると、AWSの公式ドキュメントにドンピシャなチュートリアルがあり、しめしめと思ったのですが、、、 チュートリアルに記載してある手順は簡単に述べると

  1. Security Token Service (STS) で一時トークンと一時クレデンシャルを発行
  2. そのトークン、クレデンシャルを変数にセット
  3. 後は普通にAWS CLIを実行

というものでした。STSの概念自体はだいたい把握していたので、内容的にはフムフムとすぐに理解できました。

で、チュートリアル通りやってみたのですが、一時トークン発行の所で下記のようなエラーが出てうまく行きませんでした...orz

$cat ~/.aws/credecials
[user-kawahara] #これはhoge上のuser-kawaharaに対するクレデンシャル
aws_access_key_id = YOUR_ACCESS_KEY
aws_secret_access_key = YOUR_SECRET_KEY

$aws sts assume-role --role-arn arn:aws:iam::foo:role/role-kawahara --role-session-name XXXXX --profile user-kawahara

A client error (AccessDenied) occurred when calling the AssumeRole operation: User arn:aws:iam::hoge:user/user-kawahara is not authorized to perform: sts:AssumeRole on resource: arn:aws:iam::foo:role/role-kawahara

エラーメッセージは、「foo上のロール role-kawahara は hoge上のuser-kawahara のassumeption(≒引き受け)をauthorize(≒承認)していないよ」的な事を述べているんですが、そんなわけはありません。 だって、マネジメントコンソール上でスイッチロールできているので(上のキャプチャの通り)。

マネジメントコンソールでできて、CLIでできない訳はないはず、、、と散々悩んだ挙句、AWS CLIに怪しいオプションがあるのを見つけました。 そいつは--serial-number です。 AWSでシリアルナンバーと言えば、そう、MFA(多要素認証)です。

完全にこれは盲点でしたorz。。。 だって、マネジメントコンソールでスイッチロールする時は何にも訊かれないんだもん。CLI上でもスルっと行くものだと思い込んでました1

解消方法

ということで、解消方法は「MFA関連のオプション--serial-number--token-codeを適切に設定する」です。 具体的には以下のような感じでコマンドを発行すると、一時トークンと一時クレデンシャルのJSONを取得できました。

$ aws sts assume-role --role-arn arn:aws:iam::foo:role/role-kawahara --role-session-name tektito_na_namae --serial-number arn:aws:iam::hoge:mfa/user-kawahara --token-code 123456(←ここはMFAコードの6桁の数列)
{
"AssumedRoleUser": {
"AssumedRoleId": "AROAIS2TA7QMDOV77CXMU:tektito_na_namae",
"Arn": "arn:aws:sts::foo:assumed-role/role-kawahara/tektito_na_namae"
},
"Credentials": {
"SecretAccessKey": "XXXXXXXXXXXXXXXXXXX",
"SessionToken": "YYYYYYYYYYYYYYYYYYYYY",
"Expiration": "2015-08-12T15:58:18Z",
"AccessKeyId": "ZZZZZZZZZZZZZZZZZZZZZZZZ"
}
}

で、取得した値をチュートリアル通り、変数にセットしてAWS CLIを発行します。 下記のような感じですね。

$ set AWS_ACCESS_KEY_ID=ZZZZZZZZZZZZZZZZZZZZZZZZ
$ set AWS_SECRET_ACCESS_KEY=XXXXXXXXXXXXXXXXXXX
$ set AWS_SESSION_TOKEN=YYYYYYYYYYYYYYYYYYYYY
$ aws s3 ls s3://YOUR_BUCKET_NAME

まとめ

MFAコードの入力を必須としている、かつ、スイッチロールを使用している、という方は多いと思います。 その場合、最初のログイン時にMFAコードを入力してしまえば、後はスイッチロールして複数のAWSアカウントを使っていくというパターンとなり、MFAコードは朝一に1回入力しておしまいとなり、その存在を忘れがちです。 一方、AWS CLIでクロスアカウントな事をしようと思うと、多くの操作でMFAコードの入力が要求されると思いますが、コマンドのエラーメッセージの文言によってはその原因がMFAコードであるとは想像できない場合がありそうです(今回の私のように)。

ということで、AWS CLIをさわる際は時々でよいのでMFAコードの事を思い出してあげてください。

おまけ

本稿で言及したAWS公式のチュートリアルでは、一時トークンを取得し、そして、それを変数にセットしてから、実際に実行したいコマンドを発行する、という一見しても手間だなと思ってしまう方法が説明されていました。 ですが、AWS CLIのバージョンアップによりその辺りの手順が簡略化が可能となったようです。

具体的な手順は、IAMおじさん2ブログ を参照して頂ければと思います。 コマンド一発なので、非常に楽になります。


  1. えぇ、確かに、マネジメントコンソールでhogeのAWSアカウントにuser-kawaharaでログインする際は、MFAコードを入力してましたよ。で、foo上のrole-kawaharaはMFA認証必須にしていたような気がします。が、そんな事は頭のどこか片隅に行ってました。。。 
  2. 弊社内では、その道に詳しい人のことを敬愛の意味を込めて、○○○おじさん(または、○○○おねーさん;○○○にはAWSサービス名称が入る)、と呼ぶ事があります。