AWS CLI v2 でプロジェクト毎に認証設定を隔離する（公式 Dockerイメージで、IAM Identity で SSO セッション運用）

AWSアカウントの誤用を防ぐために、個人用やプロジェクト毎認証の環境切替を行いました。
現場毎にやりがちなのでメモを作ります。

環境切替は、AWS Organizations と IAM Identity Center (旧 IAM SSO) を使って、
AWSマルチアカウントとそこへのシングルサインオンで実施します。

AWSアカウントに Organizations を設定すると、複数のアカウントを１組織の所属として権限等設定できます。
また、IAM Identify Center はAWS内のディレクトリサービスになります。

ここでは、AWSマルチアカウントの追加については他に譲り、AWS CLI v2 の Docker イメージ利用による SSO 認証設定切替に注目します。

ターミナルから AWS CLI v2 を使います。

また、AWS CLI v2 は Docker 公式イメージ (ECR public内) を使用します。
- https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/getting-started-docker.html

## 以下手順

- AWS で IAM Identify アカウントを用意する
 
- 適当なディレクトリを作り(~/someproj/.aws等)、AWS CLI の SSO 接続設定を用意する
  ```
  [default]
  region=ap-northeast-1
  output=json

  [profile SOMEPROFILE-SOMEROLE]
  sso_session=SOME-SSO-SESSION
  sso_account_id=777777777777
  sso_role_name=SOMEROLE
  region=ap-northeast-1
  output=json
  cli_pager=

  [profile SOMEPROFILE-SWITCHED-ROLE]
  sso_session=SOME-SSO-SESSION
  sso_account_id=888888888888
    :

  [sso-session SOME-SSO-SESSION]
  sso_start_url=https://a-9999999999.awsapps.com/start
  sso_region=ap-northeast-1
  sso_registration_scopes=SOMESCOPE
  ```

- Docker をインストールする
  ```shell
  $ docker --version
  Docker version 20.10.17, build 100c701
  ```

- Dockerの共有リソースとして、接続設定ファイルを共有する
  - 共有リソースの設定変更のさいはDockerを確実に再起動する
  - Docker.app だと、デバッグの虫アイコンから Restart すると大丈夫
  - 共有できていないと、```The config profile (aaaa) could not be found``` が出る

- 公式イメージを特定バージョンで取得し、起動確認する
  ```shell
  $ docker run --rm -it public.ecr.aws/aws-cli/aws-cli:2.10.3 --version
  Unable to find image 'public.ecr.aws/aws-cli/aws-cli:2.10.3' locally
  2.10.3: Pulling from aws-cli/aws-cli
  Digest: sha256:776zzzzzzz
  Status: Downloaded newer image for public.ecr.aws/aws-cli/aws-cli:2.10.3
  aws-cli/2.10.3 Python/3.9.11 Linux/5.10.124-linuxkit docker/x86_64.amzn.2 prompt/off
  ```

- SSO ログインする（aws sso loginコマンド→ブラウザでURLを開いてコード入力→許可する）
  - まず aws sso login する
    ```
    $ docker run --rm -it -v ~/SOMEPROJ/aws:/aws -v ~/SOMEPROJ/.aws:/root/.aws -eAWS_PROFILE=SOMEPROFILE-SOMEROLE public.ecr.aws/aws-cli/aws-cli:2.10.3 sso login     
    Attempting to automatically open the SSO authorization page in your default browser.
    If the browser does not open or you wish to use a different device to authorize this request, open the following URL:

    https://device.sso.ap-northeast-1.amazonaws.com/

    Then enter the code:

    AAAA-AAAA
    ```
  - ブラウザで https://device.sso.ap-northeast-1.amazonaws.com/ を開く
  - コード AAAA-AAAA を入力
  - ```Allow botocore-client-AAAAA to access your data?``` と聞かれるので Allow する (botocoreは aws cli が中で使っているボット)
  - 成功したことを確認してブラウザ閉じる
  - コンソールでも成功メッセージを確認する
    ```
    Successfully logged into Start URL: https://a-9999999999.awsapps.com/start
    ```
  - ~/SOMEPROJ/.aws に sso セッションキャッシュが保存されている (これがあるので期限切れするまで使える。使用後に削除しても丁寧)
  - 期限切れしているとエラーになる ```Error loading SSO Token: Token for AAAA does not exist``` 

