AWS Cloud Operations Blog

Deploying Custom AWS Config Rules in an AWS Organization Environment

In this post, we will show how you can deploy AWS Config custom rules across accounts in your organization, leveraging the Rules Development Kit (RDK), an open source development kit designed to support intuitive and efficient “Compliance-as-Code” workflows. With AWS Config custom rules, you can define custom logic for the desired configuration state of your resources using AWS Lambda and a supported programming language.

Using the solution outlined in this post, you can automate the setup of custom AWS Config rules across your organization. The automation of an organization-wide custom AWS Config rule deployment provides your organization with an automated setup to maintain a continuous compliance posture that is centrally managed to suit your organization’s needs, providing a streamlined develop-deploy-monitor iterative process for AWS Config rules across all accounts within your organization.

Solution Overview

To help understand the solution and concepts used in this post, refer to Figure 1, which shows an organization root that contains the management account, three organization units (OU), and three member accounts, one in each OU.

    Figure 1 shows a sample organization with an organizational root management account, 999999999999, three organizational units (OU), and three member accounts – one in each OU. Our compliance account, 111122223333, is in OU1.

Figure 1: Sample organization

 

We will register a member account from OU1 as a delegated admin account for AWS Config, granting it permissions to deploy AWS Config custom rules across the accounts in your organization. We will refer to this account as the compliance account, which is where the custom AWS Config rule will be deployed.

For our AWS Config rule to execute the corresponding checks within the organization, an AWS Identity and Access Management (IAM) role is needed to access the other accounts in the organization. This IAM role will contain a specific trust policy, allowing only Lambda functions in the compliance account to assume this role. To facilitate the creation of this role across all accounts in the organization, we use AWS CloudFormation StackSets, allowing you to centrally orchestrate AWS CloudFormation enabled service across multiple AWS accounts and regions. In our case, we will use AWS CloudFormation StackSets to deploy this centralized IAM role across AWS accounts in the organization to simplify the creation, configuration, and deletion of resources. Finally, with our permissions granted, we will use the AWS RDK to deploy the custom AWS Config rule across the accounts in our organization.

Prerequisites

To complete the steps detailed in this post, you need:

Walkthrough

This solution will complete the following steps:

  1. Delegate permissions for CloudFormation StackSets to a compliance account within your organization.
  2. Delegate permissions for AWS Config to a compliance account within your organization.
  3. Create a custom IAM role definition and deploy the role using CloudFormation StackSets across all accounts to be monitored in your organization.
  4. Create an AWS Config custom rule based on existing example rules and use the AWS RDK to deploy that custom rule.

Delegate Administrator for CloudFormation

To begin, you will first need to designate the compliance account as a delegated administrator for the AWS services used in this solution (CloudFormation and AWS Config). For this walkthrough, our management account ID is 999999999999 and our compliance account ID is 111122223333 (the delegated administrator for CloudFormation and AWS Config services).

To grant the delegated administration permissions, you will need to use CloudFormation StackSets integration with AWS Organizations, allowing you to deploy stack instances to member accounts in your organization. You do not have to create the necessary IAM roles since CloudFormation StackSets will create the IAM role in each member account for you. You can read more about enabling trusted access with AWS Organizations and registering a delegated administrator.

Once you have enabled trusted access with Organizations, you will:

  • Log in as administrator of your organization’s management account.
  • Run the following command – replace account-id 111122223333 with your compliance account’s ID.

aws organizations register-delegated-administrator --service-principal=member.org.stacksets.cloudformation.amazonaws.com --account-id="111122223333"

You can review this has been successfully by running the following command which lists the delegated admin accounts:

aws organizations list-delegated-administrators  --service-principal=member.org.stacksets.cloudformation.amazonaws.com

If successful, the response will include the account ID of the account you just added.

Delegate Administrator for AWS Config

Now we will designate our compliance account as the delegated administrator for AWS Config. Similar to CloudFormation, you need to log in as administrator in your organization management account and run the following commands to establish a trust relationship between the AWS Config service principals and Organizations. The trusted service access should cover both AWS Config rules (config-multiaccountsetup.amazonaws.com) and AWS Config (config.amazonaws.com).

aws organizations enable-aws-service-access --service-principal=config-multiaccountsetup.amazonaws.com

aws organizations enable-aws-service-access --service-principal=config.amazonaws.com

