diff --git a/README.md b/README.md
index a93095c8..5ddc7dfe 100644
--- a/README.md
+++ b/README.md
@@ -133,13 +133,14 @@ _Note: The `Quick Setup` is not designed to be used with the `Easy Setup` proced
| [Account Alternate Contacts](aws_sra_examples/solutions/account/account_alternate_contacts) | Sets the billing, operations, and security alternate contacts for all accounts within the organization. | | |
| [CloudTrail](aws_sra_examples/solutions/cloudtrail/cloudtrail_org) | Organization trail with defaults set to configure data events (e.g. S3 and Lambda) to avoid duplicating the Control Tower configured CloudTrail. Options for configuring management events. | CloudTrail enabled in each account with management events only. | |
| [Config Management Account](aws_sra_examples/solutions/config/config_management_account) | Enables AWS Config in the Management account to allow resource compliance monitoring. | Configures AWS Config in all accounts except for the Management account in each governed region. |
|
-| [Config Organization Conformance Pack](aws_sra_examples/solutions/config/config_conformance_pack_org) | Deploys a conformance pack to all accounts and provided regions within an organization. | | - [Common Register Delegated Administrator](aws_sra_examples/solutions/common/common_register_delegated_administrator)
- [Config Management Account](aws_sra_examples/solutions/config/config_management_account)
|
+| [Config Organization](aws_sra_examples/solutions/config/config_org) | Configures AWS Config in all accounts in each governed region. Deploys an Organization Config Aggregator to a delegated admin account. **This solution is incompatible with the AWS Control Tower environment**. | | - AWS Organization
- [Common Register Delegated Administrator](aws_sra_examples/solutions/common/common_register_delegated_administrator)
|
+| [Config Organization Conformance Pack](aws_sra_examples/solutions/config/config_conformance_pack_org) | Deploys a conformance pack to all accounts and provided regions within an organization. | | - AWS Config in all Org Accounts
- [Common Register Delegated Administrator](aws_sra_examples/solutions/common/common_register_delegated_administrator)
- [Config Management Account](aws_sra_examples/solutions/config/config_management_account) in Control Tower environment
|
| [Config Organization Aggregator](aws_sra_examples/solutions/config/config_aggregator_org) | **Not required for most Control Tower environments.** Deploy an Organization Config Aggregator to a delegated admin other than the Audit account. | Organization Config Aggregator in the Management account and Account Config Aggregator in the Audit account. | - AWS Control Tower
- [Common Register Delegated Administrator](aws_sra_examples/solutions/common/common_register_delegated_administrator)
|
| [EC2 Default EBS Encryption](aws_sra_examples/solutions/ec2/ec2_default_ebs_encryption) | Configures the EC2 default EBS encryption to use the default KMS key within all provided regions. | | |
| [Firewall Manager](aws_sra_examples/solutions/firewall_manager/firewall_manager_org) | Demonstrates configuring a security group policy and WAF policies for all accounts within an organization. | | |
| [GuardDuty](aws_sra_examples/solutions/guardduty/guardduty_org) | Configures GuardDuty within a delegated admin account for all accounts within an organization. | | |
| [IAM Access Analyzer](aws_sra_examples/solutions/iam/iam_access_analyzer) | Configures an organization analyzer within a delegated admin account and account level analyzer within each account. | | [Common Register Delegated Administrator](aws_sra_examples/solutions/common/common_register_delegated_administrator)
|
-| [IAM Account Password Policy](aws_sra_examples/solutions/iam/iam_password_policy) | Sets the account password policy for users to align with common compliance standards. | | |
+| [IAM Account Password Policy](aws_sra_examples/solutions/iam/iam_password_policy) | Sets the account password policy for users to align with common compliance standards. | | |
| [Macie](aws_sra_examples/solutions/macie/macie_org) | Configures Macie within a delegated admin account for all accounts within the organization. | |
| [S3 Block Account Public Access](aws_sra_examples/solutions/s3/s3_block_account_public_access) | Configures the account-level S3 BPA settings for all accounts within the organization. | Configures S3 BPA settings on buckets created by Control Tower only. | |
| [Security Hub](aws_sra_examples/solutions/securityhub/securityhub_org) | Configures Security Hub within a delegated admin account for all accounts and governed regions within the organization. | | - AWS Config in all Org Accounts
- [Config Management Account](aws_sra_examples/solutions/config/config_management_account) (_if using AWS Control Tower_)
|
@@ -202,7 +203,7 @@ Q. Why didn't the solutions use inline Lambda functions within the CloudFormatio
- You should control the dependencies in your function's deployment package as stated in the [best practices for working with AWS Lambda functions](https://docs.aws.amazon.com/lambda/latest/dg/best-practices.html).
- The [AWS Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html) might not be the latest version, which contains a feature that is needed for the solution.
-Q. I have ideas to improve this repository. What should I do? A. Please create an issue or submit a pull request.
+Q. I have ideas to improve this repository. What should I do? A. Please create an issue or submit a pull request.Sets the account password policy for users to align with common compliance standards.
## Contributors
diff --git a/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml b/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml
index f5d4d2a8..368cf642 100644
--- a/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml
+++ b/aws_sra_examples/easy_setup/templates/sra-easy-setup.yaml
@@ -45,6 +45,7 @@ Metadata:
Parameters:
- pDeployAccountAlternateContactsSolution
- pDeployCloudTrailSolution
+ - pDeployConfigSolution
- pDeployConfigManagementSolution
- pDeployConfigConformancePackSolution
- pDeployEC2DefaultEBSEncryptionSolution
@@ -88,6 +89,26 @@ Metadata:
- pCloudTrailLogGroupRetention
- pCreateCloudTrailLogGroup
- pOrganizationCloudTrailKeyAlias
+ - Label:
+ default: AWS Config Solution (This solution is incompatible with the AWS Control Tower environment)
+ Parameters:
+ - pCommonPrerequisitesRegionsOnly
+ - pConfigEnabledRegions
+ - pRecorderName
+ - pAllSupported
+ - pIncludeGlobalResourceTypes
+ - pResourceTypes
+ - pDeliveryChannelName
+ - pConfigOrgDeliveryBucketPrefix
+ - pConfigOrgDeliveryKeyAlias
+ - pFrequency
+ - pConfigTopicName
+ - pSubscribeToConfigurationTopic
+ - pConfigurationEmail
+ - pConfigOrgSnsKeyAlias
+ - pAggregatorName
+ - pAggregatorRoleName
+ - pRegisterDelegatedAdminAccount
- Label:
default: AWS Config Management Solution
Parameters:
@@ -298,6 +319,8 @@ Metadata:
default: Deploy the CloudTrail Solution
pDeployConfigConformancePackSolution:
default: Deploy the AWS Config Conformance Pack Solution
+ pDeployConfigSolution:
+ default: Deploy the AWS Config Solution (This solution is incompatible with the AWS Control Tower environment)
pDeployConfigManagementSolution:
default: Deploy the AWS Config Management Solution
pDeployEC2DefaultEBSEncryptionSolution:
@@ -437,6 +460,33 @@ Metadata:
pVpcId:
default: (Optional) Existing VPC ID
+ pCommonPrerequisitesRegionsOnly:
+ default: Common Prerequisites Regions Only
+ pConfigEnabledRegions:
+ default: (Optional) Enabled Regions
+ pRecorderName:
+ default: Recorder Name
+ pDeliveryChannelName:
+ default: Delivery Channel Name
+ pConfigOrgDeliveryBucketPrefix:
+ default: Config Delivery Bucket Prefix
+ pConfigOrgDeliveryKeyAlias:
+ default: Config Delivery KMS Key Alias
+ pConfigTopicName:
+ default: Config SNS Topic Name
+ pSubscribeToConfigurationTopic:
+ default: Subscribe to Configuration Topic
+ pConfigurationEmail:
+ default: Configuration Email
+ pConfigOrgSnsKeyAlias:
+ default: Config SNS KMS Key Alias
+ pAggregatorName:
+ default: Config Aggregator Name
+ pAggregatorRoleName:
+ default: Config Aggregator Role Name
+ pRegisterDelegatedAdminAccount:
+ default: Register Delegated Admin Account
+
Parameters:
pRepoURL:
Default: https://github.com/aws-samples/aws-security-reference-architecture-examples.git
@@ -735,6 +785,11 @@ Parameters:
Default: 'No'
Description: Deploy the AWS Config Conformance Pack solution
Type: String
+ pDeployConfigSolution:
+ AllowedValues: ['Yes', 'No']
+ Default: 'No'
+ Description: Deploy the AWS Config solution (This solution is incompatible with the AWS Control Tower environment)
+ Type: String
pDeployConfigManagementSolution:
AllowedValues: ['Yes', 'No', 'Already Deployed']
Default: 'No'
@@ -1072,7 +1127,7 @@ Parameters:
Description: You can require that IAM user passwords contain at least one uppercase character from the ISO basic Latin alphabet (A to Z).
Type: String
pResourceTypes:
- AllowedPattern: '^$|^([a-zA-Z]+::[a-zA-Z]+::[a-zA-Z]+)$|^(([a-zA-Z]+::[a-zA-Z]+::[a-zA-Z]+(,|, ))*[a-zA-Z]+::[a-zA-Z]+::[a-zA-Z]+)$'
+ AllowedPattern: '^$|^([0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+)$|^(([0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+(,|, ))*[0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+)$'
Default: ''
Description:
(Optional) A list of valid AWS resource types to include in this recording group. Eg. AWS::CloudTrail::Trail. If 'All Supported' parameter is
@@ -1136,6 +1191,82 @@ Parameters:
Description: (Optional) Existing VPC ID for the Firewall Manager Security Groups. Required if Create VPC For Security Group is "false".
Type: String
+ pCommonPrerequisitesRegionsOnly:
+ AllowedValues: ['true', 'false']
+ Default: 'true'
+ Description: Only enable in the customer regions specified in Common Prerequisites solution
+ Type: String
+ pRecorderName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: sra-ConfigRecorder
+ Description: Config recorder name
+ Type: String
+ pDeliveryChannelName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: sra-config-s3-delivery
+ Description: Config delivery channel name
+ Type: String
+ pConfigOrgDeliveryBucketPrefix:
+ AllowedPattern: '^$|^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$'
+ ConstraintDescription:
+ S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+ Default: sra-config-org-delivery
+ Description:
+ Config Delivery S3 bucket prefix. The account and region will get added to the end. e.g. sra-config-delivery-123456789012-us-east-1
+ Type: String
+ pConfigOrgDeliveryKeyAlias:
+ Default: sra-config-org-delivery-key
+ Description: Config Delivery KMS Key Alias
+ Type: String
+ pConfigTopicName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ Default: sra-ConfigNotifications
+ Description: Configuration Notification SNS Topic in Audit Account that AWS Config delivers notifications to.
+ Type: String
+ pSubscribeToConfigurationTopic:
+ AllowedValues: [true, false]
+ Default: false
+ Description: Indicates whether ConfigurationEmail will be subscribed to the Configuration Notification SNS Topic.
+ Type: String
+ pConfigurationEmail:
+ AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$'
+ ConstraintDescription: Email Validation as per RFC2822 standards.
+ Description: Email for receiving all AWS configuration events
+ Default: ''
+ Type: 'String'
+ pConfigOrgSnsKeyAlias:
+ Default: sra-config-org-sns-key
+ Description: Config SNS KMS Key Alias
+ Type: String
+ pAggregatorName:
+ AllowedPattern: '^[\w\-]+'
+ ConstraintDescription: Max 256 alphanumeric characters.
+ Default: sra-config-aggregator-org
+ MaxLength: 256
+ MinLength: 1
+ Type: String
+ pAggregatorRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -].
+ Default: sra-config-aggregator-org
+ Type: String
+ pRegisterDelegatedAdminAccount:
+ AllowedValues: ['Yes', 'No']
+ Default: 'Yes'
+ Description: Register a delegated administrator account using the Common Register Delegated Administrator solution.
+ Type: String
+ pConfigEnabledRegions:
+ AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$'
+ ConstraintDescription:
+ Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g.
+ us-east-1,ap-southeast-2)
+ Description: (Optional) Enabled regions (AWS regions, separated by commas). Leave blank to enable all regions.
+ Type: String
+
Rules:
BillingContactValidation:
RuleCondition: !And
@@ -1156,6 +1287,7 @@ Rules:
- Assert: !Or
- !Equals [!Ref pDeployConfigManagementSolution, 'Yes']
- !Equals [!Ref pDeployConfigManagementSolution, 'Already Deployed']
+ - !Equals [!Ref pDeployConfigSolution, 'Yes']
AssertDescription:
"'Deploy the AWS Config Management Solution' parameter must be set to 'Yes' or 'Already Deployed', if the 'Deploy the AWS Config Conformance
Pack Solution' parameter is set to 'Yes'."
@@ -1165,6 +1297,7 @@ Rules:
- Assert: !Or
- !Equals [!Ref pDeployConfigManagementSolution, 'Yes']
- !Equals [!Ref pDeployConfigManagementSolution, 'Already Deployed']
+ - !Equals [!Ref pDeployConfigSolution, 'Yes']
AssertDescription:
"'Deploy the AWS Config Management Solution' parameter must be set to 'Yes' or 'Already Deployed', if the 'Deploy the Security Hub Solution'
parameter is set to 'Yes'."
@@ -1194,6 +1327,16 @@ Rules:
AssertDescription:
"'Security Full Name', 'Security Title', 'Security Email' and 'Security Phone' parameters are required if the 'Security Alternate Contact
Action' parameter is set to 'add'."
+ EnabledRegionValidation:
+ RuleCondition: !Equals [!Ref pCommonPrerequisitesRegionsOnly, 'false']
+ Assertions:
+ - Assert: !Not [!Equals [!Ref pConfigEnabledRegions, '']]
+ AssertDescription: "'Enabled Regions' parameter has to have a value if 'Common Prerequisites Regions Only' parameter is set to 'false'."
+ ResourceTypesValidation:
+ RuleCondition: !Equals [!Ref pAllSupported, 'false']
+ Assertions:
+ - AssertDescription: "'Resource Types' parameter is required if 'All Supported' parameter is set to 'false'."
+ Assert: !Not [!Equals [!Ref pResourceTypes, '']]
Conditions:
cUsingKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']]
@@ -1214,12 +1357,14 @@ Conditions:
cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'Yes']
cDeployAccountAlternateContactsSolution: !Equals [!Ref pDeployAccountAlternateContactsSolution, 'Yes']
cDeployCloudTrailSolution: !Equals [!Ref pDeployCloudTrailSolution, 'Yes']
+ cDeployConfigSolution: !Equals [!Ref pDeployConfigSolution, 'Yes']
cDeployConfigManagementSolution: !Equals [!Ref pDeployConfigManagementSolution, 'Yes']
cDeployConfigManagementSolutionAlreadyDeployed: !Equals [!Ref pDeployConfigManagementSolution, 'Already Deployed']
cDeployConfigConformancePackSolution: !And
- !Or
- !Condition cDeployConfigManagementSolution
- !Condition cDeployConfigManagementSolutionAlreadyDeployed
+ - !Condition cDeployConfigSolution
- !Equals [!Ref pDeployConfigConformancePackSolution, 'Yes']
cDeployDetectiveSolution: !Equals [!Ref pDeployDetectiveSolution, 'Yes']
cDeployEC2DefaultEBSEncryptionSolution: !Equals [!Ref pDeployEC2DefaultEBSEncryptionSolution, 'Yes']
@@ -2083,3 +2228,34 @@ Resources:
pLambdaLogLevel: !Ref pLambdaLogLevel
pSRAAlarmEmail: !Ref pSRAAlarmEmail
pComplianceFrequency: !Ref pComplianceFrequency
+
+ rConfigSolutionStack:
+ Type: AWS::CloudFormation::Stack
+ DependsOn: rCommonPrerequisitesMainSsm
+ Condition: cDeployConfigSolution
+ DeletionPolicy: Delete
+ UpdateReplacePolicy: Delete
+ Properties:
+ TemplateURL: !Sub https://${pSRAStagingS3BucketNamePrefix}-${AWS::AccountId}-${AWS::Region}.s3.${AWS::Region}.${AWS::URLSuffix}/sra-config-org/templates/sra-config-org-main-ssm.yaml
+ Parameters:
+ pControlTowerRegionsOnly: !Ref pCommonPrerequisitesRegionsOnly
+ pEnabledRegions: !Ref pConfigEnabledRegions
+ pRecorderName: !Ref pRecorderName
+ pDeliveryChannelName: !Ref pDeliveryChannelName
+ pConfigOrgDeliveryBucketPrefix: !Ref pConfigOrgDeliveryBucketPrefix
+ pConfigOrgDeliveryKeyAlias: !Ref pConfigOrgDeliveryKeyAlias
+ pConfigTopicName: !Ref pConfigTopicName
+ pSubscribeToConfigurationTopic: !Ref pSubscribeToConfigurationTopic
+ pConfigurationEmail: !Ref pConfigurationEmail
+ pConfigOrgSnsKeyAlias: !Ref pConfigOrgSnsKeyAlias
+ pAggregatorName: !Ref pAggregatorName
+ pAggregatorRoleName: !Ref pAggregatorRoleName
+ pRegisterDelegatedAdminAccount: !Ref pRegisterDelegatedAdminAccount
+ pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey
+ pLambdaLogLevel: !Ref pLambdaLogLevel
+ pSRAAlarmEmail: !Ref pSRAAlarmEmail
+ pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention
+ pFrequency: !Ref pFrequency
+ pAllSupported: !Ref pAllSupported
+ pIncludeGlobalResourceTypes: !Ref pIncludeGlobalResourceTypes
+ pResourceTypes: !Ref pResourceTypes
diff --git a/aws_sra_examples/solutions/config/config_org/README.md b/aws_sra_examples/solutions/config/config_org/README.md
new file mode 100644
index 00000000..03f52c7a
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/README.md
@@ -0,0 +1,196 @@
+# Config Organization
+
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: CC-BY-SA-4.0
+
+## Table of Contents
+
+- [Table of Contents](#table-of-contents)
+- [Introduction](#introduction)
+- [Deployed Resource Details](#deployed-resource-details)
+- [Implementation Instructions](#implementation-instructions)
+- [References](#references)
+
+---
+
+## Introduction
+
+The Config Organization solution will enable AWS Config, delegate administration to a member account, and configure AWS Config for all the existing and
+future AWS Organization accounts. The Config Organization solution will enable an aggregator in delegated administrator account to collect AWS Config configuration and compliance data for the AWS Organization. AWS Config is also configured to send the configuration snapshots and configuration history files to a central S3 bucket encrypted with a KMS key.
+
+---
+
+## Deployed Resource Details
+
+![Architecture](./documentation/sra-config-org.png)
+
+### 1.0 Organization Management Account
+
+#### 1.1 AWS CloudFormation
+
+- All resources are deployed via AWS CloudFormation as a `StackSet` and `Stack Instance` within the management account or a CloudFormation `Stack` within a specific account.
+- For parameter details, review the [AWS CloudFormation templates](templates/).
+
+#### 1.2 Lambda Execution IAM Role
+
+- IAM role used by the Lambda function to enable the AWS Config and set up AWS Config delivery channel within each account and region provided.
+
+#### 1.3 Configuration IAM Role
+
+- IAM role assumed by the Lambda function within the management account to configure AWS Config within each account and region provided.
+
+#### 1.4 AWS Lambda Function
+
+- The Lambda function includes logic to enable and configure AWS Config.
+
+#### 1.5 Lambda CloudWatch Log Group
+
+- All the `AWS Lambda Function` logs are sent to a CloudWatch Log Group `` to help with debugging and traceability of the actions performed.
+- By default the `AWS Lambda Function` will create the CloudWatch Log Group and logs are encrypted with a CloudWatch Logs service managed encryption key.
+
+#### 1.6 Dead Letter Queue (DLQ)
+
+- SQS dead letter queue used for retaining any failed Lambda events.
+
+#### 1.7 Alarm SNS Topic
+
+- SNS Topic used to notify subscribers when messages hit the DLQ.
+
+#### 1.8 Regional Event Rules
+
+- The `Organization Compliance Scheduled Event Rule` triggers the `AWS Lambda Function` to capture AWS Account status updates (e.g. suspended to active).
+ - A parameter is provided to set the schedule frequency.
+ - See the [Instructions to Manually Run the Lambda Function](#instructions-to-manually-run-the-lambda-function) for triggering the `AWS Lambda Function` before the next scheduled run time.
+- The `AWS Organizations Event Rule` triggers the `AWS Lambda Function` when updates are made to accounts within the organization.
+ - When AWS Accounts are added to the AWS Organization. (e.g. account created via AWS Organizations console, account invited from another AWS Organization).
+- The `Global Event Rule` in us-east-1 forwards the AWS Organization events to the `Home Region` default Event Bus.
+ - If the `Home Region` is different from the `Global Region (e.g. us-east-1)`, then global event rules are created within the `Global Region` to forward events to the `Home Region` default Event Bus.
+
+#### 1.9 AWS Config
+
+- AWS Config is enabled for each existing active account and region during the initial setup.
+- AWS Config will be automatically enabled for new member accounts when added to the AWS Organization.
+
+---
+
+### 2.0 Log Archive Account
+
+#### 2.1 AWS CloudFormation
+
+- See [1.1 AWS CloudFormation](#11-aws-cloudformation)
+
+#### 2.2 AWS Config Delivery S3 Bucket
+
+- S3 bucket where AWS Config configurations snapshots are exported for each account/region within the AWS Organization.
+
+#### 2.3 Configuration IAM Role
+
+- See [1.3 Configuration IAM Role](#13-configuration-iam-role)
+
+#### 2.4 AWS Config
+
+- See [1.9 AWS Config](#17-aws-config)
+
+---
+
+### 3.0 Audit Account (Security Tooling)
+
+The example solutions use `Security Account Id` for the `Security Tooling Account`. _NOTE_ Conceptually the Security Tooling Account equivalent of Control Tower's default `Audit Account`. The Account ID for the `Security Account Id` SSM parameter is
+populated from the `SecurityAccountId` parameter within the `sra-easy-setup` Stack.
+
+#### 3.1 AWS CloudFormation
+
+- See [1.1 AWS CloudFormation](#11-aws-cloudformation)
+
+#### 3.2 Notification SNS Topic
+- Configuration Notification SNS Topic in Audit Account that AWS Config delivers notifications to.
+
+#### 3.3 AWS Config Delivery KMS Key
+
+- KMS key to encrypt the configuration snapshots with a customer managed KMS key.
+
+#### 3.4 Configuration IAM Role
+
+- See [1.3 Configuration IAM Role](#13-configuration-iam-role)
+
+#### 3.5 AWS Config Aggregator IAM Role
+
+- IAM role used by AWS Config to access AWS Organizations APIs.
+
+#### 3.6 AWS Config Aggregator
+
+- AWS Config Aggregator configured in the delegated administrator account to collect AWS Config configuration and compliance data for the AWS Organization.
+
+#### 3.7 SNS Topic KMS Key
+
+- KMS key to encrypt the SNS Topic with a customer managed KMS key.
+
+#### 3.8 AWS Config
+
+- See [1.9 Config](#19-aws-config)
+
+---
+
+### 4.0 All Existing and Future Organization Member Accounts
+
+#### 4.1 AWS CloudFormation
+
+- See [1.1 AWS CloudFormation](#11-aws-cloudformation)
+
+#### 4.2 Configuration IAM Role
+
+- See [1.3 Configuration IAM Role](#13-configuration-iam-role)
+
+#### 4.3 AWS Config
+
+- See [1.9 AWS Config](#19-aws-config)
+
+---
+
+## Implementation Instructions
+
+### Prerequisites
+
+1. [Download and Stage the SRA Solutions](../../../docs/DOWNLOAD-AND-STAGE-SOLUTIONS.md). **Note:** This only needs to be done once for all the solutions.
+2. Verify that the [SRA Prerequisites Solution](../../common/common_prerequisites/) has been deployed.
+
+### Solution Deployment
+
+Choose a Deployment Method:
+
+- [AWS CloudFormation](#aws-cloudformation)
+
+#### AWS CloudFormation
+
+In the `management account (home region)`, launch an AWS CloudFormation **Stack** using the option below:
+
+- Use the [sra-config-org-main-ssm.yaml](templates/sra-config-org-main-ssm.yaml) template. This is a more automated approach where some of the CloudFormation parameters are populated from SSM parameters created by
+ the [SRA Prerequisites Solution](../../common/common_prerequisites/).
+
+ ```bash
+ aws cloudformation deploy --template-file $HOME/aws-sra-examples/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-main-ssm.yaml --stack-name sra-config-org-main-ssm --capabilities CAPABILITY_NAMED_IAM
+ ```
+
+#### Verify Solution Deployment
+
+1. Log into the Audit account and navigate to the AWS Config page.
+ 1. Verify the correct AWS Config configurations have been applied to each account and region.
+ 2. Verify all existing accounts have been enabled.
+ 3. Verify the correct AWS Config Aggregator configurations have been applied.
+ 4. Verify all existing accounts have been enabled. Note: It can take a few minutes to complete.
+2. Log into the Log archive account and navigate to the S3 page.
+ 1. Verify the sample configuration snapshots have been delivered.
+
+#### Solution Delete Instructions
+
+1. In the `management account (home region)`, delete the AWS CloudFormation **Stack** (`sra-config-org-main-ssm`).
+3. In the `management account (home region)`, delete the AWS CloudWatch **Log Group** (e.g. /aws/lambda/) for the Lambda function deployed.
+4. In the `log archive acccount (home region)`, delete the S3 bucket (e.g. sra-config-delivery--) created by the solution.
+
+---
+
+## References
+
+- [AWS Config and AWS Organizations](https://docs.aws.amazon.com/organizations/latest/userguide/services-that-can-integrate-config.html)
+- [Managing AWS SDKs in Lambda Functions](https://docs.aws.amazon.com/lambda/latest/operatorguide/sdks-functions.html)
+- [Lambda runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html)
+- [Python Boto3 SDK changelog](https://github.com/boto/boto3/blob/develop/CHANGELOG.rst)
diff --git a/aws_sra_examples/solutions/config/config_org/documentation/sra-config-org.png b/aws_sra_examples/solutions/config/config_org/documentation/sra-config-org.png
new file mode 100644
index 00000000..cceed34b
Binary files /dev/null and b/aws_sra_examples/solutions/config/config_org/documentation/sra-config-org.png differ
diff --git a/aws_sra_examples/solutions/config/config_org/documentation/sra-config-org.pptx b/aws_sra_examples/solutions/config/config_org/documentation/sra-config-org.pptx
new file mode 100644
index 00000000..e933333e
Binary files /dev/null and b/aws_sra_examples/solutions/config/config_org/documentation/sra-config-org.pptx differ
diff --git a/aws_sra_examples/solutions/config/config_org/documentation/~$sra-config-org.pptx b/aws_sra_examples/solutions/config/config_org/documentation/~$sra-config-org.pptx
new file mode 100644
index 00000000..138f1a0b
Binary files /dev/null and b/aws_sra_examples/solutions/config/config_org/documentation/~$sra-config-org.pptx differ
diff --git a/aws_sra_examples/solutions/config/config_org/lambda/src/app.py b/aws_sra_examples/solutions/config/config_org/lambda/src/app.py
new file mode 100644
index 00000000..65fef0a0
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/lambda/src/app.py
@@ -0,0 +1,542 @@
+"""This script performs operations to enable, configure, and disable Config.
+
+Version: 1.0
+
+'config_org' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples
+
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+from __future__ import annotations
+
+import json
+import logging
+import os
+import re
+from time import sleep
+from typing import TYPE_CHECKING, Any, Dict, Optional
+
+import boto3
+import common
+import config
+from crhelper import CfnResource
+
+if TYPE_CHECKING:
+ from aws_lambda_typing.context import Context
+ from aws_lambda_typing.events import CloudFormationCustomResourceEvent
+ from mypy_boto3_config.type_defs import DeliveryChannelTypeDef
+ from mypy_boto3_organizations import OrganizationsClient
+ from mypy_boto3_secretsmanager import SecretsManagerClient
+ from mypy_boto3_sns import SNSClient
+ from mypy_boto3_sns.type_defs import PublishBatchResponseTypeDef
+
+LOGGER = logging.getLogger("sra")
+log_level: str = os.environ.get("LOG_LEVEL", "ERROR")
+LOGGER.setLevel(log_level)
+
+UNEXPECTED = "Unexpected!"
+SERVICE_NAME = "config.amazonaws.com"
+SLEEP_SECONDS = 60
+SNS_PUBLISH_BATCH_MAX = 10
+
+helper = CfnResource(json_logging=True, log_level=log_level, boto_level="CRITICAL", sleep_on_delete=120)
+
+try:
+ MANAGEMENT_ACCOUNT_SESSION = boto3.Session()
+ ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations")
+ SNS_CLIENT: SNSClient = MANAGEMENT_ACCOUNT_SESSION.client("sns")
+except Exception:
+ LOGGER.exception(UNEXPECTED)
+ raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None
+
+
+def process_add_update_event(params: dict, regions: list, accounts: list) -> None:
+ """Process Add or Update Events.
+
+ Args:
+ params: Configuration Parameters
+ regions: list of regions
+ accounts: list of accounts
+ """
+ LOGGER.info("...process_add_update_event")
+
+ if params["action"] in ["Add", "Update"]:
+ accounts = common.get_active_organization_accounts()
+ regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true")
+ setup_config_global(params, regions, accounts)
+
+ LOGGER.info("...ADD_UPDATE_NO_EVENT")
+
+
+def process_event(event: dict) -> None:
+ """Process Event.
+
+ Args:
+ event: event data
+ """
+ event_info = {"Event": event}
+ LOGGER.info(event_info)
+ params = get_validated_parameters({"RequestType": "Update"})
+
+ accounts = common.get_active_organization_accounts()
+ regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true")
+ process_add_update_event(params, regions, accounts)
+
+
+def process_account(aws_account_id: str, params: dict) -> None:
+ """Process Account.
+
+ Args:
+ aws_account_id: AWS Account ID
+ params: solution parameters
+ """
+ sleep(SLEEP_SECONDS)
+ config.create_service_linked_role(aws_account_id, params["CONFIGURATION_ROLE_NAME"])
+ regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true")
+ resource_types = build_resource_types_param(params)
+
+ for region in regions:
+ role_arn = f"arn:{params['AWS_PARTITION']}:iam::{aws_account_id}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig"
+ config.set_config_in_org(
+ aws_account_id,
+ region,
+ params["CONFIGURATION_ROLE_NAME"],
+ params["RECORDER_NAME"],
+ role_arn,
+ resource_types,
+ params["ALL_SUPPORTED"],
+ params["INCLUDE_GLOBAL_RESOURCE_TYPES"],
+ )
+ delivery_channel = set_delivery_channel_params(params, region)
+ config.set_delivery_channel(aws_account_id, region, params["CONFIGURATION_ROLE_NAME"], delivery_channel)
+
+
+def process_event_organizations(event: dict) -> None:
+ """Process Event from AWS Organizations.
+
+ Args:
+ event: event data
+ """
+ event_info = {"Event": event}
+ LOGGER.info(event_info)
+ params = get_validated_parameters({})
+
+ if event["detail"]["eventName"] == "AcceptHandshake" and event["detail"]["responseElements"]["handshake"]["state"] == "ACCEPTED":
+ for party in event["detail"]["responseElements"]["handshake"]["parties"]:
+ if party["type"] == "ACCOUNT":
+ aws_account_id = party["id"]
+ process_account(aws_account_id, params)
+ break
+ elif event["detail"]["eventName"] == "CreateAccountResult":
+ aws_account_id = event["detail"]["serviceEventDetails"]["createAccountStatus"]["accountId"]
+ process_account(aws_account_id, params)
+ else:
+ LOGGER.info("Organization event does not match expected values.")
+
+
+def parameter_pattern_validator(parameter_name: str, parameter_value: Optional[str], pattern: str, is_optional: bool = False) -> dict:
+ """Validate CloudFormation Custom Resource Properties and/or Lambda Function Environment Variables.
+
+ Args:
+ parameter_name: CloudFormation custom resource parameter name and/or Lambda function environment variable name
+ parameter_value: CloudFormation custom resource parameter value and/or Lambda function environment variable value
+ pattern: REGEX pattern to validate against.
+ is_optional: Allow empty or missing value when True
+
+ Raises:
+ ValueError: Parameter has a value of empty string.
+ ValueError: Parameter is missing
+ ValueError: Parameter does not follow the allowed pattern
+
+ Returns:
+ Validated Parameter
+ """
+ if parameter_value == "" and not is_optional:
+ raise ValueError(f"({parameter_name}) parameter has a value of empty string.")
+ elif not parameter_value and not is_optional:
+ raise ValueError(f"({parameter_name}) parameter is missing.")
+ elif not re.match(pattern, str(parameter_value)):
+ raise ValueError(f"({parameter_name}) parameter with value of ({parameter_value})" + f" does not follow the allowed pattern: {pattern}.")
+ return {parameter_name: parameter_value}
+
+
+def get_validated_parameters(event: dict) -> dict: # noqa: CFQ001
+ """Validate AWS CloudFormation parameters.
+
+ Args:
+ event: event data
+
+ Returns:
+ Validated parameters
+ """
+ params: dict = {}
+ actions = {"Create": "Add", "Update": "Update", "Delete": "Remove"}
+ params["action"] = actions[event.get("RequestType", "Create")]
+ true_false_pattern = r"^true|false$"
+ sns_topic_pattern = r"^arn:(aws[a-zA-Z-]*){1}:sns:[a-z0-9-]+:\d{12}:[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$"
+
+ # Required Parameters
+ params.update(
+ parameter_pattern_validator(
+ "AWS_PARTITION",
+ os.environ.get("AWS_PARTITION"),
+ pattern=r"^(aws[a-zA-Z-]*)?$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "CONFIGURATION_ROLE_NAME",
+ os.environ.get("CONFIGURATION_ROLE_NAME"),
+ pattern=r"^[\w+=,.@-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "CONFIG_TOPIC_NAME",
+ os.environ.get("CONFIG_TOPIC_NAME"),
+ pattern=r"^[\w+=,.@-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "DELIVERY_CHANNEL_NAME",
+ os.environ.get("DELIVERY_CHANNEL_NAME"),
+ pattern=r"^[\w+=,.@-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "S3_BUCKET_NAME",
+ os.environ.get("S3_BUCKET_NAME"),
+ pattern=r"^[\w+=,.@-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "DELIVERY_S3_KEY_PREFIX",
+ os.environ.get("DELIVERY_S3_KEY_PREFIX"),
+ pattern=r"^[\w+=,.@-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "ALL_SUPPORTED",
+ os.environ.get("ALL_SUPPORTED"),
+ pattern=true_false_pattern,
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "CONTROL_TOWER_REGIONS_ONLY",
+ os.environ.get("CONTROL_TOWER_REGIONS_ONLY"),
+ pattern=true_false_pattern,
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "FREQUENCY", os.environ.get("FREQUENCY"), pattern=r"^(One_Hour|Three_Hours|Six_Hours|Twelve_Hours|TwentyFour_Hours){1}$"
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "INCLUDE_GLOBAL_RESOURCE_TYPES",
+ os.environ.get("INCLUDE_GLOBAL_RESOURCE_TYPES"),
+ pattern=true_false_pattern,
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "AUDIT_ACCOUNT",
+ os.environ.get("AUDIT_ACCOUNT"),
+ pattern=r"^\d{12}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "RECORDER_NAME",
+ os.environ.get("RECORDER_NAME"),
+ pattern=r"^[\w+=,.@-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "KMS_KEY_SECRET_NAME",
+ os.environ.get("KMS_KEY_SECRET_NAME"),
+ pattern=r"^[\w+=,.@/_-]{1,64}$",
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "HOME_REGION",
+ os.environ.get("HOME_REGION"),
+ pattern=r"^$|[a-z0-9-, ]+$",
+ )
+ )
+ params.update(parameter_pattern_validator("SNS_TOPIC_ARN_FANOUT", os.environ.get("SNS_TOPIC_ARN_FANOUT"), pattern=sns_topic_pattern))
+
+ # Optional Parameters
+ params.update(
+ parameter_pattern_validator(
+ "ENABLED_REGIONS",
+ os.environ.get("ENABLED_REGIONS"),
+ pattern=r"^$|[a-z0-9-, ]+$",
+ is_optional=True,
+ )
+ )
+ params.update(
+ parameter_pattern_validator(
+ "RESOURCE_TYPES",
+ os.environ.get("RESOURCE_TYPES"),
+ pattern=r"^[\w+=,.:() @-]{1,3000}$",
+ is_optional=True,
+ )
+ )
+
+ # Convert true/false string parameters to boolean
+ params.update({"ALL_SUPPORTED": (params["ALL_SUPPORTED"] == "true")})
+ params.update({"INCLUDE_GLOBAL_RESOURCE_TYPES": (params["INCLUDE_GLOBAL_RESOURCE_TYPES"] == "true")})
+
+ return params
+
+
+def build_resource_types_param(params: dict) -> list:
+ """Build list of resource types.
+
+ Args:
+ params: Configuration Parameters
+
+ Returns:
+ list of resource types
+ """
+ params = get_validated_parameters({"RequestType": "Update"})
+ resource_types: list = []
+ if params["RESOURCE_TYPES"]:
+ resource_types_param = params["RESOURCE_TYPES"]
+ resource_types = resource_types_param.split(",")
+ return resource_types
+ return resource_types
+
+
+def get_kms_key(params: dict) -> str:
+ """Get KMS key arn for Config delivery channel.
+
+ Args:
+ params: Configuration Parameters
+
+ Returns:
+ str: KMS key arn for Config delivery channel
+ """
+ LOGGER.info("Getting KMS key arn from Secrets Manager")
+ account = params["AUDIT_ACCOUNT"]
+ secret_name = params["KMS_KEY_SECRET_NAME"]
+ region_name = params["HOME_REGION"]
+ configuration_role_name = params["CONFIGURATION_ROLE_NAME"]
+ account_session: boto3.Session = common.assume_role(configuration_role_name, "sra-get-secret", account)
+ client: SecretsManagerClient = account_session.client(service_name="secretsmanager", region_name=region_name)
+ get_secret_value_response = client.get_secret_value(SecretId=secret_name, VersionStage="AWSCURRENT")
+ secret = json.loads(get_secret_value_response["SecretString"])
+ return secret["ConfigDeliveryKeyArn"]
+
+
+def set_delivery_channel_params(params: dict, region: str) -> DeliveryChannelTypeDef:
+ """Set parameters for Config delivery channel.
+
+ Args:
+ params: Configuration Parameters
+ region: AWS Region
+
+ Returns:
+ DeliveryChannelTypeDef: Parameters for Config delivery channel
+ """
+ sns_topic_arn = f"arn:{params['AWS_PARTITION']}:sns:{region}:{params['AUDIT_ACCOUNT']}:{params['CONFIG_TOPIC_NAME']}"
+ s3_kms_key_arn = get_kms_key(params)
+ delivery_channel: DeliveryChannelTypeDef = {
+ "name": params["DELIVERY_CHANNEL_NAME"],
+ "s3BucketName": params["S3_BUCKET_NAME"],
+ "s3KeyPrefix": params["DELIVERY_S3_KEY_PREFIX"],
+ "s3KmsKeyArn": s3_kms_key_arn,
+ "snsTopicARN": sns_topic_arn,
+ "configSnapshotDeliveryProperties": {"deliveryFrequency": params["FREQUENCY"]},
+ }
+
+ return delivery_channel
+
+
+def setup_config_global(params: dict, regions: list, accounts: list) -> None:
+ """Enable the Config service and configure its global settings.
+
+ Args:
+ params: Configuration Parameters
+ regions: list of regions
+ accounts: list of accounts
+ """
+ for account in accounts:
+ config.create_service_linked_role(account["AccountId"], params["CONFIGURATION_ROLE_NAME"])
+
+ create_sns_messages(accounts, regions, params["SNS_TOPIC_ARN_FANOUT"], "configure")
+
+
+def create_sns_messages(accounts: list, regions: list, sns_topic_arn_fanout: str, action: str) -> None:
+ """Create SNS Message.
+
+ Args:
+ accounts: Account List
+ regions: list of AWS regions
+ sns_topic_arn_fanout: SNS Topic ARN
+ action: Action
+ """
+ sns_messages = []
+ for region in regions:
+ sns_message = {"Accounts": accounts, "Region": region, "Action": action}
+ sns_messages.append(
+ {
+ "Id": region,
+ "Message": json.dumps(sns_message),
+ "Subject": "Config Configuration",
+ }
+ )
+
+ process_sns_message_batches(sns_messages, sns_topic_arn_fanout)
+
+
+def publish_sns_message_batch(message_batch: list, sns_topic_arn_fanout: str) -> None:
+ """Publish SNS Message Batches.
+
+ Args:
+ message_batch: Batch of SNS messages
+ sns_topic_arn_fanout: SNS Topic ARN
+ """
+ LOGGER.info("Publishing SNS Message Batch")
+ LOGGER.info({"SNSMessageBatch": message_batch})
+ response: PublishBatchResponseTypeDef = SNS_CLIENT.publish_batch(TopicArn=sns_topic_arn_fanout, PublishBatchRequestEntries=message_batch)
+ api_call_details = {"API_Call": "sns:PublishBatch", "API_Response": response}
+ LOGGER.info(api_call_details)
+
+
+def process_sns_message_batches(sns_messages: list, sns_topic_arn_fanout: str) -> None:
+ """Process SNS Message Batches for Publishing.
+
+ Args:
+ sns_messages: SNS messages to be batched.
+ sns_topic_arn_fanout: SNS Topic ARN
+ """
+ message_batches = []
+ for i in range(
+ SNS_PUBLISH_BATCH_MAX,
+ len(sns_messages) + SNS_PUBLISH_BATCH_MAX,
+ SNS_PUBLISH_BATCH_MAX,
+ ):
+ message_batches.append(sns_messages[i - SNS_PUBLISH_BATCH_MAX : i])
+
+ for batch in message_batches:
+ publish_sns_message_batch(batch, sns_topic_arn_fanout)
+
+
+def process_event_sns(event: dict) -> None:
+ """Process SNS event to complete the setup process.
+
+ Args:
+ event: event data
+ """
+ params = get_validated_parameters({})
+ for record in event["Records"]:
+ record["Sns"]["Message"] = json.loads(record["Sns"]["Message"])
+ LOGGER.info({"SNS Record": record})
+ message = record["Sns"]["Message"]
+ if message["Action"] == "configure":
+ LOGGER.info("Continuing process to enable Config (sns event)")
+ resource_types = build_resource_types_param(params)
+
+ for account in message["Accounts"]:
+ role_arn = (
+ f"arn:{params['AWS_PARTITION']}:iam::{account['AccountId']}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig"
+ )
+ config.set_config_in_org(
+ account["AccountId"],
+ message["Region"],
+ params["CONFIGURATION_ROLE_NAME"],
+ params["RECORDER_NAME"],
+ role_arn,
+ resource_types,
+ params["ALL_SUPPORTED"],
+ params["INCLUDE_GLOBAL_RESOURCE_TYPES"],
+ )
+ delivery_channel = set_delivery_channel_params(params, message["Region"])
+ for account in message["Accounts"]:
+ config.set_delivery_channel(account["AccountId"], message["Region"], params["CONFIGURATION_ROLE_NAME"], delivery_channel)
+
+ LOGGER.info("...ADD_UPDATE_NO_EVENT")
+
+
+@helper.create
+@helper.update
+@helper.delete
+def process_event_cloudformation(event: CloudFormationCustomResourceEvent, context: Context) -> str: # noqa: U100
+ """Process Event from AWS CloudFormation.
+
+ Args:
+ event: event data
+ context: runtime information
+
+ Returns:
+ AWS CloudFormation physical resource id
+ """
+ event_info = {"Event": event}
+ LOGGER.info(event_info)
+
+ params = get_validated_parameters({"RequestType": event["RequestType"]})
+ accounts = common.get_active_organization_accounts()
+ regions = common.get_enabled_regions(params["ENABLED_REGIONS"], params["CONTROL_TOWER_REGIONS_ONLY"] == "true")
+ configuration_role_name = params["CONFIGURATION_ROLE_NAME"]
+
+ if params["action"] in ["Add", "Update"]:
+ LOGGER.info("calling process_add_update_event")
+ process_add_update_event(params, regions, accounts)
+ else:
+ LOGGER.info("...Disable Config from (process_event_cloudformation)")
+ for account in accounts:
+ for region in regions:
+ LOGGER.info(f"Stopping config recorder in {account} account in {region} region")
+ config.stop_config_recorder(account["AccountId"], region, configuration_role_name)
+
+ return "SRA-CONFIG-ORG"
+
+
+def orchestrator(event: Dict[str, Any], context: Any) -> None:
+ """Orchestration.
+
+ Args:
+ event: event data
+ context: runtime information
+ """
+ if event.get("RequestType"):
+ LOGGER.info("...calling helper...")
+ helper(event, context)
+ elif event.get("Records") and event["Records"][0]["EventSource"] == "aws:sns":
+ LOGGER.info("...aws:sns record...")
+ process_event_sns(event)
+ else:
+ LOGGER.info("...else...just calling process_event...")
+ process_event(event)
+
+
+def lambda_handler(event: Dict[str, Any], context: Any) -> None:
+ """Lambda Handler.
+
+ Args:
+ event: event data
+ context: runtime information
+
+ Raises:
+ ValueError: Unexpected error executing Lambda function
+ """
+ LOGGER.info("....Lambda Handler Started....")
+ boto3_version = boto3.__version__
+ LOGGER.info(f"boto3 version: {boto3_version}")
+ event_info = {"Event": event}
+ LOGGER.info(event_info)
+ try:
+ orchestrator(event, context)
+ except Exception:
+ LOGGER.exception(UNEXPECTED)
+ raise ValueError(f"Unexpected error executing Lambda function. Review CloudWatch logs ({context.log_group_name}) for details.") from None
diff --git a/aws_sra_examples/solutions/config/config_org/lambda/src/common.py b/aws_sra_examples/solutions/config/config_org/lambda/src/common.py
new file mode 100644
index 00000000..f9a30744
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/lambda/src/common.py
@@ -0,0 +1,208 @@
+"""This script includes common functions.
+
+Version: 1.0
+
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+from __future__ import annotations
+
+import logging
+import os
+from time import sleep
+from typing import TYPE_CHECKING
+
+import boto3
+from botocore.exceptions import ClientError, EndpointConnectionError
+
+if TYPE_CHECKING:
+ from mypy_boto3_iam.client import IAMClient
+ from mypy_boto3_organizations import OrganizationsClient
+ from mypy_boto3_ssm.client import SSMClient
+ from mypy_boto3_sts.client import STSClient
+
+# Setup Default Logger
+LOGGER = logging.getLogger("sra")
+log_level = os.environ.get("LOG_LEVEL", logging.INFO)
+LOGGER.setLevel(log_level)
+
+# Global variables
+ORGANIZATIONS_PAGE_SIZE = 20
+ORGANIZATIONS_THROTTLE_PERIOD = 0.2
+
+try:
+ MANAGEMENT_ACCOUNT_SESSION = boto3.Session()
+ ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations")
+ SSM_CLIENT: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm")
+except Exception as error:
+ LOGGER.error({"Unexpected_Error": error})
+ raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None
+
+
+def assume_role(
+ role: str,
+ role_session_name: str,
+ account: str = None,
+ session: boto3.Session = None,
+) -> boto3.Session:
+ """Assumes the provided role in the given account and returns a session.
+
+ Args:
+ role: Role to assume in target account.
+ role_session_name: Identifier for the assumed role session.
+ account: AWS account number. Defaults to None.
+ session: Boto3 session. Defaults to None.
+
+ Returns:
+ Session object for the specified AWS account
+ """
+ if not session:
+ session = boto3.Session()
+ sts_client: STSClient = session.client("sts")
+ sts_arn = sts_client.get_caller_identity()["Arn"]
+ LOGGER.info(f"USER: {sts_arn}")
+ if not account:
+ account = sts_arn.split(":")[4]
+ partition = sts_arn.split(":")[1]
+ role_arn = f"arn:{partition}:iam::{account}:role/{role}"
+
+ response = sts_client.assume_role(RoleArn=role_arn, RoleSessionName=role_session_name)
+ LOGGER.info(f"ASSUMED ROLE: {response['AssumedRoleUser']['Arn']}")
+ return boto3.Session(
+ aws_access_key_id=response["Credentials"]["AccessKeyId"],
+ aws_secret_access_key=response["Credentials"]["SecretAccessKey"],
+ aws_session_token=response["Credentials"]["SessionToken"],
+ )
+
+
+def get_active_organization_accounts(exclude_accounts: list = None) -> list:
+ """Get all the active AWS Organization accounts.
+
+ Args:
+ exclude_accounts: list of account IDs to exclude
+
+ Returns:
+ List of active account IDs
+ """
+ if exclude_accounts is None:
+ exclude_accounts = ["00000000000"]
+ accounts: list[dict] = []
+ paginator = ORG_CLIENT.get_paginator("list_accounts")
+
+ for page in paginator.paginate(PaginationConfig={"PageSize": ORGANIZATIONS_PAGE_SIZE}):
+ for account in page["Accounts"]:
+ if account["Status"] == "ACTIVE" and account["Id"] not in exclude_accounts:
+ accounts.append({"AccountId": account["Id"], "Email": account["Email"]})
+ sleep(ORGANIZATIONS_THROTTLE_PERIOD)
+
+ return accounts
+
+
+def get_control_tower_regions() -> list: # noqa: CCR001
+ """Query 'AWSControlTowerBP-BASELINE-CLOUDWATCH' CloudFormation stack to identify customer regions.
+
+ Returns:
+ Customer regions chosen in Control Tower
+ """
+ customer_regions = []
+ ssm_response = SSM_CLIENT.get_parameter(Name="/sra/regions/customer-control-tower-regions")
+ customer_regions = ssm_response["Parameter"]["Value"].split(",")
+ return list(customer_regions)
+
+
+def get_enabled_regions(customer_regions: str, control_tower_regions_only: bool = False) -> list: # noqa: CCR001, C901 # NOSONAR
+ """Query STS to identify enabled regions.
+
+ Args:
+ customer_regions: customer provided comma delimited string of regions
+ control_tower_regions_only: Use the Control Tower governed regions. Defaults to False.
+
+ Returns:
+ Enabled regions
+ """
+ if customer_regions.strip() and not control_tower_regions_only:
+ LOGGER.info({"CUSTOMER PROVIDED REGIONS": customer_regions})
+ region_list = []
+ for region in customer_regions.split(","):
+ if region != "":
+ region_list.append(region.strip())
+ elif control_tower_regions_only:
+ region_list = get_control_tower_regions()
+ else:
+ default_available_regions = [
+ "ap-northeast-1",
+ "ap-northeast-2",
+ "ap-northeast-3",
+ "ap-south-1",
+ "ap-southeast-1",
+ "ap-southeast-2",
+ "ca-central-1",
+ "eu-central-1",
+ "eu-north-1",
+ "eu-west-1",
+ "eu-west-2",
+ "eu-west-3",
+ "sa-east-1",
+ "us-east-1",
+ "us-east-2",
+ "us-west-1",
+ "us-west-2",
+ ]
+ LOGGER.info({"Default_Available_Regions": default_available_regions})
+ region_list = default_available_regions
+
+ region_session = boto3.Session()
+ enabled_regions = []
+ disabled_regions = []
+ invalid_regions = []
+ for region in region_list:
+ try:
+ sts_client = region_session.client(
+ "sts",
+ endpoint_url=f"https://sts.{region}.amazonaws.com",
+ region_name=region,
+ )
+ sts_client.get_caller_identity()
+ enabled_regions.append(region)
+ except EndpointConnectionError:
+ invalid_regions.append(region)
+ LOGGER.error(f"Region: ({region}) is not valid")
+ except ClientError as error:
+ if error.response["Error"]["Code"] == "InvalidClientTokenId":
+ disabled_regions.append(region)
+ LOGGER.error(f"Error {error.response['Error']} occurred testing region {region}")
+ except Exception:
+ LOGGER.exception("Unexpected!")
+
+ LOGGER.info(
+ {
+ "Enabled_Regions": enabled_regions,
+ "Disabled_Regions": disabled_regions,
+ "Invalid_Regions": invalid_regions,
+ }
+ )
+ return enabled_regions
+
+
+def create_service_linked_role(
+ service_linked_role_name: str,
+ service_name: str,
+ description: str = "",
+ iam_client: IAMClient = None,
+) -> None:
+ """Create the service linked role, if it does not exist.
+
+ Args:
+ service_linked_role_name: Service Linked Role Name
+ service_name: AWS Service Name
+ description: Description
+ iam_client: IAMClient
+ """
+ if not iam_client:
+ iam_client = boto3.client("iam")
+ try:
+ response = iam_client.get_role(RoleName=service_linked_role_name)
+ api_call_details = {"API_Call": "iam:GetRole", "API_Response": response}
+ LOGGER.info(api_call_details)
+ except iam_client.exceptions.NoSuchEntityException:
+ iam_client.create_service_linked_role(AWSServiceName=service_name, Description=description)
diff --git a/aws_sra_examples/solutions/config/config_org/lambda/src/config.py b/aws_sra_examples/solutions/config/config_org/lambda/src/config.py
new file mode 100644
index 00000000..666882a1
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/lambda/src/config.py
@@ -0,0 +1,169 @@
+"""This script performs operations to enable, configure, and disable config.
+
+Version: 1.0
+'config-org' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples
+
+Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+SPDX-License-Identifier: MIT-0
+"""
+from __future__ import annotations
+
+import logging
+import os
+from typing import TYPE_CHECKING
+
+import boto3
+import common
+from botocore.config import Config
+from botocore.exceptions import ClientError
+
+if TYPE_CHECKING:
+ from mypy_boto3_cloudformation import CloudFormationClient
+ from mypy_boto3_config.client import ConfigServiceClient
+ from mypy_boto3_config.type_defs import ConfigurationRecorderTypeDef, DeliveryChannelTypeDef
+ from mypy_boto3_iam import IAMClient
+ from mypy_boto3_organizations import OrganizationsClient
+ from mypy_boto3_ssm.client import SSMClient
+
+# Logging Settings
+LOGGER = logging.getLogger("sra")
+log_level: str = os.environ.get("LOG_LEVEL", "ERROR")
+LOGGER.setLevel(log_level)
+
+# Global Variables
+MAX_THREADS = 20
+ORG_PAGE_SIZE = 20 # Max page size for list_accounts
+ORG_THROTTLE_PERIOD = 0.2
+BOTO3_CONFIG = Config(retries={"max_attempts": 10, "mode": "standard"})
+
+try:
+ MANAGEMENT_ACCOUNT_SESSION = boto3.Session()
+ ORG_CLIENT: OrganizationsClient = MANAGEMENT_ACCOUNT_SESSION.client("organizations", config=BOTO3_CONFIG)
+ CFN_CLIENT: CloudFormationClient = MANAGEMENT_ACCOUNT_SESSION.client("cloudformation", config=BOTO3_CONFIG)
+ SSM_CLIENT: SSMClient = MANAGEMENT_ACCOUNT_SESSION.client("ssm")
+except Exception as error:
+ LOGGER.error({"Unexpected_Error": error})
+ raise ValueError("Unexpected error executing Lambda function. Review CloudWatch logs for details.") from None
+
+
+def create_service_linked_role(account_id: str, configuration_role_name: str) -> None:
+ """Create service linked role in the given account.
+
+ Args:
+ account_id (str): Account ID
+ configuration_role_name (str): IAM configuration role name
+ """
+ LOGGER.info(f"creating service linked role for account {account_id}")
+ account_session: boto3.Session = common.assume_role(configuration_role_name, "sra-configure-config", account_id)
+ iam_client: IAMClient = account_session.client("iam")
+ common.create_service_linked_role(
+ "AWSServiceRoleForConfig",
+ "config.amazonaws.com",
+ "A service-linked role required for AWS Config",
+ iam_client,
+ )
+
+
+def set_config_in_org(
+ account_id: str,
+ region: str,
+ configuration_role_name: str,
+ recorder_name: str,
+ role_arn: str,
+ resource_types: list,
+ all_supported: bool,
+ include_global_resource_types: bool,
+) -> None:
+ """Create Config recorder.
+
+ Args:
+ account_id: Account id
+ region: AWS Region
+ configuration_role_name: IAM configuration role name
+ recorder_name: Name for Config recorder
+ role_arn: Role arn to configure Config recorder
+ resource_types: Resource types
+ all_supported: All supported
+ include_global_resource_types: Include global resource types
+ """
+ account_session: boto3.Session = common.assume_role(configuration_role_name, "sra-configure-config", account_id)
+ LOGGER.info(f"Checking config for {account_id} in {region}") # update
+ config_client: ConfigServiceClient = account_session.client("config", region_name=region)
+ configuration_recorder: ConfigurationRecorderTypeDef = {
+ "name": recorder_name,
+ "roleARN": role_arn,
+ "recordingGroup": {
+ "allSupported": all_supported,
+ "includeGlobalResourceTypes": include_global_resource_types,
+ "resourceTypes": resource_types,
+ },
+ }
+ if len(config_client.describe_configuration_recorders()["ConfigurationRecorders"]):
+ response = config_client.describe_configuration_recorders()["ConfigurationRecorders"]
+ if response.pop(0) == configuration_recorder:
+ LOGGER.info(f"Config recorder is up to update in {account_id} in {region} region. Configurations: {configuration_recorder}")
+ else:
+ LOGGER.info(f"Updating config recorder in {account_id} account in {region} region")
+ config_client.put_configuration_recorder(ConfigurationRecorder=configuration_recorder)
+ LOGGER.info(f"Config recorder updated for {account_id} account in {region} region. Configurations: {configuration_recorder}")
+
+ if not len(config_client.describe_configuration_recorders()["ConfigurationRecorders"]):
+ LOGGER.info(f"Creating config recorder in {account_id} account in {region} region")
+ config_client.put_configuration_recorder(ConfigurationRecorder=configuration_recorder)
+ LOGGER.info(f"Config recorder started for {account_id} account in {region} region. Configurations: {configuration_recorder}")
+
+ if config_client.describe_configuration_recorder_status()["ConfigurationRecordersStatus"][0]["recording"]:
+ LOGGER.info(f"Config recorder is already started in {region}")
+ LOGGER.info(config_client.describe_configuration_recorder_status())
+
+
+def set_delivery_channel(
+ account_id: str,
+ region: str,
+ configuration_role_name: str,
+ delivery_channel: DeliveryChannelTypeDef,
+) -> None:
+ """Configure Delivery Channel.
+
+ Args:
+ account_id: Account ID
+ region: AWS Region
+ configuration_role_name: IAM configuration role name
+ delivery_channel: Configuration parameters for Config delivery channel
+ """
+ account_session: boto3.Session = common.assume_role(configuration_role_name, "sra-configure-config", account_id)
+ config_client: ConfigServiceClient = account_session.client("config", region_name=region)
+ try:
+ LOGGER.info(f"Setting up config delivery channel for account {account_id} in {region} region")
+ config_client.put_delivery_channel(DeliveryChannel=delivery_channel)
+ config_client.start_configuration_recorder(
+ ConfigurationRecorderName=config_client.describe_configuration_recorder_status()["ConfigurationRecordersStatus"][0]["name"]
+ )
+ LOGGER.info(f"Config delivery channel set for account {account_id} in {region} region. Configurations: {delivery_channel}")
+ except ClientError as e:
+ LOGGER.info(f"Error {repr(e)} enabling Config on account {account_id}")
+
+
+def stop_config_recorder(account_id: str, region: str, configuration_role_name: str) -> None:
+ """.
+
+ Args:
+ account_id (str): _description_
+ region (str): _description_
+ configuration_role_name (str): _description_
+ """
+ account_session: boto3.Session = common.assume_role(configuration_role_name, "sra-delete-config", account_id)
+ config_client: ConfigServiceClient = account_session.client("config", region_name=region)
+ if len(config_client.describe_configuration_recorders()["ConfigurationRecorders"]):
+ try:
+ LOGGER.info(f"Stopping Config recorder for {account_id} account in {region} region")
+ config_client.delete_configuration_recorder(
+ ConfigurationRecorderName=config_client.describe_configuration_recorder_status()["ConfigurationRecordersStatus"][0]["name"]
+ )
+ except ClientError as e:
+ LOGGER.info(f"Error {repr(e)} deleting Config on account {account_id}")
+ if len(config_client.describe_delivery_channels()["DeliveryChannels"]):
+ try:
+ config_client.delete_delivery_channel(DeliveryChannelName=config_client.describe_delivery_channels()["DeliveryChannels"][0]["name"])
+ except ClientError as e:
+ LOGGER.info(f"Error {repr(e)} deleting Config delivery channel on account {account_id}")
diff --git a/aws_sra_examples/solutions/config/config_org/lambda/src/requirements.txt b/aws_sra_examples/solutions/config/config_org/lambda/src/requirements.txt
new file mode 100644
index 00000000..b9435de8
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/lambda/src/requirements.txt
@@ -0,0 +1,2 @@
+#install latest
+crhelper
\ No newline at end of file
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-aggregator-org-configuration.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-aggregator-org-configuration.yaml
new file mode 100644
index 00000000..03082311
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-aggregator-org-configuration.yaml
@@ -0,0 +1,85 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template enables an AWS Organizations Config Aggregator in AWS Organization. - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+
+Metadata:
+ SRA:
+ Version: 1.0
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRASolutionName
+ - Label:
+ default: Config Aggregator Properties
+ Parameters:
+ - pAggregatorName
+ - Label:
+ default: Config Aggregator Role Properties
+ Parameters:
+ - pAggregatorRoleName
+
+ ParameterLabels:
+ pAggregatorName:
+ default: Config Aggregator Name
+ pAggregatorRoleName:
+ default: Config Aggregator Role Name
+ pSRASolutionName:
+ default: SRA Solution Name
+
+Parameters:
+ pAggregatorName:
+ AllowedPattern: '^[\w\-]+'
+ ConstraintDescription: Max 256 alphanumeric characters.
+ Default: sra-config-aggregator-org
+ MaxLength: 256
+ MinLength: 1
+ Type: String
+ pAggregatorRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -].
+ Default: sra-config-aggregator-org
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-aggregator-org]
+ Default: sra-config-aggregator-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+
+Resources:
+ rConfigAggregatorRole:
+ Type: AWS::IAM::Role
+ Metadata:
+ cfn_nag:
+ rules_to_suppress:
+ - id: W28
+ reason: An explicit role name is defined.
+ Properties:
+ RoleName: !Ref pAggregatorRoleName
+ AssumeRolePolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Effect: Allow
+ Action: sts:AssumeRole
+ Principal:
+ Service: config.amazonaws.com
+ Path: '/'
+ ManagedPolicyArns:
+ - arn:aws:iam::aws:policy/service-role/AWSConfigRoleForOrganizations
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rOrganizationConfigAggregator:
+ Type: AWS::Config::ConfigurationAggregator
+ Properties:
+ ConfigurationAggregatorName: !Ref pAggregatorName
+ OrganizationAggregationSource:
+ AllAwsRegions: True
+ RoleArn: !GetAtt rConfigAggregatorRole.Arn
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-configuration-role.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-configuration-role.yaml
new file mode 100644
index 00000000..f572fc93
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-configuration-role.yaml
@@ -0,0 +1,188 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template creates an IAM role for configuring AWS Config Recorder in AWS Organization. - 'config_org' solution in the
+ repo, https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 2
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pConfigConfigurationRoleName
+ - pConfigOrgLambdaRoleName
+ - pManagementAccountId
+ - pSRASolutionTagKey
+ - pSRASolutionName
+ - pAuditAccountId
+ - pHomeRegion
+ - pKMSKeyArnSecretName
+
+ ParameterLabels:
+ pAuditAccountId:
+ default: Audit Account ID
+ pConfigConfigurationRoleName:
+ default: Config Configuration Role Name
+ pConfigOrgLambdaRoleName:
+ default: Lambda Role Name
+ pHomeRegion:
+ default: Home Region
+ pKMSKeyArnSecretName:
+ default: KMS Key Arn Secret Name
+ pManagementAccountId:
+ default: Organization Management Account ID
+ pSRASolutionName:
+ default: SRA Solution Name
+ pSRASolutionTagKey:
+ default: SRA Solution Tag Key
+
+Parameters:
+ pAuditAccountId:
+ AllowedPattern: ^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Description: AWS Account ID of the Audit account.
+ Type: String
+ pConfigConfigurationRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
+ Default: sra-config-configuration
+ Description: Config Configuration IAM Role Name
+ Type: String
+ pConfigOrgLambdaRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
+ Default: sra-config-org-lambda
+ Description: Lambda Role Name
+ Type: String
+ pHomeRegion:
+ AllowedPattern: '^[a-z0-9-]{1,64}$'
+ ConstraintDescription: AWS Region Example - 'us-east-1'
+ Description: Name of the home region
+ Type: String
+ pKMSKeyArnSecretName:
+ AllowedValues: ['sra/config_org_delivery_key_arn']
+ Default: 'sra/config_org_delivery_key_arn'
+ Description: Secrets Manager secret name
+ Type: String
+ pManagementAccountId:
+ AllowedPattern: '^\d{12}$'
+ ConstraintDescription: Must be 12 digits
+ Description: Organization Management Account ID
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+ pSRASolutionTagKey:
+ AllowedValues: [sra-solution]
+ Default: sra-solution
+ Description: The SRA solution tag key applied to all resources created by the solution that support tagging. The value is the pSRASolutionName.
+ Type: String
+
+Resources:
+ rConfigRecorderRole:
+ Metadata:
+ cfn_nag:
+ rules_to_suppress:
+ - id: W28
+ reason: Explicit name provided
+ Type: AWS::IAM::Role
+ Properties:
+ RoleName: !Ref pConfigConfigurationRoleName
+ AssumeRolePolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Effect: Allow
+ Action: sts:AssumeRole
+ Condition:
+ StringEquals:
+ aws:PrincipalArn:
+ - !Sub arn:${AWS::Partition}:iam::${pManagementAccountId}:role/${pConfigOrgLambdaRoleName}
+ Principal:
+ AWS:
+ - !Sub arn:${AWS::Partition}:iam::${pManagementAccountId}:root
+ Path: '/'
+ Policies:
+ - PolicyName: sra-config-org-policy-iam
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: AllowReadIamActions
+ Effect: Allow
+ Action: iam:GetRole
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*
+
+ - Sid: AllowIamPassRole
+ Effect: Allow
+ Action: iam:PassRole
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+
+ - Sid: AllowCreateServiceLinkedRole
+ Effect: Allow
+ Action: iam:CreateServiceLinkedRole
+ Condition:
+ StringLike:
+ iam:AWSServiceName: config.amazonaws.com
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+
+ - Sid: AllowPolicyActions
+ Effect: Allow
+ Action: iam:PutRolePolicy
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+
+ - Sid: AllowDeleteServiceLinkRole
+ Effect: Allow
+ Action: iam:DeleteServiceLinkedRole
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+ - PolicyName: "sra-config-org-policy-config"
+ PolicyDocument:
+ Version: "2012-10-17"
+ Statement:
+ - Effect: Allow
+ Action:
+ - config:DeleteDeliveryChannel
+ - config:DescribeConfigurationRecorders
+ - config:DescribeDeliveryChannels
+ - config:StartConfigurationRecorder
+ - config:PutDeliveryChannel
+ - config:DeleteConfigurationRecorder
+ - config:DescribeConfigurationRecorderStatus
+ - config:PutConfigurationRecorder
+ Resource: '*'
+ - PolicyName: "sra-config-org-policy-secrets-manager"
+ PolicyDocument:
+ Version: "2012-10-17"
+ Statement:
+ - Effect: Allow
+ Action:
+ - secretsmanager:GetSecretValue
+ Condition:
+ StringLike:
+ aws:PrincipalAccount:
+ - !Ref pAuditAccountId
+ Resource: !Sub arn:${AWS::Partition}:secretsmanager:${pHomeRegion}:${pAuditAccountId}:secret:${pKMSKeyArnSecretName}*
+ - PolicyName: "sra-config-org-policy-kms"
+ PolicyDocument:
+ Version: "2012-10-17"
+ Statement:
+ - Effect: Allow
+ Action:
+ - kms:Decrypt
+ Condition:
+ StringLike:
+ aws:PrincipalAccount:
+ - !Ref pAuditAccountId
+ ForAnyValue:StringEquals:
+ kms:ResourceAliases: "alias/sra-secrets-key"
+ Resource: '*'
+ Tags:
+ - Key: !Ref pSRASolutionTagKey
+ Value: !Ref pSRASolutionName
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-configuration.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-configuration.yaml
new file mode 100644
index 00000000..40f72342
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-configuration.yaml
@@ -0,0 +1,723 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template enables AWS Config in AWS Organization. - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 3
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRASolutionName
+ - pAuditAccountId
+ - pLogArchiveAccountId
+ - pOrganizationId
+ - pHomeRegion
+ - pSRAAlarmEmail
+ - pSRAStagingS3BucketName
+ - Label:
+ default: Config Recorder Properties
+ Parameters:
+ - pRecorderName
+ - pAllSupported
+ - pIncludeGlobalResourceTypes
+ - pResourceTypes
+ - Label:
+ default: Config Delivery Channel Properties
+ Parameters:
+ - pFrequency
+ - pDeliveryS3KeyPrefix
+ - pDeliveryChannelName
+ - pConfigTopicName
+ - pKMSKeyArnSecretName
+ - Label:
+ default: Lambda Function Properties
+ Parameters:
+ - pConfigOrgLambdaRoleName
+ - pConfigOrgLambdaFunctionName
+ - Label:
+ default: Custom Resource Properties
+ Parameters:
+ - pConfigConfigurationRoleName
+ - pControlTowerRegionsOnly
+ - pEnabledRegions
+ - Label:
+ default: General Lambda Function Properties
+ Parameters:
+ - pCreateLambdaLogGroup
+ - pLambdaLogGroupRetention
+ - pLambdaLogGroupKmsKey
+ - pLambdaLogLevel
+ - Label:
+ default: EventBridge Rule Properties
+ Parameters:
+ - pComplianceFrequency
+ - pControlTowerLifeCycleRuleName
+ - pEventRuleRoleName
+
+ ParameterLabels:
+ pKMSKeyArnSecretName:
+ default: KMS Key Arn Secret Name
+ pComplianceFrequency:
+ default: Frequency to Check for Organizational Compliance
+ pControlTowerLifeCycleRuleName:
+ default: Control Tower Lifecycle Rule Name
+ pDeliveryChannelName:
+ default: Config Delivery Channel Name
+ pDeliveryS3KeyPrefix:
+ default: Delivery S3 Key Prefix
+ pConfigConfigurationRoleName:
+ default: Config Configuration Role Name
+ pConfigOrgLambdaFunctionName:
+ default: Lambda Function Name
+ pConfigOrgLambdaRoleName:
+ default: Lambda Role Name
+ pConfigTopicName:
+ default: Config SNS Topic Name
+ pControlTowerRegionsOnly:
+ default: Control Tower Regions Only
+ pCreateLambdaLogGroup:
+ default: Create Lambda Log Group
+ pAllSupported:
+ default: All Supported
+ pAuditAccountId:
+ default: Audit Account ID
+ pEnabledRegions:
+ default: (Optional) Enabled Regions
+ pEventRuleRoleName:
+ default: Event Rule Role Name
+ pFrequency:
+ default: Frequency
+ pHomeRegion:
+ default: Home Region
+ pIncludeGlobalResourceTypes:
+ default: Include Global Resource Types
+ pLambdaLogGroupRetention:
+ default: Lambda Log Group Retention
+ pLambdaLogGroupKmsKey:
+ default: (Optional) Lambda Logs KMS Key
+ pLambdaLogLevel:
+ default: Lambda Log Level
+ pLogArchiveAccountId:
+ default: Log Archive Account ID
+ pOrganizationId:
+ default: Organization ID
+ pRecorderName:
+ default: Recorder Name
+ pResourceTypes:
+ default: (Optional) Resource Types
+ pSRAAlarmEmail:
+ default: (Optional) SRA Alarm Email
+ pSRASolutionName:
+ default: SRA Solution Name
+ pSRAStagingS3BucketName:
+ default: SRA Staging S3 Bucket Name
+
+Parameters:
+ pKMSKeyArnSecretName:
+ AllowedValues: ['sra/config_org_delivery_key_arn']
+ Default: 'sra/config_org_delivery_key_arn'
+ Description: Secrets Manager secret name
+ Type: String
+ pComplianceFrequency:
+ ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive.
+ Default: 7
+ Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance
+ MinValue: 1
+ MaxValue: 30
+ Type: Number
+ pControlTowerLifeCycleRuleName:
+ AllowedPattern: '^[\w.-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -]
+ Default: sra-config-org-trigger
+ Description: The name of the AWS Control Tower Life Cycle Rule.
+ Type: String
+ pDeliveryChannelName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
+ Default: sra-config-s3-delivery
+ Description: Config delivery channel name
+ Type: String
+ pDeliveryS3KeyPrefix:
+ AllowedPattern: '^o-[a-z0-9]{10,32}$'
+ ConstraintDescription: Must start with 'o-' followed by from 10 to 32 lowercase letters or digits. (e.g. o-abc1234567)
+ Description: Organization ID to use as the S3 Key prefix for storing the audit logs
+ Type: String
+ pConfigConfigurationRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
+ Default: sra-config-configuration
+ Description: Config Configuration role to assume
+ Type: String
+ pConfigOrgLambdaFunctionName:
+ AllowedPattern: '^[\w-]{0,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -]
+ Default: sra-config-org
+ Description: Lambda function name
+ Type: String
+ pConfigOrgLambdaRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]
+ Default: sra-config-org-lambda
+ Description: Config configuration Lambda role name
+ Type: String
+ pConfigTopicName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ Default: sra-ConfigNotifications
+ Description: Configuration Notification SNS Topic in Audit Account that AWS Config delivers notifications to.
+ Type: String
+ pControlTowerRegionsOnly:
+ AllowedValues: [true, false]
+ Default: true
+ Description: Only enable in the Control Tower governed regions
+ Type: String
+ pCreateLambdaLogGroup:
+ AllowedValues: ['true', 'false']
+ Default: 'false'
+ Description:
+ Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS
+ Key for encryption.
+ Type: String
+ pAllSupported:
+ AllowedValues: ['true', 'false']
+ Default: 'true'
+ Description: Indicates whether to record all supported resource types. If set to 'false', then the 'Resource Types' parameter must have a value.
+ Type: String
+ pAuditAccountId:
+ AllowedPattern: '^\d{12}$'
+ ConstraintDescription: Must be 12 digits.
+ Description: AWS Account ID of the Audit (Security Tooling) account.
+ Type: String
+ pEnabledRegions:
+ AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$'
+ ConstraintDescription:
+ Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g.
+ us-east-1,ap-southeast-2)
+ Description: (Optional) Enabled regions (AWS regions, separated by commas). Leave blank to enable all regions.
+ Type: String
+ pEventRuleRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -].
+ Default: sra-config-global-events
+ Description: Event rule role name for putting events on the home region event bus
+ Type: String
+ pFrequency:
+ AllowedValues: [1hour, 3hours, 6hours, 12hours, 24hours]
+ Default: 1hour
+ Description: The frequency with which AWS Config delivers configuration snapshots.
+ Type: String
+ pHomeRegion:
+ AllowedPattern: '^[a-z0-9-]{1,64}$'
+ ConstraintDescription: AWS Region Example - 'us-east-1'
+ Description: Name of the home region
+ Type: String
+ pIncludeGlobalResourceTypes:
+ AllowedValues: ['true', 'false']
+ Default: 'true'
+ Description: Indicates whether AWS Config records all supported global resource types.
+ Type: String
+ pLambdaLogGroupRetention:
+ AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653]
+ Default: 14
+ Description: Specifies the number of days you want to retain log events
+ Type: String
+ pLambdaLogGroupKmsKey:
+ AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
+ ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
+ Description:
+ (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side
+ encryption keys.
+ Type: String
+ pLambdaLogLevel:
+ AllowedValues: [INFO, ERROR, DEBUG]
+ Default: INFO
+ Description: Lambda Function Logging Level
+ Type: String
+ pLogArchiveAccountId:
+ AllowedPattern: '^\d{12}$'
+ ConstraintDescription: Must be 12 digits.
+ Description: AWS Account ID of the Log Archive account.
+ Type: String
+ pOrganizationId:
+ AllowedPattern: '^o-[a-z0-9]{10,32}$'
+ ConstraintDescription: Must start with 'o-' followed by from 10 to 32 lowercase letters or digits. (e.g. o-abc1234567)
+ Description: AWS Organizations ID
+ Type: String
+ pRecorderName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: sra-ConfigRecorder
+ Description: Config delivery s3 bucket name
+ Type: String
+ pResourceTypes:
+ AllowedPattern: '^$|^([0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+)$|^(([0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+(,|, ))*[0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+)$'
+ Description:
+ (Optional) A list of valid AWS resource types to include in this recording group. Eg. AWS::CloudTrail::Trail. If 'All Supported' parameter is
+ set to 'false', then this parameter becomes required.
+ Type: String
+ pSRAAlarmEmail:
+ AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$'
+ ConstraintDescription: Must be a valid email address.
+ Description: (Optional) Email address for receiving DLQ alarms
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+ pSRAStagingS3BucketName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ SRA Staging S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+ Description:
+ SRA Staging S3 bucket name for the artifacts relevant to solution. (e.g., lambda zips, CloudFormation templates) S3 bucket name can include
+ numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+ Type: String
+
+Rules:
+ ResourceTypesValidation:
+ RuleCondition: !Equals [!Ref pAllSupported, 'false']
+ Assertions:
+ - AssertDescription: "'Resource Types' parameter is required if the 'All Supported' parameter is set to 'false'."
+ Assert: !Not [!Equals [!Ref pResourceTypes, '']]
+
+Conditions:
+ cComplianceFrequencySingleDay: !Equals [!Ref pComplianceFrequency, 1]
+ cCreateDLQAlarm: !Not [!Equals [!Ref pSRAAlarmEmail, '']]
+ cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true']
+ cIsAllSupported: !Equals [!Ref pAllSupported, 'true']
+ cUseGraviton: !Or
+ - !Equals [!Ref 'AWS::Region', ap-northeast-1]
+ - !Equals [!Ref 'AWS::Region', ap-south-1]
+ - !Equals [!Ref 'AWS::Region', ap-southeast-1]
+ - !Equals [!Ref 'AWS::Region', ap-southeast-2]
+ - !Equals [!Ref 'AWS::Region', eu-central-1]
+ - !Equals [!Ref 'AWS::Region', eu-west-1]
+ - !Equals [!Ref 'AWS::Region', eu-west-2]
+ - !Equals [!Ref 'AWS::Region', us-east-1]
+ - !Equals [!Ref 'AWS::Region', us-east-2]
+ - !Equals [!Ref 'AWS::Region', us-west-2]
+ cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']]
+ cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]]
+
+Mappings:
+ mSettings:
+ FrequencyMap:
+ 1hour: One_Hour
+ 3hours: Three_Hours
+ 6hours: Six_Hours
+ 12hours: Twelve_Hours
+ 24hours: TwentyFour_Hours
+
+Resources:
+
+ rConfigOrgLambdaLogGroup:
+ Type: AWS::Logs::LogGroup
+ Condition: cCreateLambdaLogGroup
+ DeletionPolicy: Retain
+ UpdateReplacePolicy: Retain
+ Properties:
+ LogGroupName: !Sub /aws/lambda/${pConfigOrgLambdaFunctionName}
+ KmsKeyId: !If
+ - cUseKmsKey
+ - !Ref pLambdaLogGroupKmsKey
+ - !Ref AWS::NoValue
+ RetentionInDays: !Ref pLambdaLogGroupRetention
+
+ rConfigOrgLambdaRole:
+ Type: AWS::IAM::Role
+ Metadata:
+ cfn_nag:
+ rules_to_suppress:
+ - id: W11
+ reason: Actions require wildcard in resource
+ - id: W28
+ reason: The role name is defined
+ checkov:
+ skip:
+ - id: CKV_AWS_111
+ comment: IAM write actions require wildcard in resource
+ Properties:
+ RoleName: !Ref pConfigOrgLambdaRoleName
+ AssumeRolePolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Action: sts:AssumeRole
+ Effect: Allow
+ Principal:
+ Service:
+ - lambda.amazonaws.com
+ Path: '/'
+ Policies:
+ - PolicyName: sra-config-org-policy-organizations
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: OrganizationsReadAccess
+ Effect: Allow
+ Action:
+ - organizations:DescribeAccount
+ - organizations:ListAccounts
+ Resource: '*'
+
+ - PolicyName: "ssm-access"
+ PolicyDocument:
+ Version: "2012-10-17"
+ Statement:
+ - Effect: "Allow"
+ Action:
+ - ssm:GetParameter
+ - ssm:GetParameters
+ Resource:
+ - !Sub "arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:parameter/sra*"
+
+ - PolicyName: sra-config-org-policy-sns
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: SNSPublish
+ Effect: Allow
+ Action:
+ - sns:Publish
+ - sns:PublishBatch
+ Resource: !Ref rConfigOrgTopic
+
+ - PolicyName: sra-config-org-policy-iam
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: AssumeRole
+ Effect: Allow
+ Action: sts:AssumeRole
+ Condition:
+ StringEquals:
+ aws:PrincipalOrgId: !Ref pOrganizationId
+ Resource:
+ - !Sub arn:${AWS::Partition}:iam::*:role/${pConfigConfigurationRoleName}
+
+ - Sid: AllowReadIamActions
+ Effect: Allow
+ Action: iam:GetRole
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/*
+
+ - Sid: AllowCreateServiceLinkedRole
+ Effect: Allow
+ Action: iam:CreateServiceLinkedRole
+ Condition:
+ StringLike:
+ iam:AWSServiceName: config.amazonaws.com
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+
+ - Sid: AllowPolicyActions
+ Effect: Allow
+ Action: iam:PutRolePolicy
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+
+ - Sid: AllowDeleteServiceLinkedRole
+ Effect: Allow
+ Action: iam:DeleteServiceLinkedRole
+ Resource: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/aws-service-role/config.amazonaws.com/AWSServiceRoleForConfig
+
+ - PolicyName: sra-config-org-policy-logs
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: CreateLogGroupAndEvents
+ Effect: Allow
+ Action:
+ - logs:CreateLogGroup
+ - logs:CreateLogStream
+ - logs:PutLogEvents
+ Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pConfigOrgLambdaFunctionName}:log-stream:*
+
+ - PolicyName: sra-config-org-policy-sqs
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: SQSSendMessage
+ Effect: Allow
+ Action: sqs:SendMessage
+ Resource: !GetAtt rConfigOrgDLQ.Arn
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigOrgLambdaFunction:
+ Type: AWS::Lambda::Function
+ Metadata:
+ cfn_nag:
+ rules_to_suppress:
+ - id: W58
+ reason: CloudWatch access provided by the attached IAM role
+ - id: W89
+ reason: Lambda is not deployed within a VPC
+ - id: W92
+ reason: Lambda does not need reserved concurrent executions.
+ checkov:
+ skip:
+ - id: CKV_AWS_115
+ comment: Lambda does not need reserved concurrent executions.
+ - id: CKV_AWS_117
+ comment: Lambda does not need to communicate with VPC resources.
+ - id: CKV_AWS_173
+ comment: Environment variables are not sensitive.
+ Properties:
+ FunctionName: !Ref pConfigOrgLambdaFunctionName
+ Description: configure Config for the Organization
+ Architectures: !If
+ - cUseGraviton
+ - [arm64]
+ - !Ref AWS::NoValue
+ Handler: app.lambda_handler
+ Role: !GetAtt rConfigOrgLambdaRole.Arn
+ MemorySize: 512
+ Runtime: python3.9
+ Timeout: 900
+ Code:
+ S3Bucket: !Ref pSRAStagingS3BucketName
+ S3Key: !Sub ${pSRASolutionName}/lambda_code/${pSRASolutionName}.zip
+ DeadLetterConfig:
+ TargetArn: !GetAtt rConfigOrgDLQ.Arn
+ Environment:
+ Variables:
+ AUDIT_ACCOUNT: !Ref pAuditAccountId
+ LOG_LEVEL: !Ref pLambdaLogLevel
+ AWS_PARTITION: !Ref AWS::Partition
+ CONFIGURATION_ROLE_NAME: !Ref pConfigConfigurationRoleName
+ CONTROL_TOWER_REGIONS_ONLY: !Ref pControlTowerRegionsOnly
+ ENABLED_REGIONS: !Ref pEnabledRegions
+ ALL_SUPPORTED: !Ref pAllSupported
+ INCLUDE_GLOBAL_RESOURCE_TYPES: !Ref pIncludeGlobalResourceTypes
+ FREQUENCY: !FindInMap
+ - mSettings
+ - FrequencyMap
+ - !Ref pFrequency
+ RESOURCE_TYPES: !If
+ - cIsAllSupported
+ - !Ref AWS::NoValue
+ - !Ref pResourceTypes
+ DELIVERY_S3_KEY_PREFIX: !Ref pDeliveryS3KeyPrefix
+ S3_BUCKET_NAME: !Sub sra-config-org-delivery-${pLogArchiveAccountId}-${pHomeRegion}
+ DELIVERY_CHANNEL_NAME: !Ref pDeliveryChannelName
+ CONFIG_TOPIC_NAME: !Ref pConfigTopicName
+ RECORDER_NAME: !Ref pRecorderName
+ KMS_KEY_SECRET_NAME: !Ref pKMSKeyArnSecretName
+ HOME_REGION: !Ref pHomeRegion
+ SNS_TOPIC_ARN_FANOUT: !Ref rConfigOrgTopic
+
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigOrgLambdaCustomResource:
+ Type: Custom::LambdaCustomResource
+ Version: '1.0'
+ Properties:
+ ServiceToken: !GetAtt rConfigOrgLambdaFunction.Arn
+ AUDIT_ACCOUNT: !Ref pAuditAccountId
+ CONFIGURATION_ROLE_NAME: !Ref pConfigConfigurationRoleName
+ CONTROL_TOWER_REGIONS_ONLY: !Ref pControlTowerRegionsOnly
+ ENABLED_REGIONS: !Ref pEnabledRegions
+ ALL_SUPPORTED: !Ref pAllSupported
+ INCLUDE_GLOBAL_RESOURCE_TYPES: !Ref pIncludeGlobalResourceTypes
+ DELIVERY_CHANNEL_NAME: !Ref pDeliveryChannelName
+ FREQUENCY: !FindInMap
+ - mSettings
+ - FrequencyMap
+ - !Ref pFrequency
+ RESOURCE_TYPES: !If
+ - cIsAllSupported
+ - !Ref AWS::NoValue
+ - !Ref pResourceTypes
+ RECORDER_NAME: !Ref pRecorderName
+ KMS_KEY_SECRET_NAME: !Ref pKMSKeyArnSecretName
+ HOME_REGION: !Ref pHomeRegion
+ SNS_TOPIC_ARN_FANOUT: !Ref rConfigOrgTopic
+
+ rConfigOrgTopic:
+ Type: AWS::SNS::Topic
+ Properties:
+ DisplayName: !Sub ${pSRASolutionName}-configuration
+ KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigOrgTopicLambdaPermission:
+ Type: AWS::Lambda::Permission
+ Properties:
+ Action: lambda:InvokeFunction
+ FunctionName: !GetAtt rConfigOrgLambdaFunction.Arn
+ Principal: sns.amazonaws.com
+ SourceArn: !Ref rConfigOrgTopic
+
+ rConfigOrgTopicSubscription:
+ Type: AWS::SNS::Subscription
+ Properties:
+ Endpoint: !GetAtt rConfigOrgLambdaFunction.Arn
+ Protocol: lambda
+ TopicArn: !Ref rConfigOrgTopic
+
+
+ rConfigOrgDLQ:
+ Type: AWS::SQS::Queue
+ Properties:
+ KmsMasterKeyId: alias/aws/sqs
+ QueueName: !Sub ${pSRASolutionName}-dlq
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+ MessageRetentionPeriod: 345600
+ DeletionPolicy: Delete
+ UpdateReplacePolicy: Delete
+
+ rConfigOrgDLQPolicy:
+ Type: AWS::SQS::QueuePolicy
+ Properties:
+ Queues:
+ - !Ref rConfigOrgDLQ
+ PolicyDocument:
+ Statement:
+ - Action: SQS:SendMessage
+ Condition:
+ ArnEquals:
+ aws:SourceArn:
+ - !GetAtt rConfigOrgLambdaFunction.Arn
+ Effect: Allow
+ Principal:
+ Service: events.amazonaws.com
+ Resource:
+ - !GetAtt rConfigOrgDLQ.Arn
+
+ rConfigOrgDLQAlarmTopic:
+ Condition: cCreateDLQAlarm
+ Type: AWS::SNS::Topic
+ Properties:
+ DisplayName: !Sub ${pSRASolutionName}-dlq-alarm
+ KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns
+ TopicName: !Sub ${pSRASolutionName}-dlq-alarm
+ Subscription:
+ - Endpoint: !Ref pSRAAlarmEmail
+ Protocol: email
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigOrgDLQAlarm:
+ Condition: cCreateDLQAlarm
+ Type: AWS::CloudWatch::Alarm
+ Properties:
+ AlarmDescription: SRA DLQ alarm if the queue depth is 1
+ Namespace: AWS/SQS
+ MetricName: ApproximateNumberOfMessagesVisible
+ Dimensions:
+ - Name: QueueName
+ Value: !GetAtt rConfigOrgDLQ.QueueName
+ Statistic: Sum
+ Period: 300
+ EvaluationPeriods: 1
+ Threshold: 1
+ ComparisonOperator: GreaterThanThreshold
+ AlarmActions:
+ - !Ref rConfigOrgDLQAlarmTopic
+ InsufficientDataActions:
+ - !Ref rConfigOrgDLQAlarmTopic
+
+ rPermissionForScheduledComplianceRuleToInvokeLambda:
+ Type: AWS::Lambda::Permission
+ Properties:
+ FunctionName: !GetAtt rConfigOrgLambdaFunction.Arn
+ Action: lambda:InvokeFunction
+ Principal: events.amazonaws.com
+ SourceArn: !GetAtt rScheduledComplianceRule.Arn
+
+ rScheduledComplianceRule:
+ Type: AWS::Events::Rule
+ Properties:
+ Name: !Sub ${pControlTowerLifeCycleRuleName}-organization-compliance
+ Description: SRA Config Trigger for scheduled organization compliance
+ ScheduleExpression: !If
+ - cComplianceFrequencySingleDay
+ - !Sub rate(${pComplianceFrequency} day)
+ - !Sub rate(${pComplianceFrequency} days)
+ State: ENABLED
+ Targets:
+ - Arn: !GetAtt rConfigOrgLambdaFunction.Arn
+ Id: !Ref pConfigOrgLambdaFunctionName
+
+ rCrossRegionEventRuleRole:
+ Type: AWS::IAM::Role
+ Condition: cNotGlobalRegionUsEast1
+ Metadata:
+ cfn_nag:
+ rules_to_suppress:
+ - id: W28
+ reason: Specific role name provided
+ Properties:
+ RoleName: !Ref pEventRuleRoleName
+ AssumeRolePolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Effect: Allow
+ Action: sts:AssumeRole
+ Principal:
+ Service:
+ - events.amazonaws.com
+ Policies:
+ - PolicyName: sra-account-org-config-policy-events
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Effect: Allow
+ Action: events:PutEvents
+ Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default
+
+ rOrganizationsRule:
+ Type: AWS::Events::Rule
+ Properties:
+ Name: !Sub ${pControlTowerLifeCycleRuleName}-org-update
+ Description: SRA Config Trigger on Organizations update
+ EventPattern:
+ source:
+ - aws.organizations
+ detail-type:
+ - AWS Service Event via CloudTrail
+ - AWS API Call via CloudTrail
+ detail:
+ eventSource:
+ - organizations.amazonaws.com
+ eventName:
+ - AcceptHandshake
+ - CreateAccountResult
+ State: ENABLED
+ Targets:
+ - Arn: !GetAtt rConfigOrgLambdaFunction.Arn
+ Id: !Ref pConfigOrgLambdaFunctionName
+
+ rPermissionForOrganizationsRuleToInvokeLambda:
+ Type: AWS::Lambda::Permission
+ Properties:
+ FunctionName: !GetAtt rConfigOrgLambdaFunction.Arn
+ Action: lambda:InvokeFunction
+ Principal: events.amazonaws.com
+ SourceArn: !GetAtt rOrganizationsRule.Arn
+
+Outputs:
+ oConfigOrgLambdaFunctionArn:
+ Description: SRA Config Lambda Function ARN
+ Value: !GetAtt rConfigOrgLambdaFunction.Arn
+ oConfigOrgLambdaLogGroupArn:
+ Condition: cCreateLambdaLogGroup
+ Description: SRA Config Lambda Log Group ARN
+ Value: !GetAtt rConfigOrgLambdaLogGroup.Arn
+ oConfigOrgLambdaRoleArn:
+ Description: SRA Config Lambda Role ARN
+ Value: !GetAtt rConfigOrgLambdaRole.Arn
\ No newline at end of file
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml
new file mode 100644
index 00000000..b1e66db4
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-kms-key.yaml
@@ -0,0 +1,172 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template creates the Config delivery KMS key - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 4
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRASolutionName
+ - pSRASecretsKeyAliasArn
+
+ - Label:
+ default: KMS Key Properties
+ Parameters:
+ - pConfigOrgDeliveryKeyAlias
+ - pManagementAccountId
+ - pLogArchiveAccountId
+
+ ParameterLabels:
+ pConfigOrgDeliveryKeyAlias:
+ default: Config Delivery KMS Key Alias
+ pManagementAccountId:
+ default: Organization Management Account ID
+ pLogArchiveAccountId:
+ default: Log Archive Account ID
+ pSRASecretsKeyAliasArn:
+ default: (Optional) SRA Secrets Manager KMS Key Alias ARN
+ pSRASolutionName:
+ default: SRA Solution Name
+
+Parameters:
+ pConfigOrgDeliveryKeyAlias:
+ Default: sra-config-org-delivery-key
+ Description: Config Delivery KMS Key Alias
+ Type: String
+ pLogArchiveAccountId:
+ AllowedPattern: ^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Description: AWS Account ID of the Log Archive account.
+ Type: String
+ pManagementAccountId:
+ AllowedPattern: '^\d{12}$'
+ ConstraintDescription: Must be 12 digits
+ Description: Management Account ID
+ Type: String
+ pSRASecretsKeyAliasArn:
+ AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*)?:kms:[a-z0-9-]+:\d{12}:alias\/[a-zA-Z0-9/_-]+$'
+ ConstraintDescription: 'Key Alias ARN example: arn:aws:kms:us-east-2:111122223333:alias/ExampleAlias'
+ Description: (Optional) SRA Secrets Manager KMS Key Alias ARN
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+
+Conditions:
+ cCreateSecret: !Not [!Equals [!Ref pSRASecretsKeyAliasArn, '']]
+
+Resources:
+ rConfigDeliveryKey:
+ Type: AWS::KMS::Key
+ Properties:
+ Description: SRA Config Delivery Key
+ EnableKeyRotation: True
+ KeyPolicy:
+ Version: 2012-10-17
+ Id: !Ref pConfigOrgDeliveryKeyAlias
+ Statement:
+ - Sid: Enable IAM User Permissions
+ Effect: Allow
+ Action: 'kms:*'
+ Resource: '*'
+ Principal:
+ AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
+
+ - Sid: Allow Config to encrypt logs
+ Effect: Allow
+ Action: kms:GenerateDataKey
+ Resource: '*'
+ Principal:
+ Service: config.amazonaws.com
+
+ - Sid: Allow alias creation during setup
+ Effect: Allow
+ Action: kms:CreateAlias
+ Condition:
+ StringEquals:
+ kms:CallerAccount: !Sub ${AWS::AccountId}
+ kms:ViaService: !Sub cloudformation.${AWS::Region}.amazonaws.com
+ Resource: '*'
+ Principal:
+ AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
+
+ - Sid: Allow Log Archive and Management account access
+ Effect: Allow
+ Action: kms:Decrypt
+ Resource: '*'
+ Principal:
+ AWS:
+ - !Sub arn:${AWS::Partition}:iam::${pLogArchiveAccountId}:root
+ - !Sub arn:${AWS::Partition}:iam::${pManagementAccountId}:root
+
+ - Sid: Allow account access
+ Effect: Allow
+ Action:
+ - kms:DescribeKey
+ - kms:Decrypt
+ Resource: '*'
+ Principal:
+ AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
+
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigDeliveryKeyAlias:
+ Type: AWS::KMS::Alias
+ Properties:
+ AliasName: !Sub alias/${pConfigOrgDeliveryKeyAlias}
+ TargetKeyId: !Ref rConfigDeliveryKey
+
+ rConfigDeliveryKeySecret:
+ Type: AWS::SecretsManager::Secret
+ Condition: cCreateSecret
+ Metadata:
+ checkov:
+ skip:
+ - id: CKV_AWS_149
+ comment: A cross-account KMS Key is used
+ Properties:
+ Name: sra/config_org_delivery_key_arn
+ Description: Config Delivery KMS Key ARN
+ SecretString: !Sub '{"ConfigDeliveryKeyArn":"${rConfigDeliveryKey.Arn}"}'
+ KmsKeyId: !Ref pSRASecretsKeyAliasArn
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigDeliveryKeySecretPolicy:
+ Type: AWS::SecretsManager::ResourcePolicy
+ Condition: cCreateSecret
+ Properties:
+ BlockPublicPolicy: True
+ SecretId: !Ref rConfigDeliveryKeySecret
+ ResourcePolicy:
+ Version: 2012-10-17
+ Statement:
+ - Action: secretsmanager:GetSecretValue # checkov:skip=CKV_SECRET_6
+ Effect: Allow
+ Principal:
+ AWS:
+ - !Sub arn:${AWS::Partition}:iam::${pManagementAccountId}:root
+ Resource: '*'
+ Condition:
+ ForAnyValue:StringEquals:
+ secretsmanager:VersionStage: AWSCURRENT
+Outputs:
+ oConfigDeliveryKeyArn:
+ Description: Config Delivery KMS Key ARN
+ Value: !GetAtt rConfigDeliveryKey.Arn
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-s3-bucket.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-s3-bucket.yaml
new file mode 100644
index 00000000..97c6757e
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-delivery-s3-bucket.yaml
@@ -0,0 +1,157 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template creates the Config delivery S3 bucket - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 5
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRASolutionName
+
+ - Label:
+ default: Config Delivery S3 Properties
+ Parameters:
+ - pConfigOrgDeliveryBucketPrefix
+ - pOrganizationId
+ - pConfigOrgDeliveryKMSKeyArn
+
+ ParameterLabels:
+ pOrganizationId:
+ default: Organization ID
+ pConfigOrgDeliveryBucketPrefix:
+ default: Config Delivery Bucket Prefix
+ pConfigOrgDeliveryKMSKeyArn:
+ default: Config Delivery KMS Key
+ pSRASolutionName:
+ default: SRA Solution Name
+ pS3KeyPrefix:
+ default: AWS Logs S3 Key Prefix
+
+Parameters:
+ pOrganizationId:
+ Description: SSM Parameter for AWS Organizations ID
+ Type: 'String'
+ pS3KeyPrefix:
+ Type: 'String'
+ Default: /sra/control-tower/organization-id
+ Description: 'Organization ID to use as the S3 Key prefix for storing the audit logs'
+ pConfigOrgDeliveryBucketPrefix:
+ AllowedPattern: '^$|^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$'
+ ConstraintDescription:
+ S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+ Default: sra-config-org-delivery
+ Description:
+ Config Delivery S3 bucket prefix. The account and region will get added to the end. e.g. sra-config-delivery-123456789012-us-east-1
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+ pConfigOrgDeliveryKMSKeyArn:
+ AllowedPattern: '^arn:(aws[a-zA-Z-]*)?:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
+ ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
+ Description: KMS Key ARN to use for encrypting Config snapshots sent to S3
+ Type: String
+
+Resources:
+ rConfigDeliveryS3Bucket:
+ DeletionPolicy: Retain
+ UpdateReplacePolicy: Retain
+ Type: AWS::S3::Bucket
+ Metadata:
+ cfn_nag:
+ rules_to_suppress:
+ - id: W35
+ reason: S3 access logging is not enabled.
+ checkov:
+ skip:
+ - id: CKV_AWS_18
+ comment: S3 access logging is not enabled.
+ Properties:
+ BucketName: !Sub ${pConfigOrgDeliveryBucketPrefix}-${AWS::AccountId}-${AWS::Region}
+ BucketEncryption:
+ ServerSideEncryptionConfiguration:
+ - ServerSideEncryptionByDefault:
+ KMSMasterKeyID: !Ref pConfigOrgDeliveryKMSKeyArn
+ SSEAlgorithm: aws:kms
+ BucketKeyEnabled: True
+ OwnershipControls:
+ Rules:
+ - ObjectOwnership: BucketOwnerPreferred
+ AccessControl: LogDeliveryWrite
+ PublicAccessBlockConfiguration:
+ BlockPublicAcls: True
+ BlockPublicPolicy: True
+ IgnorePublicAcls: True
+ RestrictPublicBuckets: True
+ VersioningConfiguration:
+ Status: Enabled
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigS3BucketPolicy:
+ Type: AWS::S3::BucketPolicy
+ Properties:
+ Bucket: !Ref rConfigDeliveryS3Bucket
+ PolicyDocument:
+ Version: 2012-10-17
+ Statement:
+ - Sid: AllowSSLRequestsOnly
+ Effect: Deny
+ Principal: '*'
+ Action: s3:*
+ Resource:
+ - !Sub "arn:${AWS::Partition}:s3:::${rConfigDeliveryS3Bucket}"
+ - !Sub "arn:${AWS::Partition}:s3:::${rConfigDeliveryS3Bucket}/*"
+ Condition:
+ Bool:
+ aws:SecureTransport: false
+ - Sid: AWSBucketPermissionsCheck
+ Effect: Allow
+ Principal:
+ Service:
+ - config.amazonaws.com
+ Action: s3:GetBucketAcl
+ Resource:
+ - !Sub "arn:${AWS::Partition}:s3:::${rConfigDeliveryS3Bucket}"
+ - Sid: AWSConfigBucketExistenceCheck
+ Effect: Allow
+ Principal:
+ Service:
+ - config.amazonaws.com
+ Action: s3:ListBucket
+ Resource:
+ - !Sub "arn:${AWS::Partition}:s3:::${rConfigDeliveryS3Bucket}"
+ - Sid: AWSBucketDeliveryForConfig
+ Effect: Allow
+ Principal:
+ Service:
+ - config.amazonaws.com
+ Action: s3:PutObject
+ Resource:
+ - Fn::Join:
+ - ""
+ -
+ - !Sub "arn:${AWS::Partition}:s3:::"
+ - !Ref "rConfigDeliveryS3Bucket"
+ - !Sub "/${pOrganizationId}/AWSLogs/*/*"
+
+Outputs:
+ oConfigDeliveryS3Bucket:
+ Description: SRA Config Delivery S3 Bucket
+ Value: !Ref rConfigDeliveryS3Bucket
+ oS3KeyPrefix:
+ Description: S3 Key prefix for storing the audit logs
+ Value: !Ref pS3KeyPrefix
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-global-events.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-global-events.yaml
new file mode 100644
index 00000000..cad7f10e
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-global-events.yaml
@@ -0,0 +1,67 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template creates an event rule to send organization events to the home region. - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 4
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRASolutionName
+ - pHomeRegion
+ - Label:
+ default: Event Rule Properties
+ Parameters:
+ - pEventRuleRoleName
+ ParameterLabels:
+ pSRASolutionName:
+ default: SRA Solution Name
+
+Parameters:
+ pEventRuleRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -].
+ Default: sra-config-global-events
+ Description: Event rule role name for putting events on the home region event bus
+ Type: String
+ pHomeRegion:
+ AllowedPattern: '^[a-z0-9-]{1,64}$'
+ ConstraintDescription: AWS Region Example - 'us-east-1'
+ Description: Name of the Control Tower home region
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution.
+ Type: String
+
+Resources:
+ rOrganizationsRule:
+ Type: AWS::Events::Rule
+ Properties:
+ Name: !Sub ${pSRASolutionName}-forward-org-events
+ Description: SRA Config Forward Organizations events to home region.
+ EventPattern:
+ source:
+ - aws.organizations
+ detail-type:
+ - AWS Service Event via CloudTrail
+ detail:
+ eventSource:
+ - organizations.amazonaws.com
+ eventName:
+ - AcceptHandshake
+ - CreateAccountResult
+ State: ENABLED
+ Targets:
+ - Arn: !Sub arn:${AWS::Partition}:events:${pHomeRegion}:${AWS::AccountId}:event-bus/default
+ Id: !Sub ${pSRASolutionName}-org-events-to-home-region
+ RoleArn: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pEventRuleRoleName}
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-main-ssm.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-main-ssm.yaml
new file mode 100644
index 00000000..e9df8881
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-main-ssm.yaml
@@ -0,0 +1,713 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template enables AWS Config in the AWS Organization and sets up AWS Config Aggregator in the Audit account. Resolving SSM parameters. - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+
+Metadata:
+ SRA:
+ Version: 1.0
+ Entry: Parameters for deploying solution resolving SSM parameters
+ Order: 1
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRAAlarmEmail
+ - pSRASolutionName
+ - pSRASolutionVersion
+ - pSRAStagingS3BucketName
+ - pAuditAccountId
+ - pLogArchiveAccountId
+ - pOrganizationId
+ - pRootOrganizationalUnitId
+ - pHomeRegion
+ - pCustomerControlTowerRegions
+ - Label:
+ default: IAM Properties
+ Parameters:
+ - pStackSetAdminRole
+ - pStackExecutionRole
+ - Label:
+ default: Config Recorder Properties
+ Parameters:
+ - pControlTowerRegionsOnly
+ - pEnabledRegions
+ - pRecorderName
+ - pAllSupported
+ - pIncludeGlobalResourceTypes
+ - pResourceTypes
+ - Label:
+ default: Config Delivery Channel Properties
+ Parameters:
+ - pDeliveryChannelName
+ - pConfigOrgDeliveryBucketPrefix
+ - pDeliveryS3KeyPrefix
+ - pConfigOrgDeliveryKeyAlias
+ - pFrequency
+ - pKMSKeyArnSecretName
+ - Label:
+ default: Config SNS Topic Properties
+ Parameters:
+ - pConfigTopicName
+ - pSubscribeToConfigurationTopic
+ - pConfigurationEmail
+ - pConfigOrgSnsKeyAlias
+ - Label:
+ default: Config Aggregator Properties
+ Parameters:
+ - pAggregatorName
+ - pAggregatorRoleName
+ - pRegisterDelegatedAdminAccount
+ - Label:
+ default: General Lambda Function Properties
+ Parameters:
+ - pCreateLambdaLogGroup
+ - pLambdaLogGroupRetention
+ - pLambdaLogGroupKmsKey
+ - pLambdaLogLevel
+ - Label:
+ default: EventBridge Rule Properties
+ Parameters:
+ - pComplianceFrequency
+ - pControlTowerLifeCycleRuleName
+
+ ParameterLabels:
+ pConfigOrgSnsKeyAlias:
+ default: Config SNS KMS Key Alias
+ pAggregatorName:
+ default: Config Aggregator Name
+ pAggregatorRoleName:
+ default: Config Aggregator Role Name
+ pRegisterDelegatedAdminAccount:
+ default: Register Delegated Admin Account
+ pKMSKeyArnSecretName:
+ default: KMS Key Arn Secret Name
+ pComplianceFrequency:
+ default: Frequency to Check for Organizational Compliance
+ pConfigurationEmail:
+ default: Configuration Email
+ pControlTowerLifeCycleRuleName:
+ default: Lifecycle Rule Name
+ pCustomerControlTowerRegions:
+ default: Customer Regions
+ pConfigTopicName:
+ default: Config SNS Topic Name
+ pDeliveryS3KeyPrefix:
+ default: Delivery S3 Key Prefix
+ pDeliveryChannelName:
+ default: Delivery Channel Name
+ pSRAAlarmEmail:
+ default: (Optional) SRA Alarm Email
+ pLambdaLogGroupKmsKey:
+ default: (Optional) Lambda Logs KMS Key
+ pEnabledRegions:
+ default: (Optional) Enabled Regions
+ pCreateLambdaLogGroup:
+ default: Create Lambda Log Group
+ pControlTowerRegionsOnly:
+ default: Common Prerequisites Regions Only
+ pRootOrganizationalUnitId:
+ default: Root Organizational Unit ID
+ pStackSetAdminRole:
+ default: Stack Set Role
+ pStackExecutionRole:
+ default: Stack execution role
+ pAllSupported:
+ default: All Supported
+ pAuditAccountId:
+ default: Audit Account ID
+ pFrequency:
+ default: Frequency
+ pHomeRegion:
+ default: Home Region
+ pIncludeGlobalResourceTypes:
+ default: Include Global Resource Types
+ pLambdaLogGroupRetention:
+ default: Lambda Log Group Retention
+ pLambdaLogLevel:
+ default: Lambda Log Level
+ pLogArchiveAccountId:
+ default: Log Archive Account ID
+ pOrganizationId:
+ default: Organization ID
+ pRecorderName:
+ default: Recorder Name
+ pResourceTypes:
+ default: (Optional) Resource Types
+ pSRASolutionName:
+ default: SRA Solution Name
+ pSRASolutionVersion:
+ default: SRA Solution Version
+ pSRAStagingS3BucketName:
+ default: SRA Staging S3 Bucket Name
+ pConfigOrgDeliveryBucketPrefix:
+ default: Config Delivery Bucket Prefix
+ pSubscribeToConfigurationTopic:
+ default: Subscribe to Configuration Topic
+ pConfigOrgDeliveryKeyAlias:
+ default: Config Delivery KMS Key Alias
+
+Parameters:
+ pConfigOrgSnsKeyAlias:
+ Default: sra-config-org-sns-key
+ Description: Config SNS KMS Key Alias
+ Type: String
+ pAggregatorName:
+ AllowedPattern: '^[\w\-]+'
+ ConstraintDescription: Max 256 alphanumeric characters.
+ Default: sra-config-aggregator-org
+ MaxLength: 256
+ MinLength: 1
+ Type: String
+ pAggregatorRoleName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -].
+ Default: sra-config-aggregator-org
+ Type: String
+ pRegisterDelegatedAdminAccount:
+ AllowedValues: ['Yes', 'No']
+ Default: 'Yes'
+ Description: Register a delegated administrator account using the Common Register Delegated Administrator solution.
+ Type: String
+ pKMSKeyArnSecretName:
+ AllowedValues: ['sra/config_org_delivery_key_arn']
+ Default: 'sra/config_org_delivery_key_arn'
+ Description: Secret name
+ Type: String
+ pComplianceFrequency:
+ ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive.
+ Default: 7
+ Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance by invoking the Lambda Function.
+ MinValue: 1
+ MaxValue: 30
+ Type: Number
+ pControlTowerLifeCycleRuleName:
+ AllowedPattern: '^[\w.-]{1,64}$'
+ ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -]
+ Default: sra-config-org-trigger
+ Description: The name of the AWS Organizations Life Cycle Rule.
+ Type: String
+ pConfigTopicName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ Default: sra-ConfigNotifications
+ Description: Configuration Notification SNS Topic in Audit Account that AWS Config delivers notifications to.
+ Type: String
+ pConfigurationEmail:
+ AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$'
+ ConstraintDescription: Email Validation as per RFC2822 standards.
+ Description: Email for receiving all AWS configuration events
+ Default: ''
+ Type: 'String'
+ pDeliveryS3KeyPrefix:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/control-tower/organization-id
+ Description: Organization ID to use as the S3 Key prefix for storing the audit logs
+ Type: AWS::SSM::Parameter::Value
+ pDeliveryChannelName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: sra-config-s3-delivery
+ Description: Config delivery channel name
+ Type: String
+ pSRAAlarmEmail:
+ AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$'
+ ConstraintDescription: Must be a valid email address.
+ Description: (Optional) Email address for receiving DLQ alarms
+ Type: String
+ pLambdaLogGroupKmsKey:
+ AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$'
+ ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab'
+ Description:
+ (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side
+ encryption keys.
+ Type: String
+ pEnabledRegions:
+ AllowedPattern: '^$|^([a-z0-9-]{1,64})$|^(([a-z0-9-]{1,64},)*[a-z0-9-]{1,64})$'
+ ConstraintDescription:
+ Only lowercase letters, numbers, and hyphens ('-') allowed. (e.g. us-east-1) Additional AWS regions can be provided, separated by commas. (e.g.
+ us-east-1,ap-southeast-2)
+ Default: ''
+ Description: (Optional) Enabled regions (AWS regions, separated by commas). If 'Common Prerequisites Regions Only' parameter is set to 'false', then this parameter becomes required.
+ Type: String
+ pCreateLambdaLogGroup:
+ AllowedValues: ['true', 'false']
+ Default: 'false'
+ Description:
+ Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS
+ Key for encryption.
+ Type: String
+ pControlTowerRegionsOnly:
+ AllowedValues: ['true', 'false']
+ Default: 'true'
+ Description: Only enable in the customer regions specified in Common Prerequisites solution
+ Type: String
+ pRootOrganizationalUnitId:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/control-tower/root-organizational-unit-id
+ Description: SSM Parameter for Root Organizational Unit ID
+ Type: AWS::SSM::Parameter::Value
+ pConfigOrgDeliveryBucketPrefix:
+ AllowedPattern: '^$|^[0-9a-zA-Z]+([0-9a-zA-Z-]*[0-9a-zA-Z])*$'
+ ConstraintDescription:
+ S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+ Default: sra-config-org-delivery
+ Description:
+ Config Delivery S3 bucket prefix. The account and region will get added to the end. e.g. sra-config-delivery-123456789012-us-east-1
+ Type: String
+ pStackSetAdminRole:
+ AllowedValues: [sra-stackset]
+ Default: sra-stackset
+ Description: The administration role name that is used in the stackset.
+ Type: String
+ pStackExecutionRole:
+ AllowedValues: [sra-execution]
+ Default: sra-execution
+ Description: The execution role name that is used in the stack.
+ Type: String
+ pAllSupported:
+ AllowedValues: ['true', 'false']
+ Default: 'true'
+ Description: Indicates whether to record all supported resource types. If set to 'false', then the 'Resource Types' parameter must have a value.
+ Type: String
+ pAuditAccountId:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/control-tower/audit-account-id
+ Description: SSM Parameter for AWS Account ID of the Audit account.
+ Type: AWS::SSM::Parameter::Value
+ pFrequency:
+ AllowedValues: [1hour, 3hours, 6hours, 12hours, 24hours]
+ Default: 1hour
+ Description: The frequency with which AWS Config delivers configuration snapshots.
+ Type: String
+ pHomeRegion:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/control-tower/home-region
+ Description: SSM Parameter for name of the home region
+ Type: AWS::SSM::Parameter::Value
+ pIncludeGlobalResourceTypes:
+ AllowedValues: ['true', 'false']
+ Default: 'true'
+ Description: Indicates whether AWS Config records all supported global resource types.
+ Type: String
+ pLambdaLogGroupRetention:
+ AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653]
+ Default: 14
+ Description: Specifies the number of days you want to retain log events
+ Type: String
+ pLambdaLogLevel:
+ AllowedValues: [INFO, ERROR, DEBUG]
+ Default: INFO
+ Description: Lambda Function Logging Level
+ Type: String
+ pLogArchiveAccountId:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/control-tower/log-archive-account-id
+ Description: SSM Parameter for AWS Account ID of the Log Archive account.
+ Type: AWS::SSM::Parameter::Value
+ pOrganizationId:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/control-tower/organization-id
+ Description: SSM Parameter for AWS Organizations ID
+ Type: AWS::SSM::Parameter::Value
+ pRecorderName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: sra-ConfigRecorder
+ Description: Config recorder name
+ Type: String
+ pResourceTypes:
+ AllowedPattern: '^$|^([0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+)$|^(([0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+(,|, ))*[0-9a-zA-Z]+::[0-9a-zA-Z]+::[0-9a-zA-Z]+)$'
+ Default: ''
+ Description:
+ (Optional) A list of valid AWS resource types to include in this recording group. Eg. AWS::CloudTrail::Trail. If 'All Supported' parameter is
+ set to 'false', then this parameter becomes required.
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+ pSRASolutionVersion:
+ AllowedValues: [v1.0]
+ Default: v1.0
+ Description: The SRA solution version. Used to trigger updates on the nested StackSets.
+ Type: String
+ pSRAStagingS3BucketName:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/staging-s3-bucket-name
+ Description:
+ SSM Parameter for SRA Staging S3 bucket name for the artifacts relevant to solution. (e.g., lambda zips, CloudFormation templates) S3 bucket
+ name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-).
+ Type: AWS::SSM::Parameter::Value
+ pSubscribeToConfigurationTopic:
+ AllowedValues: [true, false]
+ Default: false
+ Description: Indicates whether ConfigurationEmail will be subscribed to the Configuration Notification SNS Topic.
+ Type: String
+ pCustomerControlTowerRegions:
+ AllowedPattern: '^([\w.-]{1,900})$|^(\/[\w.-]{1,900})*[\w.-]{1,900}$'
+ ConstraintDescription:
+ Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names.
+ Default: /sra/regions/customer-control-tower-regions
+ Description: SSM Parameter for Customer regions
+ Type: AWS::SSM::Parameter::Value>
+ pConfigOrgDeliveryKeyAlias:
+ Default: sra-config-org-delivery-key
+ Description: Config Delivery KMS Key Alias
+ Type: String
+
+Conditions:
+ cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]]
+ cRegisterDelegatedAdmin: !Equals [!Ref pRegisterDelegatedAdminAccount, 'Yes']
+ cControlTowerRegions: !Equals [!Ref pControlTowerRegionsOnly, 'true']
+
+Rules:
+ ResourceTypesValidation:
+ RuleCondition: !Equals [!Ref pAllSupported, 'false']
+ Assertions:
+ - AssertDescription: "'Resource Types' parameter is required if 'All Supported' parameter is set to 'false'."
+ Assert: !Not [!Equals [!Ref pResourceTypes, '']]
+ EnabledRegionValidation:
+ RuleCondition: !Equals [!Ref pControlTowerRegionsOnly, 'false']
+ Assertions:
+ - Assert: !Not [!Equals [!Ref pEnabledRegions, '']]
+ AssertDescription: "'Enabled Regions' parameter has to have a value if 'Common Prerequisites Regions Only' parameter is set to 'false'."
+
+Resources:
+ rConfigSNSTopicStackSet:
+ Type: AWS::CloudFormation::StackSet
+ DependsOn: rConfigRoleStack
+ Properties:
+ StackSetName: sra-config-sns
+ AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole}
+ CallAs: SELF
+ Description: !Sub ${pSRASolutionVersion} - Deploys Notification SNS Topic in Audit Account that AWS Config delivers notifications to.
+ ExecutionRoleName: !Ref pStackExecutionRole
+ ManagedExecution:
+ Active: true
+ OperationPreferences:
+ FailureTolerancePercentage: 0
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SELF_MANAGED
+ StackInstancesGroup:
+ - DeploymentTargets:
+ Accounts:
+ - !Ref pAuditAccountId
+ Regions: !If [cControlTowerRegions, !Ref pCustomerControlTowerRegions, !Split [",", !Ref pEnabledRegions]]
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-sns.yaml
+ Parameters:
+ - ParameterKey: pConfigTopicName
+ ParameterValue: !Ref pConfigTopicName
+ - ParameterKey: pConfigurationEmail
+ ParameterValue: !Ref pConfigurationEmail
+ - ParameterKey: pSubscribeToConfigurationTopic
+ ParameterValue: !Ref pSubscribeToConfigurationTopic
+ - ParameterKey: pSRASolutionName
+ ParameterValue: !Ref pSRASolutionName
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigRoleStack:
+ Type: AWS::CloudFormation::Stack
+ DeletionPolicy: Delete
+ UpdateReplacePolicy: Delete
+ Properties:
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-configuration-role.yaml
+ Parameters:
+ pManagementAccountId: !Ref AWS::AccountId
+ pAuditAccountId: !Ref pAuditAccountId
+ pKMSKeyArnSecretName: !Ref pKMSKeyArnSecretName
+ pHomeRegion: !Ref pHomeRegion
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigRoleStackSet:
+ Type: AWS::CloudFormation::StackSet
+ Properties:
+ StackSetName: sra-config-org-configuration-role
+ AutoDeployment:
+ Enabled: true
+ RetainStacksOnAccountRemoval: false
+ CallAs: SELF
+ Capabilities:
+ - CAPABILITY_NAMED_IAM
+ Description: !Sub ${pSRASolutionVersion} - Deploys an IAM role via ${pSRASolutionName} for Config Service.
+ ManagedExecution:
+ Active: true
+ OperationPreferences:
+ FailureTolerancePercentage: 100
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SERVICE_MANAGED
+ StackInstancesGroup:
+ - DeploymentTargets:
+ OrganizationalUnitIds:
+ - !Ref pRootOrganizationalUnitId
+ Regions:
+ - !Ref AWS::Region
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-configuration-role.yaml
+ Parameters:
+ - ParameterKey: pManagementAccountId
+ ParameterValue: !Ref AWS::AccountId
+ - ParameterKey: pAuditAccountId
+ ParameterValue: !Ref pAuditAccountId
+ - ParameterKey: pKMSKeyArnSecretName
+ ParameterValue: !Ref pKMSKeyArnSecretName
+ - ParameterKey: pHomeRegion
+ ParameterValue: !Ref pHomeRegion
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigDeliveryS3BucketStackSet:
+ Type: AWS::CloudFormation::StackSet
+ DependsOn:
+ - rConfigRoleStack
+ - rConfigDeliveryKMSKeyStackSet
+ Properties:
+ StackSetName: sra-config-org-delivery-s3-bucket
+ AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole}
+ CallAs: SELF
+ Description: !Sub ${pSRASolutionVersion} - Deploys an S3 bucket via ${pSRASolutionName} for storing Config findings
+ ExecutionRoleName: !Ref pStackExecutionRole
+ ManagedExecution:
+ Active: true
+ OperationPreferences:
+ FailureTolerancePercentage: 0
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SELF_MANAGED
+ StackInstancesGroup:
+ - DeploymentTargets:
+ Accounts:
+ - !Ref pLogArchiveAccountId
+ Regions:
+ - !Ref AWS::Region
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-delivery-s3-bucket.yaml
+ Parameters:
+ - ParameterKey: pConfigOrgDeliveryBucketPrefix
+ ParameterValue: !Ref pConfigOrgDeliveryBucketPrefix
+ - ParameterKey: pOrganizationId
+ ParameterValue: !Ref pOrganizationId
+ - ParameterKey: pConfigOrgDeliveryKMSKeyArn
+ ParameterValue: !Sub '{{resolve:secretsmanager:arn:${AWS::Partition}:secretsmanager:${AWS::Region}:${pAuditAccountId}:secret:sra/config_org_delivery_key_arn:SecretString:ConfigDeliveryKeyArn:AWSCURRENT}}'
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigConfigurationStack:
+ Type: AWS::CloudFormation::Stack
+ DeletionPolicy: Delete
+ UpdateReplacePolicy: Delete
+ DependsOn:
+ - rConfigDeliveryS3BucketStackSet
+ - rConfigRoleStack
+ - rConfigRoleStackSet
+ Properties:
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-configuration.yaml
+ Parameters:
+ pComplianceFrequency: !Ref pComplianceFrequency
+ pControlTowerLifeCycleRuleName: !Ref pControlTowerLifeCycleRuleName
+ pControlTowerRegionsOnly: !Ref pControlTowerRegionsOnly
+ pCreateLambdaLogGroup: !Ref pCreateLambdaLogGroup
+ pEnabledRegions: !Ref pEnabledRegions
+ pLambdaLogGroupKmsKey: !Ref pLambdaLogGroupKmsKey
+ pLambdaLogGroupRetention: !Ref pLambdaLogGroupRetention
+ pLambdaLogLevel: !Ref pLambdaLogLevel
+ pSRAAlarmEmail: !Ref pSRAAlarmEmail
+ pSRAStagingS3BucketName: !Ref pSRAStagingS3BucketName
+ pAllSupported: !Ref pAllSupported
+ pAuditAccountId: !Ref pAuditAccountId
+ pFrequency: !Ref pFrequency
+ pHomeRegion: !Ref pHomeRegion
+ pIncludeGlobalResourceTypes: !Ref pIncludeGlobalResourceTypes
+ pLogArchiveAccountId: !Ref pLogArchiveAccountId
+ pOrganizationId: !Ref pOrganizationId
+ pResourceTypes: !Ref pResourceTypes
+ pDeliveryS3KeyPrefix: !Ref pDeliveryS3KeyPrefix
+ pConfigTopicName: !Ref pConfigTopicName
+ pRecorderName: !Ref pRecorderName
+ pKMSKeyArnSecretName: !Ref pKMSKeyArnSecretName
+ pDeliveryChannelName: !Ref pDeliveryChannelName
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigGlobalEventsStackSet:
+ Type: AWS::CloudFormation::StackSet
+ Condition: cNotGlobalRegionUsEast1
+ DependsOn: rConfigConfigurationStack
+ Properties:
+ StackSetName: sra-config-org-global-events
+ AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole}
+ CallAs: SELF
+ Capabilities:
+ - CAPABILITY_NAMED_IAM
+ Description:
+ !Sub ${pSRASolutionVersion} - Deploys EventBridge Rules via ${pSRASolutionName} for capturing global events forwarding to the home region.
+ ExecutionRoleName: !Ref pStackExecutionRole
+ OperationPreferences:
+ FailureTolerancePercentage: 0
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SELF_MANAGED
+ StackInstancesGroup:
+ - DeploymentTargets:
+ Accounts:
+ - !Ref AWS::AccountId
+ Regions:
+ - us-east-1
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-global-events.yaml
+ Parameters:
+ - ParameterKey: pHomeRegion
+ ParameterValue: !Ref AWS::Region
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigDeliveryKMSKeyStackSet:
+ Type: AWS::CloudFormation::StackSet
+ Properties:
+ StackSetName: sra-config-org-delivery-kms-key
+ AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole}
+ CallAs: SELF
+ Description: !Sub ${pSRASolutionVersion} - Deploys a KMS Key via ${pSRASolutionName} for encrypting Config findings
+ ExecutionRoleName: !Ref pStackExecutionRole
+ ManagedExecution:
+ Active: true
+ OperationPreferences:
+ FailureTolerancePercentage: 0
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SELF_MANAGED
+ StackInstancesGroup:
+ - DeploymentTargets:
+ Accounts:
+ - !Ref pAuditAccountId
+ Regions:
+ - !Ref AWS::Region
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-delivery-kms-key.yaml
+ Parameters:
+ - ParameterKey: pConfigOrgDeliveryKeyAlias
+ ParameterValue: !Ref pConfigOrgDeliveryKeyAlias
+ - ParameterKey: pLogArchiveAccountId
+ ParameterValue: !Ref pLogArchiveAccountId
+ - ParameterKey: pManagementAccountId
+ ParameterValue: !Ref AWS::AccountId
+ - ParameterKey: pSRASecretsKeyAliasArn
+ ParameterValue: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${pAuditAccountId}:alias/sra-secrets-key
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigSnsKMSKeyStackSet:
+ Type: AWS::CloudFormation::StackSet
+ Properties:
+ StackSetName: sra-config-org-sns-kms-key
+ AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole}
+ CallAs: SELF
+ Description: !Sub ${pSRASolutionVersion} - Deploys a KMS Key via ${pSRASolutionName} for encrypting Config SNS topic
+ ExecutionRoleName: !Ref pStackExecutionRole
+ ManagedExecution:
+ Active: true
+ OperationPreferences:
+ FailureTolerancePercentage: 0
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SELF_MANAGED
+ StackInstancesGroup:
+ - DeploymentTargets:
+ Accounts:
+ - !Ref pAuditAccountId
+ Regions: !If [cControlTowerRegions, !Ref pCustomerControlTowerRegions, !Split [",", !Ref pEnabledRegions]]
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-org-sns-kms-key.yaml
+ Parameters:
+ - ParameterKey: pConfigOrgSnsKeyAlias
+ ParameterValue: !Ref pConfigOrgSnsKeyAlias
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rCommonRegisterDelegatedAdminStack:
+ Type: AWS::CloudFormation::Stack
+ Condition: cRegisterDelegatedAdmin
+ DependsOn: rConfigConfigurationStack
+ DeletionPolicy: Delete
+ UpdateReplacePolicy: Delete
+ Properties:
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/sra-common-register-delegated-administrator/templates/sra-common-register-delegated-administrator-ssm.yaml
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+ Parameters:
+ pLambdaLogGroupKmsKey: ''
+ pRegisterDelegatedAdminLambdaRoleName: sra-config-aggregator-register-delegated-admin-lambda
+ pRegisterDelegatedAdminLambdaFunctionName: sra-config-aggregator-register-delegated-admin
+ pServicePrincipalList: config.amazonaws.com
+
+ rConfigAggregatorOrgStackSet:
+ Type: AWS::CloudFormation::StackSet
+ DependsOn: rConfigConfigurationStack
+ Properties:
+ StackSetName: sra-config-aggregator-org-configuration
+ AdministrationRoleARN: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:role/${pStackSetAdminRole}
+ CallAs: SELF
+ Description: !If
+ - cRegisterDelegatedAdmin
+ - !Sub [
+ "${pSRASolutionVersion} - This template enables an AWS Organizations Config Aggregator in AWS Organization. -
+ 'config_aggregator_org' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples. Delegated Admin
+ Solution - ${SolutionName}",
+ SolutionName: !GetAtt rCommonRegisterDelegatedAdminStack.Outputs.oSRASolutionName,
+ ]
+ - !Sub ${pSRASolutionVersion} - This template enables an AWS Organizations Config Aggregator in AWS Organization. -
+ 'config_aggregator_org' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples.
+ ExecutionRoleName: !Ref pStackExecutionRole
+ ManagedExecution:
+ Active: true
+ OperationPreferences:
+ FailureTolerancePercentage: 0
+ MaxConcurrentPercentage: 100
+ RegionConcurrencyType: PARALLEL
+ PermissionModel: SELF_MANAGED
+ Capabilities:
+ - CAPABILITY_NAMED_IAM
+ StackInstancesGroup:
+ - DeploymentTargets:
+ Accounts:
+ - !Ref pAuditAccountId
+ Regions:
+ - !Ref AWS::Region
+ TemplateURL: !Sub https://${pSRAStagingS3BucketName}.s3.${AWS::Region}.${AWS::URLSuffix}/${pSRASolutionName}/templates/sra-config-aggregator-org-configuration.yaml
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+ Parameters:
+ - ParameterKey: pAggregatorName
+ ParameterValue: !Ref pAggregatorName
+ - ParameterKey: pAggregatorRoleName
+ ParameterValue: !Ref pAggregatorRoleName
\ No newline at end of file
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-sns-kms-key.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-sns-kms-key.yaml
new file mode 100644
index 00000000..2955506a
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-org-sns-kms-key.yaml
@@ -0,0 +1,92 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template creates the KMS key for Config delivery SNS topic - 'config_org' solution in the repo,
+ https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 4
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pSRASolutionName
+
+ - Label:
+ default: KMS Key Properties
+ Parameters:
+ - pConfigOrgSnsKeyAlias
+
+ ParameterLabels:
+ pConfigOrgSnsKeyAlias:
+ default: Config SNS KMS Key Alias
+ pSRASolutionName:
+ default: SRA Solution Name
+
+Parameters:
+ pConfigOrgSnsKeyAlias:
+ Default: sra-config-org-sns-key
+ Description: Config SNS KMS Key Alias
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+
+Resources:
+ rConfigSnsKey:
+ Type: AWS::KMS::Key
+ Properties:
+ Description: SRA Config SNS Key
+ EnableKeyRotation: True
+ KeyPolicy:
+ Version: 2012-10-17
+ Id: !Ref pConfigOrgSnsKeyAlias
+ Statement:
+ - Sid: Enable IAM User Permissions
+ Effect: Allow
+ Action: 'kms:*'
+ Resource: '*'
+ Principal:
+ AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
+
+ - Sid: Allow Config to encrypt logs
+ Effect: Allow
+ Action:
+ - kms:GenerateDataKey
+ - kms:Decrypt
+ Resource: '*'
+ Principal:
+ Service: config.amazonaws.com
+
+ - Sid: Allow alias creation during setup
+ Effect: Allow
+ Action: kms:CreateAlias
+ Condition:
+ StringEquals:
+ kms:CallerAccount: !Sub ${AWS::AccountId}
+ kms:ViaService: !Sub cloudformation.${AWS::Region}.amazonaws.com
+ Resource: '*'
+ Principal:
+ AWS: !Sub arn:${AWS::Partition}:iam::${AWS::AccountId}:root
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rConfigSnsKeyAlias:
+ Type: AWS::KMS::Alias
+ Properties:
+ AliasName: !Sub alias/${pConfigOrgSnsKeyAlias}
+ TargetKeyId: !Ref rConfigSnsKey
+
+Outputs:
+ oConfigSnsKeyArn:
+ Description: Config SNS KMS Key ARN
+ Value: !GetAtt rConfigSnsKey.Arn
diff --git a/aws_sra_examples/solutions/config/config_org/templates/sra-config-sns.yaml b/aws_sra_examples/solutions/config/config_org/templates/sra-config-sns.yaml
new file mode 100644
index 00000000..30011268
--- /dev/null
+++ b/aws_sra_examples/solutions/config/config_org/templates/sra-config-sns.yaml
@@ -0,0 +1,113 @@
+########################################################################
+# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+# SPDX-License-Identifier: MIT-0
+########################################################################
+AWSTemplateFormatVersion: 2010-09-09
+Description:
+ This template creates Config delivery SNS topic in Audit account. - 'config_org' solution in the
+ repo, https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1u3sd7f8h)
+Metadata:
+ SRA:
+ Version: 1.0
+ Order: 2
+ AWS::CloudFormation::Interface:
+ ParameterGroups:
+ - Label:
+ default: General Properties
+ Parameters:
+ - pConfigurationEmail
+ - pConfigTopicName
+ - pSRASolutionName
+ - pSubscribeToConfigurationTopic
+ - pConfigOrgSnsKeyAlias
+
+ ParameterLabels:
+ pConfigTopicName:
+ default: Config SNS Topic Name
+ pConfigurationEmail:
+ default: Configuration Email
+ pConfigOrgSnsKeyAlias:
+ default: Config SNS KMS Key Alias
+ pSRASolutionName:
+ default: SRA Solution Name
+ pSubscribeToConfigurationTopic:
+ default: Subscribe to Configuration Topic
+
+Parameters:
+ pConfigurationEmail:
+ AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$'
+ ConstraintDescription: Email Validation as per RFC2822 standards.
+ Description: Email for receiving all AWS configuration events
+ Type: 'String'
+ pConfigOrgSnsKeyAlias:
+ Default: sra-config-org-sns-key
+ Description: Config SNS KMS Key Alias
+ Type: String
+ pConfigTopicName:
+ AllowedPattern: '^[\w+=,.@-]{1,64}$'
+ Default: sra-ConfigNotifications
+ Description: Configuration Notification SNS Topic in Audit Account that AWS Config delivers notifications to.
+ Type: String
+ pSRASolutionName:
+ AllowedValues: [sra-config-org]
+ Default: sra-config-org
+ Description: The SRA solution name. The default value is the folder name of the solution
+ Type: String
+ pSubscribeToConfigurationTopic:
+ AllowedValues: [true, false]
+ Default: false
+ Description: Indicates whether ConfigurationEmail will be subscribed to the ConfigurationTopicName topic.
+ Type: String
+
+Conditions:
+ Subscribe: !Equals
+ - !Ref pSubscribeToConfigurationTopic
+ - 'true'
+
+Resources:
+ rConfigOrgTopic:
+ Type: AWS::SNS::Topic
+ Properties:
+ DisplayName: !Ref pConfigTopicName
+ KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/${pConfigOrgSnsKeyAlias}
+ TopicName: !Ref pConfigTopicName
+ Tags:
+ - Key: sra-solution
+ Value: !Ref pSRASolutionName
+
+ rSNSAllConfigurationTopicPolicy:
+ Type: AWS::SNS::TopicPolicy
+ DependsOn: rConfigOrgTopic
+ Properties:
+ Topics:
+ - !Sub arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${pConfigTopicName}
+ PolicyDocument:
+ Statement:
+ - Sid: AWSSNSPolicy
+ Action:
+ - sns:Publish
+ Effect: Allow
+ Resource: !Sub arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${pConfigTopicName}
+ Principal:
+ Service:
+ - config.amazonaws.com
+
+ rSNSAllConfigurationEmailNotification:
+ Condition: Subscribe
+ Type: AWS::SNS::Subscription
+ DependsOn:
+ - rConfigOrgTopic
+ - rSNSAllConfigurationTopicPolicy
+ Properties:
+ Endpoint: !Ref pConfigurationEmail
+ Protocol: email
+ TopicArn: !Sub arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${pConfigTopicName}
+
+Outputs:
+ ConfigTopicARN:
+ Description: All Configuration Notification SNS Topic ARN
+ Value: !Sub arn:${AWS::Partition}:sns:${AWS::Region}:${AWS::AccountId}:${pConfigTopicName}
+ ConfigTopicName:
+ Description: All Configuration Notification SNS Topic Name
+ Value: !GetAtt rConfigOrgTopic.TopicName
+