AWS CloudFormation template with ConfigRule

I'm new to AWS but already tried looking everywhere for this, and couldn't find a proper answer.

My aim is to create a CloudFormation template which forms a new stack, without assuming that AWS Config is already enabled. This template should define several more items, one of them should be a ConfigRule.

In order to achieve that, I found this template which seems fine, then tried to add a ConfigRule from one of these examples, into the same template file. But when I try to create a new stack from this combined template, I get this error:

You must create a configuration recorder before you can create or update a Config rule. (Service: AmazonConfig; Status Code: 400; Error Code: NoAvailableConfigurationRecorderException

Since the template file does define a configuration recorder, I'm not sure what's wrong with it. This is basically a copy of the linked template, and I marked with comments around the places which I added only in order to add some example config rule which should be created as part of the template:


AWSTemplateFormatVersion: 2010-09-09
Description: 'The AWS CloudFormation template creates KMS encryption keys for Config and S3, an encrypted S3 bucket, and enables Config for the account'

# added for configRule - start (1)
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Configuration
        Parameters:
          - Frequency
    ParameterLabels:
      Frequency:
        default: Frequency

Parameters:
  Frequency:
    Type: String
    Default: 24hours
    Description: Maximum rule execution frequency.
    AllowedValues:
      - 1hour
      - 3hours
      - 6hours
      - 12hours
      - 24hours

Mappings:
  Settings:
    FrequencyMap:
      1hour   : One_Hour
      3hours  : Three_Hours
      6hours  : Six_Hours
      12hours : Twelve_Hours
      24hours : TwentyFour_Hours
# added for configRule - end (#1)

Resources:
# added for configRule - start (2)
  CheckForRootMFA:
    Type: AWS::Config::ConfigRule
    Properties:
      Description: Checks whether the root user of your AWS account requires multi-factor authentication for console sign-in.
      MaximumExecutionFrequency: !FindInMap
          - Settings
          - FrequencyMap
          - !Ref Frequency
      Source:
        Owner: AWS
        SourceIdentifier: ROOT_ACCOUNT_MFA_ENABLED
# added for configRule - end (2)
  # KMS S3 Config Service encryption key
  s3configKey:
    Type: AWS::KMS::Key
    Properties:
      KeyPolicy:
        Version: 2012-10-17
        Id: key-s3config
        Statement:
          - Sid: Enable IAM User Permissions
            Effect: Allow
            Principal:
              AWS: !Join
                - ''
                - - 'arn:aws:iam::'
                  - !Ref 'AWS::AccountId'
                  - ':root'
            Action: 'kms:*'
            Resource: '*'
  s3configKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/s3config
      TargetKeyId:
        Ref: s3configKey

  # Build AWS Config Service S3 Bucket for Storage
  AWSConfigS3Bucket:
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    Properties:
      BucketEncryption:
        ServerSideEncryptionConfiguration:
        - ServerSideEncryptionByDefault:
            KMSMasterKeyID: !Sub 'arn:aws:kms:${AWS::Region}:${AWS::AccountId}:${s3configKeyAlias}'
            SSEAlgorithm: 'aws:kms'

  # Build AWS Config Recorder
  ConfigRecorder:
    Type: 'AWS::Config::ConfigurationRecorder'
    Properties:
      Name: 'ConfigRecoder'
      RecordingGroup:
        AllSupported: true
        IncludeGlobalResourceTypes: true
      RoleARN: !GetAtt
        - AWSIAM
        - Arn

  # Build IAM Role for Config
  AWSIAM:
    Type: 'AWS::IAM::Role'
    Properties:
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/service-role/AWSConfigRole'
      Path: /
      Policies:
        - PolicyName: S3-access
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action:
                  - 's3:PutObject'
                Resource: !Join
                  - ''
                  - - 'arn:aws:s3:::'
                    - !Ref AWSConfigS3Bucket
                    - /AWSLogs/
                    - !Ref 'AWS::AccountId'
                    - /*
                Condition:
                  StringLike:
                    's3:x-amz-acl': bucket-owner-full-control
              - Effect: Allow
                Action:
                  - 's3:GetBucketAcl'
                Resource: !Join
                  - ''
                  - - 'arn:aws:s3:::'
                    - !Ref AWSConfigS3Bucket

  # Create Config Delivery Channel
  DeliveryChannel:
    Type: 'AWS::Config::DeliveryChannel'
    Properties:
      S3BucketName: !Ref AWSConfigS3Bucket

Outputs:
    S3KMSKeyAlias:
        Description: 'S3 KMS Key Alias'
        Value:
            Ref: 's3configKeyAlias'
    AWSIAM:
        Description: 'IAM Role for Config'
        Value:
            Ref: 'AWSIAM'     
    AWSConfigS3Bucket:
        Description: 'Encrypted S3 Bucket for Config Logs'
        Value:
            Ref: 'AWSConfigS3Bucket'
    ConfigRecorder:
        Description: 'Config Recorder'
        Value:
            Ref: 'ConfigRecorder'
    DeliveryChannel:
        Description: 'Config Delivery Channel'
        Value:
            Ref: 'DeliveryChannel'

Solution 1:

CloudFormation usually works out the correct order for deployment of components, but sometimes it gets it wrong. You can use the DependsOn attribute to give it a hint to say the Config Recorder must be created before the Config Rule. I'm not 100% sure this will help but it's worth a shot.

CheckForRootMFA:
  DependsOn: ConfigRecorder
  Type: AWS::Config::ConfigRule
  Properties:
    (etc)

Looking at my own Config templates I can see I create the following

  • AWS::Config::ConfigurationRecorder
  • AWS::Config::DeliveryChannel
  • AWS::SNS::Topic

But I don't actually create config rules as I use AWS Security Hub which creates them for me.