- AWS CLI のプロファイルを確認する
  ```
  $ docker run --rm -it -v ~/SOMEPROJ/aws:/aws -v ~/SOMEPROJ/.aws:/root/.aws -eAWS_PROFILE=SOMEPROFILE-SOMEROLE public.ecr.aws/aws-cli/aws-cli:2.10.3 configure list
        Name                    Value             Type    Location
        ----                    -----             ----    --------
     profile     SOMEPROFILE-SOMEROLE              env    ['AWS_PROFILE', 'AWS_DEFAULT_PROFILE']
  access_key     ****************xxxx              sso    
  secret_key     ****************yyyy              sso    
      region           ap-northeast-1      config-file    ~/.aws/config
  ```

- 動いたら、alias を作っておく （さらにめんどくさい時はターミナルに入って　alias aws=aws-someprojなどとしてしまっている）
  ```
  $ alias aws-someproj='docker run --rm -it -v ~/SOMEPROJ/aws:/aws -v ~/SOMEPROJ/.aws:/root/.aws -eAWS_PROFILE=SOMEPROFILE-SOMEROLE public.ecr.aws/aws-cli/aws-cli:2.10.3'
  $ aws-someproj configure list
  $ aws-someproj sts get-caller-identity
  {
    "UserId": "AAAAAAAAAAAAAAAAAAAAA:sato1043",
    "Account": "999999999999",
    "Arn": "arn:aws:sts::999999999999:assumed-role/SOMEROLE/sato1043"
  }
  $ aws-someproj s3 mb s3://someproj-sometest
  make_bucket: someproj-sometest
  $ aws-someproj s3 rb s3://someproj-sometest
  remove_bucket: someproj-sometest
  $ aws-someproj sso logout
  ```

- SSO するうちの 別の AWS アカウントを切り替えたい時は、指定するプロファイルを変える

- aws ssm も受け付けているようだったが次回あればそのとき検証

- 次は、スクリプトでの利用例；
  ```shell
  #!/usr/bin/env sh

  alias aws=aws-someproj # とかなんとか

  AWS_REGION=$(aws configure get region)
  [ -z $AWS_REGION ] && exit -1
  echo $AWS_REGION

  AWS_ACCOUNT_ID=$(aws sts get-caller-identity --output text --query Account)
  [ -z $AWS_ACCOUNT_ID ] && exit -1
  echo $AWS_ACCOUNT_ID

  aws s3 mb s3://someproj-$AWS_REGION-$AWS_ACCOUNT_ID
  ```

- 2023/3/5 追記； Organizations からアカウントを抜く場合、抜く側の AWS アカウントに請求情報設定と電話認証済が必要になる
  - 留意点として、抜く側の AWS アカウントが Organizations から作成していた場合、前記２点が未設定状態である。
    - なのでそもそも経費精算用のクレジットカードが必要である
    - それからフリーコールが通る電話番号（固定電話であれば問題ない）が要る
    - ２点設定のため、Organizations とは関係なしに、**このアカウントの** root コンソールログインを設定する
  - まず、抜く側の AWS アカウントで AWS Console に root ログインする
    - 抜く側の AWS アカウントのメールアドレスを調べ、メーラーでメール受信できることを確認しておく
    - 普通に AWS Console を開き、そのメアドで root ログインを試みる
      - https://console.aws.amazon.com/
    - ここで AWS Organizations ではパスワードを設定することがないので、パスワードが未設定になっている
    - パスワードを忘れたのリンクからパスワードを再設定する。その際にメーラーに再設定リンクが届くことになる
    - 再設定リンクから開くブラウザタブでパスワードを設定し、ログインする
    - ここで MFA を設定しても丁寧である
  - 次に請求情報設定を設定する
    - これは通常通り、Billing から有効なクレジットカードを登録する
  - 最後に、電話番号を認証する
    - 抜く側の AWS アカウントで AWS Organizations を開く
    - するとすでに組織に属している状態で表示される
    - 組織から抜けるボタンがあるのでクリックする
    - それを実行するとエラーになる（ここでは PIN 認証がされてないエラーになる想定）
    - エラーの説明中で、初回登録画面を開くようリンクが指示されているので、開く
      - https://aws-portal.amazon.com/gp/aws/developer/registration/index.html
      - 初回登録画面に遷移し、必要な情報がすでに揃っていれば、あとは未設定の箇所まで進んでくれる
    - 電話番号を認証する
      - 携帯電話が通らないフリーコール？はかかってこないで失敗する。固定電話で retry すればいい
    - ちなみに、時間がかかってもいいなら、正式にはサポートコンソールから問い合わせをするといいらしい
      - https://aws.amazon.com/jp/premiumsupport/knowledge-center/phone-verify-no-call/

__END__