Implementing AWS Config for your Organization with CloudFormation
Tags: aws, config, audit, security
Published: 2024-06-04 05:33:07

## Objective

This lab is centered on deploying **AWS Config** within your AWS Organization for the first time. It's advisable to familiarize yourself with essential concepts of AWS Config, AWS CloudFormation, and how they integrate with AWS Organizations if you are new to them. In case you're interested I have published a concise [summary of AWS Config in a separate post](https://dev.to/diegotrujillo/introduction-to-aws-config-544k).

I was motivated to develop this lab since I was testing some AWS Organization features and started creating multiple accounts. Subsequently, I recognized that deploying basic AWS Security Services across all accounts would be the most secure approach.

## Solution Structure

With that in mind, there are numerous options available for AWS Config. In this lab, we will utilize the following setup and components:
- (Pre-requisite) An AWS Organization must be already set up.
- We'll use AWS CloudFormation StackSets to automatically enable AWS Config on every member account. It should be noted that as per the [AWS Documentation](https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_DeploymentTargets.html), the StackSet will not be deployed to the Management Account.
- As we plan to integrate AWS Config and AWS CloudFormation with AWS Organizations, we will assign the role of Delegated Administrator to one member account, thereby avoiding using the Management Account.
- We will create a single S3 Bucket within the Delegated Admin account to centralize AWS Config Log files from all member accounts.
- We will deploy a CloudFormation Stack to set up the Config StackSet and the centralized S3 Bucket.
- Once AWS Config is enabled across all accounts, we will begin establishing Organization Config Rules within the Delegated Admin account.
- Finally, a Config Aggregator will be set up in the Delegated Admin account to consolidate compliance data from all accounts and create reports.


**Accounts Structure**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r36ey5arq78ntmibi3vy.jpg)


