Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IAC-1753] Update CIS compliance guide #426

Merged
merged 39 commits into from
Jun 16, 2021
Merged

Conversation

ina-stoyanova
Copy link
Contributor

@ina-stoyanova ina-stoyanova commented May 24, 2021

Add (if missing) and review the below sections:
-> we can copy& paste directly from the LZ guide on the website, but be careful of links, code & any information that needs changing.

  • Pre-requisites @robmorgan
  • The Gruntwork solution @robmorgan
  • Added: Create the root account @ina
  • Replace with LZ instructions: Complete the manual steps @ina
  • Create an IAM user in the root account @ina
  • Lock down the root account IAM users @ina
  • Configure the security baseline for the root account @ina
  • Import existing resources from the root account @ina
  • Apply the security baseline to the root account @ina
  • Reset the root user password in each child account @ina
  • Lock down the root user in the child accounts @ina
  • Apply the security baseline to the logs account @ina
  • Apply the security baseline to the security account @ina
  • Apply the security baseline to the other child accounts @ina
  • Configure AWS Security Hub in the root account @robmorgan
  • Try authenticating as an IAM user to the child accounts @robmorgan
  • Use IAM roles for EC2 instances (?) @robmorgan
  • Maintaining compliance by following IAM best practices
  • Maintaining compliance by following Storage best practices
    • S3 Buckets
    • Encrypt EBS volumes [Remove this section] @robmorgan
  • Maintaining compliance by following Logging best practices
    • Cloudtrail [Remove this section] @robmorgan
    • AWS Config [Remove this section] @robmorgan
    • Enable key rotation for KMS keys
    • Create VPC flow logs @robmorgan
  • Maintaining compliance by following Monitoring best practices
    • Subscribe to SNS topics
  • Maintaining compliance by following Networking best practices
    • VPC Networks
  • Rewrite the Traceability matrix (leave until last) @infraredgirl

@netlify
Copy link

netlify bot commented May 24, 2021

✔️ Deploy Preview for keen-clarke-470db9 ready!

🔨 Explore the source changes: 3473f35

🔍 Inspect the deploy log: https://app.netlify.com/sites/keen-clarke-470db9/deploys/60c87dd47edd14000756d39c

😎 Browse the preview: https://deploy-preview-426--keen-clarke-470db9.netlify.app

