AWSでアクセスキーが漏洩した時に検知・削除する仕組みを実装する

# 初めに
IAMのアクセスキーが漏洩してしまった際に、漏洩を検知して対象のIAMアクセスキーを削除する仕組みを作る必要があったのでその内容について記載します。

# 構成
Trusted Adviserのルールを利用してEventBridegeで検知し、SNSを利用して通知し、Step FunctionsとLambdaで検知したIAMアクセスキーを削除します。
構成としては以下のようになります。
※この構成はTrusted Adviserがバージニア北部リージョンでしか情報を取得できない関係で、バージニア北部リージョンで作成する必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517194/ee99a603-7eb6-eb57-b543-f3fc20802a8e.png)


今回は以下のTrusted Advisor toolsを参考にしました。

https://github.com/aws/Trusted-Advisor-Tools/tree/master/ExposedAccessKeys

# Trusted Adviser
Trusted Adviserでは有効化しておけば特に設定しておくことはないです。
「漏洩したアクセスキー」のルールを使用してIAMアクセスキーの漏洩を検知します。
以下は「漏洩したアクセスキー」のルールの内容です。

>・一般的に漏洩してしまったアクセスキーおよび悪用されたアクセスキーが原因で発生するAmazon Elastic Compute Cloud (Amazon EC2) の不規則な使用状況について、頻繁に利用されているコードリポジトリをチェックします。アクセスキーは、アクセスキー ID とそれに対応するシークレットアクセスキーで構成されています。漏洩したアクセスキーは、ユーザーのアカウントとその他ユーザーに対するセキュリティリスクになり、許可されていない行為につながる場合があります。その上、乱用から生じる法外な料金の原因となり、AWS カスタマーアグリーメント違反となる可能性があります。アクセスキーが漏洩した場合は、直ちにアカウントのセキュア化対策を講じてください。漏洩されたアクセスキーが特定された場合、法外な料金の発生帽子のため、特定の AWS のリソース作成機能を一時的に制限します。これはアカウントを保護するものではなく、ユーザーに課金される可能性がある不正使用を部分的に制限するのが目的です。注意: このチェックは、漏洩されたアクセスキーまたは悪用された EC2 インスタンスの特定を保証するものではありません。アクセスキーと AWS のリソースの安全とセキュリティに対する最終的な責任はユーザーにあります。
>アクセスキーに期限が表示されている場合、指定期限日までに不正使用が停止されないとユーザーの AWS アカウントを停止することがあります。アラートがエラーに起因するとお考えの場合は、AWS サポートまでご連絡ください。
>Trusted Advisor に表示される情報にはアカウントの最新状態を反映していない場合があります。漏洩されたアクセスキーは、アカウント上のすべての漏洩されたアクセスキーが解決されるまで解決済みとしてマーク付けされません。データの同期には最大 1 週間かかる場合があります。
・アラート基準
赤色: 悪用の可能性 – AWS は、インターネット上で漏洩し、悪用 (使用) された可能性があるアクセスキー ID と、対応するシークレットアクセスキーを特定しました。
赤色: 漏洩 – AWS は、インターネット上で漏洩したアクセスキー ID と、対応するシークレットアクセスキーを特定しました。
赤色: 悪用の疑い – Amazon EC2 の不規則な使用状況が、アクセスキーが悪用された可能性を示していますが、インターネット上での漏洩は特定されていません。
・推奨されるアクション
対象のアクセスキーをできる限り早急に削除してください。キーが IAM ユーザーに関連付けられている場合は、「IAM ユーザーのアクセスキーの管理」を参照してください。
不正使用についてアカウントをチェックします。AWS マネジメントコンソールにログインし、疑わしいリソースについて各サービスコンソールをチェックします。実行中の Amazon EC2 インスタンス、スポットインスタンスリクエスト、アクセスキー、および IAM ユーザーには特に注意を払ってください。請求とコスト管理ダッシュボードで全体的な使用状況をチェックすることもできます。

# EventBridge
EventBridgeではTrusted Adviserのアクセスキー漏洩のルールを契機にStep FunctionsとSNSを起動する設定でルールを作成します。
イベントパターンには以下の設定を行い、アクセスキー漏洩ルールがエラーになった場合にEventBridgeを起動するようにします。
ターゲットには後述するSNSとStepFunctionsを設定しておきます。

```
{
  "source": ["aws.trustedadvisor"],
  "detail-type": ["Trusted Advisor Check Item Refresh Notification"],
  "detail": {
    "status": ["ERROR"],
    "check-name": ["漏洩したアクセスキー"]
  }
}
```

