通常AWSコンソールへのアクセスはIAMアカウントとパスワードが必要だが、Temporary Security Credential(期限付き一時認証)でAWSコンソールアクセスの為のURLを生成できるらしい。元ネタはこれ

もちろんSDKを使うべきだけど、無理矢理AWS CLIとbashだけでやってみた。bash環境で、AWS CLIとjq等は用意されている前提。実行結果を確認しながら進むために敢えてファイルを生成しながらの手順としているので、後でファイルは削除してください(一時認証がExpireするまでは使えてしまうので)。

0. Temporary Security Credential(期限付き一時認証)の基本

取得できるTemporary Security Credentialの種類としては大きく3種類。詳しくはこちらを。

一時認証種別 説明 MFA利用 CrossAccount 有効期間  権限
AssumeRole  IAMロールにマップされた認証情報を返す  可 最大1h 制限可
GetSessionToken 呼び出し元が持っている一時認証を返す 不可 最大36h 制限不可
GetFederationToken Federatedユーザとその一時認証情報を返す 不可 不可 最大36h 制限可

取得した一時認証には、下記が含まれる。

キー 説明
AccessKeyId アクセスキー
SecretAccessKey シークレットアクセスキー
SessionToken セッショントークン
Expiration 有効期限

通常のCredentialは、AccessKeyIdおよびSecretAccessKeyのみで構成されるが、SessionTokenとExpirationがあるのが違い。

1. STSにTemporary Security Credentialを要求(GetFederationToken)

AssumeRoleでもAWSマネージメントコンソールにはログインできる(そもそもSwitch Roleできるようになったし)が、今回はFederatedユーザを使ってやってみる。権限はS3フルアクセスのみに制限する為、事前にポリシーファイルを作成する(もちろんGetFederationTokenするアカウントは、Federatedユーザ以上の権限を有していることが前提となる)。GetFederationTokenでポリシー指定をしないと、Federatedユーザはリソースベースで付与されているもの以外に何もアクセスできない。

$ POLICY_FILE=s3_policy.json
$ cat << EOF > ${POLICY_FILE}
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "s3:*",
      "Resource": "*"
    }
  ]
}
EOF

このファイルを使って、GetFederationTokenする。

(コマンド)
$ FED_USER=feduser
$ SESSION_TOKEN_FILE=session_token.json
$ aws sts get-federation-token --name ${FED_USER} --policy file://./${POLICY_FILE} \
    | tee ${SESSION_TOKEN_FILE}

(結果)
{
  "FederatedUser": {
    "FederatedUserId": "111122223333:feduser",
    "Arn": "arn:aws:sts::111122223333:federated-user/feduser"
  },
  "Credentials": {
    "SecretAccessKey": "yyyyyyyy",
    "SessionToken": "zzzzzzzzzzzz",
    "Expiration": "2015-05-19T21:09:57Z",
    "AccessKeyId": "xxxx"
  },
  "PackedPolicySize": 5
}
※実際には、キーやトークンはもっと長い。

2. URLエンコードもbashでできそう

URLエンコードも下記のfunction定義で乗り切ることができた。こちらをそのまま拝借したのだけど、今のところこのまま使ってバグってはいない。

urlencode() {
  local length="${#1}"
  for (( i = 0; i < length; i++ )); do
    local c="${1:i:1}"
    case $c in
      [a-zA-Z0-9.~_-]) printf "$c" ;;
      *) printf '%%%02X' "'$c"
    esac
  done
}

3. getSigninTokenするURLの生成

取得したSessionTokenからgetSigninTokenする為のURLを生成する為に、少々整形が必要。

