share facebook facebook2 twitter menu hatena pocket slack

2014.07.30 WED

IAMとSTS その2

sebastian

WRITTEN BY sebastian

AWSで権限に関わる機能の名前

意外と多いのでちょっと整理

  • User-Based Policy
  • Resource-Based Policy
  • Role
  • Cross-Account Access Using Resource-Based Policies
  • Cross-Account API Access Using IAM Roles
User-Based Policy

要するにUserに対してこのユーザーは何の権限を持ってますよってマネジメントコンソールのIAMから設定してるあれです
余りにも当たり前に使うので割愛

Resource-Based Policy

S3、SNS、SQS、OpsWorksでのみサポートされるリソース単位で誰がアクセスを出来ると設定できる機能
下記のようにUser-Basedが指定ユーザーが指定リソースにアクセスできるではなく
指定リソースにアクセスできるユーザーを設定する形で指定できる。

01

ただ、とても残念な事に上の4つ以外はサポートされていない
これが全てのサービスに存在していれば僕のしたい事は全て終わっていた。

Role

ポリシーとは別に独立した権限管理一覧を持つ役割定義を指す。
勘違いしがちだがUserやGroupとは一切関係なく
DelegationとFederationの定義の為に存在し
内部サービスもしくは外部サービスに対して自身のAWSの権限を渡す際の定義として機能する

Cross-Account Access Using Resource-Based Policies

上記のResource-Based Policyにて自分以外の他のAWSアカウントに対してS3などへのアクセスを権限を付与する事。

Cross-Account API Access Using IAM Roles

広義にはCross-Accountアクセスと纏めて紹介されたり
AssumeRoleと呼ばれたりもしている様だ
ここではDelegateと言う言葉で説明していく

Roleを用いてRoleにて定義されたリソースを同様にRoleにて定義されたAWS Userに対して委任する機能を指す。 
Role内のPrincipalにて定義されたAWS Userを信任し、アクセス権限を委任
委任されたUserがSTSにてAssumeRoleを行う事で信任を受け入れ
委任されたユーザーはRoleに定義された権限の範囲で信任元のAWSサービスへAPIアクセスできるアクセスキーとシークレットキーを得る。

02

つまり、このDelegateはAPIでアクセスを行う際にCross Account Accessと同様に他ユーザーの管理するリソースへのアクセス権限を一時的に発行してくれる訳である。
イメージとしてはLinuxのsudoに近いかもしれない。

Delegate

手順としては

  1. 委任元が委任用Roleを作成する
  2. 委任先が委任用RoleにSTSでaccess出来る様にPolicyを設定する
  3. 委任先がRoleをSTSでAssumeRoleする
  4. AssumeRoleの結果得られるAcces-KeyとSceret-Key、TokenでAPIにAccessする

委任するServiceのRoleを作成する

委任を行うにはまず、委任元のユーザーから委任するサービスと信任するユーザーを指定してRoleを作成する必要がある

ここでは委任元をPrinceOfDeploy
委任される相手をSebastianとしよう

Account ID User Name
委任元 123456789000 PrinceOfDeploy
委任先 111222333000 Sebastian
  1. PrinceOfDeployのマネジメントコンソールのIAMにてRole for Cross-Account Accessを選択しProvide access between AWS accounts you ownを選択する。
  2. Account IDの入力を求められるので信任する相手であるSebastianのAccount ID:[111222333000]を入力する。
  3. Set Permissionのダイアログに遷移するので委任したい内容のPolicyを入力する。

名前は適当にDeployRoleとでもしておこう
Roleの作成が済むとTrust Relationshipに以下のような内容が格納されているはずである。

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "",
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::1112223330:root"
    },
    "Action": "sts:AssumeRole"
  }
 ]
}

このままだとrootユーザーに対して信任してしまうので”AWS”: “arn:aws:iam::1112223330:root”を”AWS”: “arn:aws:iam::1112223330:user/Sebastian”に書き換えて以下の様にする

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "",
    "Effect": "Allow",
    "Principal": {
      "AWS": "arn:aws:iam::1112223330:user/Sebastian"
    },
    "Action": "sts:AssumeRole"
  }
 ]
}

ここで注目すべきはPrincipalで示してる内容はそのものズバリ信任先である。
こうして出来上がったRoleはTrust Relationshipの情報とPolicyの情報の二つを持つ構造になる
当然、一つのRoleに対して複数のPolicyを持ったりも出来るので必要ならPolicyを追加して信任者に対して許可する内容を追加しても良い。

Roleを受領準備

委任元でRoleの作成が済んだら委任先でRoleの受領準備必要である
何故ならこのままでは委任先であるSebastianからはPrinceOfDeployが作成したRoleにアクセスが出来ないので受取り様がないからだ
そこで委任先のSebastianで以下のようなPolicyをUserに持たせる

{ "Statement": [
   {
    "Effect": "Allow",
    "Action": "sts:AssumeRole",
    "Resource": "arn:aws:iam::123456789000:role/DeployRole"
   }
  ]
}

Roleを受け取る

先程、委任先のSebastian側でSTSからRoleにaccess出来るようにしたので実際にSTSでRoleを受領する

