Skip to content

Commit

Permalink
Merge pull request #440 from ericzbeard/stacksets
Browse files Browse the repository at this point in the history
StackSets
  • Loading branch information
ericzbeard authored Jul 18, 2024
2 parents eef4a48 + a94daf8 commit 271e64a
Show file tree
Hide file tree
Showing 17 changed files with 1,036 additions and 31 deletions.
3 changes: 3 additions & 0 deletions CloudFormation/StackSets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*-pkg.yaml
local/

116 changes: 116 additions & 0 deletions CloudFormation/StackSets/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# CloudFormation StackSets Sample with Cross-Account Log Consolidation

This sample configures a service-managed stack set in an organization and pipes
all log events from the target accounts into the management account. The events
are limited to the CloudFormation stack events, which helps to consolidate logs
from stacks that are being deployed as part of a stack set to many environments.

<img src="stacksetslogging.png" />

## Prerequisites

You should have an AWS Organization structure set up with a primary management
account and several accounts under management. (Although not necessary for this
solution, in general it is highly recommended to set up your organization with
[AWS Control Tower](https://aws.amazon.com/controltower/), or to migrate to
Control Tower if you set up your landing zone manually.)

A typical starting point for an organization might look like this:

- root
- core
- Audit account
- Log archive account
- custom
- Account 1
- Account 2
- Management account

Despite the fact that we have a standard Log archive account, we do not use
that one for the centralized logging in this sample, since that account is
meant for compliance and investigations, and should be locked down. The point
of centralized logging in this sample is to assist in troubleshooting, so that
if something goes wrong during a StackSets deployment, it is easy for the
administrator to see the errors from one place.

Make sure that you have enabled trusted access from the management account.

<img src="activate-trusted.png" />

## Templates/Stacks

### `common-resources.yaml`

This is the template that will be deployed to all target accounts. It has the
common resources that we want to appear consistently in all accounts across the
organization. For sample purposes, the infrastructure is a simple one,
consisting of S3 buckets. If you are adapting this solution for your
environment, this is the template you would replace with whatever it is you
want to deploy across accounts and regions.

The consolidated logging solution is focused on events from stacks created with
this template. Filters are available on either the source side or the
destination to limit the results to only root cause failures.

### `common-resources-stackset.yaml`

This template deploys the stack set itself into the management account. For
this sample we are using IaC to define IaC. Instead of logging in to the
console to create the stack set, we define it in a template and deploy it via
CloudFormation.

### `log-setup-target-accounts.yaml`

Set up the logging infrastructure in target accounts to pipe all CloudFormation
events to the management account.

### `log-setup-management.yaml`

Set up the logging infrastructure in the management account. This template also
contains a stack set resource, to deploy the logging setup to target accounts.

## Deployment

In order to deploy this sample, you will need to first install
[Rain](https://github.com/aws-cloudformation/rain), which is necessary to
process the `!Rain` directives in the templates.

Deploy the logging resources to the management account and to the target accounts.

`rain --profile [org-management-account-admin] deploy log-setup-management.yaml`

Package the common resources template.

`rain pkg -x common-resources.yaml > common-resources-pkg.yaml`

Then deploy the sample resources that are common to each account, to cause the
CloudWatch log group in the management account to receive events. This template
creates a stack set to manage the deployment of the packaged common resources template.

`rain --profile [org-management-account-admin] --experimentaldeploy common-resources-stackset.yaml`

## Build and Test

If you are doing development on this sample, you will need a Python environment
and cfn-lint installed.

Create a Python virtual environment.

```sh
python3 -m venv .env
source .env/bin/activate
```

Install cfn-lint

```sh
pip install cfn-lint
```

Build and validate

```sh
./build.sh
```


Binary file added CloudFormation/StackSets/activate-trusted.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions CloudFormation/StackSets/build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/env bash
set -eou pipefail

GUARD_RULES=../../scripts/rules.guard

echo "Packaging common resources..."
rain pkg -x common-resources.yaml > common-resources-pkg.yaml

echo "Linting common resources..."
cfn-lint common-resources-pkg.yaml

echo "Guarding common resources..."
cfn-guard validate -d common-resources-pkg.yaml -r $GUARD_RULES

echo "Packaging common resources stack set..."
rain pkg common-resources-stackset.yaml > common-resources-stackset-pkg.yaml

echo "Linting common resources stack set..."
cfn-lint common-resources-stackset-pkg.yaml

echo "Guarding common resources stack set..."
cfn-guard validate -d common-resources-stackset-pkg.yaml -r $GUARD_RULES

echo "Linting log setup for target accounts..."
cfn-lint log-setup-target-accounts.yaml

echo "Guarding log setup for target acounts..."
cfn-guard validate -d log-setup-target-accounts.yaml -r $GUARD_RULES

echo "Packaging log setup for the management account..."
rain pkg log-setup-management.yaml > log-setup-management-pkg.yaml

echo "Linting log setup for the management account..."
cfn-lint log-setup-management-pkg.yaml

echo "Guarding log setup for the management account..."
cfn-guard validate -d log-setup-management-pkg.yaml -r $GUARD_RULES




37 changes: 37 additions & 0 deletions CloudFormation/StackSets/common-resources-stackset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
AWSTemplateFormatVersion: 2010-09-09

Description: This template contains a stack set that deploys common-resource.yaml to target accounts

Parameters:
OUID:
Type: String
Default: ou-qxtx-vv0thlla

Resources:
StackSet:
Type: AWS::CloudFormation::StackSet
Properties:
TemplateBody: !Rain::Embed common-resources-pkg.yaml
Capabilities:
- CAPABILITY_IAM
StackInstancesGroup:
- DeploymentTargets:
OrganizationalUnitIds:
- !Ref OUID
Regions:
- us-east-1
- us-west-2
Parameters:
- ParameterKey: AppName
ParameterValue: stackset-logging-sample
PermissionModel: SERVICE_MANAGED
Description: This stack set is part of a sample that demonstrates how to set up cross account logging
OperationPreferences:
FailureToleranceCount: 0
MaxConcurrentCount: 2
RegionConcurrencyType: PARALLEL
AutoDeployment:
Enabled: true
RetainStacksOnAccountRemoval: true
StackSetName: common-resources

43 changes: 43 additions & 0 deletions CloudFormation/StackSets/common-resources.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Description: |
This template has resources that will be installed into all managed accounts
in the OU. For the purposes of the sample it's not important what exactly we
are creating here. To demonstrate the consolidated logging, errors can be
introduced into this template, such as choosing a bucket name that already
exists. This template uses a Rain module, which can be packaged with `rain
pkg -x common-resources.yaml`.
Parameters:
AppName:
Type: String
Description: This name will be used as part of resource names
Default: stacksets-sample

Resources:

Storage:
Type: !Rain::Module "../../RainModules/bucket.yml"
Properties:
AppName: !Ref AppName

TestQ:
Type: AWS::SQS::Queue
Properties:
QueueName: test-events17

# BadBucket:
# Type: AWS::S3::Bucket
# Metadata:
# guard:
# SuppressedRules:
# - S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED
# - S3_BUCKET_DEFAULT_LOCK_ENABLED
# - S3_BUCKET_VERSIONING_ENABLED
# - S3_BUCKET_REPLICATION_ENABLED
# - S3_BUCKET_PUBLIC_WRITE_PROHIBITED
# - S3_BUCKET_PUBLIC_READ_PROHIBITED
# - S3_BUCKET_LOGGING_ENABLED
# Comment:
# This bucket is purposefully using an existing name, to cause a deployment failure
# Properties:
# BucketName: rain-artifacts-646934191481-us-east-1

Loading

0 comments on commit 271e64a

Please sign in to comment.