(コマンド)
$ SESSION_TOKEN_ENV=session_token.env
$ cat ${SESSION_TOKEN_FILE} \
    | awk '
        $1 == "\"AccessKeyId\":" { gsub(/"/,""); gsub(/,/,""); print "SESSION_ID=\""$2"\""}
        $1 == "\"SecretAccessKey\":" { gsub(/"/,""); gsub(/,/,""); print "SESSION_KEY=\""$2"\"" }
        $1 == "\"SessionToken\":" { gsub(/"/,""); gsub(/,/,""); print "SESSION_TOKEN=\""$2"\"" }
    ' \
    | tee ${SESSION_TOKEN_ENV}

(結果)
SESSION_KEY="yyyyyyyy"
SESSION_TOKEN="zzzzzzzzzzzz"
SESSION_ID="xxxx"
※実際には、キーやトークンはもっと長い。

取得した変数を使ってjsonにする。

(コマンド)
$ source ${SESSION_TOKEN_ENV}
$ JSON_FORMED_SESSION=$(echo "{\"sessionId\":\"${SESSION_ID}\",\"sessionKey\":\"${SESSION_KEY}\",\"sessionToken\":\"${SESSION_TOKEN}\"}") \
 && echo ${JSON_FORMED_SESSION}

(結果)
{"sessionId":"xxxx","sessionKey":"yyyyyyyy","sessionToken":"zzzzzzzzzzzz"}
※実際には、キーやトークンはもっと長い。

urlencodeを駆使しながら、getSigninToken用のURLを生成。ここでURLエンコードせずに、curlの”–data-urlencode”でやるという手もあったのだけど、最後のURL生成と手順を揃える為にここでやることにした。

(コマンド)
$ SIGNIN_URL="https://signin.aws.amazon.com/federation"
$ GET_SIGNIN_TOKEN_URL="${SIGNIN_URL}?Action=getSigninToken&SessionType=json&Session=$(urlencode ${JSON_FORMED_SESSION})"
$ echo ${GET_SIGNIN_TOKEN_URL}

(結果)
https://signin.aws.amazon.com/federation?Action=getSigninToken&SessionType=json&Session=%7B%22sessionId%22%3A%2...
※実際には、トークンはもっと長い。

4. SigninTokenを取得

getSigninTokenした結果を整形して、SigninTokenを取得する。

(コマンド)
$ SIGNIN_TOKEN_FILE=signin_token.json
$ curl -s "${GET_SIGNIN_TOKEN_URL}" \
    | tee ${SIGNIN_TOKEN_FILE}

(結果)
{ "SigninToken": "xxxxyyyyzzzz" }
※実際には、トークンはもっと長い。

5. Federatedユーザ用のログインURL生成

取得したSigninTokenを使ってログイン用URLを生成する。ここでもurlencodeを駆使する必要がある。”Issuser”の使い方がよくわらないが、何を指定しても問題は無さそう。

(コマンド)
$ ISSUER_URL="https://mysignin.internal.mycompany.com/"
$ CONSOLE_URL="https://console.aws.amazon.com/"
$ SIGNIN_TOKEN=$(cat ${SIGNIN_TOKEN_FILE} \
    | jq . \
    | awk '
        $1 == "\"SigninToken\":" { gsub(/"/,""); gsub(/,/,""); print $2 }
    ')
$ LOGIN_URL="${SIGNIN_URL}?Action=login&Issuer=$(urlencode ${ISSUER_URL})&Destination=$(urlencode ${CONSOLE_URL})&SigninToken=$(urlencode ${SIGNIN_TOKEN})"
$ echo "${LOGIN_URL}"

(結果)
https://signin.aws.amazon.com/federation?Action=login&Issuer=https%3A%2F%2Fmysignin.internal.mycompany.com%2F&Destination=https%3A%2F%2Fconsole.aws.amazon.com%2F&SigninToken=ROjYCgENQ3r_alOlNDFsHwfwQuaEZKQLmoue_P6HU2L3PNvR7iu1ASyNK_E93nK_TgleTIRNXkdORhk7f9TPEDWFiyHJnLwvwxIot67FO...
※実際には、トークンはもっと長い。

 

実際にログインできるとけっこう嬉しい。あれ?ということはIAMパスワードって不要なのでは?あまり簡単にできてしまうとまずいだろうか。S3のみのアクセス権限となることを確認してみてください。

 

TOP