なになれ

IT系のことを記録していきます

AWS SSOを導入したら色々やることがあったので情報をまとめる

AWS SSOを導入したところ、色々やることがあり、なかなか大変だったので、その情報をまとめます。

AWS SSOとは

名前の通り、AWSの認証をシングルサインオン化できるサービスです。
認証方法として、外部のIDプロバイダーを利用できます。
マルチアカウントに対応しており、ユーザに割り当てられたAWSアカウントへのアクセス許可を設定できます。

前提

今回の前提事項は以下の通りです。

  • Google WorkspaceによるGoogleアカウントをIDプロバイダーとする
  • AWS Organizationsを使用している
  • Jumpアカウントによるクロスアカウントアクセスの仕組みがある
  • 各種AWS向けの操作でJumpアカウントを前提とした設定が行われている

このような前提事項があり、なるべく既存の権限の設定を変更せずにAWS SSOへ切り替える方針で行いました。

実施したこと

まずは、AWS SSOを使えるようにするまでに実施したことです。

AWS SSOの設定

AWS SSOの初期セットアップとGoogle Admin Console上での作業を行います。
以下の内容の通りに実施して、設定します。

aws.amazon.com

AWS SSOのユーザ、グループの作成

AWS SSOのユーザおよびユーザが所属するグループを作成します。

上記ブログ記事にあるとおり、Googleアカウントでは自動的にユーザを作成する機能がサポートされていません。
代わりに、ssosyncというプログラムで自動的にユーザとグループを作成します。

github.com

ssosyncはGoogleグループのグループとユーザを元にして、AWS SSOのグループとユーザのリソースを作成します。

ssosyncの実行にあたってはGoogle Developers Consoleから認証情報を作成し、利用します。
詳しい設定については以下を参考にします。

GitHub - awslabs/ssosync: Populate AWS SSO directly with your G Suite users and groups using either a CLI or AWS Lambda

Googleグループを使って、AWS SSOのグループやユーザを作成することになるため、事前にGoogleグループのデータを精査しておく必要があります。
今回はAWS SSO用のGoogleグループとして、新規で作成することにしました。
これはAWS SSOのグループ単位でAWSアカウントへのアクセス権限やアクセス権限セットという権限ポリシーを設定する必要があるため、既存のGoogleグループでは要件を満たさなかったためです。

このあたりを理解するには、以下が参考になります。
dev.classmethod.jp

アクセス権限セットのポリシーの中身はIAMポリシーとなるため、既存のIAMポリシーをほぼそのまま移行することができます。
複数のカスタムポリシーを設定することができないため、そのあたりは注意が必要になります。
自分の場合は、既存の複数のIAMポリシーの内容を1つのポリシーにマージすることでなんとか対応することができました。

ssosyncの定期実行

ssosyncはGoogleグループのデータからリソースを同期する都合上、定期的に実行する必要があります。
ssosyncでは、定期実行を前提としたSAMによるAWS環境へのデプロイをサポートしています。
この仕組みを使うことで、比較的簡単に定期実行の仕組みを整えることができます。

デプロイするにあたって、ssosyncを実行するLambda関数のタイムアウト値を最大の15分に設定しておくと良いです。
以下のように、template.yamlを修正します。

template.yaml

  SSOSyncFunction:
    Type: AWS::Serverless::Function
    Properties:
      FunctionName: ssosync
      Runtime: go1.x
      Handler: dist/ssosync_linux_amd64/ssosync
-      Timeout: 300
+      Timeout: 900
      Environment:

READMEだと使い方が分かりづらいのですが、以下のコマンドでデプロイできます。

$ make package
$ sam deploy --template-file [ssosync directory]/packaged.yaml --stack-name ssosync --guided --capabilities CAPABILITY_IAM

sam deployをすることで、パラメータ値の入力を求められます。
GoogleCredentialsというパラメータはGoogle Developers Consoleからダウンロードしたcredentials.jsonの内容を与える必要があります。
自分の環境だと、コマンド入力からこの値を入力する術が見つからなかったため、仮の値を一旦入力し、後で変更するというやり方で回避しました。
ssosyncで利用されるGoogleCredentialsをはじめとしたセキュアな情報はSecretsManagerで管理されているため、sam deploy後にSecretsManagerの画面から値を変更することができます。

AWS CLIの利用方法

これ以降は、AWS SSOにすることで、既存の認証の仕組みが変わり、対応が必要になったことです。

AWS SSOによる認証情報で、AWS CLIを利用するための内容についてです。

設定

AWS CLI version2をインストールします。
AWS CLI バージョン 2 のインストール、更新、アンインストール - AWS Command Line Interface

AWS SSO用のAWS CLIのprofileを作成します。

$ aws configure sso

質問に答えて、AWS SSOの設定をします。
既存のAWS CLIの設定がある場合には、被らないようにprofile名を指定し、後で~/.aws/configを修正して既存のprofile名と置き換えます。