# SNS
通知先としてSNSトピックを作成します。
特に特別な設定は必要ないです。作成したら通知先をサブスクリプションに登録しておきます。

# Step Fucntions
EventBridgeから通知を受け取り、Lambdaを起動するStep Functionsを作成します。
ここでStepFunctionsを挟むのは漏洩したアクセスキーの情報を変数として受け取るためです。
以下の定義でStepFunctionsを作成します。

```
{
  "Comment": "Deletes exposed IAM access keypairs and notifies security",
  "StartAt": "DeleteAccessKeyPair",
  "States": {
    "DeleteAccessKeyPair": {
      "Type": "Task",
      "Resource": "<LambdaのARNを指定>",
      "End": true
    }
  }
}
```

# Lambda
Step Functionsから通知を受け取り、漏洩したアクセスキーの削除を実行するLambdaを作成します。
以下の内容でLambdaを作成します。
ランタイムはPython3.8を使用しています。


```
import boto3

iam = boto3.client('iam')


def lambda_handler(event, context):
    account_id = event['account']
    time_discovered = event['time']
    details = event['detail']['check-item-detail']
    username = details['User Name (IAM or Root)']
    access_key_id = details['Access Key ID']
    exposed_location = details['Location']
    print('Deleting exposed access key pair...')
    delete_exposed_key_pair(username, access_key_id)
    return {
        "account_id": account_id,
        "time_discovered": time_discovered,
        "username": username,
        "deleted_key": access_key_id,
        "exposed_location": exposed_location
    }


def delete_exposed_key_pair(username, access_key_id):
    """ Deletes IAM access key pair identified by access key ID for specified user.
    Args:
        username (string): Username of IAM user to delete key pair for.
        access_key_id (string): IAM access key ID to identify key pair to delete.
    Returns:
        (None)
    """
    try:
        iam.delete_access_key(
            UserName=username,
            AccessKeyId=access_key_id
        )
    except Exception as e:
        print(e)
        print('Unable to delete access key "{}" for user "{}".'.format(access_key_id, username))
        raise(e)
```

# 検証
アクセスキーを実際に漏洩させるわけにはいかないので、今回はStep Functionsから変数を渡して実行する形でLambdaでアクセスキーの削除ができるか確認します。
まずはテスト用IAMアクセスキーを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517194/76faf22b-c67c-7698-478c-c6a402dbc575.png)

次にStep Functionsから実行を行います。
入力値に以下の値を入力します。
「test-user」の部分には削除対象のアクセスキーを持つIAMユーザー名を、「ACCESS_KEY_ID_HERE」には削除対象のアクセスキーIDを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517194/e4b9d903-6d81-2942-ec9f-a4cb7bec2539.png)

```
{
    "version": "0",
    "id": "f2b7e2dd-20ce-4a2b-baa8-fe24ed0be19a",
    "detail-type": "Trusted Advisor Check Item Refresh Notification",
    "source": "aws.trustedadvisor",
    "account": "111222333444",
    "time": "2017-06-10T03:16:34Z",
    "region": "us-east-1",
    "resources": [],
    "detail": {
        "check-name": "Exposed Access Keys",
        "check-item-detail": {
            "Case ID": "02648f3b-e18f-4019-8d68-ce25efe080ff",
            "Usage (USD per Day)": "0",
            "User Name (IAM or Root)": "test-user",
            "Deadline": "1440453299248",
            "Access Key ID": "ACCESS_KEY_ID_HERE",
            "Time Updated": "1497064411198",
            "Fraud Type": "Exposed",
            "Location": "www.github.com/some_user/some_repo/some_file"
        },
        "status": "ERROR",
        "resource_id": "",
        "uuid": "cce6d28f-e44b-4e61-aba1-5b4af96a0f59"
    }
}
```

実行すると処理が完了し、アクセスキーが削除されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517194/ad360b83-4bde-32bd-abbc-42b3e94ec3be.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517194/700cb052-db6e-538a-6bf0-13065f36ed88.png)

# 参考
冒頭にも記載しましたが、今回は以下のTrusted Advisor toolsを参考にしました。

https://github.com/aws/Trusted-Advisor-Tools/tree/master/ExposedAccessKeys

# 終わりに
アクセスキーの漏洩はAWSの操作権限が流出してしまうことになるので非常に危険なリスクであると思います。
そのため可能であれば対策しておくことが必要だと思います。
少しでも参考になれば幸いです。