🐷

特定 CloudTrail イベント発生時 Lambda を実行

2023/02/27に公開

ゴール / やりたいこと

CloudTrail で 特定イベントがあった場合に Lambda を実行する
※今回は作成/更新されたポリシー内でリソース * に対してアクションが Allow とされているかのチェック

アーキテクチャ図

詳細

監視している CloudTrail で CloudWatch Logs へのログ保存を有効にする

CloudWatch Logs で Lambda をターゲットとしたサブスクリプションフィルターを作成する

ターゲットにする Lambda を指定して Filter 設定をする
※Log format は CloudTrail にして Filter 対象はイベント名がCreatePolicyまたはPutRolePolicy

https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/FilterAndPatternSyntax.html

Lambda コード詳細

import base64, json

def lambda_handler(event, context):

    print(event)
    # CloudWatchLogsからのデータはbase64エンコードされているのでデコード
    decoded_data = base64.b64decode(event['awslogs']['data'])
    # バイナリに圧縮されているため展開
    json_data = json.loads(gzip.decompress(decoded_data))
    
    # CloudWatch Logsに複合&解凍したログを出力
    print("--- Base Log ---")
    BaseLog = json_data["logEvents"][0]["message"]
    print(BaseLog)

    CustomLog = json.loads(BaseLog)
    print("--- Customize Log ---")
    User = CustomLog["userIdentity"]["arn"]
    PolicyName = CustomLog["requestParameters"]["policyName"]
    print("User: " + User)
    print("Policy Name: " + PolicyName)
    eventname = CustomLog["eventName"]
    Username = User.split("/")[2]
    print(Username)
    URLorigin = "https://us-east-1.console.aws.amazon.com/iam/home?region=us-east-1#/policies/"
    URLPOLICY = CustomLog["responseElements"]["policy"]["arn"]
    
    doc = json.loads(CustomLog["requestParameters"]["policyDocument"])
    Document = str(doc["Statement"])
    for i in range(len(doc["Statement"])):
        Resource =  doc["Statement"][i]["Resource"]
        Effect = doc["Statement"][i]["Effect"]
        print(i)
        print("Policy Document: " + Document)
        print("Resource Parameter: " + Resource)
        if "*" == Resource and "Allow" == Effect:
              print(PolicyName)
              print(eventname)
              post_msg = "イベント名: "+ eventname + "\r \nポリシー名: "+ PolicyName + "\r \nユーザー名:" + Username + "\r \n注意: フルアクセス権限のままのポリシーがあります"+"\r \n please see the URL : " + URLorigin + URLPOLICY
              title = "フルアクセスイベント検知"
              seeURL = "plese see the URL : " + URLorigin+URLPOLICY

CloudWatch Logs から送られるイベントの内容

送られる実データ

https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-cloudwatch-filter/

{
  "awslogs": {
    "data": "H4sIAAAAAAAAAHWPwQqCQBCGX0Xm7EFtK+smZBEUgXoLCdMhFtKV3akI8d0bLYmibvPPN3wz00CJxmQnTO41whwWQRIctmEcB6sQbFC3CjW3XW8kxpOpP+OC22d1Wml1qZkQGtoMsScxaczKN3plG8zlaHIta5KqWsozoTYw3/djzwhpLwivWFGHGpAFe7DL68JlBUk+l7KSN7tCOEJ4M3/qOI49vMHj+zCKdlFqLaU2ZHV2a4Ct/an0/ivdX8oYc1UVX860fQDQiMdxRQEAAA=="
  }
}

["awslogs"]["data"] を base64 ででコードしたもの

{
    "messageType": "DATA_MESSAGE",
    "owner": "xxx",
    "logGroup": "aws-cloudtrail-logs-xxx",
    "logStream": "xxx_CloudTrail_ap-northeast-1_3",
    "subscriptionFilters": [
        "test"  # サブスクリプションフィルター名
    ],
    "logEvents": [
        {
            "id": "37408450509333532446236020242338017431792257269505589323",
            "timestamp": 1677452936048,
            "message": "~~~"  # 以下 CloudTrail のログが含まれる
        }
    ]
}

CloudTrail のログ

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "xxx",
        "arn": "arn:aws:sts::xxx:assumed-role/xxx/xxx",
        "accountId": "xxx",
        "accessKeyId": "xxx",
        "sessionContext": {
            "sessionIssuer": {
                "type": "Role",
                "principalId": "xxx",
                "arn": "arn:aws:iam::xxx:role/xxx",
                "accountId": "xxx",
                "userName": "xxx"
            },
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2023-02-26T04:46:10Z",
                "mfaAuthenticated": "false"
            }
        }
    },
    "eventTime": "2023-02-26T06:26:27Z",
    "eventSource": "iam.amazonaws.com",
    "eventName": "CreatePolicy",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "x.x.x.x",
    "userAgent": "AWS Internal",
    "requestParameters": {
        "policyName": "test",
        "policyDocument": "{\n    \"Version\": \"2012-10-17\",\n    \"Statement\": [\n        {\n            \"Sid\": \"VisualEditor0\",\n            \"Effect\": \"Allow\",\n            \"Action\": \"ec2:*\",\n            \"Resource\": \"*\"\n        }\n    ]\n}",
        "tags": [
            {
                "key": "xxx",
                "value": "xxx"
            }
        ]
    },
    "responseElements": {
        "policy": {
            "policyName": "test",
            "policyId": "xxx",
            "arn": "arn:aws:iam::xxx:policy/test",
            "path": "/",
            "defaultVersionId": "v1",
            "attachmentCount": 0,
            "permissionsBoundaryUsageCount": 0,
            "isAttachable": true,
            "createDate": "Feb 26, 2023 6:26:27 AM",
            "updateDate": "Feb 26, 2023 6:26:27 AM",
            "tags": [
                {
                    "key": "xxx",
                    "value": "xxx"
                }
            ]
        }
    },
    "requestID": "4aa1660e-f5c4-45b0-9e6f-2c62869e9013",
    "eventID": "9b2ea1bc-28e8-4e24-9371-eede765a5df0",
    "readOnly": false,
    "eventType": "AwsApiCall",
    "managementEvent": true,
    "recipientAccountId": "333053306512",
    "eventCategory": "Management",
    "sessionCredentialFromConsole": "true"
}

Logs Insights

CloudWatch Logs に対して簡単な Filter でクエリできて整形して表示してくれる
めちゃくちゃ便利だった

クエリ

実行結果

Discussion