AWSで使用するAdmin権限をSSMオートメーションを使用して承認制にしてみた
はじめに
株式会社ココペリのSREグループの尾嵜 成真です。
SREとして日々ココペリサービスの信頼性の向上に命を捧げております!(`・ω・´)ゞ
弊社ではAWSのIAMポリシーを厳格に運用しておりまして、特に本番環境ではベストプラクティスに沿って必要最低限の操作しかできないようなポリシー設定となっています。
しかし当然ながら日々サービスを運用するにあたって、ポリシーが付与されていない操作が必要になることはあります。
弊社ではそういった場合には、Admin権限を承認制にして一時的に付与するような形にしています。
またログを出力して可視化することによって、Admin権限を使用して「誰が」「どの時間に」「どこのアカウントで」「何をしたか」というのがわかるようにして、できるだけセキュリティ違反を起こさない、起きてもすぐに気づけるような仕組みを作っています。
ということで、今回はSSMオートメーションを使用したAdmin権限の承認フローを解説していきたいと思います!
本構成でできること
SSMオートメーションを使用してAdmin権限の付与を承認制にする
Organizations内のすべてのアカウントで運用ができる
Admin権限の使用の申請をCLIを使ったシェルスクリプトで実行する
Admin権限を使用したログをSlackに通知する
構成図
前提の設定
IAMの管理は「IAM Identity Center(旧 AWS Single Sign-on)」で行なっている
Admin権限の許可セットが事前に作成されている
Organizations内の全アカウントのCloudTrailの証跡はログ集約アカウントに集約されている
ログをAthenaでクエリする際のテーブルは作成されている
構築はCDKで行う
※以降の記載では「IAM Identity Center」を「SSO」と表記することがあります。
実行フロー
Admin権限を使用したいユーザーが権限リクエストスクリプトを実行します
AccountID、申請者、承認者、使用時間、申請理由を入力します
Slackに申請内容が通知されます
SSO管理アカウント内でSSM Automationが実行されて、Slackに承認メールが届きます
承認者はSSO管理アカウントにログインして、申請を承認します
承認とともにEventBridgeが起動して、Admin権限付与のLambdaが実行されます
申請したユーザーに対して一時的にAdmin権限が付与され、Slackに権限が付与されたことが通知されます
使用時間が経過するとEventBridgeが起動して、Admin権限解除のLambdaが実行されます
申請したユーザーのAdmin権限が解除され、Slackに権限が解除されたことが通知されます
SQSにAdmin権限を使用した情報をキューイングして、ログ集約アカウントにメッセージを送ります
ログ集約アカウントでメッセージの情報を元に、Admin権限の操作実行ログのクエリをするLambdaが実行されます
Athenaのクエリ結果が承認者のメンション付きでSlackに通知されます
CDKのコードツリー
admin-access-workflow
├── cdk
│ ├── bin
│ │ └── cdk.ts
│ └── lib
│ ├── log.ts
│ └── main.ts
├── lambda
│ ├── log.py
│ └── main.py
└── scripts
└── RequestAdminPermission.sh
各コード(GitHub Gist)
主要リソースの解説
scripts/RequestAdminPermission.sh
このスクリプトを実行して、入力したAdmin権限を使用したいユーザー、アカウント、時間などの情報を元にSSMオートメーションを実行します。 また、申請者や承認者のSlackIDをパラメータストアに保管して、後続のLambdaがSlackメンションできるようにします。
CLIで使用するProfileはSSOで管理されているため、SSOログインの処理がスクリプト内に入っています。 申請者の「.aws/config」からProfileを読み取って、ログインができていない場合は自動的にログイン処理を行うようにしています。
ログ集約アカウントでログの出力後に承認者がSlackでログチェックを行えるようにするため、ログ集約アカウントに承認者のSlackIDを送信しています。この辺りは好みになってくるかなと思います。
スクリプトで入力した内容を元にSlackに通知します。
また、SSMオートメーションの承認ステップで設定したSNSの通知先に承認メールが届きます。
承認者がSSO管理アカウントにログインして承認をすると、SSMオートメーションの次のステップが実行されます。cdk/lib/main.ts lambdaExecutionRole
Admin権限を付与するLambdaの実行ロールです。
このロールは一番のつまづきポイントでした。
Lambdaの処理の中で「CreateAccountAssignment」APIを実行しています。
このAPIはSSOのAdmin許可セットとそれを使用したいアカウントの紐付けを行います。
LambdaはSSO管理アカウントで実行されますが、許可セットの紐付けを管理アカウント自身に対して行う場合と、メンバーアカウントに行う場合で使用する権限が異なります。
許可セットの紐付けを管理アカウントに対して行う場合は、Lambdaは管理アカウントの実行ロール「lambdaExecutionRole」を使用します。
許可セットの紐付けをメンバーアカウントに対して行う場合は、Lambdaはメンバーアカウント内のサービスリンクロール「AWSServiceRoleForSSO」を使用します。
このロールは IAM Identity Center を有効化すると組織内の各アカウントに自動で作成されます。
ということでこの実行ロールは許可セットの紐付けを管理アカウントに対して行う場合に使用するLambdaの実行ロールになります。
権限は以下のリンクを参考にしています。
https://docs.aws.amazon.com/ja_jp/singlesignon/latest/userguide/iam-auth-access-using-id-policies.html#policyexamplemanageconnecteddirectorycdk/lib/main.ts lambdaFunction
Admin権限を付与、解除するLambdaになります。
SSMオートメーションからLambdaを呼ぶ際に、Admin権限付与に関するパラメータを渡しています。 スクリプトで入力した値がSSMに渡されて、その後Lambdaにそのまま渡されます。 受け取ったパラメータを元に、「対象者」「アカウント」に対してAdmin権限の「付与・解除」を実行します。 解除する際は、解除後に解除が正しく行われているかListで確認して、ログ調査用としてAdmin権限の使用者情報のメッセージをSQSに渡します。cdk/lib/main.ts sqsQueueLambda
lambdaFunctionから受け取ったメッセージをログ集約アカウントの実行ログ出力Lambdaに渡す役割を担います。
ユーザーがAdmin権限を使用してから、実際にCloudTrailのログがS3に出力されるまで数分のラグがあるため、遅延キューによって5分間メッセージを保持した後にメッセージを配信します。
今回の構成では、CloudTrailのログがログ集約アカウントに出力されるため、ログ集約アカウントに対してプリンシパルを指定します。cdk/lib/main.ts automationDocument
SSMオートメーションのドキュメントです。 このドキュメントに従って、SSMオートメーションが3つのステップで実行されます。
「approveStep」 承認ステップになります。 承認されると次のステップが実行されます。
「setStartSchdulerStep」 Admin権限を付与するLambdaの実行トリガーとなるEventBridgeSchedulerを作成します。 付与開始時間は、RequestAdminPermission.shを実行した時間になります。
「setEndSchdulerStep」 Admin権限を解除するLambdaの実行トリガーとなるEventBridgeSchedulerを作成します。 解除する時間は、RequestAdminPermission.shで入力した時間になります。cdk/lib/log.ts AdminAccessWorkflowLogNotificationFunction
sqsQueueLambdaから受け取ったメッセージを元に、CloudTrailのログテーブルに対してAthenaでクエリを実行します。
CloudTrailのログデータで、「eventtime」「eventsource」「 eventname」「 requestparameters」を取得できれば、実行ログの確認としては充分かなと思います。 requestparametersは実行操作によっては値が無い場合や、値があっても結果がバラバラなので、「requestparameters_extract_first_key_value」でいい感じに抽出してます。
実行したクエリ結果を見やすいように整形して、Slackに通知します。
実際にやってみた
今回はテストなので自分自身でAdmin権限の申請と承認を一人二役でやってみようと思います。
1.Admin権限を使用したいユーザーがRequestAdminPermission.shを実行します。
% bash ./aws-cdk/admin-access-workflow/RequestAdminPermission.sh
2.AccountID、申請者、承認者、使用時間、申請理由を入力します。
実際に実行したログになります。
% bash ./aws-cdk/admin-access-workflow/RequestAdminPermission.sh
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:
Successfully logged into Start URL: https://d-xxxxxxxxxx.awsapps.com/start#/
SSOログインチェック完了: sso-profile
1.使用するAWSアカウントを選択してください
1) 333333333333: dev
2) 444444444444: stg
3) 555555555555: prd
#? 3
2.Admin権限を使用するユーザーのEmailを選択してください
1) ozaki@xxx.xxx
2) hogesan@xxx.xxx
3) Others
#? 1
3.承認者を選択してください
1) 尾嵜
2) HOGE
#? 1
4.使用したい時間数を入力してください(1~9): 1
Admin権限の使用できる時刻は以下の通りです:
開始時間: 2024-08-05T10:48:40
終了時間: 2024-08-05T11:48:41
5.Admin権限を使用する理由を入力してください
理由: テスト
AWS SSMコマンドを実行します:
{
"Version": 57,
"Tier": "Standard"
}
{
"AutomationExecutionId": "2c4048af-a785-4040-88b5-085c7a910845"
}
AWS SSMコマンドの実行が完了しました!
尾嵜から承認をもらってください
ok
Log集約アカウントにログインして、パラメーターを送信します
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:
Successfully logged into Start URL: https://d-xxxxxxxxxx.awsapps.com/start#/
SSOログインチェック完了: log-profile
{
"Version": 50,
"Tier": "Standard"
}
パラメーターの送信が完了しました!
3.Slackに申請内容が通知されます。
4.SSO管理アカウント内でSSM Automationが実行されて、Slackに承認メールが届きます。 承認メールの通知先はSSM Automationで変更できます。
5.承認者はSSO管理アカウントにログインして、申請をApproveします。
6.承認とともにEventBridgeが起動して、Admin権限付与のLambdaが実行されます。
EventBridgeはSSMオートメーションで作成されたSchedulerで、実行後に解除されます。
SSMオートメーションの実行を確認してみましょう。
https://ap-northeast-1.console.aws.amazon.com/systems-manager/automation/executions
実行されたオートメーションのActionステータスがSuccessになってますね。
7.申請したユーザーに対して一時的にAdmin権限が付与され、Slackに権限が付与されたことが通知されます。
Slackに通知が来ました!
SSOにAdmin権限が付与されてます。
Admin権限でログインして、適当にIAMロールの作成と削除を行なってみます。
8.使用時間が経過するとEventBridgeが起動して、Admin権限解除のLambdaが実行されます。
9.申請したユーザーのAdmin権限が解除され、Slackに権限が解除されたことが通知されます。
10.SQSにAdmin権限を使用した情報をキューイングして、ログ集約アカウントにメッセージを送ります。
メッセージが送られていることをSQSのNumberOfMessagesSentメトリクスから確認できます。
11.ログ集約アカウントで、メッセージの情報を元にAdmin権限の操作実行ログのクエリをするLambdaが実行されます。
Athenaのクエリ実行履歴を確認すると、CloudTrailのテーブルに対してクエリができていることが確認できます。
12.Athenaのクエリ結果が承認者のメンション付きでSlackに通知されます。
IAMロールの作成と解除のログが出力されてました。 エンティティをEC2にしていたので、内部的にインスタンスプロフィルが作成されていました。
承認者はログに問題ないかを確認します。
無事にAdmin権限の付与と解除が正しく行われました!
ログが出てどんな操作をしたのかが可視化されたので、操作に問題があった場合はすぐに気づけそうです!
参考にしたサイト
まとめ
弊社では本番環境においては、CloudFormationの操作権限とその他閲覧権限しか与えておらず、それ以外の操作を行う際は必ずチケット作成や権限承認が必要となり、アカウント操作の運用ルールを厳格に定めています。
強めの権限がある程度自由に使えてしまうというのは、意外にやりがちな運用方法なのではないかなと思います( ´△`)
そこをしっかりと仕組み化して運用ルールを決めることによって、ミスオペレーションをできるだけ減らし、より信頼性の高いサービスの運用を行うことができます。
ただ、権限を絞りすぎると却って運用コストが高くなってしまうということもあり得るので、そこはバランスをとりつつ信頼性を担保していく必要はありそうですね( ・∇・)
この記事でみなさんのサービスの信頼性が少しでも高まることができれば幸いです。
ではまた!
この記事が気に入ったらサポートをしてみませんか?