LoginSignup
0
0

More than 1 year has passed since last update.

AWS IAMで未使用者のアクセスキーを無効する

Last updated at Posted at 2022-07-29

背景

AWS認定資格の学習中に、「未使用期間が90日以上経過したIAMユーザーのユーザーアクセスキーを無効する作業を自動化するには?」という問題がありました。
AWSの設定のみで実現できないルーチンワーク的なセキュリティ処理をLambda関数などで作成するという解答はAWS認定試験の問題集などに散見されるのですが、具体的にどうやるのかの情報があまりヒットしないので、自分で作って確認してみることにしました。

目次

  1. 選択肢
  2. 実現方法
  3. 参考文献

選択肢

  1. 管理コンソールのIAMサービスからIAMユーザーの利用状況をダウンロードし、90日以上経過したユーザーをピックアップし、無効化する
    手動操作、および目視確認のため、自動化には程遠い
      →却下
  2. AWS CLIで以下のコマンドを実行する
    $ aws iam generate-credential-report
	$ aws iam get-credential-report
    $ aws iam update-access-key

取得した認証情報はbase64でエンコードされたテキストファイルで取得できるが、そのファイルをテキスト抽出し、更にCLIコマンドを実施するのは結構労力を要する。
そもそもアクセスキー、シークレットキーの管理が必要でセキュリティ的に不向きに思われる。
 →却下

3. AWS SDKでのGenerateCredentialReportでレポート作成後、GetCredentialReportでダウンロードし、UpdateAccesskeyを使用して無効化する
 →こちらが正解

実現方法

実装環境

  1. AWS CloudShell上にpython3.8をインストールする
  2. boto3などライブラリをインストール
  3. 実装する

実装したコード

※参照する列が間違ってたので修正しました。
CSVで出力される列の「access_key_1_last_rotated」で取得される日付が90日以上経過している場合にアクセスキーを無効にする処理を実施しています。
GenerateCredentialReport/GetCredentialReport/UpdateAccesskeyの利用例の一例ですが、ご使用は自己責任でお願いします。

inactive_unused_access_key_.py
import sys
import time
import boto3
from datetime import timedelta
from datetime import datetime as dt
from botocore.exceptions import ClientError

iam = boto3.resource('iam')

def generate_credential_report():
    try:
        response = iam.meta.client.generate_credential_report()
    except ClientError:
        print("Couldn't generate a credentials report for your account.")
        raise
    else:
        return response

def get_credential_report():
    try:
        response = iam.meta.client.get_credential_report()
        print(response['Content'])
    except ClientError:
        print("Couldn't get credentials report.")
        raise
    else:
        return response['Content']

def suspend_user(username):
	update_res = []
	check_access_keys = iam.meta.client.list_access_keys(UserName=username)
	for key_lists in check_access_keys['AccessKeyMetadata']:
	    print()
	    res = iam.meta.client.update_access_key(UserName=username, AccessKeyId=key_lists['AccessKeyId'], Status='Inactive')
	    update_res.append(res)
	return update_res

def inactive_unused_access_key():
    print("Let's generate a credentials report...")
    report_state = None
    while report_state != 'COMPLETE':
        cred_report_response = generate_credential_report()
        old_report_state = report_state
        report_state = cred_report_response['State']
        if report_state != old_report_state:
            print(report_state, sep='')
        else:
            print('.', sep='')
        sys.stdout.flush()
        time.sleep(1)

    USER = 0
    ACCESS_KEY_1_LAST_ROTATED = 9
    cred_report = get_credential_report()
    col_count = ACCESS_KEY_1_LAST_ROTATED + 1
    print(f"Got credentials report. Showing only the first {col_count} columns.")
    cred_lines = [line.split(',')[:col_count] for line in cred_report.decode('utf-8').split('\n')]


    col_width = max([len(item) for line in cred_lines for item in line]) + 2
    today = dt.today()

    for line in cred_report.decode('utf-8').split('\n'):
        if line.split(',')[ACCESS_KEY_1_LAST_ROTATED] == "access_key_1_last_rotated" or line.split(',')[ACCESS_KEY_1_LAST_ROTATED] == "N/A" :
            continue
        else:
            date = line.split(',')[ACCESS_KEY_1_LAST_ROTATED]
            lastloginday = dt.strptime(date[0:9], '%Y-%m-%d')

            if  lastloginday < (today - timedelta(days=90)):
                print(line.split(',')[USER] + "is not used. Update access key to inactive. ")
                suspend_user(line.split(',')[USER])

if __name__ == '__main__':
    inactive_unused_access_key()

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0