Blog

Deploy AWS Config rules across your organization

15 Feb, 2024
Xebia Background Header Wave

In my previous blog I showed you how you can write your own config rules. But it will only bring you value if you deploy the rule in your AWS Accounts. In this blog we will dive into the distribution of these config rules.

What are my options?

There are many ways you can deploy these rules in your member accounts. In this blog I will only focus on the 2 real options:

  • Deploy the rules using CloudFormation StackSets in each account.
  • Use conformance packs.

Using CloudFormation StackSets

When you look at what CloudFormation StackSets does, you will see the reason why this would be a good fit:

Example how CloudFormation StackSets work

You need to have a delegated administrator. This admin has the ability to deploy the template in other accounts. You define all the account ids and regions you want to deploy the config rules in.

If you combine this with a landingzone you most likely already have this in place.

Using Conformance Packs

A conformance pack is nothing more than a bunch of config rules grouped together. But having this bundle gives you some more benefits. For example, you can see the compliance score of your bundle in your account. You can compare it to the compliance scores that you can see in Security Hub. Assume you have 10 config rules. Now one has resources that are non-compliant you will have a compliance score of 90%.

But this alone would not address the need to distribute the rules across all your accounts. But the conformance packs come in 2 flavors, regular and organizational conformance packs. Regular rules deploy the conformance pack in a single account. The organizational conformance pack will deploy the rule in all accounts.

Note, You can deploy the regular config rules using an organization config rule. This would not give you the grouping of all your rules. For this reason I tend to use conformance packs.

Show me an example

It’s always better to use an example, this snippet will only work when you follow the prerequisites. When you deploy this template in the account that is setup as the delegated administrator. All member accounts will have the config rules available.

Resources:

 ConformancePackBucket:
   Type: AWS::S3::Bucket
   DeletionPolicy: Retain
   UpdateReplacePolicy: Retain
   Properties:
     BucketName: !Sub awsconfigconforms-${AWS::AccountId}-${AWS::Region}
     BucketEncryption:
       ServerSideEncryptionConfiguration:
         - ServerSideEncryptionByDefault:
             SSEAlgorithm: AES256
     PublicAccessBlockConfiguration:
       BlockPublicAcls: True
       BlockPublicPolicy: True
       IgnorePublicAcls: True
       RestrictPublicBuckets: True

 ConformancePackBucketPolicy:
   Type: AWS::S3::BucketPolicy
   Properties:
     Bucket: !Ref ConformancePackBucket
     PolicyDocument:
       Version: 2012-10-17
       Statement:
         - Sid: AWSConfigConformsCheckAcls
           Action: s3:GetBucketAcl
           Effect: Allow
           Resource: !GetAtt ConformancePackBucket.Arn
           Principal:
             AWS: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config-conforms.amazonaws.com/AWSServiceRoleForConfigConforms
           Condition:
             StringEquals:
               aws:PrincipalOrgID: ${aws:PrincipalOrgID}
             Bool:
               aws:SecureTransport: true
         - Sid: AWSConfigConformsReadWriteBucket
           Action:
             - s3:PutObject
             - s3:GetObject
           Effect: Allow
           Resource: !Sub ${ConformancePackBucket.Arn}/*
           Principal:
             AWS: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config-conforms.amazonaws.com/AWSServiceRoleForConfigConforms
           Condition:
             StringEquals:
               aws:PrincipalOrgID: ${aws:PrincipalOrgID}
             Bool:
               aws:SecureTransport: true

 OrganizationConformancePack:
   Type: AWS::Config::OrganizationConformancePack
   Properties:
     OrganizationConformancePackName: lz-framework
     DeliveryS3Bucket: !Ref ConformancePackBucket
     ExcludedAccounts: [ "000000000000" ] # AccountID to exclude
     TemplateBody: |-
       Resources:
         S3AccessLogging:
           Type: AWS::Config::ConfigRule
           Properties:
             ConfigRuleName: lz-my-custom-rule
             Description: My custom rule
             EvaluationModes:
               - Mode: DETECTIVE
             Scope:
               ComplianceResourceTypes:
                 - AWS::S3::Bucket
             Source:
               Owner: CUSTOM_POLICY
               SourceDetails:
                 - EventSource: aws.config
                   MessageType: ConfigurationItemChangeNotification
                 - EventSource: aws.config
                   MessageType: OversizedConfigurationItemChangeNotification
               CustomPolicyDetails:
                 EnableDebugLogDelivery: 'true'
                 PolicyRuntime: guard-2.x.x
                 PolicyText: |-
                   # The rule definition goes here

The template only includes 3 main resources, but 2 actual logical components. A bucket with a policy and the conformance pack definition. Let’s go over all the components in the example.

S3 Bucket and the bucket policy

This bucket needs to start with awsconfigconforms. The config-conforms.amazonaws.com service will use this bucket to upload the template. The template comes from the OrganizationConformancePack resource. The policy allows the service to put and get objects as long as it is within the organization. This allows the service to deploy the template in all member accounts.

Organization Conformance Pack

The organization conformance pack definition looks big but it’s quite simple. If you have a closer look you will notice it has only 4 properties:

  • OrganizationConformancePackName
  • DeliveryS3Bucket
  • ExcludedAccounts
  • TemplateBody

Now the first 3 options are pretty straight forward. The template itself is a bit more complicated. In my example I used an inline template, I did this for the sake of this blog. But you can also reference an existing object on S3. This way you can use linting tools like cfn-lint on your conformance pack. This will reduce errors during deployment as you can catch them before you commit and push your code.

If you need help with setting up the conformance pack template, have a look at these samples.

Conclusion

When you combine custom rules in a conformance pack. It will allow you to simplify the distribution of these rules. You don’t need to maintain any pipelines or stack sets. And you outsource the distribution of your rules to AWS.

This removes all the maintenance on the infrastructure to do this distribution yourself. And you don’t need to think about scenarios like, adding/removing accounts.

Photo by ELEVATE

Joris Conijn
Joris has been working with the AWS cloud since 2009 and focussing on building event driven architectures. While working with the cloud from (almost) the start he has seen most of the services being launched. Joris strongly believes in automation and infrastructure as code and is open to learn new things and experiment with them, because that is the way to learn and grow. In his spare time he enjoys running and runs a small micro brewery from his home.
Questions?

Get in touch with us to learn more about the subject and related solutions

Explore related posts