## Steps
Below are the sequential steps for deploying our AWS Config solution. The complete source code is available in the [GitHub Repository](https://github.com/diegotrp/lab-awsconfig-for-orgs).
1. Assign a Delegated Administrator for AWS Config and CloudFormation.
2. Establish AWS Config Recorders using CloudFormation StackSets.
3. Implement Organization Config Rules across all accounts.
4. Set up an AWS Aggregator for cross-account reporting.


## Step 1. Assign a Delegated Administrator for AWS Config and CloudFormation.

As mentioned in AWS Documentation, run the following commands from the Management Account for enabling [AWS Config](https://docs.aws.amazon.com/config/latest/developerguide/set-up-aggregator-cli.html#register-a-delegated-administrator-cli) and [AWS CloudFormation](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-orgs-delegated-admin.html#:~:text=To%20register%20a%20delegated%20administrator%20%28console%29%20Sign%20in,StackSets.%20Under%20Delegated%20administrators%2C%20choose%20Register%20delegated%20administrator.) for your Organization, and assigning a Delegated Admin.

- Enable service access as a delegated administrator for your organization to aggregate AWS Config data across your organization:
```
aws organizations enable-aws-service-access --service-principal=config.amazonaws.com
```

- Enable service access as a delegated administrator for your organization to deploy and manage AWS Config rules and conformance packs across your organization:
```
aws organizations enable-aws-service-access --service-principal=config-multiaccountsetup.amazonaws.com
```

- Enable service access as delegated administrator for your organization to create and manage stack sets across your organization:
```
aws organizations enable-aws-service-access --service-principal=member.org.stacksets.cloudformation.amazonaws.com
```

- To check if the enable service access is complete, enter the following command and press Enter to execute the command:
```
aws organizations list-aws-service-access-for-organization
```
You should see output similar to the following:
```
{
    "EnabledServicePrincipals": [
        {
            "ServicePrincipal": "config-multiaccountsetup.amazonaws.com",
            "DateEnabled": "2024-05-23T18:09:52.878000+00:00"
        },
        {
            "ServicePrincipal": "config.amazonaws.com",
            "DateEnabled": "2024-05-24T16:27:31.462000+00:00"
        },
        {
            "ServicePrincipal": "member.org.stacksets.cloudformation.amazonaws.com",
            "DateEnabled": "2024-05-24T16:56:08.933000+00:00"
        }
    ]
}
```

- Next, enter the following commands to register a member account as a Delegated Admin for Config and CloudFormation:
```
aws organizations register-delegated-administrator --service-principal=config-multiaccountsetup.amazonaws.com --account-id MemberAccountID
aws organizations register-delegated-administrator --service-principal=config.amazonaws.com --account-id MemberAccountID
aws organizations register-delegated-administrator --service-principal=member.org.stacksets.cloudformation.amazonaws.com --account-id MemberAccountID
```

- To check if the registration of the delegated administrator is complete, enter the following commands:
```
aws organizations list-delegated-administrators --service-principal=config-multiaccountsetup.amazonaws.com
aws organizations list-delegated-administrators --service-principal=config.amazonaws.com
aws organizations list-delegated-administrators --service-principal=member.org.stacksets.cloudformation.amazonaws.com
```
You should see output similar to the following:

```
{
    "DelegatedAdministrators": [
        {
            "Id": "MemberAccountID",
            "Arn": "arn:aws:organizations::MemberAccountID:account/o-c7esubdi38/MemberAccountID",
            "Email": "name@amazon.com",
            "Name": "name",
            "Status": "ACTIVE",
            "JoinedMethod": "INVITED",
            "JoinedTimestamp": 1604867734.48,
            "DelegationEnabledDate": 1607020986.801
        }
    ]
}
```

You can validate the following IAM Roles created on your AWS Member Accounts:
- AWSServiceRoleForConfig
- AWSServiceRoleForConfigMultiAccountSetup
- AWSServiceRoleForCloudFormationStackSetsOrgMember


## Step 2. Establish AWS Config Recorders using CloudFormation StackSets.

Before setting up Config Rules, it is necessary to begin recording resource changes, which requires the creation of a Configuration Recorder in each member account of our Organization.

There are various methods to activate AWS Config across multiple accounts; however, in this lab, we will utilize AWS CloudFormation StackSets to centrally manage Config Recorders from the Delegated Admin Account. We will also employ a Service-managed StackSet to automatically generate the required IAM Roles, prefixed with "stacksets-exec."

AWS offers various CloudFormation templates for AWS Config; however, we will utilize the template named [EnableAWSConfigForOrganizations.yml](https://cloudformation-stackset-sample-templates-us-east-1.s3.us-east-1.amazonaws.com/EnableAWSConfigForOrganizations.yml). 

You can review the entire file to see all the functionalities the template supports. In this lab, we will concentrate on the following resources:
- Configuration Recorder to record all resource types (or to filter the resource types you prefer)
- Delivery Channel to send Config History and Config Snapshot files to S3, and optionally to SNS

```
  ConfigRecorder:
    Type: AWS::Config::ConfigurationRecorder
    Properties:
      RecordingGroup:
        AllSupported: !Ref AllSupported
        IncludeGlobalResourceTypes: !Ref IncludeGlobalResourceTypes
        ResourceTypes: !If
          - IsAllSupported
          - !Ref AWS::NoValue
          - !Ref ResourceTypes
      RoleARN:
        Fn::Sub:
          "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig"

  ConfigDeliveryChannel:
    Type: AWS::Config::DeliveryChannel
    Properties:
      Name: !If
        - IsGeneratedDeliveryChannelName
        - !Ref AWS::NoValue
        - !Ref DeliveryChannelName
      ConfigSnapshotDeliveryProperties: !If
        - DisableSnapshots
        - !Ref AWS::NoValue
        - DeliveryFrequency: !FindInMap
            - Settings
            - FrequencyMap
            - !Ref Frequency
      S3BucketName: !If
        - CreateBucket
        - !Ref ConfigBucket
        - !Ref S3BucketName
      S3KeyPrefix: !If
        - UsePrefix
        - !Ref S3KeyPrefix
        - !Ref AWS::NoValue
      SnsTopicARN: !If
        - UseSNS
        - !If
          - CreateTopic
          - !Ref ConfigTopic
          - !Ref TopicArn
        - !Ref AWS::NoValue
```

I have developed a CloudFormation template that implements our StackSet for enabling AWS Config on all accounts, thereby automating its creation via the AWS CLI. The template includes the following functionalities:
- Creation of a new S3 Bucket exclusively for centralized AWS Config logging.
- Implementation of the StackSet across all our organization accounts, with the Delivery Channel set up to relay logs to the centralized S3 Bucket.

Please review the entire template and make any necessary modifications as needed.

```
AWSTemplateFormatVersion: 2010-09-09
Description:
  This CloudFormation Stack creates a StackSet that deploys the "EnableAWSConfigForOrganizations.yml" template to an Organization, in addition to a S3 Bucket for centralized logging.
  The StackSet will deploy a Stack containing the Config componentes to each member account.
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: General Parameters
        Parameters:
          - ConfigRegions
          - TagName
          - TagUnit
          - TagEnvironment
      - Label:
          default: Centralized Bucket Parameters
        Parameters:
          - OrganizationId
          - CentralizedBucketName
      - Label:
          default: Cfn StackSet Resource Parameters
        Parameters:
          - StackSetOuId
          - StackSetAutoDeployment
          - StackSetManagedExecution
          - StackSetCallAsAccount
      - Label:
          default: Config StackSet Template Parameters
        Parameters:
          - StSeParAllSupported
          - StSeParIncludeGlobalResourceTypes
          - StSeParResourceTypes
          - StSeParServiceLinkedRoleRegion
          - StSeParDeliveryChannelName
          - StSeParS3KeyPrefix
          - StSeParFrequency
          - StSeParSNS
          - StSeParTopicArn
          - StSeParNotificationEmail
Parameters:
  ConfigRegions:
    Type: List<String>
    Default: us-east-1
    Description: Specifies list of Regions to be configured as Deployment Target.
  TagName:
    Type: String
    Description: Specifies the prefix for the 'Name' tag for stack resources.
  TagUnit:
    Type: String
    Description: Specifies the value for the 'Unit' tag for stack resources.
  TagEnvironment:
    Type: String
    Description: Specifies the value for the 'Environment' tag for stack resources.
  OrganizationId:
    Type: String
    Default: <OrgId>
    Description: Organization Id, for restricting access to centralized logging bucket.
  CentralizedBucketName:
    Type: String
    Default: <CentrBucket>
    Description: Name for Centralized Logging Bucket in Administration Account.
  StackSetOuId:
    Type: String
    Default: <OuId>
    Description: ID of Organization Unit to be configured as Deployment Target.
  StackSetAutoDeployment:
    Type: String
    Default: true
    Description: Specifies whether to enable Auto Deployment. This feature
      automatically deploys StackSets to AWS Organizations accounts that are
      added to a target.
    AllowedValues:
      - true
      - false
  StackSetManagedExecution:
    Type: String
    Default: false
    Description: Describes whether StackSets performs non-conflicting operations
      concurrently and queues conflicting operations.
    AllowedValues:
      - true
      - false
  StackSetCallAsAccount:
    Type: String
    Default: DELEGATED_ADMIN
    Description:
      Specifies whether you are acting as an account administrator in the
      organization's management account or as a delegated administrator in a
      member account.
    AllowedValues:
      - SELF
      - DELEGATED_ADMIN
  StSeParAllSupported:
    Type: String
    Default: true
    Description:
      StackSet Parameter "AllSupported" - Indicates whether to record all
      supported resource types.
    AllowedValues:
      - true
      - false
  StSeParIncludeGlobalResourceTypes:
    Type: String
    Default: false
    Description:
      StackSet Parameter "IncludeGlobalResourceTypes" - Indicates whether
      AWS Config records all supported global resource types.
    AllowedValues:
      - true
      - false
  StSeParResourceTypes:
    Type: List<String>
    Description:
      StackSet Parameter "ResourceTypes" - A list of valid AWS resource
      types to include in this recording group, such as AWS::EC2::Instance or
      AWS::CloudTrail::Trail.
    Default: <All>
  StSeParServiceLinkedRoleRegion:
    Type: String
    Description:
      StackSet Parameter "ResourceTypes" - A region such as us-east-1. If
      specified, the Config service-linked role will only be created if the
      stack is deployed to this region.
    Default: <DeployToAnyRegion>
  StSeParDeliveryChannelName:
    Type: String
    Default: <Generated>
    Description:
      StackSet Parameter "DeliveryChannelName" - The name of the delivery
      channel.
  StSeParS3KeyPrefix:
    Type: String
    Default: <Prefix>
    Description:
      StackSet Parameter "S3KeyPrefix" - Prefix for the specified Amazon
      S3 bucket.
  StSeParFrequency:
    Type: String
    Default: 24hours
    Description: StackSet Parameter "Frequency" - The frequency with which AWS
      Config delivers configuration snapshots.
    AllowedValues:
      - 1hour
      - 3hours
      - 6hours
      - 12hours
      - 24hours
  StSeParSNS:
    Type: String
    Default: true
    Description:
      StackSet Parameter "TopicArn" - Describes wether AWS Config sends
      SNS notifications.
    AllowedValues:
      - true
      - false
  StSeParTopicArn:
    Type: String
    Default: <New Topic>
    Description:
      StackSet Parameter "TopicArn" - The Amazon Resource Name (ARN) of
      the Amazon Simple Notification Service (Amazon SNS) topic that AWS Config
      delivers notifications to.
  StSeParNotificationEmail:
    Type: String
    Default: <None>
    Description: StackSet Parameter "NotificationEmail" - address for AWS Config
      notifications (for new topics).
Resources:
  CentralizedBucket:
    DeletionPolicy: Retain
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref CentralizedBucketName
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      Tags:
        - Key: Name
          Value: !Sub
            - "${tag}-${bucket}"
            - tag: !Ref TagName
              bucket: !Ref CentralizedBucketName
        - Key: Unit
          Value: !Ref TagUnit
        - Key: Environment
          Value: !Ref TagEnvironment
  CentralizedBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref CentralizedBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: AWSConfigBucketPermissionsCheck
            Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action: s3:GetBucketAcl
            Resource:
              - !Sub arn:${AWS::Partition}:s3:::${CentralizedBucket}
            Condition:
              StringEquals:
                aws:SourceOrgID: !Ref OrganizationId
          - Sid: AWSConfigBucketExistenceCheck
            Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action: s3:ListBucket
            Resource:
              - !Sub arn:${AWS::Partition}:s3:::${CentralizedBucket}
            Condition:
              StringEquals:
                aws:SourceOrgID: !Ref OrganizationId
          - Sid: AWSConfigBucketDelivery
            Effect: Allow
            Principal:
              Service:
                - config.amazonaws.com
            Action: s3:PutObject
            Resource:
              - !Sub arn:${AWS::Partition}:s3:::${CentralizedBucket}/${StSeParS3KeyPrefix}/AWSLogs/*
            Condition:
              StringEquals:
                aws:SourceOrgID: !Ref OrganizationId
  ConfigStackSet:
    Type: AWS::CloudFormation::StackSet
    Properties:
      StackSetName: ConfigStackSet
      Description: StackSet for deploying AWS Config to an Organization Unit
      PermissionModel: SERVICE_MANAGED
      Capabilities:
        - CAPABILITY_IAM
      ManagedExecution:
        Active: !Ref StackSetManagedExecution
      OperationPreferences:
        FailureToleranceCount: 0
        MaxConcurrentCount: 1
        RegionConcurrencyType: SEQUENTIAL
      StackInstancesGroup:
        - DeploymentTargets:
            OrganizationalUnitIds:
              - !Ref StackSetOuId
          Regions: !Ref ConfigRegions
      CallAs: !Ref StackSetCallAsAccount
      AutoDeployment:
        Enabled: !Ref StackSetAutoDeployment
        RetainStacksOnAccountRemoval: true
      Parameters:
        - ParameterKey: AllSupported
          ParameterValue: !Ref StSeParAllSupported
        - ParameterKey: IncludeGlobalResourceTypes
          ParameterValue: !Ref StSeParIncludeGlobalResourceTypes
        - ParameterKey: ResourceTypes
          ParameterValue: !Join
            - ","
            - !Ref StSeParResourceTypes
        - ParameterKey: ServiceLinkedRoleRegion
          ParameterValue: !Ref StSeParServiceLinkedRoleRegion
        - ParameterKey: DeliveryChannelName
          ParameterValue: !Ref StSeParDeliveryChannelName
        - ParameterKey: S3BucketName
          ParameterValue: !Ref CentralizedBucket
        - ParameterKey: S3KeyPrefix
          ParameterValue: !Ref StSeParS3KeyPrefix
        - ParameterKey: Frequency
          ParameterValue: !Ref StSeParFrequency
        - ParameterKey: SNS
          ParameterValue: !Ref StSeParSNS
        - ParameterKey: TopicArn
          ParameterValue: !Ref StSeParTopicArn
        - ParameterKey: NotificationEmail
          ParameterValue: !Ref StSeParNotificationEmail
      TemplateURL: https://cloudformation-stackset-sample-templates-us-east-1.s3.us-east-1.amazonaws.com/EnableAWSConfigForOrganizations.yml
      Tags:
        - Key: Name
          Value: !Sub
            - "${tag}-StackSet"
            - tag: !Ref TagName
        - Key: Unit
          Value: !Ref TagUnit
        - Key: Environment
          Value: !Ref TagEnvironment
```

Upload the template to an S3 Bucket, and then execute the following command, replacing the necessary values.
```
aws cloudformation create-stack --stack-name Config-StackSetConfigRecorder \ 
--template-url https://xxxxxxxx-templates.s3.amazonaws.com/2-StackSetConfigOrg.yml \ 
--parameters \
      ParameterKey=ConfigRegions,ParameterValue=us-east-1 \
      ParameterKey=TagName,ParameterValue=Config-StackSetConfigRecorder \
      ParameterKey=TagUnit,ParameterValue=Security \
      ParameterKey=TagEnvironment,ParameterValue=Prod \
      ParameterKey=OrganizationId,ParameterValue=o-xxxxxxx \
      ParameterKey=CentralizedBucketName,ParameterValue=centralized-aaa-bbb-c \
      ParameterKey=StackSetOuId,ParameterValue=r-xxxx \
      ParameterKey=StackSetAutoDeployment,ParameterValue=true \
      ParameterKey=StackSetManagedExecution,ParameterValue=false \
      ParameterKey=StackSetCallAsAccount,ParameterValue=DELEGATED_ADMIN \
      ParameterKey=StSeParAllSupported,ParameterValue=true \
      ParameterKey=StSeParIncludeGlobalResourceTypes,ParameterValue=false \
      ParameterKey=StSeParResourceTypes,ParameterValue="<All>" \
      ParameterKey=StSeParServiceLinkedRoleRegion,ParameterValue="<DeployToAnyRegion>" \
      ParameterKey=StSeParDeliveryChannelName,ParameterValue="<Generated>" \
      ParameterKey=StSeParS3KeyPrefix,ParameterValue=o-xxxxxxx \
      ParameterKey=StSeParFrequency,ParameterValue=24hours \
      ParameterKey=StSeParSNS,ParameterValue=false \
      ParameterKey=StSeParTopicArn,ParameterValue="<New Topic>" \
      ParameterKey=StSeParNotificationEmail,ParameterValue="<None>"
```

Following the successful creation of the Stack, you may proceed to verify the establishment of the following resources:

_CloudFormation Stack in Delegated Admin account_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/e0ohul9t2nuly707yzks.png)
_S3 Bucket in Delegated Admin account_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ccp0fjwiw3qb95xk0149.png)
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vyzbels8rxaekibzw39o.png)
_CloudFormation StackSet in Delegated Admin account_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l042j0zolohn5453ohzz.png)
_CloudFormation Stacks in Member Accounts_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fcmukm6v0yk2l6qj2dso.png)
_IAM Role for Service-managed StackSet in Member Accounts_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/16hvtqebu3czshb2xagq.png)
_AWS Config enabled in Member Accounts_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ogqg9teya2uk4qb083z8.png)


