How do I create an AWS Config rule for unsupported resource types?

6 minute read
0

I want to create a rule for a resource type that AWS Config doesn't support.

Short description

AWS Config allows you to create rules to verify if AWS resources comply with a specified configuration. By default, AWS Config supports a limited number of AWS resource types. However, you can create a custom AWS Config rule for unsupported resource types.

When you deploy a custom rule, AWS Lambda creates a function to evaluate the resources. Use this function to evaluate an unsupported resource type and return the compliance result to the custom rule.

Note: By default, AWS Config doesn't capture the historical configuration or compliance changes of unsupported resource types. To do this, complete the steps in Recording configurations for third-party resources, and create a rule that evaluates that custom resource type. For more information on recording and evaluating custom resources, see Using AWS Config custom resources to track any resource on AWS.

Resolution

Note: The following steps and code example create a custom AWS Config role to evaluate Amazon Cognito. This is an unsupported resource.

Prerequisites

Create an AWS Identity and Access Management (IAM) role for the Lambda function to allow Lambda to make the necessary API calls.

  1. Open the IAM console, and then choose Roles from the navigation pane.

  2. Choose Create role.

  3. For Choose a use case, under Common use cases, choose Lambda.

  4. Choose Next: Permissions.

  5. Choose Create policy.
    Note: The Create policy page opens in a new tab. You are returned to the original tab later in this process.

  6. Choose the JSON tab, and then enter this policy:

    {  "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "VisualEditor0",
          "Effect": "Allow",
          "Action": [
            "config:PutEvaluations",
            "cognito-idp:ListUserPools"
            "`cognito-idp:DescribeUserPool"`
          ],
          "Resource": "*"
        }
      ]
    }
  7. Choose Next: Tags, and then choose Next: Review.

  8. For Name, enter a policy name.

  9. Choose Create policy.

  10. Return to the Create role tab from step 5, and then choose the refresh icon on the right side of the policy list.

  11. Find and select the new policy name, and then choose Next: Tags.

  12. Choose Next: Review.

  13. For Role name, enter lambda-role.

  14. Choose Create role.

Create a Lambda function for the custom AWS Config rule

  1. Open the Lambda console.
  2. Choose Create function.
  3. Choose Author from scratch.
    For Function name, enter a name.
    For Runtime, select Python 3.8.
  4. For Permissions, expand Change default execution role.
    For Execution role, choose Use an existing role.
    For Existing role, choose the role that you created to allow Lambda to make the necessary API calls in the Prerequisites section of this article.
  5. Choose Create function.
  6. For Code source, open the lambda_function.py file in the Lambda console, replace the default code with the following, and then choose Deploy.
    Note: The following code example finds all the Amazon Cognito UserPools that have MFA: OFF, and marks the results as NON_COMPLIANT. For information and resources to customize this guidance for other unsupported services and objectives, see the article section PutEvaluations API and AWS::::Account resource type value.
    ## Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.// SPDX-License-Identifier: MIT-0
    
    import json
    import boto3
    
    def lambda_handler(event,context):
      cognito = boto3.client('cognito-idp')
      userpools = cognito.list_user_pools(
        MaxResults=5
        )
      userpool_list = userpools['UserPools']
      userpool_ids = []
      
      for i in userpool_list:
        userpool_ids.append(i['Id'])
      
      evaluations = []
      orderingtime = json.loads(event['invokingEvent'])['notificationCreationTime']
      
      for j in userpool_ids:
         userpool_describe = cognito.describe_user_pool(
            UserPoolId = j
          )
         userpool_MFA = userpool_describe['UserPool']['MfaConfiguration']
         if userpool_MFA == 'OFF':
           evaluations.append(
              {
              'ComplianceResourceType': 'AWS::::Account',
              'ComplianceResourceId': j,
              'ComplianceType': 'NON_COMPLIANT',
              'Annotation': 'Test',
              'OrderingTimestamp': orderingtime
              }
            )
         else:
           evaluations.append(
              {
              'ComplianceResourceType': 'AWS::::Account',
              'ComplianceResourceId': j,
              'ComplianceType': 'COMPLIANT',
              'Annotation': 'Test',
              'OrderingTimestamp': orderingtime
              }
            )
      
      result_token = event['resultToken']
      config = boto3.client('config')
      response = config.put_evaluations(
                  Evaluations = evaluations,
                  ResultToken = result_token,
                  TestMode = False
                )

This code performs three major steps:

  • Lists all resources to create an inventory
  • Evaluates each resource in the inventory against the specified configuration
  • Uses the PutEvaluations API call to AWS Config to return the compliance status

Create a custom periodic AWS Config rule

Create a custom periodic rule in AWS Config. Then, associate the custom rule with the Lambda function that you created in the previous section. For instructions, see Creating a Custom Lambda Rule to Evaluate Amazon EC2 Instances.

Important: Note the Amazon Resource Name (ARN) of the new custom rule for a later step.

Authorize the AWS Config service to invoke the Lambda function

  1. Open the Lambda console, and then choose Functions from the navigation pane.
  2. Choose the hyperlinked Function name for your Lambda function to open the function details.
  3. From the Configuration tab, choose Permissions.
  4. For Resource-based policy, choose Add permissions.
    For Policy statement, choose AWS service.
    For Service, choose Other.
    For Principal, enter config.amazonaws.com.
    For Source ARN, enter the ARN of the custom rule that you created in the previous section.
    Note: To find the custom rule ARN, open the AWS Config console, and then choose Rules from the navigation pane. Choose the hyperlinked rule Name, and then copy the Config rule ARN.
    For Action, choose lambda:InvokeFunction.
    For Statement ID, enter a unique ID.
  5. Choose Save.

PutEvaluations API and AWS::::Account resource type value

The steps and examples in this resolution find all the Amazon Cognito UserPools that have MFA: OFF and then mark the results as NON_COMPLIANT. However, you can modify the process to meet your specific requirements with any unsupported resource type. For more code examples that use the AWS::::Account resource type, see the aws-config-rules GitHub page.

The PutEvaluations API call includes the following parameters:

{   "Evaluations": [ 
    { 
     "Annotation": "string",
     "ComplianceResourceId": "string",
     "ComplianceResourceType": "string",
     "ComplianceType": "string",
     "OrderingTimestamp": number
    }
   ],
   "ResultToken": "string",
   "TestMode": boolean
}

For unsupported resource types, enter AWS::::Account as the value for ComplianceResourceType. The AWS::::Account resource type reports on the whole account instead of a specific resource:

{  'ComplianceResourceType': 'AWS::::Account',
  'ComplianceResourceId': 'Resource Id',
  'ComplianceType': 'COMPLIANT'|'NON_COMPLIANT',
  'Annotation': 'string',
  'OrderingTimestamp': number
}

If an unsupported resource is entered as the ComplianceResourceType value instead of AWS::::Account, then you get the following errors:

  • On the AWS Config console: "No results available"
  • Lambda CloudWatch logs: ""Error: ClientError: An error occurred (InternalFailure) when calling the PutEvaluations operation (reached max retries: 4)"
  • Cloudtrail (PutEvaluations API): "Error: ClientError: An error occurred (InternalFailure) when calling the PutEvaluations operation (reached max retries: 4)

When you use the AWS::::Account resource type value, keep the following points in mind:

  • A configuration item isn't recorded for this resource type.
  • A compliance configuration item under AWS::Config::ResourceCompliance isn't recorded for this resource type.
  • A resource timeline isn't available for this resource type.
  • In the AWS Management Console, the Manage Resource button is unavailable for this resource type.

Related information

Creating an AWS Lambda function for a custom AWS Config rule

AWS OFFICIAL
AWS OFFICIALUpdated a year ago