Skip to content

Commit

Permalink
improve documentation, formatting and code placement
Browse files Browse the repository at this point in the history
  • Loading branch information
marwinbaumannsbp committed Dec 23, 2024
1 parent 6645557 commit 6287bb8
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 119 deletions.
113 changes: 65 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,56 +8,82 @@ Overview of Landing Zone tools & services:

The SBP AWS Landing Zone consists of 3 repositories:

- [MCAF Landing Zone module (current repository)](https://github.com/schubergphilis/terraform-aws-mcaf-landing-zone): the foundation of the Landing Zone and manages the 3 core accounts: audit, logging, master
- [MCAF Landing Zone module (current repository)](https://github.com/schubergphilis/terraform-aws-mcaf-landing-zone): the foundation of the Landing Zone and manages the 3 core accounts: audit, logging, management
- [MCAF Account Vending Machine (AVM) module](https://github.com/schubergphilis/terraform-aws-mcaf-avm): providing an AWS AVM. This module sets up an AWS account with one or more Terraform Cloud/Enterprise (TFE) workspace(s) backed by a VCS project
- [MCAF Account Baseline module](https://github.com/schubergphilis/terraform-aws-mcaf-account-baseline): optional module providing baseline configuration for AWS accounts


## Pre-Requisites

> [!IMPORTANT]
> Before deploying this module, ensure the following pre-requisites are met:
> - AWS Control Tower is deployed in the `core-management` account.
> - AWS Control Tower governed regions include at least `us-east-1` (and your designated home region).
## Basic configuration

```hcl
locals {
control_tower_account_ids = {
audit = "012345678902"
logging = "012345678903"
}
}
Refer to [examples/basic](examples/basic/main.tf) for an example of minimal setup.

provider "aws" {}
### Specifying the correct regions

provider "aws" {
alias = "audit"
**Home Region**

assume_role {
role_arn = "arn:aws:iam::${local.control_tower_account_ids.audit}:role/AWSControlTowerExecution"
}
}
The mandatory `regions.home_region` variable specifies the AWS Control Tower home region. This must match the region defined in your AWS provider that deploys this module.

provider "aws" {
alias = "logging"
To find your home region:
1. Log in to the **core-management account**.
2. Navigate to **AWS Control Tower****Landing Zone Settings**.
3. The home region is listed under **Home Region**.

assume_role {
role_arn = "arn:aws:iam::${local.control_tower_account_ids.logging}:role/AWSControlTowerExecution"
}
}
**Linked Regions**

provider "datadog" {
validate = false
}
The optional `regions.linked_regions` variable defines the AWS Control Tower governed regions. This module ensures proper configuration of AWS Security Hub and AWS Config for all specified linked regions to collect data from them.

provider "mcaf" {
aws {}
}
To find your linked regions:
1. Log in to the **core-management account**.
2. Navigate to **AWS Control Tower****Landing Zone Settings**.
3. Linked regions are listed under **Landing Zone Regions**.

module "landing_zone" {
providers = { aws = aws, aws.audit = aws.audit, aws.logging = aws.logging }
*Note:* By default, `us-east-1` is included as a linked region to ensure data collection from global services. To restrict deployment of non-global resources in this region, use the `allowed_regions` functionality described in the section below.

> [!IMPORTANT]
> All specified linked regions need to be an AWS Control Tower governed region. This ensures that an AWS Config recorder is enabled by AWS Control Tower in all governed regions. AWS Security Hub will only function correctly if an AWS Config recorder exists in all linked regions.
**Allowed Regions**

The optional `regions.allowed_regions` variable defines the allowed regions within your AWS Organization. This triggers the deployment of a [Service Control Policy (SCP)](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_examples.html#example-scp-deny-region), which is attached to the root of your AWS Organization.

source = "github.com/schubergphilis/terraform-aws-mcaf-landing-zone?ref=VERSION"
#### Configuration Scenarios

control_tower_account_ids = local.control_tower_account_ids
allowed_regions = ["eu-central-1", "eu-west-1"]
tags = { Terraform = true }
**Scenario 1: Home region only (no deployment in other regions)**

- **Home region:** `eu-central-1`
- **Requirement:** Prevent deployment in all other regions.

You need to configure the `regions` variable as follows:

```hcl
regions = {
allowed_regions = ["eu-central-1"]
home_region = "eu-central-1"
}
```

*Note:* Ensure that `us-east-1` is included as a governed region in AWS Control Tower since the `linked_region` variable defaults to this value.

**Scenario 2: Home region with additional governed regions**

- **Home region:** `eu-central-1`
- **Requirement:** Also allow deploying resources in `eu-west-1`.

You need to configure the `regions` variable as follows:

```hcl
regions = {
allowed_regions = ["eu-central-1", "eu-west-1]
home_region = "eu-central-1"
linked_regions = ["eu-west-1", "us-east-1"]
}
```

## Detailed configuration
Expand Down Expand Up @@ -102,9 +128,9 @@ additional_auditing_trail = {

### AWS Config Rules

This module provisions by default a set of basic AWS Config Rules. In order to add extra rules, a list of [rule identifiers](https://docs.aws.amazon.com/config/latest/developerguide/managed-rules-by-aws-config.html) can be passed via the variable `aws_config` using the attribute `rule_identifiers`.
This module provisions by default a set of basic AWS Config Rules. In order to add extra rules, a list of [rule identifiers](https://docs.aws.amazon.com/config/latest/developerguide/managed-rules-by-aws-config.html) can be passed via the variable `aws_config.rule_identifiers`.

If you would like to authorize other accounts to aggregate AWS Config data, the account IDs and regions can also be passed via the variable `aws_config` using the attributes `aggregator_account_ids` and `aggregator_regions` respectively.
If you would like to authorize other accounts to aggregate AWS Config data, the account IDs can also be passed via the variable `aws_config.aggregator_account_ids`.

NOTE: This module already authorizes the `audit` account to aggregate Config data from all other accounts in the organization, so there is no need to specify the `audit` account ID in the `aggregator_account_ids` list.

Expand All @@ -113,7 +139,6 @@ Example:
```hcl
aws_config = {
aggregator_account_ids = ["123456789012"]
aggregator_regions = ["eu-west-1"]
rule_identifiers = ["ACCESS_KEYS_ROTATED", "ALB_WAF_ENABLED"]
}
```
Expand All @@ -122,13 +147,13 @@ aws_config = {

This module supports enabling GuardDuty at the organization level which means that all new accounts that are created in, or added to, the organization are added as member accounts to the `audit` account GuardDuty detector.

The feature can be controlled via the `aws_guardduty` variable and is enabled by default. The finding publishing frequency has been reduced from 6 hours to every 15 minutes, and the Malware Protection, Kubernetes and S3 Logs data sources are enabled out of the box.
The feature can be controlled via the `aws_guardduty` variable and is enabled by default.

Note: In case you are migrating an existing AWS organization to this module, all existing accounts except for the `master` and `logging` accounts have to be enabled like explained [here](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_organizations.html#guardduty_add_orgs_accounts).
Note: In case you are migrating an existing AWS organization to this module, all existing accounts except for the `management` and `logging` accounts have to be enabled like explained [here](https://docs.aws.amazon.com/guardduty/latest/ug/guardduty_organizations.html#guardduty_add_orgs_accounts).

## AWS KMS

The module creates 3 AWS KMS keys, one for the master account, one for the audit account, and one for the log archive account. We recommend to further scope down the AWS KMS key policy in the master account by providing a secure policy using `kms_key_policy`. The default policy "Base Permissions" can be overwritten and should be limited to the root account only, for example by using the statement below:
The module creates 3 AWS KMS keys, one for the management account, one for the audit account, and one for the log archive account. We recommend to further scope down the AWS KMS key policy in the management account by providing a secure policy using `kms_key_policy`. The default policy "Base Permissions" can be overwritten and should be limited to the root account only, for example by using the statement below:

```hcl
statement {
Expand Down Expand Up @@ -321,15 +346,7 @@ aws_service_control_policies = {

#### SCP: Restricting AWS Regions

If you would like to define which AWS Regions can be used in your AWS Organization, you can pass a list of region names to the variable `aws_service_control_policies` using the `allowed_regions` attribute. This will trigger this module to deploy a [Service Control Policy (SCP) designed by AWS](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_policies_scps_examples.html#example-scp-deny-region) and attach it to the root of your AWS Organization.

Example:

```hcl
aws_service_control_policies = {
allowed_regions = ["eu-west-1"]
}
```
See the section `Specifying the correct regions`.

#### SCP: Restricting Root User Access

Expand Down
99 changes: 82 additions & 17 deletions UPGRADING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,43 +4,108 @@ This document captures required refactoring on your part when upgrading to a mod

## Upgrading to v5.0.0

### Behaviour
### Key Changes

> [!IMPORTANT]
> **This version changes the [Security Hub configuration to Central](https://docs.aws.amazon.com/securityhub/latest/userguide/central-configuration-intro.html).
#### Transition to Centralized Security Hub Configuration

This version transitions Security Hub configuration from **Local** to **Central**. Learn more in the [AWS Security Hub Documentation](https://docs.aws.amazon.com/securityhub/latest/userguide/central-configuration-intro.html).

**Default Behavior:**

- Security Hub Findings Aggregation is enabled for regions defined in:
- `regions.home_region`
- `regions.linked_regions`. `us-east-1` is automatically included for global services.

This version enables Security Hub Findings Aggregation for all regions specfied in `regions.home_region` and `regions.linked_regions`. You can change this behauviour by setting `var.aws_security_hub.aggregator_linking_mode` to `ALL_REGIONS_EXCEPT_SPECIFIED` and providing the list of regions via `var.aws_security_hub.aggregator_specified_regions`. More information on this in the [AWS Security Hub Documentation](https://docs.aws.amazon.com/securityhub/latest/userguide/central-configuration-intro.html).
#### Dropping Support for Local Configuration

### Removing local Security Hub Standards in logging account
**Local configurations are no longer supported.** Centralized configuration aligns with AWS best practices and reduces complexity.

Since the state of version < 5.0.0 contains an unknown number of instances of `aws_securityhub_standards_subscription` resources for the Logging account, Terraform wants to remove them. Since the configuration of this is moved to the central `aws_securityhub_configuration_policy` resource, we don't want to disable them, but just 'forget' about them.
### Variables

The following variables have been replaced:
* `aws_service_control_policies.allowed_regions``regions.allowed_regions`
* `aws_config.aggregator_regions` → the union of `regions.home_region` and `regions.linked_regions`

Since there is an unknown number of instances (a for_each on `local.security_hub_standards_arns`) and [Terraform does not support `for_each` on `removed` statements yet](https://github.com/hashicorp/terraform/issues/34439), we need to remove the resources manually from the state.
The following variables have been introduced:
* `aws_security_hub.aggregator_linking_mode`. Indicates whether to aggregate findings from all of the available Regions or from a specified list.
* `aws_security_hub.disabled_control_identifiers`. List of Security Hub control IDs that are disabled in the organisation.
* `aws_security_hub.enabled_control_identifiers`. List of Security Hub control IDs that are enabled in the organisation.

The following variables have been removed:
* `aws_security_hub.auto_enable_new_accounts`. This variable is not configurable anymore using security hub central configuration.

### How to upgrade.

1. Verify Control Tower Governed Regions.

Ensure your AWS Control Tower Landing Zone regions includes `us-east-1`.

To check:
1. Log in to the **core-management account**.
2. Navigate to **AWS Control Tower****Landing Zone Settings**.
3. Confirm `us-east-1` is listed under **Landing Zone Regions**.

If `us-east-1` is missing, update your AWS Control Tower settings **before upgrading**.

> [!NOTE]
> For more details on the `regions` variable, refer to the [Specifying the correct regions section in the readme](README.md).
The following shell snippet generates the removal statements:
2. Update the variables according to the variables section above.

3. Manually Removing Local Security Hub Standards

Previous versions managed `aws_securityhub_standards_subscription` resources locally in core accounts. These are now centrally configured using `aws_securityhub_configuration_policy`. **Terraform will attempt to remove these resources from the state**. To prevent disabling them, the resources must be manually removed from the Terraform state.

*Steps to Remove Resources:*

a. Generate Removal Commands. Run the following shell snippet:

```shell
terraform init
for local_standard in $(terraform state list | grep "module.landing_zone.aws_securityhub_standards_subscription.logging"); do
for local_standard in $(terraform state list | grep "module.landing_zone.aws_securityhub_standards_subscription"); do
echo "terraform state rm '$local_standard'"
done
```

Evaluate the output and run the commands. The statements should look something like this:
b. Execute Commands: Evaluate and run the generated statements. They will look like:

```shell
terraform state rm 'module.landing_zone.aws_securityhub_standards_subscription.logging["arn:aws:securityhub:eu-central-1::standards/pci-dss/v/3.2.1"]'
...
```

### Variables
*Why Manual Removal is Required*

The following variables have been replaced:
* `aws_service_control_policies.allowed_regions` -> `regions.allowed_regions`
* `aws_config.aggregator_regions` -> the union of `regions.home_region` and `regions.linked_regions`
Terraform cannot handle `for_each` loops in `removed` statements ([HashiCorp Issue #34439](https://github.com/hashicorp/terraform/issues/34439)). Therefore the resources created with a `for_each` loop on `local.security_hub_standards_arns` must be manually removed from the Terraform state to prevent unintended deletions.

4. Upgrade your mcaf-landing-zone module to v5.x.x.

### Troubleshooting

#### Issue: AWS Security Hub control `AWS Config should be enabled and use the service-linked role for resource recording` fails for multiple accounts after upgrade

#### Resolution Steps

1. **Verify `regions.linked_regions`:**
- Ensure that `regions.linked_regions` matches the AWS Control Tower Landing Zone regions.
- For guidance, refer to the [Specifying the correct regions section in the README](README.md).

2. **Check Organizational Units (OUs):**
- Log in to the **core-management account**.
- Navigate to **AWS Control Tower****Organization**.
- Confirm all OUs have the **Baseline state** set to `Succeeded`.

3. **Check Account Baseline States:**
- In **AWS Control Tower****Organization**, verify that all accounts show a **Baseline state** of `Succeeded`.
- If any accounts display `Update available`:
- Select the account.
- Go to **Actions****Update**.

4. **Allow Time for Changes to Propagate:**
- Wait up to **24 hours** for updates to propagate and resolve the Security Hub findings.

If all steps are completed and the issue persists, review AWS Control Tower settings and logs for additional troubleshooting.

The following variables are added:
* `aws_security_hub.disabled_control_identifiers`. List of Security Hub control IDs that are disabled in the organisation.
* `aws_security_hub.enabled_control_identifiers`. List of Security Hub control IDs that are enabled in the organisation.

## Upgrading to v4.0.0

Expand Down
2 changes: 2 additions & 0 deletions config.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ locals {
}
]
])

aws_config_rules = setunion(
try(var.aws_config.rule_identifiers, []),
[
Expand All @@ -16,6 +17,7 @@ locals {
"S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED"
]
)

aws_config_s3_name = coalesce(
var.aws_config.delivery_channel_s3_bucket_name,
"aws-config-configuration-history-${var.control_tower_account_ids.logging}-${data.aws_region.current.name}"
Expand Down
11 changes: 5 additions & 6 deletions examples/basic/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ locals {
}

provider "aws" {
region = "eu-west-1"
region = "eu-central-1"
}

provider "aws" {
alias = "audit"
region = "eu-west-1"
region = "eu-central-1"

assume_role {
role_arn = "arn:aws:iam::${local.control_tower_account_ids.audit}:role/AWSControlTowerExecution"
Expand All @@ -20,7 +20,7 @@ provider "aws" {

provider "aws" {
alias = "logging"
region = "eu-west-1"
region = "eu-central-1"

assume_role {
role_arn = "arn:aws:iam::${local.control_tower_account_ids.logging}:role/AWSControlTowerExecution"
Expand All @@ -41,10 +41,9 @@ module "landing_zone" {
source = "../../"

control_tower_account_ids = local.control_tower_account_ids

regions = {
allowed_regions = ["eu-central-1", "eu-west-1"]
allowed_regions = ["eu-central-1"]
home_region = "eu-central-1"
linked_regions = ["eu-west-1"]
}
tags = { Terraform = true }
}
Loading

0 comments on commit 6287bb8

Please sign in to comment.