## Step 3. Implement Organization Config Rules across all accounts.

Next, we will deploy a few Organization Config Rules. You can explore all the available [Managed Rules](https://docs.aws.amazon.com/config/latest/developerguide/managed-rules-by-aws-config.html) or create your Custom Rules. For this lab, we will use the ACCESS_KEYS_ROTATED and REQUIRED_TAGS rules to fit my use case.

It should be noted that Organization Config Rules are automatically deployed to the Management Account. However, during Step 2, when the StackSet was deployed to activate Config, it did not include the Management Account. Therefore, if you wish to set up Config for the Management Account, you must first manually activate Config and then establish the necessary Service-Linked accounts using these commands:
```
aws iam create-service-linked-role --aws-service-name config.amazonaws.com
aws iam create-service-linked-role --aws-service-name config-multiaccountsetup.amazonaws.com
```

For simplicity, we will not deploy Config Rules to the Management Account. Therefore, we will include an additional parameter "ExcludedAccounts" with the Management account ID as its value to prevent the creation of Config Rules in that account.

Please review the following template and make any necessary modifications as needed.

```
AWSTemplateFormatVersion: 2010-09-09
Description: This CloudFormation Stack creates a StackSet that deploys a group of Organization Config Rules.
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: Organization Config Rules Parameters
        Parameters:
          - OrgRulePrefixName
Parameters:
  OrgRulePrefixName:
    Type: String
    Default: <OrgRulePrefix>
    Description: Prefix for the name of the Organization Config Rules.
  OrgRuleExcludedAccounts:
    Type: List<String>
    Default: <OrgRuleExcludedAccounts>
    Description: List of excluded accounts for the Organization Config Rules.
Resources:
  ConfigOrgRuleRequiredTags:
    Type: AWS::Config::OrganizationConfigRule
    Properties:
      OrganizationConfigRuleName: !Sub
        - "${prefix}-requiredtags"
        - prefix: !Ref OrgRulePrefixName
      ExcludedAccounts: !Ref OrgRuleExcludedAccounts
      OrganizationManagedRuleMetadata:
        RuleIdentifier: REQUIRED_TAGS
        Description: Checks if your resources have the standard tags.
        InputParameters: !Sub '{"tag1Key":"Name", "tag2Key":"Unit", "tag2Value":"Management,Security,Applications", "tag3Key":"Environment", "tag3Value": "Prod,Dev,Test,Sandbox"}'
  ConfigOrgRuleAccessKeysRotated:
    Type: AWS::Config::OrganizationConfigRule
    Properties:
      OrganizationConfigRuleName: !Sub
        - "${prefix}-accesskeysrotation"
        - prefix: !Ref OrgRulePrefixName
      ExcludedAccounts: !Ref OrgRuleExcludedAccounts
      OrganizationManagedRuleMetadata:
        RuleIdentifier: ACCESS_KEYS_ROTATED
        Description: Checks if active IAM access keys are rotated within 90 days.
        InputParameters: !Sub '{"maxAccessKeyAge": "90"}'
        MaximumExecutionFrequency: TwentyFour_Hours
```

Upload the new template to S3 and run the following command for creating the stack.

```
aws cloudformation create-stack --stack-name Config-OrgConfigRules \ 
--template-url https://xxxxxxxx-templates.s3.amazonaws.com/3-StackSetConfigRules.yml \ 
--parameters \
      ParameterKey=TagName,ParameterValue=Config-StackSetConfigRecorder \
      ParameterKey=TagUnit,ParameterValue=Security \
      ParameterKey=TagEnvironment,ParameterValue=Prod \
      ParameterKey=OrgRulePrefixName,ParameterValue="compliance" \
      ParameterKey=OrgRuleExcludedAccounts,ParameterValue="XXXXXXXXXXXXX"
```

After successfully creating the Stack, you can confirm the establishment of the Config Rules in the Member Accounts:

_List Organization Config Rules using the CLI_
```
aws configservice describe-organization-config-rules
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zu1g0l8rudxmm2e2nzgu.png)

_List Organization Config Rules using the Console_
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6wr57daaz7toehr07q3x.png)


## Step 4. Set up an AWS Aggregator for cross-account reporting.

Now that we've implemented some Config Rules, it's necessary to have a straightforward method to monitor compliance across all accounts, which is why we are proceeding to establish our Config Aggregator.

We will create a final stack to deploy the Config Aggregator, along with a new IAM Role that the Aggregator needs to gather data from all accounts within an organization.

Please review the following template and make any necessary modifications as needed.

```
AWSTemplateFormatVersion: 2010-09-09
Description: This CloudFormation Stack creates a StackSet that deploys the
  "EnableAWSConfig.yml" template to an Organization
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: General Parameters
        Parameters:
          - ConfigRegions
          - TagName
          - TagUnit
          - TagEnvironment
      - Label:
          default: Aggregator Parameters
        Parameters:
          - ConfigAggRoleName
          - ConfigAggName
Parameters:
  ConfigRegions:
    Type: List<String>
    Default: us-east-1
    Description: Specifies list of Regions to be configured as Deployment Target.
  TagName:
    Type: String
    Description: Specifies the prefix for the 'Name' tag for stack resources.
  TagUnit:
    Type: String
    Description: Specifies the value for the 'Unit' tag for stack resources.
  TagEnvironment:
    Type: String
    Description: Specifies the value for the 'Environment' tag for stack resources.
  ConfigAggRoleName:
    Type: String
    Default: <AggregatorRoleName>
    Description: Name for Config Aggregator IAM Role.
  ConfigAggName:
    Type: String
    Default: <AggregatorName>
    Description: Name for Config Aggregator.
Resources:
  ConfigAggregatorRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Ref ConfigAggRoleName
      Description: Role for organizational AWS Config aggregator
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: config.amazonaws.com
            Action: sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSConfigRoleForOrganizations
      Tags:
        - Key: Name
          Value: !Sub
            - "${tag}-${rolename}"
            - tag: !Ref TagName
              rolename: !Ref ConfigAggRoleName
        - Key: Unit
          Value: !Ref TagUnit
        - Key: Environment
          Value: !Ref TagEnvironment
  ConfigAggregator:
    Type: AWS::Config::ConfigurationAggregator
    Properties:
      ConfigurationAggregatorName: !Ref ConfigAggName
      OrganizationAggregationSource:
        AllAwsRegions: false
        AwsRegions: !Ref ConfigRegions
        RoleArn: !GetAtt ConfigAggregatorRole.Arn
      Tags:
        - Key: Name
          Value: !Sub
            - "${tag}-${agg}"
            - tag: !Ref TagName
              agg: !Ref ConfigAggName
        - Key: Unit
          Value: !Ref TagUnit
        - Key: Environment
          Value: !Ref TagEnvironment
```

Upload the new template to S3 and run the following command to create the stack.

```
aws cloudformation create-stack --stack-name Config-OrgConfigAggregator \ 
--template-url https://xxxxxxxx-templates.s3.amazonaws.com/4-StackSetConfigAgg.yml \ 
--capabilities CAPABILITY_NAMED_IAM \ 
--parameters \
    ParameterKey=ConfigRegions,ParameterValue=us-east-1 \
    ParameterKey=TagName,ParameterValue=Config-StackSetConfigRecorder \
    ParameterKey=TagUnit,ParameterValue=Security \
    ParameterKey=TagEnvironment,ParameterValue=Prod \
    ParameterKey=ConfigAggRoleName,ParameterValue="ConfigAggregatorRole" \
    ParameterKey=ConfigAggName,ParameterValue="aggregator"
```

Once the command is executed successfully, an 'OK' status will appear on the aggregator page. However, the aggregator dashboard may take a while to reflect the data from all accounts.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/c97xsnape6oxitidusri.png)

You can execute a query in the Console utilizing data from all accounts and examine all the available fields. To view data from all S3 buckets, run the following query.

```
SELECT
  resourceId,
  resourceName,
  resourceCreationTime,
  accountId
WHERE
  resourceType = 'AWS::S3::Bucket'
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zjgi6emxe9zygmva7s6x.png)