Next, register your delegated administrator account by running the following commands, replacing account-id 111122223333 with your compliance account’s ID:

aws organizations register-delegated-administrator --account-id 111122223333 --service-principal config-multiaccountsetup.amazonaws.com

aws organizations register-delegated-administrator --account-id 111122223333 --service-principal config.amazonaws.com

Review this has been successful by running the following command, which lists the delegated admin accounts:

aws organizations list-delegated-administrators  --service-principal=config.amazonaws.com

aws organizations list-delegated-administrators  --service-principal=config-multiaccountsetup.amazonaws.com

If successful, the response will include the account ID of the account you just added.

Create IAM Role Using CloudFormation StackSets

Next we will create the IAM role. This will need to be created from the compliance account. Since this role needs to exist in all the member accounts, we will use CloudFormation StackSets to deploy this role across the accounts using a YAML file with the resources defined. There is no need to manually create the role.

From a security perspective this is a critical part, so please get familiar with the different concepts before proceeding through this step. IAM Roles are defined by two important pieces – the permissions policy and the trust policy. The permission policy defines the permissions the resource using this role will have, and the trust policy defines which resources are able to use it.

We will create an IAM role with permissions to be used by the AWS Config service in the compliance account. To do this, we will create an IAM trust policy, where 111122223333 is the compliance account where your AWS Config custom rule (Lambda-backed) will be deployed. From a permissions standpoint, this role should include the AWS Managed Policy AWS_ConfigRole as well as any the minimum permissions your custom rule needs to run properly to maintain the principle of Least Privilege. In this example, we will use AWS Managed Policies. For your reference, you can review the Trust Policy for this role in Figure 2:

Figure 2 shows a sample IAM role for the AWS Config service and with your compliance account 111122223333 as the principal.

Figure 2: Sample IAM Role

We will use a YAML template with our resource defined to create this IAM role using AWS CloudFormation StackSets. This CloudFormation StackSet will create an IAM role named rdk-config-role-org in all organization accounts and will be referred to later in the AWS Config rule configuration. Create a directory in your compliance account and save the following YAML file in it as stack-set-rdk-config-role.yaml.

---
AWSTemplateFormatVersion: 2010-09-09
Description: "This StackSet will create an IAM Role that allows AWS Config run checks in the different accounts in the organization"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Config Rule Lambda Account Holder"
        Parameters:
          - DelegatedConfigRuleAccount
    ParameterLabels:
      DelegatedConfigRuleAccount:
        default: "REQUIRED: Account ID that hosts the Lambda Function(s) that back the Organization Rules."

Parameters:
  DelegatedConfigRuleAccount:
    Type: String
    Description: "Account ID that contains Lambda functions for Config Rules."

Resources:
  ConfigRole:
    Type: AWS::IAM::Role
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: Template creates a Role that is referenced by Config Rules to assume in multiple accounts, so it must be consistently named across the organization
    Properties:
      RoleName: rdk-config-role-org
      ManagedPolicyArns:
      - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWS_ConfigRole"
      - !Sub "arn:${AWS::Partition}:iam::aws:policy/job-function/ViewOnlyAccess"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Sid: LOCAL
          Effect: Allow
          Principal:
            Service:
            - config.amazonaws.com
          Action: sts:AssumeRole
        - Sid: REMOTE
          Effect: Allow
          Principal:
            AWS: !Sub "arn:${AWS::Partition}:iam::${DelegatedConfigRuleAccount}:root"
          Action: sts:AssumeRole

With the YAML file added to our directory, we will run the following command to create the CloudFormation StackSet from the stack-set-rdk-config-role.yaml file. Replace the parameter value in the command with the account ID for your compliance account. Please see the sample command below:

aws cloudformation create-stack-set \
    --stack-set-name rdk-config-role-org-stack \
    --description "Create Cross Account Role used by RDK-defined Config Rules" \
    --template-body file://stack-set-rdk-config-role.yaml \
    --parameters "ParameterKey=DelegatedConfigRuleAccount,ParameterValue=111122223333" \
    --permission-model SERVICE_MANAGED \
    --auto-deployment Enabled=True,RetainStacksOnAccountRemoval=True \
    --capabilities CAPABILITY_NAMED_IAM --call-as DELEGATED_ADMIN