@ina-stoyanova ina-stoyanova changed the title IAC-1753 - Update CIS compliance guide [IAC-1753] WIP - Update CIS compliance guide May 24, 2021
Comment on lines +1463 to +1471
accounts = {
logs = "409800740445"
security = "673123100581"
shared = "384759303421"
dev = "293847503945"
stage = "384924092834"
prod = "784260063686"
root = "216044045972"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, in the LZ guide, I've moved these into the root accounts.json that gets included in the root common.hcl as accounts = jsondecode(file("accounts.json")). Then every terragrunt.hcl that needs it does

locals {
  # A local for more convenient access to the accounts map.
  accounts = local.common_vars.locals.accounts
  ...
}

It's a nit, but wonder if it's something you want to follow here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1. Seems worth doing in a follow-up PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, this comment applies to all the accounts = { ... } in all the terragrunt.hcl files in this guide.

# All of the other accounts send logs to this account.
config_linked_accounts = [
for name, id in local.accounts :
id if name != "logs"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: In my view, this is a line under the for loop, so it seems like it should be further indented. (We need to update the ref arch generation to reflect this too.)

cloudtrail_allow_kms_describe_key_to_external_aws_accounts = true
cloudtrail_external_aws_account_ids_with_write_access = [
for name, id in local.accounts :
id if name != "logs"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: In my view, this is a line under the for loop, so it seems like it should be further indented. (We need to update the ref arch generation to reflect this too.)

Comment on lines +1728 to +1735
logs = "409800740445"
security = "673123100581"
shared = "384759303421"
dev = "293847503945"
stage = "384924092834"
prod = "784260063686"
root = "216044045972"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: See comment in the logs section on DRYing up this part.

Comment on lines +2000 to +2007
logs = "409800740445"
security = "673123100581"
shared = "384759303421"
dev = "293847503945"
stage = "384924092834"
prod = "784260063686"
root = "216044045972"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: See comment in logs section about DRYing this up.

Comment on lines +996 to +998
accounts = {
root = "216044045972"
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Perhaps this ID could be stored as a root key in the accounts.json that I mention in the comment under the logs section below.

Comment on lines +1737 to +1742
# Both buckets are created in the logs account by account-baseline-root
config_s3_bucket_name = "acme-config-bucket-logs"
cloudtrail_s3_bucket_name = "acme-cloudtrail-logs"

# The Cloudtrail KMS Key is deployed at the logs account but it's value is an output from the root account.
cloudtrail_kms_key_arn = "arn:aws:kms:us-east-1:216044045972:alias/cloudtrail-acme"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Is it worth replacing these hardcoded values with placeholder values, with a comment above them telling them how to get them? Like:

  # Use the S3 bucket and KMS key that were already created in the logs account by account-baseline-root
  cloudtrail_s3_bucket_name = "<CLOUDTRAIL_BUCKET_NAME>"
  cloudtrail_kms_key_arn    = "<CLOUDTRAIL_KMS_KEY_ARN>"

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you have currently works fine. In either case, it's up to the customer whether they want to store the values in locals, and if you have them set it there, then it makes no difference that you reference the local here.

Copy link
Contributor

@rhoboat rhoboat Jun 16, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made this modification in #442, so we store the bucket names and arns in common.hcl. Updating the LZ guide, too, in #443.

Comment on lines +1473 to +1478
# Both buckets are created in the logs account by account-baseline-root
config_s3_bucket_name = "acme-config-bucket-logs"
cloudtrail_s3_bucket_name = "acme-cloudtrail-logs"

# The Cloudtrail KMS Key is deployed at the logs account but it's value is an output from the root account.
cloudtrail_kms_key_arn = "arn:aws:kms:us-east-1:409800740445:alias/cloudtrail-acme"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Same nit as below on replacing hardcoded values with placeholders.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Or, alternatively, extract into the same common.hcl.

Comment on lines +2009 to +2014
# Both buckets are created in the logs account by account-baseline-root
config_s3_bucket_name = "acme-config-bucket-logs"
cloudtrail_s3_bucket_name = "acme-cloudtrail-logs"

# The Cloudtrail KMS Key is deployed at the logs account but it's value is an output from the root account.
cloudtrail_kms_key_arn = "arn:aws:kms:us-east-1:409800740445:alias/cloudtrail-acme"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: Same nit about hardcoded values.


# Prefix all resources with this name
name_prefix = "<COMPANY_NAME>-stage"
name_prefix = "stage-logs"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, this one I'm not sure about. Setting the name_prefix for the environment + account is not what we're currently doing in the ref arch deploys. See the LZ guide for how we set name_prefix (in common.hcl, usually as the company name, and then in the root terragrunt.hcl, so that no downstream terragrunt.hcls need to set it). It makes me wonder if our ref arch is setting the name_prefix a little too generic? Pinging @bwhaley for another opinion.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does need to be something unique as it will ultimately be used to create the S3 bucket, which is a global namespace among all AWS users. Identifying a good rule of thumb is tricky because it must be both (a) short enough to not run in to length constraints, and (b) globally unique. <COMPANY_NAME> is usually unique enough, but runs the risk of being too long. Many customers have chosen a prefix that is an acronym or shortened identifiable version of the company name, like phc or mf.

I think we ought to share this context in the comment on the preceding line, and go with something like:

name_prefix = "<SOME UNIQUE IDENTIFIER>-logs"

Copy link
Contributor

@rhoboat rhoboat Jun 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Ben. Seems like we need to update the LZ guide and the Ref Arch code, too. Looking at the terraform-aws-architecture-catalog, we set name_prefix in only one place, which gets passed around from the root terragrunt (and actually it's duplicated here, which we can simplify). That means it's not unique for the S3 buckets, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like I must be missing something. It can't be that we use the same name_prefix everywhere. Maybe it does get overridden in each account's terragrunt, but I'm not seeing it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bwhaley Thoughts on this?

}
kms_grants = {
ami_encryption_key = {
kms_cmk_arn = "arn:aws:kms:us-east-1:${local.accounts.shared}:alias/ami-encryption"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: I might remove the reference to us-east-1 here, using local.aws_region or some such, instead.
Or maybe this whole arn should be a placeholder text.

Copy link
Contributor

@rhoboat rhoboat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just left a few comments after looking more in depth at the terragrunt code.

@robmorgan robmorgan changed the title [IAC-1753] WIP - Update CIS compliance guide [IAC-1753] Update CIS compliance guide Jun 16, 2021
Copy link
Member

@brikis98 brikis98 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, just did a review pass. I found a bunch of NITs, which you can safely ignore for now, and perhaps implement in follow-up PRs. I also found a few places that look like legit bugs. These should probably be fixed ASAP. That said, I'll still mark this with a "ship it," as this PR has been open for ages, is still an improvement over the current guide, and even the "ASAP" fixes can still be done in follow-up PRs.

One more NIT: There are a very large number of sub-sections below deployment walkthrough:

Screen Shot 2021-06-16 at 3 46 21 PM

That might scare users off... Is it worth grouping some of those into slightly larger sections?


[[gruntwork_solution]]
=== The Gruntwork solution
Gruntwork offers battle-tested infrastructure as code modules to help you create production grade infrastructure in a
fraction of the time it would take to develop from scratch. Each of the code modules are "compliance-ready"; they are
fraction of the time it would take to develop from scratch. Each of the core modules are "compliance-ready"; they are
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: I found this "The Gruntwork solution" section a little hard to follow, especially with the mix of terms like modules, services, architectures, wrapper modules, etc.

I'd propose the following structure for a follow-up PR:

  • We should define, in bullet points, the (a) module catalog, (b) service catalog, (c) architecture catalog. These definitions should be short, and point to the full blog post for more details.
  • Next, we should explain that we offer a standard service catalog and a CIS service catalog. The former is the baseline: it has all the core services ready for most usage. The latter has the subset of services that must be configured in a specific way to be compliant with the CIS benchmark.
  • To deploy a CIS compliant infra, you first look in the CIS service catalog, and if the service you need is there, use it; otherwise, use the service from the standard service catalog; if that doesn't have the service you need, you can create your own service by combining modules from the module catalog.
  • Alternatively, you can get an out-of-the-box CIS compliant architecture from our arch catalog (link to Ref Arch page) in one day.

The key difference from the current structure is:

  1. This section can be shorter.
  2. We should focus on CIS Service Catalog instead of "wrapper modules." The latter is technically accurate, but not as effective of a way to present the concept to customers as Service Catalog.

That said, I don't feel strongly about this, so feel free to leave as is or tweak or whatever else you decide.

config_s3_bucket_name = local.config_s3_bucket_name

# Do not allow objects in the Config S3 bucket to be forcefully removed during destroy operations.
config_force_destroy = false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: isn't false the default for all the xxx_force_destroy params? If so, perhaps we don't need to include them here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This same comment applies to the same xxx_force_destroy params in all the terragrunt.hcl files below, too.

provider "aws" {
region = var.aws_region
terraform {
source = "git::[email protected]/gruntwork-io/terraform-aws-cis-service-catalog//modules/landingzone/account-baseline-app?ref=v0.22.0"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be account-baseline-root?

Comment on lines +1093 to +1094
# By granting access to the root ARN of the Security account in each of the roles below,
# we allow administrators to further delegate access to other IAM entities
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What roles below? What security account? It doesn't exist yet... Copy/paste issue?

Comment on lines +1096 to +1104
# Assuming the developers role will grant access to these services.
dev_permitted_services = [
"ec2",
"ecs",
"lambda",
"rds",
"elasticache",
"route53",
]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be no devs in the root account and no need to grant these permissions

[.exceptional]
IMPORTANT: You must be a [js-subscribe-cta]#Gruntwork subscriber# to access `terraform-aws-cis-service-catalog`.

Next, we'll configure a security baseline for the root account that is responsible for creating all the child accounts.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: we should call out explicitly somewhere that:

  1. We have security baselines for root, security, and app accounts.
  2. These security baselines implement most of the requirements from CIS: e.g., CloudTrail, AWS Config, IAM roles, etc.
  3. So 99% of the work is configuring a security baseline for each account and running apply on it.

Comment on lines +1463 to +1471
accounts = {
logs = "409800740445"
security = "673123100581"
shared = "384759303421"
dev = "293847503945"
stage = "384924092834"
prod = "784260063686"
root = "216044045972"
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, this comment applies to all the accounts = { ... } in all the terragrunt.hcl files in this guide.

Comment on lines +1819 to +1830
# A list of account root ARNs that should be able to assume the auto deploy role.
allow_auto_deploy_from_other_account_arns = [
# External CI/CD systems may use an IAM user in the security account to perform deployments.
"arn:aws:iam::${local.accounts.security}:root",

# The shared account contains automation and infrastructure tools, such as CI/CD systems.
"arn:aws:iam::${local.accounts.shared}:root",
]
auto_deploy_permissions = [
"iam:GetRole",
"iam:GetRolePolicy",
]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, what auto deploy do we do here? Also, you're allowing access from the security account... But this is the security account, so this doesn't quite make sense.

Comment on lines +1959 to +1961
You can re-use the `account-baseline-app` module you created earlier in your `infrastructure-modules` repo for all of
these child accounts; this module can be used interchangeably between app accounts and log accounts as they deploy most
of the same resources.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be talking about the account-baseline-app from the CIS Service Catalog, not anything with infra-modules.

Comment on lines +2267 to +2270
Hub will show a low security score for the CIS AWS Foundations Benchmark v1.2.0. This is due to AWS limitations on
checking compliance standards for cross-region/cross-account rules. This does not indicate that the accounts are not in
compliance; it is a failure of the AWS audit tool. Note also that the accounts are configured for the latest version of
the benchmark, v1.3.0; the AWS Security Hub does not support this version at the current time.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NIT: might be worth putting this in a callout to make it more visible. Lots of customers stumble on this exact point.

@ina-stoyanova
Copy link
Contributor Author

ina-stoyanova commented Jun 16, 2021

Thanks @brikis98 @bwhaley & @rhoboat for the thorough reviews!

I think here we should follow your suggestion:

OK, just did a review pass. I found a bunch of NITs, which you can safely ignore for now, and perhaps implement in follow-up PRs. I also found a few places that look like legit bugs. These should probably be fixed ASAP. That said, I'll still mark this with a "ship it," as this PR has been open for ages, is still an improvement over the current guide, and even the "ASAP" fixes can still be done in follow-up PRs.

In this morning's EU team catchup we discussed exactly that - there are many valuable suggestions in the last few rounds of review, but follow up PRs will be easier to manage, and with this state, we still add value to the customers. I'll go ahead and merge it if everyone's ok with this.

@ina-stoyanova
Copy link
Contributor Author

Oops - before posting the last comment I pressed the wrong button and closed the PR by mistake! Apologies

@ina-stoyanova ina-stoyanova merged commit c8fca45 into master Jun 16, 2021
@ina-stoyanova ina-stoyanova deleted the cis-service-catalog branch June 16, 2021 16:00
@ina-stoyanova ina-stoyanova restored the cis-service-catalog branch June 16, 2021 16:01
@ina-stoyanova ina-stoyanova deleted the cis-service-catalog branch June 16, 2021 16:15
@rhoboat rhoboat mentioned this pull request Jun 16, 2021
7 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants