├── .gitignore ├── LICENSE ├── amis └── ami │ ├── ami.json │ ├── user_data.sh │ └── variables.json ├── docs ├── AMIs.md ├── AWS Service Level Security Compliance.md ├── Arch.graffle │ ├── data.plist │ ├── image1.pdf │ ├── image10.pdf │ ├── image11.pdf │ ├── image12.pdf │ ├── image14.pdf │ ├── image15.pdf │ ├── image18.pdf │ ├── image19.pdf │ ├── image20.pdf │ ├── image21.pdf │ ├── image22.pdf │ ├── image24.pdf │ ├── image25.pdf │ ├── image3.pdf │ ├── image4.pdf │ ├── image5.pdf │ └── image7.pdf ├── Bastion.md ├── Containers.md ├── Multi Account Setup.md ├── Patterns.md ├── README.md └── Standards.md ├── environments ├── account │ ├── config.tf │ ├── iam.tf │ ├── locals.tf │ ├── main.tf │ └── versions.tf └── domain │ ├── cloudfront-lambda-viewer-response.js │ ├── cloudfront.tf │ ├── dynamodb.tf │ ├── ecs-alb.tf │ ├── ecs-nlb.tf │ ├── ecs.tf │ ├── elasticsearch.tf │ ├── elasticsearch │ └── mappings.json │ ├── locals.tf │ ├── main.tf │ ├── mysql.tf │ ├── postgres.tf │ ├── postgres │ ├── postgis.sql │ └── uuid.sql │ ├── redis.tf │ ├── versions.tf │ └── vpc.tf ├── master ├── account │ ├── config.tf │ ├── iam.tf │ ├── locals.tf │ ├── main.tf │ ├── organization.tf │ └── versions.tf ├── operations │ ├── ami.tf │ ├── dns.tf │ ├── ecr.tf │ ├── locals.tf │ ├── main.tf │ └── versions.tf └── state │ ├── main.tf │ └── versions.tf └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # .tfvars files 9 | #*.tfvars 10 | 11 | 12 | terraform-profile.auto.tfvars 13 | 14 | # Node 15 | node_modules 16 | package-lock.json 17 | 18 | # IDE 19 | .idea 20 | *.iml 21 | 22 | 23 | # OS 24 | .DS_Store 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 will Farrell 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /amis/ami/ami.json: -------------------------------------------------------------------------------- 1 | { 2 | "variables": { 3 | "profile": "", 4 | "region": "", 5 | "ami_regions": "" 6 | }, 7 | "builders": [ 8 | { 9 | "type": "amazon-ebs", 10 | "profile": "{{user `profile`}}", 11 | "region": "{{user `region`}}", 12 | "ami_regions": "{{user `ami_regions`}}", 13 | "source_ami_filter": { 14 | "filters": { 15 | "virtualization-type": "hvm", 16 | "name": "amzn-ami-vpc-nat-hvm-*-x86_64-ebs", 17 | "root-device-type": "ebs" 18 | }, 19 | "owners": [ 20 | "137112412989" 21 | ], 22 | "most_recent": true 23 | }, 24 | "instance_type": "t2.micro", 25 | "ssh_username": "ec2-user", 26 | "ami_name": "amzn-ami-vpc-nat-hvm-{{isotime \"20060102030405\"}}-x86_64-ebs" 27 | } 28 | ], 29 | "provisioners": [ 30 | { 31 | "type": "shell", 32 | "script": "user_data.sh", 33 | "execute_command": "sudo -S env {{ .Vars }} {{ .Path }}" 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /amis/ami/user_data.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo "***** Update *****" 4 | yum update -y 5 | -------------------------------------------------------------------------------- /amis/ami/variables.json: -------------------------------------------------------------------------------- 1 | { 2 | "profile": "default", 3 | "ami_regions": "us-east-2,us-west-2,ca-central-1", 4 | "region": "us-east-1" 5 | } 6 | -------------------------------------------------------------------------------- /docs/AMIs.md: -------------------------------------------------------------------------------- 1 | # Packer 2 | Packer scripts for creating up to date AMIs for faster initial boot time. 3 | The subfolders are named as their respective terraform modules e.g. the scripts 4 | for creating AMI for the bastion modules are in "bastion" subfolder. 5 | Creating the AMI in all required regions is a prerequisite for using the ec2, bastion and ecs terraform modules. 6 | 7 | ## Features 8 | - Updated operating system 9 | - CloudWatch logging enabled 10 | - CloudWatch agent for collecting additional metrics 11 | - Inspector agent for allowing running of security assessments in Amazon Inspector 12 | - SSM Agent for allowing shell access from Session AWS Systems Manager 13 | - bastion AMI only - `authorized_keys` generated from users in an IAM group 14 | 15 | ## Requirements 16 | ```bash 17 | $ brew install packer 18 | ``` 19 | 20 | ## Setup 21 | To create the AMIs, go to the respective subfolder, edit the `variables.json`, and run: 22 | ```bash 23 | packer build -var-file=variables.json ami.json 24 | ``` 25 | 26 | ## Input - these are located in variables.json 27 | - **profile** the profile to use in the shared credentials file for AWS. 28 | - **ami_regions:** a list of regions to copy the AMI to. Tags and attributes are copied along with the AMI. 29 | - **region:** the name of the region, such as us-east-1, in which to launch the EC2 instance to create the AMI. 30 | - **user_data.sh:** - this file contain the provisioning shell script. 31 | 32 | ## Output 33 | Along with the entire output from running the provisioning commands at the end of successfull execution the AMI ids in all regions are displayed. 34 | 35 | 36 | -------------------------------------------------------------------------------- /docs/AWS Service Level Security Compliance.md: -------------------------------------------------------------------------------- 1 | # AWS Service Level Security Compliance 2 | 3 | Last reviewed: 2019-08-01 4 | Sources: 5 | - https://aws.amazon.com/compliance/programs 6 | - https://aws.amazon.com/compliance/csa 7 | - https://aws.amazon.com/compliance/services-in-scope 8 | - https://aws.amazon.com/compliance/fips 9 | 10 | Compliance Report: https://aws.amazon.com/artifact/getting-started 11 | 12 | ## Certifications 13 | - CSA 14 | - SOC: 1,2,3 15 | - PCI: DSS Level 1 16 | - ISO: 9001:2015, 27001:2013, 27017:2015, 27018:2014 17 | - FIPS: 140-2 18 | 19 | Service | SOC | PCI | ISO | FIPS | Dependencies | NOTES + CONSIDERATIONS 20 | -----------------------------------|-----|-----|-----|------|--------------|------------ 21 | API Gateway (APIG) | Yes | Yes | Yes | US | | Deployed with serverless 22 | Certificate Manager (ACM) | Yes | Yes | Yes | No | | Security Secret Management 23 | CloudFront (CDN) | Yes | Yes | Yes | No | | Edge Service 24 | CloudFormation | Yes | Yes | Yes | US | | DevOps, Deployed with serverless 25 | CloudHSM | Yes | Yes | Yes | No | | Security Secret Management 26 | CloudTrail | Yes | Yes | Yes | US | S3 | Edge Service, Security Logging 27 | CloudWatch | Yes | Yes | Yes | No | | DevOps, PCI for Logs only 28 | Config | Yes | Yes | Yes | US | | Security Scanning 29 | Cognito | Yes | Yes | Yes | US | | Security Authentication 30 | DynamoDB | Yes | Yes | Yes | Yes | | 31 | Elastic Block Storage (EBS) | Yes | Yes | Yes | US | VPC | 32 | Elastic Compute Cloud (EC2) | Yes | Yes | Yes | Yes | VPC | 33 | Elastic Container Registry (ECR) | Yes | Yes | Yes | No | | 34 | Elastic Container Service (ECS) | Yes | Yes | Yes | No | VPC | 35 | Elastic File System (EFS) | Yes | Yes | Yes | No | VPC | 36 | Elastic Load Balancing (ELB) | Yes | Yes | Yes | US | VPC | 37 | ElastiCache | Yes | Yes | Yes | US | VPC | redis only 38 | Elasticsearch Service | Yes | Yes | Yes | US | | 39 | GuardDuty | Yes | Yes | Yes | No | | Security Scanner 40 | Identity & Access Management (IAM) | Yes | Yes | Yes | US | | Edge Service 41 | Inspector | Yes | Yes | Yes | US | EC2 | Security Scanner 42 | Key Management Service (KMS) | Yes | Yes | Yes | US | | Security Secret Management 43 | Kinesis Data Firehose | Yes | Yes | Yes | US | | Security Logging 44 | Lambda | Yes | Yes | Yes | US | | 45 | Lambda@Edge | Yes | Yes | No | No | CDN | Edge Service currently used with CloudFront to enforce CSP headers on static assets 46 | Macie | Yes | Yes | Yes | No | S3 | Security Scanner 47 | Organizations | Yes | No | Yes | No | | Edge Service 48 | Relational Database Service (RDS) | Yes | Yes | Yes | Yes | VPC | 49 | Route 53 (DNS) | Yes | Yes | Yes | US | | Edge Service 50 | Security Hub | Yes | Yes | Yes | No | | Security Scanner 51 | Security Token Service (STS) | --- | --- | --- | Yes | | Security 52 | Shield | Yes | Yes | Yes | US | APIG,CDN,ELB | Security 53 | Simple Email Service (SES) | Yes | No | Yes | No | | Edge service 54 | Simple Notification Service (SNS) | Yes | Yes | Yes | US | | 55 | Simple Queue Service (SQS) | Yes | Yes | Yes | US | | 56 | Simple Storage Service (S3) | Yes | Yes | Yes | US | | Includes Glacier 57 | Step Functions | Yes | Yes | Yes | No | | 58 | Systems Manager (SSM) | Yes | Yes | Yes | No | | Security Secret Management 59 | Trusted Advisor | No | No | Yes | No | | Edge Service, Security Scanner 60 | Virtual Private Cloud (VPC) | Yes | Yes | Yes | US | | 61 | Web Application Firewall (WAF) | Yes | Yes | Yes | US | APIG,CDN,ELB | Security Scanner 62 | X-Ray | Yes | Yes | Yes | No | APIG,EC2,ECS | DevOps 63 | 64 | ## Encryption at Rest 65 | 66 | Service | Keys | Notes 67 | ----------------------------------|------|------ 68 | DynamoDB | AWS | 69 | Elastic Block Storage (EBS) | KMS | 70 | Elastic Compute Cloud (EC2) AMI | KMS | Encrypted AMI can only be used in the same account. 71 | Elastic Container Registry (ECR) | No | 72 | Elastic File System (EFS) | KMS | 73 | ElastiCache | AWS | 74 | Elasticsearch Service | KMS | Only certain instances [Docs](https://docs.aws.amazon.com/elasticsearch-service/latest/developerguide/aes-supported-instance-types.html) 75 | Lambda | KMS | 76 | Relational Database Service (RDS) | KMS | Only certain instances [Docs](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.Encryption.html#Overview.Encryption.Limitations) 77 | Simple Storage Service (S3) | KMS* | ELB logs cannot use KMS - TODO re-check 78 | 79 | ## Encryption in Transit 80 | Service | TLS | Notes 81 | ----------------------------------|------|------ 82 | Elastic File System (EFS) | 1.2 | OCSP option 83 | ElastiCache | 1.2? | 84 | Elasticsearch Service | 1.2? | 85 | Relational Database Service (RDS) | 1.2? | Requires `ssl:true` to be set in application, or use serverless. 86 | -------------------------------------------------------------------------------- /docs/Arch.graffle/data.plist: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/data.plist -------------------------------------------------------------------------------- /docs/Arch.graffle/image1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image1.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image10.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image11.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image12.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image12.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image14.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image14.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image15.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image15.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image18.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image18.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image19.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image19.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image20.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image20.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image21.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image21.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image22.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image22.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image24.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image24.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image25.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image25.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image3.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image4.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image5.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image5.pdf -------------------------------------------------------------------------------- /docs/Arch.graffle/image7.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/willfarrell/terraform-aws-template/6050637c59019a4f6d39c6b544adcc5ac1de1133/docs/Arch.graffle/image7.pdf -------------------------------------------------------------------------------- /docs/Bastion.md: -------------------------------------------------------------------------------- 1 | # Bastion Docs 2 | Connecting to services in your AWS VPC. 3 | 4 | ## IAM 5 | ### Generate Key 6 | Run [script](https://gist.github.com/willfarrell/e9b7553367f5edca0ac7e0b8e9647a040) or see below 7 | ```bash 8 | # Amazon only accepts RSA Keys 9 | $ ssh-keygen -q -t rsa -b 4096 -o -N '' -C "Your Device Name Here" -f ~/.ssh/id_rsa 10 | $ ssh-add ~/.ssh/id_rsa 11 | ``` 12 | 13 | ### Upload to AWS 14 | Copy your key contents: 15 | ```bash 16 | $ cat ~/.ssh/id_rsa.pub 17 | ``` 18 | 19 | Go to `https://console.aws.amazon.com/iam/home?#/users/username?section=security_credentials`. 20 | 21 | Press `Upload SSH public key`. 22 | 23 | Paste contents in and press `Upload SSH public key`. 24 | 25 | ### AWS Config 26 | You should have the proper access keys in your `~/.aws/credentials` file. They should follow the below pattern. 27 | ```bash 28 | # ~/.aws/credentials 29 | [${name}] 30 | aws_access_key_id = 31 | aws_secret_access_key = 32 | 33 | [${name}-${workspace}] 34 | source_profile = ${name} 35 | role_arn = arn:aws:iam::${SUB_ACCOUNT_ID}:role/admin 36 | session_name = ${name}-${workspace} 37 | ``` 38 | 39 | ## SSH 40 | Keep your ssh configs clean, used `config.d`. 41 | **~/.ssh/config** 42 | ```bash 43 | Include config.d/* 44 | ``` 45 | 46 | **~/.ssh/config.d/example** 47 | ```bash 48 | ### Company Name (cn) ### 49 | 50 | # ssh -N cn-proxy-${environment} 51 | Host cn-proxy-${environment} 52 | HostName ${BASTION_IP} 53 | IdentityFile ~/.ssh/id_rsa 54 | User ${USERNAME} 55 | ControlPath /tmp/ssh_cn-proxy-${environment} 56 | LocalForward 3307 mysql-test.*****.us-east-1.rds.amazonaws.com:3306 57 | LocalForward 5432 postgres-test.*****.us-east-1.rds.amazonaws.com:5432 58 | LocalForward 6378 redis-test.*****.0001.use1.cache.amazonaws.com:6379 59 | # TODO elasticsearch example 60 | # TODO Private ALB example 61 | 62 | Host cn-bastion-${environment} 63 | HostName ${BASTION_IP} 64 | IdentityFile ~/.ssh/id_rsda 65 | User ${USERNAME} 66 | ControlPath /tmp/ssh_cn-bastion-${environment} 67 | 68 | Host cn-${environment}-* 69 | ProxyCommand ssh -W %h:%p cn-bastion-${environment} 70 | IdentityFile ~/.ssh/id_rsa 71 | User ${USERNAME} 72 | 73 | Host cn-${environment}-nat 74 | HostName ${PRIVATE_IP} 75 | ``` 76 | 77 | ## SSM 78 | Install the Session Manager Plugin for the AWS CLI - https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html 79 | 80 | To start new shell session from aws cli 81 | ```bash 82 | $ aws ssm start-session --target i-00000000000000000 --region ca-central-1 --profile ${name} 83 | ``` 84 | -------------------------------------------------------------------------------- /docs/Containers.md: -------------------------------------------------------------------------------- 1 | 2 | # ECS 3 | 4 | 5 | ## Fargate 6 | - fixed memory 7 | - tasks 8 | 9 | ## EC2 10 | - shared volumes 11 | - long running services 12 | 13 | ### EC2 w/ ALB 14 | - reachable by the public 15 | 16 | ### EC2 w/ NLB 17 | - tasks 18 | - reachable by the private resources 19 | 20 | ### EC2 21 | - tasks 22 | - long running services 23 | -------------------------------------------------------------------------------- /docs/Multi Account Setup.md: -------------------------------------------------------------------------------- 1 | # Multi Account Setup 2 | 3 | ## Manual Steps 4 | 1. Create Master Account * 5 | 1. Create Sub Accounts * 6 | 1. Setup Master Account * 7 | 1. Setup Login Account * 8 | 1. Setup Sub Accounts * 9 | 10 | \* See collection of re-usable steps below. 11 | 12 | ### Create Master Account 13 | See [How do I create and activate a new Amazon Web Services account?](https://aws.amazon.com/premiumsupport/knowledge-center/create-and-activate-aws-account/) 14 | 1. Go to [AWS](https://aws.amazon.com/). 15 | 1. Click `Create an AWS Account`, orange button in the top right corner. 16 | 1. Enter `Email` (aws+master@example.com), `Password`, `Confirm Password`, `AWS account name` (master) and press `Continue`. 17 | 1. Enter `Account type` (Professional), remaining fields and press `Create Account and Continue`. 18 | 1. Enter payment information and press `Secure Submit`. 19 | 1. Enter `Security Check` and press `Call me now`. 20 | 1. Enter 4-digit code into your phone after picking up and press `Continue`. 21 | 1. Press `Free`. 22 | 1. Setup MFA * 23 | 1. Press `Add` . 24 | 1. Services activation can take up to 24h. 25 | 26 | ### Setup Master Account 27 | 1. Create `terraform` User * 28 | 1. `terraform apply` `./master/state` 29 | 1. `terraform apply` `./master/account` 30 | 1. Delete `terraform` User from account 31 | 32 | ### Create Sub Accounts 33 | If `terraform` is unsuccessful. 34 | 1. Must request from support to up the limit for Organizations / Number of Accounts to 6+ from 2 35 | 1. Organizations -> `Create Organization` 36 | 1. You should of received an `AWS Organizations email verification request`, Click `Verify your email address` in the email 37 | 1. Press `Add Account` 38 | 1. `Create Account` -> Enter Name, email 39 | 40 | ### Setup Sub Accounts 41 | 1. Set Sub Account Root Password (See [Accessing and Administering the Member Accounts in Your Organization](https://docs.aws.amazon.com/organizations/latest/userguide/orgs_manage_accounts_access.html#orgs_manage_accounts_access-as-root)) 42 | 1. Create `terraform` User * 43 | 1. `terraform apply` `./environments/account` 44 | 1. Delete `terraform` User from account 45 | 1. Repeat for each sub account 46 | 47 | ### Create `terraform` User 48 | 1. Go to IAM. 49 | 1. Press `Add User`. 50 | 1. Enter `User name` as `terraform`, check `Programmatic access` and press `Next: Permissions`. 51 | 1. Press `Attach existing policies directly`, check `AdministratorAccess` and press `Next Review`. 52 | 1. Press `Create user`. 53 | 1. Copy `Access key ID` and `Secret access key` to `~/.aws/credentials` into `[main]` or `[main-account]`. 54 | 1. Press `Close`. 55 | 56 | 57 | ### Setup Login Account 58 | 1. Go to [AWS Console Login](https://console.aws.amazon.com/iam/home/) (https://${alias}.signin.aws.amazon.com/console) 59 | 1. Enter `Account ID or alias`, `IAM user name`, and `Passowrd` and press `Sign In`. 60 | 1. Enter `Old Password`, `New password`, `Retype new password` and press `Confirm password change`. 61 | 1. Got to [`IAM`](https://console.aws.amazon.com/iam/) if not already there. 62 | 1. Setup MFA * 63 | 1. Create Access Keys * 64 | 65 | ### Create Access Keys 66 | 1. Got to [`IAM`](https://console.aws.amazon.com/iam/home/) if not already there. 67 | 1. Click `Users` -> `${username}` -> `Security credentials` -> `Create access key` under `Access Keys`. 68 | 1. Copy into `~/.aws/credentials`. 69 | 70 | ```bash 71 | [main] 72 | aws_access_key_id = access_key_id 73 | aws_secret_access_key = secret_access_key 74 | ``` 75 | 76 | ### Setup MFA 77 | 1. Got to [`IAM`](https://console.aws.amazon.com/iam/home/) if not already there. 78 | 1. Click `Users` -> `${username}` -> `Security credentials` -> `Manage` beside `Assigned MFA device:`. 79 | 1. Choose `Virtual device` and press `Continue`. 80 | 1. Click `Show QR code` and scan QRCode into MFA device. 81 | 1. Enter `MFA code 1`, wait ~30sec, enter `MFA code 2` and press `Assign MFA`. 82 | 1. Press `Close`. 83 | 84 | ### Setup `Switch Role` in Console 85 | 1. From account drop down choose `Switch Role`. 86 | 1. Press `Switch Role`. 87 | 1. Enter `Account` (ID), `Role` (`OrganizationAccountAccessRole`,`admin`,`developer`), `Display Name` and press `Switch Role`. 88 | 89 | ### Setup `Assume Role` in CLI 90 | Update `~/.aws/credentials`: 91 | ```bash 92 | [main-environment] 93 | source_profile = main 94 | role_arn = arn:aws:iam::${account_id}:role/admin 95 | session_name = main-environment 96 | ``` 97 | 98 | ## Enabled Account level services 99 | 100 | ### Trusted Advisor 101 | 1. Go to [Trusted Advisor Dashboard](https://console.aws.amazon.com/trustedadvisor/home) 102 | 1. TODO https://aws.amazon.com/premiumsupport/trustedadvisor/ 103 | 104 | ### Macie 105 | 1. [Set Up](https://docs.aws.amazon.com/macie/latest/userguide/macie-setting-up.html#macie-setting-up-enable) 106 | 107 | -------------------------------------------------------------------------------- /docs/Patterns.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ## Environmental Variables 6 | 7 | AWS Secret Manager: 8 | - DB passwords 9 | - 3rd party account passwords 10 | AWS Systems Manager Parameter Store: 11 | - Environment configurations variables 12 | 13 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Infrastructure 2 | Visit [`willfarrell/terraform-aws-template`](https://github.com/willfarrell/terraform-aws-template) for the latest improvements and most up to date documentation. 3 | 4 | ## Accounts 5 | 6 | Name | Account ID | Colour | Root Email | 7 | ------------|--------------|--------|--------------------| 8 | master | | ------ | | 9 | production | | Red | | 10 | staging | | Orange | | 11 | testing | | Yellow | | 12 | development | | Green | | 13 | operations | | Blue | | 14 | forensics | | Purple | | 15 | 16 | ## Project Structure 17 | 18 | ```bash 19 | ${project}-infrastructure 20 | |-- package.json # Script shortcuts (lint, install, deploy, test) & versioning? 21 | |-- amis # Collection of AMIs, built by Packer 22 | | |-- {name} # AMI folders, ie bastion, ecs, nat or custom ones 23 | |-- master # Setup for root level account 24 | | |-- state # Sets up state management for terraform 25 | | |-- account # Account setup (Groups, Monitoring) 26 | | |-- operations # Setup for operation pieces 27 | |-- environments 28 | | |-- account # Account setup (Roles, Monitoring) 29 | | |-- domain # Domain specific VPC, App, API, ECS, etc. Rename folder to `name`. 30 | |-- modules # Collection of project specific modules 31 | ``` 32 | 33 | ## Getting Started 34 | For up to date documentation and modules see [terraform-aws-template](https://github.com/willfarrell/terraform-aws-template). 35 | 36 | ### Installing CLIs 37 | ```bash 38 | $ brew install terraform 39 | 40 | # Optional, for building AMIs 41 | $ brew install packer 42 | ``` 43 | 44 | - [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-macos.html) 45 | - [AWS SSM Plugin](https://docs.aws.amazon.com/systems-manager/latest/userguide/session-manager-working-with-install-plugin.html) 46 | - [AWS ECS CLI](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ECS_CLI_installation.html) 47 | 48 | ### Setup Terraform Workspaces 49 | To create the workspaces, go to the respective subfolder (`/environments/*/`), and run: 50 | 51 | ```bash 52 | $ terraform init 53 | $ terraform workspace new production 54 | $ terraform workspace new staging 55 | $ terraform workspace new testing 56 | $ terraform workspace new development 57 | ``` 58 | 59 | Ensure you have the right workspace selected before you `apply`. 60 | 61 | ```bash 62 | $ terraform workspace select development 63 | $ terraform workspace list 64 | ``` 65 | 66 | ### Setup Multi-Accounts 67 | See [docs](./docs/Multi Account Setup.md) for detailed steps. 68 | 69 | ### Build AMIs 70 | To create the AMIs, go to the respective subfolder (`/amis/*/`), edit the `variables.json`, and run: 71 | ```bash 72 | $ packer build -var-file=variables.json ami.json 73 | ``` 74 | 75 | See [docs](./docs/AMIs.md) for configuration and full documentation. 76 | 77 | ### Install node dependencies 78 | ```bash 79 | $ npm run install:npm 80 | ``` 81 | 82 | ## Switch Roles 83 | - `OrganizationAccountAccessRole`: Admin Access 84 | 85 | It is recommended that the `account/roles` module be forks to customized to specific needs 86 | 87 | ## Manual Steps 88 | - [Well-Architected Tool](https://aws.amazon.com/well-architected-tool/) 89 | - [Trust Advisor](https://aws.amazon.com/premiumsupport/technology/trusted-advisor/) 90 | - [Macie](https://docs.aws.amazon.com/macie/latest/userguide/macie-setting-up.html#macie-setting-up-enable) 91 | 92 | ## Deployment Steps 93 | 1. Build an AMIs that will be needed 94 | ```bash 95 | packer build -var-file=variables.json ami.json 96 | ``` 97 | 98 | 1. master/state 99 | 100 | 1. master/account 101 | - [ ] Users (Manual) 102 | - [ ] Macie (Manual) 103 | - [x] Sub-Accounts / Organization 104 | - [x] Groups for sub account access 105 | - [x] Roles for sub accounts (bastion, ECR) 106 | - [x] AMI permissions 107 | - [x] CloudTrail 108 | - [x] GuardDuty 109 | - [ ] Security Hub 110 | 111 | 1. Switch Roles into each sub-account using `OrganizationAccountAccessRole`. Create a `terraform` user to bootstrap assume roles. 112 | Be sure to delete the user after you bootstrap 113 | 114 | 1. Setup `terraform` workspaces 115 | Run the following in each `environments` folder 116 | ```bash 117 | terraform workspace new production 118 | terraform workspace new staging 119 | terraform workspace new testing 120 | terraform workspace new development 121 | terraform workspace select ${sub_account_name} 122 | ``` 123 | 124 | 1. environment/account 125 | - [x] Roles (admin, developer, operator, audit, etc) 126 | - [x] API Gateway Logs 127 | - [x] CloudTrail 128 | - [x] GuardDuty 129 | - [ ] Inspector Agent 130 | - [ ] Macie (Manual) 131 | 132 | 1. At this point you'll need to update your AWS credentials. 133 | Update `~/.aws/credentials`: 134 | ```bash 135 | [${profile}-${sub_account_name}] 136 | source_profile = ${profile} 137 | role_arn = arn:aws:iam::${sub_account_id}:role/admin 138 | session_name = ${profile}-${sub_account_name} 139 | ``` 140 | 141 | 1. environment/domain 142 | - [x] VPC 143 | - [x] VPC Endpoints (S3, DynamoDB) 144 | - [x] Bastion 145 | - [x] RDS (postgres,mysql) 146 | - [x] ElasticCache (redis) 147 | - [x] ElasticSearch 148 | - [x] DynamoDB 149 | - [x] ALB + ECS 150 | - [x] NLB + ECS 151 | - [x] ECS 152 | - [ ] API Gateway 153 | - [ ] Events, SQS, SNS, Lambda, S3, 154 | - [x] CloudFront 155 | - [x] S3 156 | - [ ] CloudWatch Dashboards 157 | 158 | ## Built With 159 | - [Terraform](https://www.terraform.io/) 160 | - [Packer](https://www.packer.io/) 161 | - [NodeJS](https://nodejs.org/en/) 162 | 163 | ### Modules 164 | - [state module](https://github.com/willfarrell/terraform-state-module) 165 | - [account modules](https://github.com/willfarrell/terraform-account-modules) 166 | - [logs module](https://github.com/willfarrell/terraform-logs-module) 167 | - [VPC module](https://github.com/willfarrell/terraform-vpc-module) 168 | - [DB modules](https://github.com/willfarrell/terraform-db-modules) 169 | - [EC modules](https://github.com/willfarrell/terraform-ec-modules) 170 | - [WAF module](https://github.com/willfarrell/terraform-waf-module) 171 | - [LB module](https://github.com/willfarrell/terraform-lb-module) 172 | - [IdP module](https://github.com/willfarrell/terraform-idp-module) - TODO 173 | - [CDN module](https://github.com/willfarrell/terraform-public-static-assets-module) 174 | 175 | ## Contributing 176 | See Developer Guide (TODO add link) 177 | 178 | ## Versioning 179 | We use [SemVer](http://semver.org/) for versioning. For the versions available, see the [tags on this repository](https://github.com/willfarrell/terraform-aws-template/tags). 180 | 181 | ## Authors 182 | - [will Farrell](https://github.com/willfarrell) 183 | 184 | See also the list of [contributors](https://github.com/willfarrell/terraform-aws-template/contributors) who participated in this project. 185 | 186 | ## License 187 | 188 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 189 | 190 | ## Acknowledgments 191 | 192 | -------------------------------------------------------------------------------- /docs/Standards.md: -------------------------------------------------------------------------------- 1 | # Standards 2 | 3 | ## User Interface 4 | - a11y: accessibility 5 | - ARIA: Accessible Rich Internet Applications 6 | - WAI: Web Accessibility Initiative 7 | - WCAG: Web Content Accessibility Guidelines 8 | - i18n: internationalization 9 | - l10n: localization 10 | 11 | ## Data Format 12 | - ISO 639-1: Language - ex. `en` for English `fr` for French 13 | - ISO 3166-1: Country - ex. `CA` for Canada 14 | - ISO 3166-2: Region - ex. `AB` for Alberta 15 | - RFC 3282: Content Language Headers - combines ISO 639-1 & 3166-1 to identify one preferred Locale - ex `en-CA` for Canadian English 16 | - RFC 3492: Punycode for Internationalized Domain Names - ex support of emojis in email addresses 17 | - ISO 19160: International Addressing (United Postal Union S42) 18 | - E.164: International Public Telecommunication Numbering Plan - ex `+18005554444` -------------------------------------------------------------------------------- /environments/account/config.tf: -------------------------------------------------------------------------------- 1 | # Edge Region 2 | 3 | module "edge-logs" { 4 | #source = "git@github.com:willfarrell/terraform-logs-module?ref=v0.5.2" 5 | source = "../../../../../github/terraform-logs-module" 6 | name = "${local.workspace["name"]}-${local.workspace["env"]}-edge" 7 | providers = { 8 | aws = aws.edge 9 | } 10 | tags = { 11 | Name = "Edge Logs" 12 | } 13 | } 14 | 15 | module "cloudtrail" { 16 | #source = "git@github.com:willfarrell/terraform-account-modules//cloudtrail?ref=v0.0.1" 17 | source = "../../../../../github/terraform-account-modules/cloudtrail" 18 | name = local.workspace["name"] 19 | logging_bucket = module.edge-logs.id 20 | providers = { 21 | aws = aws.edge 22 | } 23 | } 24 | 25 | module "apigateway-logs" { 26 | #source = "git@github.com:willfarrell/terraform-account-modules//api-gateway?ref=v0.0.1" 27 | source = "../../../../../github/terraform-sub-account-modules/api-gateway" 28 | providers = { 29 | aws = aws.edge 30 | } 31 | } 32 | 33 | module "route53-logs" { 34 | #source = "git@github.com:willfarrell/terraform-account-modules//route53?ref=v0.0.1" 35 | source = "../../../../../github/terraform-sub-account-modules/route53" 36 | } 37 | 38 | module "elasticsearch-logs" { 39 | #source = "git@github.com:willfarrell/terraform-account-modules//route53?ref=v0.0.1" 40 | source = "../../../../../github/terraform-sub-account-modules/elasticsearch" 41 | } 42 | 43 | 44 | 45 | # Primary Region 46 | 47 | module "region-logs" { 48 | #source = "git@github.com:willfarrell/terraform-logs-module?ref=v0.5.2" 49 | source = "../../../../../github/terraform-logs-module" 50 | name = "${local.workspace["name"]}-${local.workspace["env"]}-${local.workspace["region"]}" 51 | tags = { 52 | Name = "${local.workspace["region"]} Logs" 53 | } 54 | } 55 | 56 | 57 | -------------------------------------------------------------------------------- /environments/account/iam.tf: -------------------------------------------------------------------------------- 1 | module "roles" { 2 | source = "git@github.com:willfarrell/terraform-account-modules//roles?ref=v0.0.1" 3 | type = "member" 4 | master_account_id = data.terraform_remote_state.master.outputs.account_id 5 | providers = { 6 | aws = aws.edge 7 | } 8 | } 9 | 10 | output "role_arns" { 11 | value = module.roles.arns 12 | } 13 | -------------------------------------------------------------------------------- /environments/account/locals.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | env = { 3 | default = { 4 | env = terraform.workspace 5 | name = "{**NAME**}" 6 | profile = "{**PROFILE**}" 7 | region = "us-west-2" 8 | } 9 | 10 | production = {} 11 | 12 | staging = {} 13 | 14 | testing = {} 15 | 16 | development = {} 17 | } 18 | 19 | workspace = merge(local.env["default"], local.env[terraform.workspace]) 20 | } 21 | 22 | output "workspace" { 23 | value = terraform.workspace 24 | } 25 | -------------------------------------------------------------------------------- /environments/account/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | backend "s3" { 3 | bucket = "terraform-state-{**NAME**}" 4 | key = "account/terraform.tfstate" 5 | region = "us-east-1" 6 | profile = "{**PROFILE**}" 7 | dynamodb_table = "terraform-state-{**NAME**}" 8 | encrypt = true 9 | } 10 | } 11 | 12 | # On first run have terraform user creds attached to profile 13 | # change credentials for assume role for future runs 14 | provider "aws" { 15 | profile = "${local.workspace["profile"]}-${local.workspace["env"]}" 16 | region = local.workspace["region"] 17 | } 18 | 19 | provider "aws" { 20 | profile = "${local.workspace["profile"]}-${local.workspace["env"]}" 21 | region = "us-east-1" 22 | alias = "edge" 23 | } 24 | 25 | data "terraform_remote_state" "master" { 26 | backend = "s3" 27 | 28 | config = { 29 | bucket = "terraform-state-${local.workspace["name"]}" 30 | key = "master/account/terraform.tfstate" 31 | region = "us-east-1" 32 | profile = local.workspace["profile"] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /environments/account/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | -------------------------------------------------------------------------------- /environments/domain/cloudfront-lambda-viewer-response.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const headers = { 4 | 'any': { 5 | 'Server': '', 6 | 'X-Content-Type-Options': 'nosniff', 7 | 'Referrer-Policy': 'no-referrer', 8 | 'Strict-Transport-Security': 'max-age=31536000; includeSubdomains; preload' 9 | //"Expect-CT":"" 10 | }, 11 | 'html': { 12 | // Content-Security-Policy-Report-Only: https://${username}.report-uri.com/r/d/csp/reportOnly 13 | // Content-Security-Policy: https://${username}.report-uri.com/r/d/csp/enforce 14 | 'Content-Security-Policy-Report-Only': 'default-src \'none\';' + 15 | ' img-src \'none\';' + 16 | ' script-src \'none\';' + 17 | ' style-src \'none\';' + 18 | ' connect-src \'none\';' + 19 | ' base-uri \'none\';' + 20 | ' frame-ancestors \'none\';' + 21 | ' block-all-mixed-content;' + 22 | ' upgrade-insecure-requests;' + 23 | ' report-uri https://*******.report-uri.com/r/d/csp/reportOnly', 24 | // https://github.com/WICG/feature-policy/blob/master/features.md 25 | 'Feature-Policy': '' + 26 | 'camera \'none\'' + 27 | ' fullscreen \'self\'' + 28 | ' gyroscope \'none\'' + 29 | ' geolocation \'none\'' + 30 | ' magnetometer \'none\'' + 31 | ' microphone \'none\'' + 32 | ' midi \'none\'' + 33 | ' payment \'none\'' + 34 | ' speaker \'none\'' + 35 | ' sync-xhr \'self\'', 36 | 'X-Frame-Options': 'DENY', 37 | 'X-XSS-Protection': '1; mode=block', 38 | 'X-UA-Compatible': 'ie=edge' 39 | } 40 | } 41 | 42 | // Reformat headers object for CF 43 | function makeHeaders (headers) { 44 | const formattedHeaders = {} 45 | Object.keys(headers).forEach((key) => { 46 | formattedHeaders[key.toLowerCase()] = [{ 47 | key: key, 48 | value: headers[key] 49 | }] 50 | }) 51 | return formattedHeaders 52 | } 53 | 54 | function getHeaders (mime) { 55 | return makeHeaders(headers[mime]) 56 | } 57 | 58 | function handler (event, context, callback) { 59 | const request = event.Records[0].cf.request 60 | const response = event.Records[0].cf.response 61 | 62 | //console.log(JSON.stringify(request),JSON.stringify(response)) 63 | 64 | let responseHeaders = getHeaders('any') 65 | 66 | // Catch 304 w/o Content-Type from S3 67 | if (!response.headers['content-type'] && request.uri === '/') { 68 | response.headers['content-type'] = [{ 69 | key: 'Content-Type', 70 | value: 'text/html; charset=utf-8' 71 | }] 72 | } 73 | 74 | if (response.headers['content-type'] && response.headers['content-type'][0].value.indexOf('text/html') !== -1) { 75 | Object.assign(responseHeaders, getHeaders('html')) 76 | } 77 | 78 | Object.assign(response.headers, responseHeaders) 79 | 80 | return callback(null, response) 81 | } 82 | 83 | module.exports = { 84 | makeHeaders, 85 | headers, 86 | handler 87 | } 88 | -------------------------------------------------------------------------------- /environments/domain/cloudfront.tf: -------------------------------------------------------------------------------- 1 | data "aws_acm_certificate" "main" { 2 | provider = "aws.edge" 3 | domain = local.workspace["app_domain"] 4 | 5 | statuses = [ 6 | "ISSUED", 7 | ] 8 | 9 | providers = { 10 | aws = "aws.edge" 11 | } 12 | } 13 | 14 | module "app" { 15 | source = "git@github.com:willfarrell/terraform-public-static-assets-module?ref=v0.2.1" 16 | name = local.workspace["name"] 17 | 18 | aliases = [ 19 | local.workspace["app_domain"], 20 | ] 21 | 22 | acm_certificate_arn = data.aws_acm_certificate.main.arn 23 | web_acl_id = module.waf.id 24 | lambda = { 25 | "viewer-response" = file("${path.module}/cloudfront-lambda-viewer-response.js") 26 | } 27 | logging_bucket = "${local.workspace["name"]}-${local.workspace["env"]}-edge-logs" 28 | providers = { 29 | aws = "aws.edge" 30 | } 31 | } 32 | 33 | module "waf" { 34 | source = "git@github.com:willfarrell/terraform-waf-module?ref=v0.0.1" 35 | type = "edge" 36 | name = local.workspace["name"] 37 | defaultAction = "ALLOW" 38 | logging_bucket = "${local.workspace["name"]}-${local.workspace["env"]}-edge-logs" 39 | providers = { 40 | aws = "aws.edge" 41 | } 42 | } 43 | 44 | output "waf_bad-bot_ipset_id" { 45 | value = module.waf.ipset_bad-bot_id 46 | } 47 | -------------------------------------------------------------------------------- /environments/domain/dynamodb.tf: -------------------------------------------------------------------------------- 1 | # VPC 2 | resource "aws_vpc_endpoint" "dynamodb" { 3 | vpc_id = module.vpc.id 4 | service_name = "com.amazonaws.${local.workspace["region"]}.dynamodb" 5 | route_table_ids = module.vpc.private_route_table_ids 6 | 7 | policy = <