Next, you will create the CloudFormation Stack Instances. First, you need to identify the root account ID for your organization. This account ID is formatted “r-” and you can find this within the AWS console. Similarly, you can find it by running the following command:

aws organizations list-roots

Next, you will need to run the Organizations list-children command to get the OU IDs for the children in your organization. To do this, run the following command, replacing the parent-id value with the root account ID you obtained previously:

aws organizations list-children --parent-id {Root-Account-ID} --child-type ORGANIZATIONAL_UNIT

You can now create the Stack instances. In the sample code below, replace your deployment targets with your OrganizationUnitIDs outputted in the last step and change your AWS Region to the region you are using. Please note, this only deploys in a specific region. You may need to repeat this for all the regions you want to cover.

aws cloudformation create-stack-instances \
    --stack-set-name rdk-config-role-org-stack \
    --deployment-targets "OrganizationalUnitIds={Account-OU-ID1},{Account-OU-ID2}" \
    --operation-preferences "FailureTolerancePercentage=50, MaxConcurrentCount=5" \
    --regions "{AWS-Region}" --call-as DELEGATED_ADMIN

Building and Deploying a Custom AWS Config Rule

With your organization prepared for AWS Config to run custom rules, we will now discuss how you can develop these rules. Each custom rule is a Lambda function that contains the logic to evaluate whether your AWS resources comply with your compliance logic. You associate this function with your rule, and the rule can invoke the function periodically or in response to configuration changes. The function then evaluates whether your resources comply with your rule and sends its evaluation results to AWS Config. For general understanding of this process, you can read more here.

Before we create our custom AWS Config Rule, we need to ensure the AWS RDK is installed. Installing the RDK will allow you to create your working directory and set up your AWS Config environment. If you are not familiar with the RDK, please take some time to familiarize yourself with it here.

You can install the RDK by running the following command and verifying the version installed:

pip install rdk
rdk -v

Next you will need to run the init command, which sets up the AWS Config Service in your AWS account and includes:

  • AWS Config Configuration Recorder and Delivery Channel
  • IAM Role for Delivery Channel
  • Amazon S3 Buckets for Configuration Snapshots and Lambda Code

You can run the following commands to create the above resources:

rdk init

With the RDK installed, we can begin creating our AWS Config custom rules. In this post, we will use a sample rule from the AWS Community repository of custom AWS Config rules and modify it to make it Organizations aware. You can refer to the AWS Community repository, which has plenty of sample custom AWS Config rules here.

You can start by cloning the AWS Community repository of custom AWS Config rules to your directory by running the git clone command below:

git clone https://github.com/awslabs/aws-config-rules.git

For this example, we will take python/SQS_PUBLIC_ACCESS_CHECK AWS Config Rule and add some customizations. This rule (SQS Public Access Check) was developed to be run in a single account and as such, has a hard-coded parameter named ASSUME_ROLE_MODE set to False. We need to change this parameter’s value to True to allow the function to run with a custom role. That custom role will have permissions to check SQS configuration and simultaneously report the compliance status of each resource in AWS Config.

Next, we need to create a directory to host the AWS Config rule code and copy the sample rule code from the sample repository to this directory. To do this, run the following commands:

mkdir org-SQS_PUBLIC_ACCESS_CHECK #This is going to be the rule name
cd org-SQS_PUBLIC_ACCESS_CHECK
cp -r ~/aws-config-rules/python/SQS_PUBLIC_ACCESS_CHECK org-SQS_PUBLIC_ACCESS_CHECK #Copy the code from the cloned repo to your new directory

Rename the rule files to match the name of the rule. This is because the directory and function file have to share the same name since the AWS RDK uses that to define the Lambda handler. You can achieve this by running the below commands:

cd org-SQS_PUBLIC_ACCESS_CHECK
mv SQS_PUBLIC_ACCESS_CHECK.py org-SQS_PUBLIC_ACCESS_CHECK.py
mv SQS_PUBLIC_ACCESS_CHECK_test.py org-SQS_PUBLIC_ACCESS_CHECK_test.py

Edit the org-SQS_PUBLIC_ACCESS_CHECK.py file. Specifically, we will look for the line ASSUME_ROLE_MODE = False and change the value to True to allow this function to run with a custom Role. This is shown in Figure 3 below:

