├── .gitignore ├── .kitchen.yml ├── Gemfile ├── LICENSE.md ├── README.md ├── TESTING_AGAINST_AWS.md ├── pre-kitchen.rb └── test └── integration ├── cis ├── build │ ├── account_settings.tf │ ├── aws.tf │ ├── cloudtrail.tf │ ├── cloudwatch.tf │ ├── configservice.tf │ ├── configservice_us_east_1.tf │ ├── configservice_us_east_2.tf │ ├── configservice_us_west_1.tf │ ├── configservice_us_west_2.tf │ ├── ec2.tf │ ├── iam_manager.tf │ ├── iam_master.tf │ ├── outputs.tf │ ├── variables.tf │ ├── vpc.tf │ └── vpc_ssh_security_group.tf └── inspec.yml └── minimal ├── build ├── aws.tf └── variables.tf ├── inspec.yml └── verify ├── controls └── aws_iam_root_user.rb └── inspec.yml /.gitignore: -------------------------------------------------------------------------------- 1 | *.lock 2 | *.gem 3 | *.rbc 4 | 5 | !Gemfile.lock 6 | .attribute.yml 7 | 8 | /.config 9 | /coverage/ 10 | /InstalledFiles 11 | /pkg/ 12 | /spec/reports/ 13 | /spec/examples.txt 14 | inspec-azure.plan 15 | inspec-aws-*.plan 16 | 17 | 18 | *.tfstate 19 | *.tfstate.* 20 | .terraform/ 21 | terraform.tfvars 22 | 23 | .kitchen/ 24 | .kitchen.local.yml 25 | kitchen.local.yml 26 | 27 | .vagrant 28 | 29 | inspec-deprecations-in-cfg.txt 30 | inspec-deprecations-in-lib.txt 31 | 32 | # Docker 33 | *.retry 34 | .backup 35 | 36 | 37 | # OSX 38 | # General 39 | .DS_Store 40 | .AppleDouble 41 | .LSOverride 42 | 43 | # Icon must end with two \r 44 | Icon 45 | 46 | # Thumbnails 47 | ._* 48 | 49 | # Files that might appear in the root of a volume 50 | .DocumentRevisions-V100 51 | .fseventsd 52 | .Spotlight-V100 53 | .TemporaryItems 54 | .Trashes 55 | .VolumeIcon.icns 56 | .com.apple.timemachine.donotpresent 57 | 58 | # Directories potentially created on remote AFP share 59 | .AppleDB 60 | .AppleDesktop 61 | Network Trash Folder 62 | Temporary Items 63 | .apdisk 64 | 65 | # Logs 66 | *.log 67 | 68 | 69 | ## Documentation cache and generated files: 70 | /.yardoc/ 71 | /_yardoc/ 72 | /doc/ 73 | /rdoc/ 74 | 75 | # Ignore bundler config 76 | /.bundle/ 77 | /vendor/ 78 | /vendor/bundle 79 | vendor/cookbooks 80 | 81 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 82 | .rvmrc 83 | .packer 84 | 85 | # for a library or gem, you might want to ignore these files since the code is 86 | # intended to run in multiple environments; otherwise, check them in: 87 | .ruby-version 88 | .ruby-gemset 89 | 90 | 91 | ## JetBrain 92 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 93 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 94 | .idea/ 95 | 96 | ## Specific to RubyMotion: 97 | .dat* 98 | .repl_history 99 | *.bridgesupport 100 | 101 | # File-based project format 102 | *.iws 103 | 104 | # IntelliJ 105 | out/ 106 | 107 | # mpeltonen/sbt-idea plugin 108 | .idea_modules/ 109 | 110 | # Crashlytics plugin (for Android Studio and IntelliJ) 111 | com_crashlytics_export_strings.xml 112 | crashlytics.properties 113 | crashlytics-build.properties 114 | fabric.properties 115 | 116 | # JIRA plugin 117 | atlassian-ide-plugin.xml 118 | 119 | 120 | # Build Folder 121 | /build/ 122 | /build-iPhoneOS/ 123 | /build-iPhoneSimulator/ 124 | 125 | 126 | # Ignore rendered files from docs/ 127 | source/docs/reference/ 128 | examples/meta-profile/vendor/ 129 | habitat/VERSION 130 | habitat/results 131 | /lib/bundler/man/ 132 | 133 | 134 | # USER 135 | /.gitignoredir/ 136 | /tmp/ 137 | /test/tmp/ 138 | /test/version_tmp/ 139 | /.emacs.desktop 140 | .gitter 141 | *.elc 142 | nbproject 143 | auto-save-list 144 | tramp 145 | /.direnv 146 | /.envrc 147 | results/ 148 | contrib/* 149 | 150 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: terraform 4 | variables: 5 | region: "<%= ENV['AWS_DEFAULT_REGION'] %>" 6 | instance_type: "<%= ENV['AWS_DEFAULT_INSTANCE_TYPE'] %>" 7 | ssh_security_group_cidr: "<%= ENV['SSH_SG_CIDR'] %>" 8 | 9 | provisioner: 10 | name: terraform 11 | 12 | platforms: 13 | - name: setup 14 | 15 | verifier: 16 | name: terraform 17 | format: json 18 | output: aws_results.json 19 | groups: 20 | - name: default 21 | 22 | suites: 23 | - name: minimal 24 | driver: 25 | root_module_directory: "./test/integration/minimal/build/" 26 | verifier: 27 | inspec_tests: 28 | - path: "./test/integration/minimal/verify" 29 | 30 | - name: cis 31 | driver: 32 | variables: 33 | prefix: "cis" 34 | root_module_directory: "./test/integration/cis/build/" 35 | 36 | verifier: 37 | inspec_tests: 38 | - git: https://github.com/mitre/cis-aws-foundations-baseline.git 39 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | source 'https://rubygems.org' 4 | 5 | gem 'test-kitchen' 6 | gem 'kitchen-terraform' 7 | gem 'inspec', '~> 1.51.0' #remove version pinning after json output bug is fixed 8 | gem 'kitchen-inspec' 9 | 10 | gem 'aws-sdk', '~> 2' 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Licensed under the Apache 2.0 license, except as noted below. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | - Redistributions of source code must retain the above copyright/ digital rights legend, this list of conditions and the following Notice. 6 | 7 | - Redistributions in binary form must reproduce the above copyright copyright/ digital rights legend, this list of conditions and the following Notice in the documentation and/or other materials provided with the distribution. 8 | 9 | - Neither the name of The MITRE Corporation nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | MITRE’s licensed products include third-party materials that are subject to open source or free software licenses (“Open Source Materials”). The Open Source Materials are as follows: 12 | 13 | * CIS Benchmarks. Please visit www.cisecurity.org for full terms of use. 14 | 15 | The Open Source Materials are licensed under the terms of the applicable third-party licenses that accompany the Open Source Materials. MITTRE’s license does not limit a licensee’s rights under the terms of the Open Source Materials license. MITRE’s license also does not grant licensee rights to the Open Source Materials that supersede the terms and conditions of the Open Source Materials license. 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cis-aws-foundations-hardening - v1.1.0 2 | 3 | A terraform / kitchen-terraform hardening baseline the CIS AWS Foundations Benchmark v1.1.0. 4 | 5 | ## Overview 6 | 7 | This will help you setup and validate an AWS Environment as per CIS AWS Benchmark. This build will not modify existing resources. 8 | It will modify default `default vpc` and each `default security group` as per CIS guidance. 9 | 10 | ## Versioning and State of Development 11 | This project uses the [Semantic Versioning Policy](https://semver.org/). 12 | 13 | ### Branches 14 | The master branch contains the latest version of the software leading up to a new release. 15 | 16 | Other branches contain feature-specific updates. 17 | 18 | ### Tags 19 | Tags indicate official releases of the project. 20 | 21 | Please note 0.x releases are works in progress (WIP) and may change at any time. 22 | 23 | ### Tech Used 24 | - kitchen-terraform (>=v3.0.0) 25 | - test-kitchen (v.1.60.0) 26 | - inspec.io 27 | - terraform ( > v0.10.2) 28 | - tfenv 29 | - awscli (v1.1) 30 | 31 | ## Pre-Checks 32 | 33 | A. Use `tfenv` to switch to your `tf v0.11.0` environment 34 | B. Install any needed gems via `bundle install` 35 | C. Use the `pre-kitchen.rb` script to ensure you have all the env_vars setup as needed. 36 | ``` 37 | ruby pre-kitchen.rb 38 | ``` 39 | 40 | ## Usage 41 | 42 | ### Setup your Environment 43 | 44 | Please see TESTING_AGAINST_AWS.md for details on how to setup the needed AWS accounts to perform testing. 45 | 46 | Follow these instructions carefully. 47 | 48 | 1. Create an AWS account. Make a note of the account email and root password in a secure secret storage system. 49 | 2. Create an IAM user named `test-fixture-maker`. 50 | * Enable programmatic access (to generate an access key) 51 | * Note the access key and secret key ID that are generated. 52 | 3. Create an IAM Group named `test-fixture-maker-group`. 53 | * Direct-attach the policy AdministratorAccess 54 | * Add user `test-fixture-maker` to the group 55 | 56 | 4. Set the required env variables. 57 | 58 | - AWS Credentials 59 | ``` 60 | AWS_ACCESS_KEY_ID - The AWS Access Key that is to be used (default: none) 61 | AWS_SECRET_ACCESS_KEY - The AWS Secret Access Key that is to be used (default: none) 62 | ``` 63 | - TF_VAR_ prevents credentials from being populated on terrafrom logs 64 | ``` 65 | TF_VAR_aws_ssh_key_id - The value is the name of the AWS key pair you want to use (default: none) (hide from logs) 66 | TF_VAR_aws_access_key - The AWS Access Key that is to be used (default: none) (hide from logs) 67 | TF_VAR_aws_secret_key - The AWS Secret Access Key that is to be used (default: none) (hide from logs) 68 | ``` 69 | - Infrastructure Data 70 | ``` 71 | AWS_DEFAULT_REGION - The AWS Region you would like to use (default: us-east-1) 72 | AWS_DEFAULT_INSTANCE_TYPE - The EC2 instance type (also known as size) to use. (default: none) 73 | SSH_SG_CIDR - Specify an IP address in CIDR notation, a CIDR block for ssh ingress rule. (default: none) 74 | ``` 75 | 76 | ### Build/Verify 77 | 78 | Run Test kitchen 79 | 80 | a. `bundle exec kitchen list` 81 | b. `bundle exec kitchen create cis-setup` 82 | c. `bundle exec kitchen converge cis-setup` 83 | d. `bundle exec kitchen verify cis-setup` 84 | e. `bundle exec kitchen destroy cis-setup` 85 | 86 | 87 | ### Known Issues 88 | 89 | 1) AWS Simple Queue Service takes a few minutes to build, so please wait a few minutes before running `kitchen verify`. 90 | 91 | 2) Known Terrafrom bug that affects Managed policy attachment shows up on a second `kitchen converge` or `kitchen destroy`. 92 | https://github.com/hashicorp/terraform/issues/5979 . 93 | Please converge or destroy again to get past the error. 94 | 95 | ## Questions 96 | 97 | - see: https://newcontext-oss.github.io/kitchen-terraform/tutorials/amazon_provider_ec2.html 98 | - see: https://github.com/chef/inspec-aws 99 | 100 | ## Developing 101 | 102 | We use a feature-branch model for development. Plese create a fork and push a PR as a feature-branch. 103 | 104 | ## NOTICE 105 | 106 | © 2018 The MITRE Corporation. 107 | 108 | Approved for Public Release; Distribution Unlimited. Case Number 18-3678. 109 | 110 | ## NOTICE 111 | MITRE hereby grants express written permission to use, reproduce, distribute, modify, and otherwise leverage this software to the extent permitted by the licensed terms provided in the LICENSE.md file included with this project. 112 | 113 | ## NOTICE 114 | 115 | This software was produced for the U. S. Government under Contract Number HHSM-500-2012-00008I, and is subject to Federal Acquisition Regulation Clause 52.227-14, Rights in Data-General. 116 | 117 | No other use other than that granted to the U. S. Government, or to those acting on behalf of the U. S. Government under that Clause is authorized without the express written permission of The MITRE Corporation. 118 | 119 | For further information, please contact The MITRE Corporation, Contracts Management Office, 7515 Colshire Drive, McLean, VA 22102-7539, (703) 983-6000. 120 | 121 | ## NOTICE 122 | 123 | CIS Benchmarks are published by the Center for Internet Security (CIS), see: https://www.cisecurity.org/. 124 | -------------------------------------------------------------------------------- /TESTING_AGAINST_AWS.md: -------------------------------------------------------------------------------- 1 | # Testing Against AWS - Integration Testing 2 | 3 | ## Problem Statement 4 | 5 | We want to be able to test AWS-related InSpec resources against AWS itself. This means we need to create constructs ("test fixtures") in AWS to examine using InSpec. For cost management, we also want to be able to destroy 6 | 7 | ## General Approach 8 | 9 | We use Terraform to setup test fixtures in AWS, then run a CIS AWS Foundations Inspec Profile against these (which should all pass), and finally tear down the test fixtures with Terraform. For fixtures that cannot be managed by Terraform, we manually setup fixtures using instructions below. 10 | 11 | We use the AWS CLI credentials system to manage credentials. 12 | 13 | 14 | ### Installing Terraform 15 | 16 | Download [Terraform](https://www.terraform.io/downloads.html). We require at least v0.10 . To install and choose from multiple Terraform versions, consider using [tfenv](https://github.com/kamatama41/tfenv). 17 | 18 | ### Installing AWS CLI 19 | 20 | Install the [AWS CLI](http://docs.aws.amazon.com/cli/latest/userguide/installing.html). We will store profiles for testing in the `~/.aws/credentials` file. 21 | 22 | ## Limitations 23 | 24 | There are some things that we can't (or very much shouldn't) do via Terraform - like manipulating the root account MFA settings. 25 | 26 | Also, there are some singleton resources (such as the default VPC, or Config status) that we should not manipulate without consequences. 27 | 28 | ## Current Solution 29 | 30 | Our solution is to create two AWS accounts, each dedicated to the task of integration testing inspec-aws. 31 | 32 | In the "default" account, we setup all fixtures that can be handled by Terraform. For any remaining fixtures, 33 | such as enabling MFA on the root account, we manually set one value in the "default" account, and manually set the opposing value in the "minimal" account. This allows use to perform testing on any reachable resource or property, regardless of whether or not Terraform can manage it. 34 | 35 | All tests (and test fixtures) that do not require special handling are placed in the "default" set. That includes both positive and negative checks. 36 | 37 | Note that some tests will fail for the first day or two after you set up the accounts, due to the tests checking properties such as the last usage time of an access key, for example. 38 | 39 | Additionally, the first time you run the tests, you will need to accept the user agreement in the AWS marketplace for the linux AMIs we use. You'll need to do it 4 times, once for each of debian and centos on the two accounts. 40 | 41 | ### Creating the build/verify account 42 | 43 | Follow these instructions carefully. Do not perform any action not specified. 44 | 45 | 1. Create an AWS account. Make a note of the account email and root password in a secure secret storage system. 46 | 2. Create an IAM user named `test-fixture-maker`. 47 | * Enable programmatic access (to generate an access key) 48 | * Note the access key and secret key ID that are generated. 49 | 3. Create an IAM Group named `test-fixture-maker-group`. 50 | * Direct-attach the policy AdministratorAccess 51 | * Add user `test-fixture-maker` to the group 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /pre-kitchen.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | require 'yaml' 3 | 4 | @run_kitchen = true 5 | my_vars = 6 | [ 7 | 'AWS_ACCESS_KEY_ID', 8 | 'AWS_SECRET_ACCESS_KEY', 9 | 'TF_VAR_aws_ssh_key_id', 10 | 'TF_VAR_aws_access_key', 11 | 'TF_VAR_aws_secret_key', 12 | 'AWS_DEFAULT_REGION', 13 | 'AWS_DEFAULT_INSTANCE_TYPE', 14 | 'SSH_SG_CIDR', 15 | ] 16 | 17 | my_vars.each do |value| 18 | if ENV.fetch(value,nil).to_s != '' 19 | puts "#{value} is: " + ENV.fetch(value,nil).to_s 20 | else 21 | @run_kitchen=false 22 | puts "Please set #{value}" 23 | end 24 | end 25 | 26 | puts "If you want to get JSON output, please set the USE_JSON = 'true'" 27 | 28 | puts '' 29 | puts '----------' 30 | puts 'You are OK to run Test Kitchen' if @run_kitchen == true 31 | puts 'Please SET the above Envrioment variables before running kitchen' if @run_kitchen == false 32 | 33 | require 'rubygems'; require 'json'; 34 | 35 | 36 | my_vpcs = JSON.parse(%x[aws ec2 describe-vpcs]); 37 | 38 | 39 | re = Regexp.union('false') 40 | if my_vpcs['Vpcs'][0]['IsDefault'].to_s.match(re) 41 | puts 'Default VPC does NOT exist' 42 | puts ' --- ' 43 | puts ' - please use an account/region with default VPC' 44 | puts ' - alternativelly, consider hard-coding default vpc with terraform by setting Environment Variable to your VPC (below)' 45 | puts ' export TF_VAR_vpc_id=' + my_vpcs['Vpcs'][0]['VpcId'] 46 | else 47 | puts 'Default VPC Exists' 48 | end -------------------------------------------------------------------------------- /test/integration/cis/build/account_settings.tf: -------------------------------------------------------------------------------- 1 | resource "aws_iam_account_password_policy" "CISBenchmark" { 2 | minimum_password_length = 14 3 | password_reuse_prevention = 24 4 | max_password_age = 90 5 | require_uppercase_characters = true 6 | require_lowercase_characters = true 7 | require_symbols = true 8 | require_numbers = true 9 | } 10 | -------------------------------------------------------------------------------- /test/integration/cis/build/aws.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = "> 0.10.0" 3 | } 4 | 5 | provider "aws" { 6 | access_key = "${var.aws_access_key}" 7 | secret_key = "${var.aws_secret_key}" 8 | region = "${var.region}" 9 | version = "~> 1.4" 10 | } 11 | 12 | data "aws_caller_identity" "creds" {} 13 | 14 | data "aws_region" "region" {} 15 | 16 | provider "aws" { 17 | alias = "east1" 18 | region = "us-east-1" 19 | } 20 | 21 | provider "aws" { 22 | alias = "east2" 23 | region = "us-east-2" 24 | } 25 | 26 | provider "aws" { 27 | alias = "west1" 28 | region = "us-west-1" 29 | } 30 | 31 | provider "aws" { 32 | alias = "west2" 33 | region = "us-west-2" 34 | } 35 | -------------------------------------------------------------------------------- /test/integration/cis/build/cloudtrail.tf: -------------------------------------------------------------------------------- 1 | resource "aws_s3_bucket" "cloudtrail_bucket_access_log_bucket" { 2 | bucket_prefix = "${var.prefix}-cloudtrail-access-log-bucket-" 3 | force_destroy = true 4 | acl = "log-delivery-write" 5 | } 6 | 7 | resource "aws_s3_bucket" "cloudtrail_bucket" { 8 | bucket_prefix = "${var.prefix}-cloudtrail-bucket-" 9 | force_destroy = true 10 | 11 | logging { 12 | target_bucket = "${aws_s3_bucket.cloudtrail_bucket_access_log_bucket.id}" 13 | target_prefix = "log/" 14 | } 15 | } 16 | 17 | resource "aws_s3_bucket_policy" "cloudtrail_bucket_policy" { 18 | bucket = "${aws_s3_bucket.cloudtrail_bucket.id}" 19 | 20 | policy = <