STSはマネジメントコンソールからは呼び出す事が出来ないのでAPIにて操作を行う必要がある。
何故かAWSはPHPのサンプルだけが除外されまくってるので敢えてPHPで書く

<?php
require 'aws/aws-autoloader.php';
use AwsStsStsClient;

$objStsClient = StsClient::factory();

$result = $objStsClient->assumeRole(array(
    'RoleArn' => 'arn:aws:iam::123456789000:role/DeployRole',
    'RoleSessionName' => 'DeployAssumeRole',
    'DurationSeconds' => 3600,
));

$credentials = $result->get('Credentials');
var_dump($credentials);
?>

実行すると以下の様な出力が出ると思う

array(4) {
  ["SessionToken"]=>  string(400) "AQoDYXdzEJn//////////wEakAJLNtwojm5H9bmX+P503Cjb6gOj6fjJWotW3UahDkYNefD9mAVKI0nAnb/G4MYn6qU3/V5t7tOFjVGM7Lsh4IqGQ/TrKzcQgxBhSg8aTxIppikWP92HWvAQwR0A7C/vnXsFvyoS8Z9qUcER5dlcYcRCltcs7F9BVMs6Eyt0IzqTxAtUw1JWoKmey48MDpcrzuFpLYRowbVSAz1UKVKvF1VcfRZ+75ukIm58uHkBEJm+inI013ZOQoQXIFeYIsmr3pIjhbK1c4ur6OwDEwMeYh5l4tXdlRAuyAzPCCXhmHw8cr7AsWmljhtqYCknuiKecuzDpWv7QLjtH+6lw2OcUcsoLRP+ZRD1++NuRRruanoigiDt+dCeBQ=="
  ["SecretAccessKey"]=>  string(40) "+upSxMJdbWaTm4bShJaBRpRbVYbx3W4rKbZRavqx"
  ["Expiration"]=>  string(20) "2014-07-27T00:00:00Z"
  ["AccessKeyId"]=>  string(20) "ASIAJZT4FN3V6SAPQRCQ"
}

これで得られたSessionToken、AccessKey、SecretKeyにてアクセスを行うとRoleにて委任された内容にアクセスが可能となる

Roleでマネジメントコンソールにアクセスする

上記の内容で概ね、Roleを用いたCross Account Accessの動きが理解で来て
取りあえずAPIで彼是出来る~って状態になったと思う

だが!!!
だが、しかし!!!

そうじゃないんだ!
俺はAPIからアクセスしたいだけじゃないんだ!!!

与えられた権限でマネジメントコンソールにアクセスしたいんだ!!

と言うか、何かの権限を誰かに渡すたびにそれを操作するプログラムをAPIで書くのか?
誰しもがそんな事出来るのか?
否!断じて否である!!!
そんな事だれでも出来たらプログラマは廃業しちまうだろ!

と言うか、俺はそもそもマネジメントコンソールでアクセスさせる趣旨でこいつを調べ始めたんだよ!

そういう訳で

取得したCredentials情報からマネジメントコンソールにログインしてアクセスする方法~~~
調べたらRuby,PYTHON,JAVAでこれを実現する方法はawsに記載があった。
例によって例の如くかAWSはPHPのサンプルだけが除外されまくってるのでPHPで書く
と言うかAMAZONにはPHP書く人居ないのか?
人が書いた物をそのまま書いてもつまらん!

$credentials = $result->get('Credentials');

$strIssuerURL = "https://mysignin.internal.mycompany.com/";
$strConsoleURL = "https://console.aws.amazon.com/sns";
$strSignInURL = "https://signin.aws.amazon.com/federation";
// CredentialsをURLエンコードしたJSONにする
$strSessionJson = sprintf(
  '{"%1$s":"%2$s","%3$s":"%4$s","%5$s":"%6$s"}',
  'sessionId'    , $credentials['AccessKeyId'],
  'sessionKey'   , $credentials['SecretAccessKey'],
  'sessionToken' , $credentials['SessionToken']);
$strEncodedJson = urlencode($strSessionJson);

// サインイントークンを取得する
$strGetSigninTokenURL = "$strSignInURL?Action=getSigninToken&SessionType=json&Session=$strEncodedJson";
$htmlSigninToken = file_get_contents($strGetSigninTokenURL);
$arySigninToken = json_decode($htmlSigninToken , true);
$strSigninToken = $arySigninToken['SigninToken'];
$strEncodedSigninToken = urlencode($strSigninToken);

// ログインURLを作成する
$strSigninTokenParameter = "&SigninToken=$strEncodedSigninToken";
$strIssuerParameter = "&Issuer=".urlencode($strIssuerURL);
$strDestinationParameter = "&Destination=".urlencode($strConsoleURL);
$strLoginURL = "$strSignInURL?Action=login$strSigninTokenParameter$strIssuerParameter$strDestinationParameter";

echo $strLoginURL;

以上だ!
これを先程のAssumeRoleを行うPHPの後に続けて書くと画面上にログインURLを表示するはずだ
別にサーバープログラムとしてPHPを走らせてるならそのまま取得したURLで画面遷移しても良いだろう

そういう訳でこれで求めていたマネジメントコンソールまで辿りつけた訳だ

元記事は、こちら

sebastian

sebastian