操作

AWS SSOによる認証の有効期限が切れた場合、以下のコマンドで再度ログインします。

$ aws sso login --profile <awsprofilename>

AWS CLIAWS SSO経由で操作する場合には、--profileを指定して実行するだけです。

参考

AWS Single Sign-On を使用するための AWS CLI の設定 - AWS Command Line Interface

Terraformの利用方法

TerraformでAWSのリソースを作成する環境のため、Terraformの実行にも影響があります。

AWS SSOの権限でTerraformを実行する手段の選択肢については以下にわかりやすくまとめられています。
dev.classmethod.jp

この内容を参考にさせてもらい、最終的にaws2-wrapを使う方法を採用しました。
これには今までのやり方をなるべく変えないようにする意図があります。
今までTerraformを実行する方法として、AssumeRoleによって対象のAWSアカウントの認証情報を取得して、Terraformを実行していました。
これを変えないようにするために、aws2-wrapでAWS SSOの認証を行い、もともとTerraformを実行していたIAMロールにAWS SSOのIAMロールからAssumeRoleをするという流れにしました。

これを行うにあたっては以下を参考にしました。
dev.classmethod.jp

aws2-wrapは以下のREADMEを見て、インストールします。
github.com

Terraformを実行する際には以下のコマンドで、AWSの認証情報を環境変数に設定した後で実行します。

$ eval $(aws2-wrap --profile <awsprofilename> --export)

Session ManagerによるSSH方法

踏み台サーバにSSHする際にSession Managerを使っていたため、SSHでも影響がありました。

~/.ssh/configのProxyCommandにあるaws ssm start-sessionAWS SSOで設定したprofileを付与します。

~/.ssh/config

...
ProxyCommand sh -c "env PATH=/usr/local/bin:$PATH aws --profile <awsprofilename> ssm start-session --target %h --document-name AWS-StartSSHSession --parameters 'portNumber=%p'"
...

これはAWS CLIを使うのと本質的には同じ話なので対応としては簡単です。

AWS SDK for JavaScriptの対応

ローカル環境のNode.jsからAWSリソースにアクセスして処理を行うスクリプトがあり、それをAWS SSOに対応する必要がありました。

AWS SSOによる認証を行うにあたっては、AWS SDK for JavaScriptのv3を利用する必要があります。
v3より前のバージョンではAWS SSOに対応していないためです。

@aws-sdk/credential-providersモジュールのfromSSOメソッドを使ってAWSの認証を行います。

import { fromSSO } from "@aws-sdk/credential-providers"; 
...
const client = new FooClient({ credentials: fromSSO({ profile: "my-sso-profile" });

このあたりは情報が少なく苦労しました。他のプログラムでも同様の対応が必要となるはずです。

参考

@aws-sdk/credential-providers | AWS SDK for JavaScript v3

EKSのaws-authの設定方法

AWS SSOの認証情報からEKSで作成したKubernetes環境にアクセスできるようにします。
これはAWS SSOで作られたIAM RoleをEKSのユーザ認証を管理しているaws-authリソースのmapRolesに追加することで対応できます。
IAM Roleの追加にあたってはARNをそのまま記載してもエラーとなってしまうため、注意が必要です。
詳しくは以下が参考になります。
qiita.com

AWS SSOのメリット

AWS SSO化による想定していた効果として、セキュリティ強化があります。SSOでIDを統一することができたため、退職者管理が適切に行われることが期待されます。
また、ユーザに紐づく永続的な認証情報であるAWSアクセスキーを廃止できることが大きいです。AWSアクセスキーを漏洩してしまうリスクは人が操作する以上、起こりうる可能性がある問題です。
また、副次的な効果として、AWS SSOによるAWS認証の体験が良いことが挙げられます。
Jumpアカウントによるクロスアカウントアクセスのときには、Jumpアカウントにログインして、自分が操作したいAWSアカウントのIAMロールにスイッチするという操作が必要だったために面倒でした。
AWS SSOによって自分が操作したいAWSアカウントに直接アクセスできるようになります。
そのほかには、AWS SSOでGoogleアカウントの認証となるため、AWSの認証ではMFAが不要になります。IAMによるAWS認証ではMFAを導入していたため、このあたりも面倒がなくなって良いです。
Jumpアカウントを運用するときには、各AWSアカウントにスイッチロールするためのIAMのリソースを作る手間があったのですが、AWS SSOではアクセス権限セットに権限が集約されるため、運用面でもシンプルになります。

おわりに

セキュリティ強化以外にも多くのメリットがあり、AWS SSOを導入して良かったと思います。
AWSをある程度使ってからAWS SSOを導入するよりもAWSの運用を開始するタイミングからAWS SSOを導入しておくと、AWSの運用が最初から楽になるので良いと思います。

参考

AWS SSO を導入してセキュリティと利便性を改善した話 - スタディサプリ Product Team Blog