Skip to content
Advertisement

Parsing JSON in AWS Lambda Python

For a personal project I’m trying to write an AWS Lambda in Python3.9 that will delete a newly created user, if the creator is not myself. For this, the logs in CloudWatch Logs will trigger (via CloudTrail and EventBridge) my Lambda. Therefore, I will receive the JSON request as my event in :

def lambdaHandler(event, context)

But I have trouble to parse it…

If I print the event, I get that :

{'version': '1.0', 'invokingEvent': '{
        "configurationItemDiff": {
            "changedProperties": {},
            "changeType": "CREATE"
        },
        "configurationItem": {
            "relatedEvents": [],
            "relationships": [],
            "configuration": {
                "path": "/",
                "userName": "newUser",
                "userId": "xxx",
                "arn": "xxx",
                "createDate": "2022-11-23T09:02:49.000Z",
                "userPolicyList": [],
                "groupList": [],
                "attachedManagedPolicies": [],
                "permissionsBoundary": null,
                "tags": []
            },
            "supplementaryConfiguration": {},
            "tags": {},
            "configurationItemVersion": "1.3",
            "configurationItemCaptureTime": "2022-11-23T09:04:40.659Z",
            "configurationStateId": 1669194280659,
            "awsAccountId": "141372946428",
            "configurationItemStatus": "ResourceDiscovered",
            "resourceType": "AWS::IAM::User",
            "resourceId": "xxx",
            "resourceName": "newUser",
            "ARN": "arn:aws:iam::xxx:user/newUser",
            "awsRegion": "global",
            "availabilityZone": "Not Applicable",
            "configurationStateMd5Hash": "",
            "resourceCreationTime": "2022-11-23T09:02:49.000Z"
        },
        "notificationCreationTime": "2022-11-23T09:04:41.317Z",
        "messageType": "ConfigurationItemChangeNotification",
        "recordVersion": "1.3"
    }', 'ruleParameters': '{
        "badUser": "arn:aws:iam::xxx:user/badUser"
    }', 'resultToken': 'xxx=', 'eventLeftScope': False, 'executionRoleArn': 'arn:aws:iam: : xxx:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig', 'configRuleArn': 'arn:aws:config:eu-west-1: xxx:config-rule/config-rule-q3nmvt', 'configRuleName': 'UserCreatedRule', 'configRuleId': 'config-rule-q3nmvt', 'accountId': 'xxx'
}

And for my purpose, I’d like to get the "changeType": "CREATE" value to say that if it is CREATE, I check the creator and if it is not myself, I delete newUser.

So the weird thing is that I copy/paste that event into VSCode and format it in a .json document and it says that there are errors (line 1 : version and invokingEvent should be double quote for example, but well).

For now I only try to reach and print the

"changeType": "CREATE"

by doing :

import json
import boto3
import logging

iam = boto3.client('iam')

def lambda_handler(event, context):
    """
    Triggered if a user is created
    Check the creator - if not myself :
    - delete new user and remove from groups if necessary
    """
    
    try:
        print(event['invokingEvent']["configurationItemDiff"]["changeType"])
    except Exception as e:
        print("Error because :")
        print(e)

And get the error string indices must be integers – it happens for ["configurationItemDiff"]. I understand the error already (I’m new to python though so maybe not completely) and tried many things like :

  • print(event['invokingEvent']['configurationItemDiff']) : swapping double quote by simple quote but doesnt change anything
  • print(event['invokingEvent'][0]) : but it gives me the index { and [2] gives me the c not the whole value.

At this point I’m stuck and need help because I can’t find any solution on this. I don’t use SNS, maybe should I ? Because I saw that with it, the JSON document would not be the same and we can access through ["Records"][...] ? I don’t know, please help

Advertisement

Answer

What you are printing is a python dict, it looks sort of like JSON but is not JSON, it is the representation of a python dict. That means it will have True / False instead of true / false, it will have ‘ instead of “, etc.

You could do print(json.dumps(event)) instead.

Anyway, the actual problem is that invokingEvent is yet another JSON, but in its string form, you need to to json.loads that nested JSON string. You can see that because the value after invokingEvent is inside another set of '...', therefore it is a string, not a parsed dict already.

invoking_event = json.loads(event['invokingEvent'])
change_type = invoking_event["configurationItemDiff"]["changeType"]

ruleParameters would be another nested JSON which needs parsing first if you wanted to use it.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement