AWS上で稼働する本番環境用のIAMUserを必要な時だけ活性化するための仕組みの検討
この記事では、AWS上で稼働する本番環境用のIAMUserを必要な時だけ活性化するための仕組みについて検討します。
本番環境を保守運用する上ではIAMUserが必要になりますが、保守運用のためのIAMUserの中にはAdministrator Access権限など強い権限を持つユーザが存在するケースも多く、不正な手段で窃取された際のセキュリティ上のリスクが高いです。
この対応として、本番環境用のIAMUserを必要な時だけ活性化する仕組みを検討します。
本番環境用のIAMUserを必要な時だけ活性化するための仕組み
前提
今回の構成において考えているIAMの前提は以下です。
- IAMUser自体には何のIAMPolicyも付与せず権限を持たない
- AccessKeyの払い出しは一切行わなず、IAMUserを利用するにあたってマネジメントコンソールを用いる以外の方法はない
- IAMGroupに対して作業に必要な権限を付与する
→IAMUserは適切なIAMGroupに所属することえで初めて作業が可能な状態になる
フローと構成
本番環境用のIAMUserを必要な時だけ活性化するための仕組みは、以下のような処理フローとなります。
1. 作業者がIAMUserを用いてマネジメントコンソールへログインする
2. AWS CloudTrailを有効化し、本番環境のマネジメントコンソールにログインした際にそれを検知する
3. Amazon EventBridgeにてCloudTrailからマネジメントコンソールへのログインを検知する
4. Amazon EventBridgeがAWS Lambda関数を実行する
5. AWS Lambda関数の処理の中でログインしたIAMUserの情報と、そのIAMUserに権限を付与してよいか確認する通知をSNSを用いてシステム管理者にメールする
6. (作業者の手動作業)作業者がシステム管理者に対してメール通知がされていることと承認の依頼を行う
7. (システム管理者の手動作業)作業が予定されたものであることを確認の上、SNS通知メールの中に含まれるURLをクリックする→URLはAmazon API Gateway向けのURL
8. Amazon API Gatewayから実行されたLambda関数によってIAMUserがIAMGroupに所属するための処理が行われる
No8の処理が完了することによってIAMUserがIAMGroupに所属することで作業者は作業が可能となります。
上記を実現する具体的な構成図は以下の通りです。
この構成図に記載の通り、IAMUserで本番作業を行うにあたってシステム管理者の承認という行為を経る必要があるため、仮にIAMUser情報が悪意ある第三者に不正窃取されたとしても本番環境作業される恐れはなくなります。
コードサンプル
EventBridgeから起動されSNS通知を行うためのLambda関数:
import json
import os
import boto3
sns_client = boto3.client('sns')
def handler(event, context):
print(event)
# EventBridgeからのイベントを解析
detail = event.get('detail', {})
# JSONからarnを取得
arn = event.get('detail', {}).get('userIdentity', {}).get('arn', '')
# arnからメールアドレス部分を抽出
user_name = arn.split('/')[-1]
# 特定のURLを含むメッセージを作成
url = "https://<fqdn>/prod/add-to-group/{}".format(user_name)
message = f"User {user_name} has logged into the AWS Management Console. If this is a scheduled task, please click this URL: {url}"
# SNSトピックARNを環境変数から取得
sns_topic_arn = os.environ['SNS_TOPIC_ARN']
# SNSでメール通知を送信
response = sns_client.publish(
TopicArn=sns_topic_arn,
Message=message,
Subject='AWS Management Console Login Alert'
)
return {
'statusCode': 200,
'body': json.dumps('Notification sent successfully')
}
Amazon API Gatewayから起動されIAMUserを特定のIAMGroupに所属させるためのLambda関数:
import json
import boto3
import os
iam_client = boto3.client('iam')
def lambda_handler(event, context):
# API Gatewayからのイベントを解析
path_parameters = event.get('pathParameters', {})
user_name = path_parameters.get('proxy', '')
if not user_name:
return {
'statusCode': 400,
'body': json.dumps('User name not provided in the path')
}
# IAMグループ名を環境変数から取得
iam_group_name = os.environ['IAM_GROUP_NAME']
try:
# IAMユーザーを特定のIAMグループに追加
response = iam_client.add_user_to_group(
GroupName=iam_group_name,
UserName=user_name
)
return {
'statusCode': 200,
'body': json.dumps(f'User {user_name} added to group {iam_group_name} successfully')
}
except iam_client.exceptions.NoSuchEntityException:
return {
'statusCode': 404,
'body': json.dumps(f'User {user_name} or group {iam_group_name} not found')
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps(f'Error adding user to group: {str(e)}')
}
API Gateway上の設定:
パス: /add-to-group/{proxy+}
Lambdaプロキシ統合を有効にする
作業後の無効化処理について
ここまで記載した内容を実装することで作業時にIAMUserを活性化することが可能になります。
しかし、この状況では一度活性化されたIAMUserはずっとIAMGroupに所属し続けることとなってしまいますので、IAMUserが活性化された状態で本番環境に対する作業を行った後、作業完了後に再度不活性化(IAMGroupからの対象IAMUserの除外)することが必要になります。
その点については以下のような方式が考えられます。
- 作業者が作業完了後に手動で対象のIAMGroupからの対象IAMUserの除外処理を実施する
- 作業開始から特定時間経過後に自動的にIAMGroupからの対象IAMUserの除外処理が行われるような仕組みを実装する
- 活性化と同様の仕組みとして不活性化の仕組みを実装し担当者による申請+システム管理者による承認を経て不活性化を行う
1点目は手動作業になりますので特別な実装を作りこむ必要がないという利点がある一方で作業漏れによりセキュリティ対策が有効に機能しないという大きなリスクがあります。
2点目は完全自動で行われるため作業負荷を増やすことなく対応が可能であるというメリットがあります。それに対してデメリットとしては30分や1時間程度の作業の場合でも特定時間(24時間等)内はずっと活性化された状態であるため、その時間帯はセキュリティ強度が弱くなってしまうという点があります。
3点目は作業の開始・終了をシステム管理者が厳格に管理でき、かつ必要な時間のみIAMUserを活性化させることができるというメリットがあるのに対し、1点目と同様に人手の作業が入るため作業漏れが発生するリスクがあります。
今回は無効化処理までの実装を行っていませんが、多少タイムラグが発生したとしても最終的には確実に不活性化処理が行えるという点を踏まえてこの案を採用することを想定し、2点目の方式について机上でのアーキテクチャ検討をしたいと思います。
これを実現するにあたっては以下2つの方式案が考えられます。
方式案①. AWS Step Functions利用案
この方式では活性化処理を行うLambda関数が処理の最後にAWS Step Functionsのマシンを起動します。
Step Functionsマシンのフローの中で24時間待機する処理の後Lambdaが実行されます。
このLambdaの役割は待機していた24時間の間に同一IAMUserで別作業が行われていないかどうかをチェックすることです。
1日の間に複数回同一IAMUserを用いて作業をするケースもあり得るかと思います。例えば作業をしてから23時間30分後(ギリギリ24時間に満たないぐらいのタイミング)に再度そのIAMUserを用いた作業を行った場合、本番作業の途中でこの不活性化処理が実行されてしまい本番作業ができなくなってしまうということが考えらるためこのチェックを入れています。
具体的なチェック方法としては過去24時間の間にCloudTrailでConsoleLogin処理が行われたかどうか、を確認することが妥当と考えています。
チェックの結果別作業が存在しない場合には後続で別のLambda関数を実行します。
このLambda関数は対象のIAMUserをIAMGroupから離脱させるというシンプルな処理です。これによりIAMUserは何の権限も持たない状態に戻ることになります。
方式案②. Amazon DynamoDB利用案
この方式では活性化処理を行うLambda関数が処理の最後にAmazon DynamoDBに対して対象のIAMUserとその活性化時刻情報を格納します。
それとは別に日次でAmazon EventBridgeからAWS Lambdaを実行し、そのLambda関数がDynamoDBに対してScanをおこない24時間経過したIAMUserのIAMGroupからの離脱を行います。
この場合も方式案①と同様に他の本番作業で対象のIAMUserを利用していないか確認が必要なので、DynamoDBのScanを行った後に対象のIAMUser情報が複数存在していないか、存在している場合にはその最新の時刻はいつなのかをチェックする必要があります。
方式案①と②については特に実装の難易度や実装にかかる工数負荷が大きく変わるものではないかと思いますので、実装する方のスキルセットに応じて選択頂くのが良いと考えています。
まとめ
この記事では、AWS上で稼働する本番環境用のIAMUserを必要な時だけ活性化するための仕組みについて詳細に解説しました。主な内容は以下の通りです:
- 本番環境用IAMUserのセキュリティリスクと、それを軽減するための仕組みの必要性
- IAMUserを必要時のみ活性化する具体的な構成と実装方法
- AWS CloudTrail、Amazon EventBridge、AWS Lambda、Amazon SNS、Amazon API Gateway、AWS WAFなどのAWSサービスを組み合わせた解決策
- 作業後のIAMUser無効化に関する複数の方式案とその比較
この記事は、主にAWS環境でのセキュリティ強化を検討しているシステム管理者やクラウドアーキテクトを対象としています。特に、本番環境のIAMユーザー管理に課題を感じている方々を想定して記事を作成しています。
この記事を参考にして頂くことで本番環境のセキュリティリスクを大幅に低減できると考えています。
また、特に日本企業においては本番環境の作業において厳格なプロセスを経て行うことが求められるケースがあるかと思いますので、そういった課題をクリアするための一助となれば幸いです。