外部 AWS アカウントでも IAM User なしで AWS CLI からアクセスしたい

AWSが標準提供するSSO機能とクロスアカウントのAssumeRole機能とを組み合わせることで、外部のAWSアカウントにIAM Userなしでも Programmatic にアクセス（AWS CLI など）できるようにしました。

これにより、自社のSSO設定でユーザ認証情報を一元管理可能です。
また、外部AWSアカウント側に IAM User を作成する必要がないため、AWS CLI が必要なケースであっても、メンバーのオンボーディング・オフボーディングの度に外部AWSアカウント管理者の方に作業を依頼する必要がなくなります。

## 概要

=> 自社AWSアカウントへのSSOログイン + 外部AWSアカウントへのクロスアカウントAssumeRole

自社AWS Organization配下にSSO踏み台専用のAWSアカウントを用意し、そこに作成したIAM Roleから外部AWSアカウント上のIAM RoleにAssume Roleし、Programmatic にアクセスできるようにする、という内容です。

基本的には、 [こちら](https://qiita.com/zagvym/items/c234b82bbc0659ac429c) の記事で紹介した、 SSO Profile ベースの Assume Role の応用です。
本手法では、SSOログイン先とは別のAWSアカウントの IAM Role に対して AssumeRole (Switch Role) するような設定にすることで、表題の操作を実現します。

## 目的

IAM User を使わずに AWS アカウントにアクセスする方法として、 Single Sign-On (SSO) 機能が利用可能です。

自社 AWS Organization 配下の AWS アカウントであれば、 SSO 、 AWS Console にもログイン可能です。また、一時的な Credentials 情報 (AWS Key, Secret, SessionToken) を取得し、AWS CLI など Programmatic なアクセスに利用することも可能です。

ですが、 下図で示すような外部の AWS アカウントについては、 AWS コンソールへの SSO ログインが可能な状態であっても、 単純には Programmatic アクセス に必要な認証情報を取得できません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/a7a1f084-1372-81b4-06e5-3e33b557fec1.png)

本記事は、このような外部AWSアカウントに対しても、自社Organization配下のAWSアカウントと同様に、 SSO認証情報を使って Programmatic アクセスを可能にする構成と設定方法例を紹介しています。

## 構成

今回は、下図に示すような構成で、外部 AWS アカウントに対する Programmatic アクセスを可能にしました。

**SSO + 外部 AWS アカウントへの AssumeRole の構成概要図**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/f128d8cc-2267-a72d-8972-4d95748040a0.png)

まず、自社 AWS 配下に、SSO踏み台となるAWSアカウントを用意します。そのAWSアカウント上へ SSO ログインする際に割り当てられる IAM Role から、外部 AWS アカウント側の IAM Role に AssumeRole (Switch Role) 可能となるように、各所に設定を行います。

### その他の実現方法について

[AWS の公式ドキュメント](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/troubleshoot_saml_view-saml-response.html) でも、 SSO start page からブラウザの dev-tool などを使って SAML Response を表示し、そこから Programmatic Access でも利用可能な認証関連情報を取得する方法が紹介されています。
ただ、利用時に毎回この手順を行うのは煩雑であると考え、より簡易に利用できるような方法を検討した結果、本記事の方式に思い至りました。

