AssumeRoleWithSAMLを利用してAPI用の一時クレデンシャルを取得する方法

IAM

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

西澤です。ADFSサーバを利用したAWSマネージメントコンソールへのSSOについて以前に書きましたが、APIを利用する方法が整理できていないことが課題となっていました。SAMLを利用したAPI認証の方法については藤本さんが詳しく書いてくれています。

この方法は理解の為には良いのですが、そのまま運用で使うにはやや手順が複雑な印象を受けたので、これをもう少し簡単に利用する方法がないかとさらに情報を漁ってみたところ、公式ブログでツールとその利用手順が紹介されていました。今回はこちらを試してみたいと思います。

  1. How to Implement Federated API and CLI Access Using SAML 2.0 and AD FS - AWS Security Blog
  2. How to Set Up Federated API Access to AWS by Using Windows PowerShell - AWS Security Blog

AssumeRoleWithSAMLを利用した認証方式

こちらも公式ブログの図を拝借させていただきました。詳しくはSAMLを勉強しなければいけませんが、大きな流れとしては以下の通りです。

  1. ADFSがFederatedユーザを認証
  2. ADFSからSAML assertionを取得
  3. STSにAssumeRoleWithSAMLをリクエスト
  4. 一時クレデンシャルを取得
  5. 一時クレデンシャルを利用してAPIコール(AWSリソースにアクセス)

事前準備

AWSと連携済のADFSサーバと接続用のADアカウントは事前に準備しておきます。詳細な手順は以前の記事をご覧ください。これがなかなか骨が折れるところではあるのですが。

1. pythonスクリプトを利用したAssumeRoleWithSAML

まずは始めにご紹介した公式ブログ1で説明されているsamlapi.pyを利用した一時クレデンシャルの取得手順を試してみます。再現可能な手順をご紹介したかったので、今回は最新版のAmazon Linux環境で1からセットアップしてみました。

samlapi.py実行前の準備

まずは前提のパッケージをpipコマンドを利用してインストールしておきます。Amazon Linuxでなければ、Python SDK(boto)も必要です。

$ sudo pip install beautifulsoup4
You are using pip version 6.1.1, however version 8.0.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting beautifulsoup4
  Downloading beautifulsoup4-4.4.1-py2-none-any.whl (81kB)
    100% |################################| 81kB 4.7MB/s 
Installing collected packages: beautifulsoup4
Successfully installed beautifulsoup4-4.4.1

$ sudo pip install requests-ntlm
You are using pip version 6.1.1, however version 8.0.2 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
Collecting requests-ntlm
  Downloading requests_ntlm-0.2.0.tar.gz
Collecting requests>=2.0.0 (from requests-ntlm)
  Downloading requests-2.9.1-py2.py3-none-any.whl (501kB)
    100% |################################| 503kB 1.0MB/s 
Collecting python-ntlm3 (from requests-ntlm)
  Downloading python_ntlm3-1.0.2-py2.py3-none-any.whl
Requirement already satisfied (use --upgrade to upgrade): six in /usr/lib/python2.7/dist-packages (from python-ntlm3->requests-ntlm)
Installing collected packages: requests, python-ntlm3, requests-ntlm
  Found existing installation: requests 1.2.3
    Uninstalling requests-1.2.3:
      Successfully uninstalled requests-1.2.3
  Running setup.py install for requests-ntlm
Successfully installed python-ntlm3-1.0.2 requests-2.9.1 requests-ntlm-0.2.0

公式ブログにも記載がありますが、事前にcredentialsファイルを作成する必要がありました。今回はリージョンはOregon(us-west-2)を指定しました。アクセスキーやシークレットアクセスキーは空の状態で問題ありません。

$ cat ~/.aws/credentials 
[default]
output = json
region = us-west-2
aws_access_key_id =
aws_secret_access_key =

続けて、用意されているsamlapi.pyをダウンロードして実行権限を付与します。

$ curl -s -O https://s3.amazonaws.com/awsiammedia/public/sample/SAMLAPICLIADFS/samlapi.py
$ chmod u+x samlapi.py

これをそのまま実行できれば一番良いのですが、接続先の修正や警告を回避する為、少しだけ手を加えました。

$ diff samlapi.py samlapi.py.org 
36c36
< idpentryurl = 'https://xxx.xxx.xxx.xxx/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices' 
---
> idpentryurl = 'https://<fqdn>/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices' 
54,55c54
< requests.packages.urllib3.disable_warnings()
< response = session.get(idpentryurl, verify=False) 
---
> response = session.get(idpentryurl, verify=sslverification) 
67c66
< soup = BeautifulSoup(response.text.decode('utf8'), 'html.parser') 
---
> soup = BeautifulSoup(response.text.decode('utf8'))
  • idpentryurlをADFSサーバのFQDNまたはIPアドレスに変更する必要があります
  • 自己署名証明書を利用したADFSサーバ環境だった為、警告を抑止しつつ証明書のVerifyをしないように変更しました
  • BeautifulSoupでparser指定が無いとの警告が出たので明示的に指定するようにしました

(2016/03/08追記) 下記の変更も追加しました。

:::
reload(sys) ###UnicodeEncodeError対応として追加
sys.setdefaultencoding('utf-8') ###UnicodeEncodeError対応として追加
soup = BeautifulSoup(response.text.decode('utf8'), 'html.parser')
:::
:::
headers = {'User-Agent': 'Mozilla/5.0 (compatible, MSIE 11, Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko'} ###ADFS3.0のUserAgent判定対応として追加
response = session.get(idpentryurl, verify=False, headers=headers) ###ADFS3.0のUserAgent判定対応として変更
:::