## Cleanup
This lab outlined enabling AWS Config using the AWS CLI to easily replicate each setting. It's important to remember to clean up all CloudFormation stacks and any IAM Role created by AWS.


## Further steps
If you're interested in further exploring AWS Config features and enhancing your setup, consider these suggestions:
- Implement Conformance Packs to utilize a single template that establishes Config Rules across all accounts, avoiding the constraints of Organization Config Rules that necessitate individual rule definition.
- Extend the scope of AWS Config to a multi-region setting within AWS Organizations.
- Introduce server-side encryption for the Centralized S3 Bucket using KMS, which will entail adding IAM Policies to numerous IAM Roles.
- Experiment with AWS Control Tower, a service that simplifies many of the manual configurations associated with AWS Config.
- Implement SNS Notifications for the Config Delivery channel to centralize all messages into one account.

---

## Additional resources

- [AWS Config: Setting Up an Aggregator Using the AWS Command Line Interface](https://docs.aws.amazon.com/config/latest/developerguide/set-up-aggregator-cli.html#add-an-aggregator-organization-cli)
- [Using delegated admin for AWS Config operations and aggregation](https://aws.amazon.com/blogs/mt/using-delegated-admin-for-aws-config-operations-and-aggregation/)
- [AWS CloudFormation: Working with AWS CloudFormation StackSets](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/what-is-cfnstacksets.html)
- [AWS CloudFormation: StackSets concepts](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacksets-concepts.html)