Figure 3 shows the custom AWS Config rule file, where we are changing the value of ASSUME_ROLE_MODE from False to True.

Figure 3: AWS Config Custom Rule File

In addition, within the same directory there will be a parameters.json file. We will set the name of the IAM execution role name to rdk-config-role-org, which you copy from the sample code below:

{
  "Version": "1.0",
  "Parameters": {
    "RuleName": "SQS_PUBLIC_ACCESS_CHECK",
    "SourceRuntime": "python3.7",
    "CodeKey": "SQS_PUBLIC_ACCESS_CHECK.zip",
    "InputParameters": "{\"QueueNameStartsWith\":\"\", \"ExecutionRoleName\":\"rdk-config-role-org\"}",
    "OptionalParameters": "{}",
    "SourcePeriodic": "Three_Hours"
  },
  "Tags": "[]"
}

Once you have updated the parameters.json file, you can finally deploy the rule across your organization. To do this, run the following commands:

cd ..
rdk deploy org-SQS_PUBLIC_ACCESS_CHECK

Console View to Confirm Deployment

If the AWS Config rule was successfully deployed, you can verify this by navigating to AWS Config within the AWS console and checking the rules. You will see there is a new rule called org-SQS_PUBLIC_ACCESS_CHECK, which you can see in Figure 4 below:

Figure 4 shows a screenshot of the AWS Config console with our newly created rule "org-SQS-PUBLIC-ACCESS-CHECK" created.

Figure 4: Console View of AWS Config Rules

Clean Up

In order to delete the resources created as part of this walkthrough, run the following RDK commands.

Run the following command to remove the AWS Config Rule and its Lambda function from the targeted account:

rdk undeploy -a

You will be asked Delete specified Rules and Lambda Functions from your AWS Account? (y/N). Type y.

Next run the following command to completely remove the AWS Config resources from your account, including the Amazon S3 bucket, roles, and permissions:

rdk clean

You will be asked Delete specified Rules and Lambda Functions from your AWS Account? (y/N). Type y.

To delete the CloudFormation Stack Instances, run the following command. Be sure to replace your OU IDs and AWS region with the values you used before.

aws cloudformation delete-stack-instances --stack-set-name rdk-config-role-org-stack  --deployment-targets OrganizationalUnitIds='["{Account-OU-ID1}","{Account-OU-ID2}"]' --regions "{AWS-Region}" --no-retain-stacks --call-as DELEGATED_ADMIN

In addition, delete the CloudFormation StackSet by running the following command:

aws cloudformation delete-stack-set --stack-set-name rdk-config-role-org-stack

Finally, to deregister the compliance account as a delegated admin, you can run the following three commands from your management account. Please replace the account ID in the command with that of your compliance account:

aws organizations deregister-delegated-administrator --service-principal=member.org.stacksets.cloudformation.amazonaws.com --account-id="111122223333"

aws organizations deregister-delegated-administrator --account-id 111122223333 --service-principal config-multiaccountsetup.amazonaws.com

aws organizations deregister-delegated-administrator --account-id 111122223333 --service-principal config.amazonaws.com

Conclusion

This walkthrough detailed how to create AWS Config custom rules within your organization. The automation of an organization-wide custom AWS Config rule deployment provides your organization with an automated setup to centrally manage and maintain a continuous compliance posture.

To complete this, we deployed Lambda backed AWS Config custom rules across our organization using the AWS RDK. With the rules deployed across our organization, compliance checks can be run periodically or in response to configuration changes, allowing you to ensure the resources in your organization’s accounts comply with your custom rule.

For more information about AWS Config custom rules, you can read more on AWS Config custom Lambda rules. To learn more about AWS Organizations and how you can use CloudFormation StackSets for delegated access, see the following blogs: Using AWS CloudFormation StackSets in an AWS Organization and AWS CloudFormation Delegated Administration.

About the authors:

Ariana Rahgozar

Ariana Rahgozar is a Solutions Architect at AWS, helping customers design and implement technical solutions as part of their cloud journey.

Pablo Colazurdo

Pablo is a Principal Solutions Architect at AWS where he enjoys helping customers to launch successful projects in the Cloud. He has many years of experience working on varied technologies and is passionate about learning new things. Pablo grew up in Argentina but now enjoys the rain in Ireland while listening to music, reading or playing D&D with his kids.