본문 바로가기

AWS Lambda ƛ/⚡ 자동태깅

CloudTrail 정보를 활용하여 AWS Lambda로 개발하기

# CloudTrail에서 넘어오는 정보를 활용하여 AWS Lambda로 개발하기

1. 시나리오 작성하기

- 시나리오를 짜보면 아래와 같다.

일단 김 짱구라는 AWS 사용자가 존재한다.

김 짱구 라는 사용자는 인스턴스를 생성하면 자동으로 누가 해당 인스턴스를 만들었는지 그리고 EBS에 생성한 사용자와 인스턴스 id 를 자동으로 태깅하고 싶었다.

2. 작업시작하기

- 일단 인스턴스가 생성될때 태깅을 해야하므로 특정한 사용자가 인스턴스를 생성 했다 라는 정보를 어디선가 가져와야 한다. 가장 일반적으로 CloudTrail은 해당 계정의 AWS 리소스의 거의 모든 생성 및 변경 그리고 삭제 내역에 대한 정보를 가지고 있으므로 인스턴스가 생성될때 발생하는 이벤트 정보를 당연히 가져올 수 있다.

그럼 인스턴스가 생성될때 발생하는 이벤트 이름은 뭘까? CloudTrail에서 조회해보면 RunInstances 라는 항목을 확인 할 수있다. 해당 이벤트 이름이 바로 인스턴스를 생성할때 발생하는 이벤트 이름이다.

- 이 이벤트 이름이 EventBaridge에 이벤트 패턴 규칙 이름과 동일해야 이벤트 브릿지에서 동작한다.

3. CloudTrail의 RunInstances 데이터를 보면 아래와 같다.

- 일부만 발췌해서 보면 아래와 같다.

{
    "eventVersion": "1.08",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "AAAAAAAAAAAAAAA",
        "arn": "arn:aws:iam::123456789101:user/seungkim",
        "accountId": "123456789101",
        "accessKeyId": "AAAAAAAAAAAAAAA",
        "userName": "seungkim",
        "sessionContext": {
            "sessionIssuer": {},
            "webIdFederationData": {},
            "attributes": {
                "creationDate": "2023-08-03T04:34:10Z",
                "mfaAuthenticated": "false"
            }
        }
    },
    "eventTime": "2023-08-03T04:36:27Z",
    "eventSource": "ec2.amazonaws.com",
    "eventName": "RunInstances",
    "awsRegion": "ap-northeast-2",
    "sourceIPAddress": "210.207.40.218",
    "userAgent": "AWS Internal",
    "requestParameters": {
        "instancesSet": {
            "items": [
                {
                    "imageId": "ami-0000000000000000",
                    "minCount": 1,
                    "maxCount": 1,
                    "keyName": "Auto-Tagging-Test"
                }
            ]
        },
        "instanceType": "t2.micro",
        "blockDeviceMapping": {},
        "monitoring": {
            "enabled": false
        },
        "disableApiTermination": false,
        "disableApiStop": false,
        "clientToken": "11111111-1111-111-1111-1111111111",
        "networkInterfaceSet": {
            "items": [
                {
                    "deviceIndex": 0,
                    "subnetId": "subnet-0",
                    "associatePublicIpAddress": true,
                    "groupSet": {
                        "items": [
                            {
                                "groupId": "sg-0"
                            }
                        ]
                    }
                }
            ]
        },
        "ebsOptimized": false,
        "tagSpecificationSet": {
            "items": [
                {
                    "resourceType": "instance",
                    "tags": [
                        {
                            "key": "Name",
                            "value": "Auto-Tagging-Test"
                        }
                    ]
                }
            ]
        },
...
...
...

4. Lambda에서 동작하는 절차 확인하기.

해당 RunInstances의 데이터 값을 람다에서 받아서 처리하는 절차에 대해서 간략하게 알아보면 아래와 같다.

위의 RunInstacnes json 데이터를 보면 userIdentity 항목이 보일 것이다. 해당 정보를 가지고 사용자 정보를 가져오는 람다 코드는 아래와 같다.

아래의 코드에서 궁금했던 것이 바로 if 'detail' in event: 이부분 이었다. detail이 도대체 어디 있는건가 한참을 찾았는데, 이벤트 브릿지에 있었다. 이벤트 패턴을 보면 "detail"이 보인다. 해당 이벤트 패턴이 람다를 실행할때 CloudTrail 데이터와 같이 넘어오는 것 같다.

어쨌든 람다 코드를 보면 아래와 같다.

...
def lambda_handler(event, context):
    if 'detail' in event:
        try:
            if 'userIdentity' in event['detail']:
                if event['detail']['userIdentity']['type'] == 'AssumedRole':
                    user_name = str(
                        'UserName: ' + event['detail']['userIdentity']['principalId'].split(':')[1] + ', Role: ' +
                        event['detail']['userIdentity']['sessionContext']['sessionIssuer']['userName'] + ' (role)')
                elif event['detail']['userIdentity']['type'] == 'IAMUser':
                    user_name = event['detail']['userIdentity']['userName']
                elif event['detail']['userIdentity']['type'] == 'Root':
                    user_name = 'root'
                else:
                    logging.info('유저 이름을 정의할 수 없습니다. (unknown iam userIdentity) ')
                    user_name = ''
            else:
                logging.info('유저 이름을 정의할 수 없습니다. (no userIdentity data in cloudtrail')
                user_name = ''
        except Exception as e:
            logging.info('유저 이름을 찾을 수 없습니다., exception: ' + str(e))
            user_name = ''
...

위의 코드를 보면 아마 event 부분에 이벤트브릿지의 이벤트 패턴 정보와 CloudTrail에서 RunInstances 정보가 담겨서 넘어 오는것 같다.

그래서 위의 람다 코드와 그 위에 CloudTrail json 데이터를 보면 충분히 프로그래밍 가능하다는것을 알 수 있다.

어떤 식으로 데이터를 가져와서 AWS 리소스 수정을 하는지 궁금했었는데 다소 궁금증이 해결이 되었다.

 

- 끝 -