samlapi.pyの実行

これで利用できる環境が整いましたので実行してみます。遷移できるIAMロールが表示されますので、先頭の数字を1つ選んで入力します。

$ ./samlapi.py 
Username: adfs\testuser
Password: 


Please choose the role you would like to assume:
[ 0 ]:  arn:aws:iam::123456789012:role/ADFS-Develop
[ 1 ]:  arn:aws:iam::123456789012:role/ADFS-Production
Selection:  1


----------------------------------------------------------------
Your new access key pair has been stored in the AWS configuration file /home/ec2-user/.aws/credentials under the saml profile.
Note that it will expire at 2016-02-17T12:58:27Z.
After this time you may safely rerun this script to refresh your access key pair.
To use this credential call the AWS CLI with the --profile option (e.g. aws --profile saml ec2 describe-instances).
----------------------------------------------------------------


Simple API example listing all s3 buckets:
[<Bucket: hogehoge>, <Bucket: hogehoge2>, <Bucket: hogehoge3]

最後のS3バケットの一覧は、取得した一時クレデンシャルでの接続確認結果として出力されるものです。samlというprofile名で認証情報が保存されたようですので、credentialsファイルを確認してみます。

$ cat ~/.aws/credentials 
[default]
output = json
region = us-west-2
aws_access_key_id = 
aws_secret_access_key = 

[saml]
output = json
region = us-west-2
aws_access_key_id = ASIAXXXXXXXXXXXXXXXX
aws_secret_access_key = U6vkYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY
aws_session_token = AQoDZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ

追加されているようですね。このprofileを利用することで(AWS CLIであれば--profile saml)、一時クレデンシャルが期限切れになるまでの間(1h)、AWS CLIでもbotoでも取得した認証情報を利用することができます。

2. AWS Tools for Windows Powershellを利用したAssumeRoleWithSAML

次に公式ブログ2のPowershellを利用する手順も確認してみました。

Set-AWSSamlRoleProfileの前提

こちらは標準のコマンドレットSet-AWSSamlRoleProfileが用意されていますので、v3.1.31.0以降を準備すればすぐに利用することができます(執筆 時点での最新は、v3.1.44.0)

AWS Tools for Windows PowerShell 3.1.31.0 Release Date: 2015-12-01 Summary of Changes Added information to the Getting Started section about new cmdlets that use Security Assertion Markup Language (SAML) to support configuring federated identity for users.

PS C:> Get-Module -Name AWSPowerShell | Format-List
Name              : AWSPowerShell
Path              : C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.dll
Description       : The AWS Tools for Windows PowerShell lets developers and administrators manage their AWS services from the Windows PowerShell scripting environment.
ModuleType        : Binary
Version           : 3.1.44.0
NestedModules     : {}
ExportedFunctions :
ExportedCmdlets   : {Add-ASAAttachmentsToSet, Add-ASACommunicationToCase, Add-ASInstances, Add-ASLoadBalancer...}
ExportedVariables :
ExportedAliases   :

Set-AWSSamlRoleProfileの実行

こちらでもADFSサーバの自己署名証明書によりエラーが発生しましたので、それを無視する手順を加えることで回避しました。

PS C:> [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

以降は、公式ブログに記載の通りです。ADFSサーバと同じドメインに所属しているアカウントを利用すればもう少し簡単ですが、下記手順ではドメインに参加していない状態で手動でアカウント情報を入力します。

PS C:> $endpoint = "https://xxx.xxx.xxx.xxx/adfs/ls/IdpInitiatedSignOn.aspx?loginToRp=urn:amazon:webservices"
PS C:> $epName = Set-AWSSamlEndpoint -Endpoint $endpoint -StoreAs ADFS-Demo -AuthenticationType NTLM
PS C:> $credential = Get-Credential -Message "Enter the domain credentials for the endpoint"

ここで認証情報の入力を要求されます。

saml_credentials

入力した認証情報を利用して、Set-AWSSamlRoleProfileを実行すると、こちらでも遷移可能なIAMロールを選ぶことができました。

PS C:> Set-AWSSamlRoleProfile -EndpointName $epName -NetworkCredential $credential -StoreAs SAMLDemoProfile

Select Role
Select the role to be assumed when this profile is active
[A] A - 123456789012:role/ADFS-Develop  [B] B - 123456789012:role/ADFS-Production  [?] ヘルプ (既定値は "A"): B
SAMLDemoProfile

SAMLDemoProfileというプロファイル名で認証情報が保存されました。これでPowershellでも一時クレデンシャルの期限切れまでこの認証情報を利用できます。

PS C:> Set-AWSCredentials -ProfileName SAMLDemoProfile
PS C:> Get-AWSCredentials
CustomCallbackState           : Amazon.PowerShell.Common.SAMLCredentialCallbackState
RequestUserCredentialCallback : Amazon.SecurityToken.SAML.StoredProfileSAMLCredentials+RequestUserCredential
ProfileName                   : SAMLDemoProfile
ProfilesLocation              :
ProfileData                   : Amazon.Util.SAMLRoleProfile

まとめ

今回は2種類のAssumeRoleWithSAML利用方法をご紹介しました。このような便利なツールがあれば、SAML経由でのAPI利用も問題なしです。AD環境を構築するひと手間は変わりませんが、一度用意さえしてしまえば、ほぼ全ての権限管理をADアカウントに集約できそうですね。ぜひ活用してみてください。