また、 [こちらの記事](https://qiita.com/wadahiro/items/79eaed9390391b0f40cc) のように、何かしらツールを導入することでも、本記事の紹介内容と同様の操作は可能と思われます。
本記事では、外部ツールを導入なしに、AWSの標準的な機能の組み合わせで、目的とする外部AWSアカウントへのSSO認証アクセスを目指しました。


## AWS側設定

### 事前準備: AWS Organization の SSO連携設定 

以降の手順は、 AWS Organization と Identity Provider (IdP) との連携設定が完了し、 SSO が可能な状態を前提としています。
利用するIdPごとに設定方法が異なりますので、ここでは説明を省略します。
（連携設定例: [AWS Startup ブログ | G Suite アカウントを用いた AWS へのシングルサインオン](https://aws.amazon.com/jp/blogs/startup/techblog-saml-gsuite/)）

### 踏み台AWSアカウント上での設定確認

SSO ログイン先として利用する、 AWS Organization 配下のAWSアカウントで、必要な情報を確認します。
なお、権限セット（Permission Set）の作成やユーザへの割り当ては、各組織のポリシーに応じて適宜設定してください。ただし、本構成の実現のため、外部AWSアカウントに対する AssumeRole 実行に必要な権限は付与してください。
（参考: SSO権限セットについて https://docs.aws.amazon.com/ja_jp/singlesignon/latest/userguide/permissionsets.html ）

<details>
<summary>SSO踏み台AWSアカウントの権限セットに割り当てるポリシー例</summary>

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowSSOAndAssumeRole",
            "Effect": "Allow",
            "Action": [
                "sts:AssumeRole*",
                "sts:Get*"
            ],
            "Resource": "*"
        },
        {
            "Sid": "AllowReadAccessToIAMRole",
            "Effect": "Allow",
            "Action": [
                "iam:GetRole",
                "iam:ListRoles"
            ],
            "Resource": "*"
        }
    ]
}
```
</details>


1. 踏み台AWSアカウントのSSO Profileとして使用する権限セット名を確認
    - 例: SSO start page 上での限セット名を表示して確認 ![スクリーンショット 2023-06-23 20.16.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/5b76ada6-2f43-b087-3e5f-d84c7671a563.png)
2. SSO権限セットに対応する IAM Role ARN を取得
    - 踏み台AWSアカウントのWebコンソール上で該当Roleを検索し![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/9c97309e-81a4-97d3-45bd-ce184955a585.png)
    - IAM RoleのARNを取得して控えておく ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/4225ba6a-29f5-afeb-9eba-ba3c6ba04f06.png)

    
### Assume Role先の外部AWSアカウント側設定手順

外部AWSアカウントの管理者の方に、 控えておいたSSO踏み台AWSアカウントのIAM Role ARNをお渡しして、 AssumeRole が可能となるように IAM Role 設定を依頼してください。
（参考: https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_create_for-user.html#roles-creatingrole-user-console ）

- 踏み台AWSアカウント経由でアクセスするユーザアカウントにに割り当てる IAM ロールの作成
- IAM Role への信頼関係ポリシーの `Principal` に作成したSSO踏み台AWSアカウントのIAM Role ARNを追加
    - AWS Console 上での設定例（信頼ポリシーの編集）: ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/deb2a62b-5e1d-d9cf-2647-03b6e2546a0b.png)
    - SSO踏み台AWSアカウントのIAM Role ARNからのAssume Roleを許可する設定を追記 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434222/ae8b2b9b-6fbf-90e5-28db-ccea8a6da55a.png)
        - 追加する Policy Statement の例: 
          ```json
          {
                "Effect": "Allow",
                "Principal": {
                    "AWS": "{{SSO踏み台AWSアカウントのIAM Role ARN}}"
                },
                "Action": "sts:AssumeRole"
          }
          ```

【重要】完了後、先方側から、設定した（AssumeRole 先の） IAM Role ARN を受領してください。次の利用者向け AWS CLI 設定時に必要となります。


## 利用者側設定

外部AWSアカウントにアクセスする利用者の方それぞれのローカル開発環境上で、 AWS CLI 設定を行なっていただく想定です。

requirements:
- aws-cli >= v2.11
    - sso-session の設定に対応するため ([関連issue](https://github.com/aws/aws-cli/issues/7496))

[AWS公式ドキュメント](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/sso-configure-profile-token.html) などを参考に、 AWS CLIで参照する SSO Profile の設定を行ないます。

なお記載内容は、[AWS CLI で SSO profile を元にした AssumeRole profile の設定](https://qiita.com/drafts/c234b82bbc0659ac429c) の記事で紹介している内容とほぼ同様です。
ただし、こちらは AssumeRole Profile 設定で指定する `role_arn` パラメータに、外部AWSアカウントの IAM Role を指定します。これにより、SSO Profile を元にしたクロスアカウントでの AWS CLIやその他の Programmatic アクセスを可能にしています。

以下、 ~/.aws/config に記載する設定例です。
（各プロファイルのリージョン指定（`sso_region`, `region` ) は適宜読み替えてください。）

```INI
# SSO認証の共通設定
[sso-session my-sso]
sso_start_url = https://my-sso-portal.awsapps.com/start
sso_registration_scopes = sso:account:access
sso_region = ap-northeast-1

# SSO踏み台AWSアカウントへのログインユーザのプロファイル
[profile my-bastion]
sso_session = my-sso
sso_account_id = {{SSO踏み台AWSアカウントのID}}
sso_role_name = {{SSO踏み台AWSアカウントのIAM Role名}}
region = ap-northeast-1

# 外部AWSアカウントへの AssumeRole (Switch Role) 用のプロファイル設定プロファイル
[profile ex1] 
source_profile = my-bastion
role_arn = {{信頼関係ポリシーを設定した外部IAM RoleのARN}}
region = ap-northeast-1
```

まず、`my-sso` SSO session で認証を行う `my-sso-profile` を定義します。
さらにそれを source_profile に指定し、外部AWSアカウント上の IAM Role に対する AssumeRole Profile として `ex1` を定義しています。

### aws-cli からの利用

`--profile` オプションなどで、↑で設定した外部AWSのAssumeRole profile名を指定してください。

コマンド実行例:

```sh
$ aws --profile ex1 s3 ls
...
```

プロファイル設定状況確認例:

```sh
$ aws --profile ex1 sts get-caller-identity
{
    "UserId": "AROXXXXXXXXXX:botocore-session-xxxx",
    "Account": "xxxxxxxxxxxx",
    "Arn": "arn:aws:sts:::assumed-role/ex1/botocore-session-xxxx"
} 

$ aws --profile ex1 configure list
      Name                    Value             Type    Location
      ----                    -----             ----    --------
   profile                      ex1           manual    --profile
access_key     ****************UCUA      assume-role
secret_key     ****************GRsL      assume-role
    region           ap-northeast-1      config-file    ~/.aws/config
```


### その他の Programmatic アクセスからの利用

各種ライブラリ (aws-sdk, etc) や ツール類 (aws-cdk, etc) からの Programmatic アクセスの際も、 上記 AWS CLI 向けに設定した AWS Profile を指定可能な見込みです。

`AWS_PROFILE` 環境変数もしくは所定の設定項目に、外部AWSアカウントのAssume Role Profile設定情報を記載するなどして利用する想定です。

詳しくは、各ライブラリやツールのドキュメントをご参照ください。


## まとめ

AWSのSSO機能とクロスアカウントAssumeRole機能を組み合わせて、外部AWSアカウントに対して AWS CLIのような Programmatic アクセス を行うためのシステム構成とその設定例を紹介しました。