├── .gitignore
├── LICENSE
├── README.md
├── packer
├── aws
│ ├── ubuntu
│ │ ├── base.json
│ │ ├── consul.json
│ │ ├── haproxy.json
│ │ ├── nodejs.json
│ │ └── vault.json
│ └── windows
│ │ ├── base.json
│ │ └── web.json
├── config
│ ├── consul
│ │ ├── consul_client.json
│ │ ├── consul_server.json
│ │ ├── haproxy.json
│ │ ├── nodejs.json
│ │ └── vault.json
│ ├── consul_template
│ │ ├── base.hcl
│ │ ├── haproxy.hcl
│ │ ├── nodejs.hcl
│ │ ├── nodejs_aws.hcl
│ │ └── templates
│ │ │ ├── haproxy.ctmpl
│ │ │ ├── vault_aws.ctmpl
│ │ │ └── vault_generic.ctmpl
│ ├── envconsul
│ │ ├── base.hcl
│ │ └── nodejs.hcl
│ └── vault
│ │ ├── policies
│ │ ├── aws_nodejs.json
│ │ ├── nodejs.hcl
│ │ └── nodejs.json
│ │ ├── scripts
│ │ ├── setup_aws.sh
│ │ ├── setup_transit.sh
│ │ ├── setup_vault.sh
│ │ ├── write_policy.sh
│ │ └── write_role.sh
│ │ └── vault.hcl
├── google
│ └── ubuntu
│ │ ├── base.json
│ │ ├── consul.json
│ │ ├── haproxy.json
│ │ ├── nodejs.json
│ │ └── vault.json
└── scripts
│ ├── ubuntu
│ ├── cleanup.sh
│ ├── consul.sh
│ ├── consul_template.sh
│ ├── dependencies.sh
│ ├── dnsmasq.sh
│ ├── envconsul.sh
│ ├── haproxy.sh
│ ├── nodejs.sh
│ ├── nodejs_app
│ │ ├── compile.json
│ │ ├── package.json
│ │ └── server.js
│ ├── upstart
│ │ ├── consul.conf
│ │ ├── consul_template.conf
│ │ ├── haproxy.conf
│ │ ├── nodejs.conf
│ │ └── vault.conf
│ └── vault.sh
│ └── windows
│ ├── config
│ └── ec2_user_data.conf
│ ├── consul_client.json
│ ├── install_consul.ps1
│ ├── install_web_server.ps1
│ ├── install_windows_updates.ps1
│ └── set_ec2_config.ps1
├── setup
├── gen_cert.sh
├── gen_key.sh
└── openssl.cnf
└── terraform
├── empty.tf
├── modules
├── aws
│ ├── compute
│ │ ├── compute.tf
│ │ ├── haproxy
│ │ │ ├── haproxy.sh.tpl
│ │ │ └── haproxy.tf
│ │ └── nodejs
│ │ │ ├── nodejs.sh.tpl
│ │ │ └── nodejs.tf
│ ├── data
│ │ ├── consul
│ │ │ ├── consul.sh.tpl
│ │ │ └── consul.tf
│ │ ├── data.tf
│ │ └── vault
│ │ │ ├── vault.sh.tpl
│ │ │ └── vault.tf
│ ├── network
│ │ ├── bastion
│ │ │ └── bastion.tf
│ │ ├── nat
│ │ │ └── nat.tf
│ │ ├── network.tf
│ │ ├── openvpn
│ │ │ └── openvpn.tf
│ │ ├── private_subnet
│ │ │ └── private_subnet.tf
│ │ ├── public_subnet
│ │ │ └── public_subnet.tf
│ │ └── vpc
│ │ │ └── vpc.tf
│ └── util
│ │ ├── artifact
│ │ └── artifact.tf
│ │ ├── deploy
│ │ └── deploy.tf
│ │ ├── iam
│ │ └── iam.tf
│ │ └── website
│ │ └── website.tf
└── google
│ ├── compute
│ ├── compute.tf
│ ├── haproxy
│ │ ├── haproxy.sh.tpl
│ │ └── haproxy.tf
│ └── nodejs
│ │ ├── nodejs.sh.tpl
│ │ └── nodejs.tf
│ ├── data
│ ├── consul
│ │ ├── consul.sh.tpl
│ │ └── consul.tf
│ ├── data.tf
│ └── vault
│ │ ├── vault.sh.tpl
│ │ └── vault.tf
│ └── network
│ ├── bastion
│ └── bastion.tf
│ ├── network.tf
│ ├── private_subnet
│ └── private_subnet.tf
│ └── public_subnet
│ └── public_subnet.tf
└── providers
├── aws
├── README.md
├── global
│ ├── global.tf
│ └── terraform.tfvars
├── us_east_1_prod
│ ├── terraform.tfvars
│ └── us_east_1_prod.tf
└── us_east_1_staging
│ ├── terraform.tfvars
│ └── us_east_1_staging.tf
└── google
├── README.md
└── us_central1_prod
├── terraform.tfvars
└── us_central1_prod.tf
/.gitignore:
--------------------------------------------------------------------------------
1 | account.json
2 | .terraform
3 | *tfstate*
4 | setup/*
5 | crash.log
6 | dist
7 | *.zip
8 | logs
9 | *.srl
10 | *.crt
11 | *.csr
12 | *.key
13 | *.pub
14 | *.pem
15 | *.swp
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deprecated
2 |
3 | This repository is deprecated. Please checkout the official [Terraform Module Registry](https://registry.terraform.io) instead.
4 |
5 | ## Best Practices Ops
6 |
7 | Below are the infrastructures we currently have best practices for. Navigate to each provider to see what will be provisioned.
8 |
9 | - [AWS](terraform/providers/aws/README.md)
10 | - [Google](terraform/providers/google/README.md)
11 |
12 | ### Getting Started
13 |
14 | This repository contains best-practice infrastructures across different cloud providers, regions, environments, and operating systems.
15 |
16 | You can think of this as a library of Packer templates and Terraform modules that allow you to provision unique infrastructures by referencing the different templates and modules. We've tried to set this repository up in a way that we don't have to duplicate code, allowing templates and modules to be used across multiple environments.
17 |
18 | Each environment is a best practices guide for how to use HashiCorp tooling to provision that specific type of infrastructure. Use each as a reference when building your own infrastructure. The best way to get started is to pick an environment that resembles an infrastructure you are looking to build, get it up and running, then configure and modify it to meet your specific needs.
19 |
20 | No example will be exactly what you need, but it should provide you with enough examples to get you headed in the right direction.
21 |
22 | A couple things to keep in mind...
23 |
24 | - Each environment's README will reference different sections in [General Setup](https://github.com/hashicorp/atlas-examples/blob/master/setup/general.md) to get your environment properly setup to build the infrastructure at hand.
25 | - Each environment will assume you're using Atlas. If you plan on doing anything locally, there are portions of environments that may not work due to the extra features Atlas provides that we are taking advantage of.
26 | - Each environment's instructional documentation is based off of the assumption that certain information will be saved as environment variables. If you do not wish to use environment variables, there are different ways to pass this information, but you may have to take extra undocumented steps to get commands to work properly.
27 | - Any `packer push` commands must be performed in the base [packer/.](packer) directory.
28 | - Any `terraform push` commands must be performed in the appropriate Terraform environment directory (e.g. [terraform/providers/aws/us\_east\_1\_staging](terraform/providers/aws/us_east_1_staging)).
29 |
--------------------------------------------------------------------------------
/packer/aws/ubuntu/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
5 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
6 | "us_east_1_ami": "ami-9a562df2",
7 | "name": "aws-ubuntu-base",
8 | "us_east_1_name": "aws-us-east-1-ubuntu-base",
9 | "ssh_username": "ubuntu",
10 | "scripts_dir": "scripts/ubuntu",
11 | "config_dir": "config",
12 | "dns_listen_addr": "127.0.0.1"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../.",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/upstart/*",
20 | "{{user `config_dir`}}/*",
21 | "{{user `config_dir`}}/consul/*",
22 | "{{user `config_dir`}}/consul_template/*",
23 | "{{user `config_dir`}}/consul_template/templates/*",
24 | "{{user `config_dir`}}/envconsul/*",
25 | "{{user `config_dir`}}/vault/*",
26 | "{{user `config_dir`}}/vault/policies/*"
27 | ],
28 | "vcs": false
29 | },
30 | "builders": [
31 | {
32 | "name": "aws-us-east-1-ubuntu-base",
33 | "type": "amazon-ebs",
34 | "access_key": "{{user `aws_access_key`}}",
35 | "secret_key": "{{user `aws_secret_key`}}",
36 | "region": "us-east-1",
37 | "vpc_id": "",
38 | "subnet_id": "",
39 | "source_ami": "{{user `us_east_1_ami`}}",
40 | "instance_type": "c3.large",
41 | "ssh_username": "{{user `ssh_username`}}",
42 | "ssh_timeout": "10m",
43 | "ami_name": "{{user `us_east_1_name`}} {{timestamp}}",
44 | "ami_description": "{{user `us_east_1_name`}} AMI",
45 | "run_tags": { "ami-create": "{{user `us_east_1_name`}}" },
46 | "tags": { "ami": "{{user `us_east_1_name`}}" },
47 | "ssh_private_ip": false,
48 | "associate_public_ip_address": true
49 | }
50 | ],
51 | "provisioners": [
52 | {
53 | "type": "shell",
54 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
55 | "inline": [
56 | "mkdir -p /ops/{{user `scripts_dir`}}",
57 | "chmod a+w /ops/{{user `scripts_dir`}}",
58 | "mkdir -p /ops/{{user `config_dir`}}",
59 | "chmod a+w /ops/{{user `config_dir`}}"
60 | ]
61 | },
62 | {
63 | "type": "file",
64 | "source": "{{user `scripts_dir`}}/.",
65 | "destination": "/ops/{{user `scripts_dir`}}"
66 | },
67 | {
68 | "type": "file",
69 | "source": "{{user `config_dir`}}/.",
70 | "destination": "/ops/{{user `config_dir`}}"
71 | },
72 | {
73 | "type": "shell",
74 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
75 | "inline": [
76 | "sh /ops/{{user `scripts_dir`}}/dependencies.sh",
77 | "sh /ops/{{user `scripts_dir`}}/consul.sh {{user `config_dir`}} {{user `scripts_dir`}}",
78 | "sh /ops/{{user `scripts_dir`}}/consul_template.sh {{user `config_dir`}} {{user `scripts_dir`}}",
79 | "sh /ops/{{user `scripts_dir`}}/envconsul.sh {{user `config_dir`}}",
80 | "sh /ops/{{user `scripts_dir`}}/dnsmasq.sh {{user `dns_listen_addr`}}",
81 | "sh /ops/{{user `scripts_dir`}}/cleanup.sh"
82 | ]
83 | }
84 | ],
85 | "post-processors": [
86 | {
87 | "type": "atlas",
88 | "only": ["aws-us-east-1-ubuntu-base"],
89 | "artifact": "{{user `atlas_username`}}/{{user `us_east_1_name`}}",
90 | "artifact_type": "amazon.image",
91 | "metadata": {
92 | "created_at": "{{timestamp}}"
93 | }
94 | }
95 | ]
96 | }
97 |
--------------------------------------------------------------------------------
/packer/aws/ubuntu/consul.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
5 | "aws_region": "{{env `AWS_DEFAULT_REGION`}}",
6 | "base_ami": "{{env `ATLAS_BASE_ARTIFACT_AMAZON_IMAGE_ID`}}",
7 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
8 | "name": "aws-{{env `AWS_DEFAULT_REGION`}}-ubuntu-consul",
9 | "ssh_username": "ubuntu",
10 | "scripts_dir": "scripts/ubuntu",
11 | "config_dir": "config",
12 | "dns_listen_addr": "0.0.0.0"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../.",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `config_dir`}}/*",
20 | "{{user `config_dir`}}/consul/*"
21 | ],
22 | "vcs": false
23 | },
24 | "builders": [
25 | {
26 | "type": "amazon-ebs",
27 | "access_key": "{{user `aws_access_key`}}",
28 | "secret_key": "{{user `aws_secret_key`}}",
29 | "region": "{{user `aws_region`}}",
30 | "vpc_id": "",
31 | "subnet_id": "",
32 | "source_ami": "{{user `base_ami`}}",
33 | "instance_type": "c3.large",
34 | "ssh_username": "{{user `ssh_username`}}",
35 | "ssh_timeout": "10m",
36 | "ami_name": "{{user `name`}} {{timestamp}}",
37 | "ami_description": "{{user `name`}} AMI",
38 | "run_tags": { "ami-create": "{{user `name`}}" },
39 | "tags": { "ami": "{{user `name`}}" },
40 | "ssh_private_ip": false,
41 | "associate_public_ip_address": true
42 | }
43 | ],
44 | "provisioners": [
45 | {
46 | "type": "shell",
47 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
48 | "inline": [
49 | "mkdir -p /ops/{{user `scripts_dir`}}",
50 | "chmod a+w /ops/{{user `scripts_dir`}}",
51 | "mkdir -p /ops/{{user `config_dir`}}",
52 | "chmod a+w /ops/{{user `config_dir`}}"
53 | ]
54 | },
55 | {
56 | "type": "file",
57 | "source": "{{user `scripts_dir`}}/.",
58 | "destination": "/ops/{{user `scripts_dir`}}"
59 | },
60 | {
61 | "type": "file",
62 | "source": "{{user `config_dir`}}/.",
63 | "destination": "/ops/{{user `config_dir`}}"
64 | },
65 | {
66 | "type": "shell",
67 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
68 | "inline": [
69 | "cp /ops/{{user `config_dir`}}/consul/consul_server.json /etc/consul.d/base.json",
70 | "sh /ops/{{user `scripts_dir`}}/dnsmasq.sh {{user `dns_listen_addr`}}",
71 | "sh /ops/{{user `scripts_dir`}}/cleanup.sh"
72 | ]
73 | }
74 | ],
75 | "post-processors": [
76 | {
77 | "type": "atlas",
78 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
79 | "artifact_type": "amazon.image",
80 | "metadata": {
81 | "created_at": "{{timestamp}}"
82 | }
83 | }
84 | ]
85 | }
86 |
--------------------------------------------------------------------------------
/packer/aws/ubuntu/haproxy.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
5 | "aws_region": "{{env `AWS_DEFAULT_REGION`}}",
6 | "base_ami": "{{env `ATLAS_BASE_ARTIFACT_AMAZON_IMAGE_ID`}}",
7 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
8 | "name": "aws-{{env `AWS_DEFAULT_REGION`}}-ubuntu-haproxy",
9 | "ssh_username": "ubuntu",
10 | "scripts_dir": "scripts/ubuntu",
11 | "config_dir": "config"
12 | },
13 | "push": {
14 | "name": "{{user `atlas_username`}}/{{user `name`}}",
15 | "base_dir": "../../.",
16 | "include": [
17 | "{{user `scripts_dir`}}/*",
18 | "{{user `scripts_dir`}}/upstart/*",
19 | "{{user `config_dir`}}/*",
20 | "{{user `config_dir`}}/consul/*",
21 | "{{user `config_dir`}}/consul_template/*",
22 | "{{user `config_dir`}}/consul_template/templates/*"
23 | ],
24 | "vcs": false
25 | },
26 | "builders": [
27 | {
28 | "type": "amazon-ebs",
29 | "access_key": "{{user `aws_access_key`}}",
30 | "secret_key": "{{user `aws_secret_key`}}",
31 | "region": "{{user `aws_region`}}",
32 | "vpc_id": "",
33 | "subnet_id": "",
34 | "source_ami": "{{user `base_ami`}}",
35 | "instance_type": "c3.large",
36 | "ssh_username": "{{user `ssh_username`}}",
37 | "ssh_timeout": "10m",
38 | "ami_name": "{{user `name`}} {{timestamp}}",
39 | "ami_description": "{{user `name`}} AMI",
40 | "run_tags": { "ami-create": "{{user `name`}}" },
41 | "tags": { "ami": "{{user `name`}}" },
42 | "ssh_private_ip": false,
43 | "associate_public_ip_address": true
44 | }
45 | ],
46 | "provisioners": [
47 | {
48 | "type": "shell",
49 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
50 | "inline": [
51 | "mkdir -p /ops/{{user `scripts_dir`}}",
52 | "chmod a+w /ops/{{user `scripts_dir`}}",
53 | "mkdir -p /ops/{{user `config_dir`}}",
54 | "chmod a+w /ops/{{user `config_dir`}}"
55 | ]
56 | },
57 | {
58 | "type": "file",
59 | "source": "{{user `scripts_dir`}}/.",
60 | "destination": "/ops/{{user `scripts_dir`}}"
61 | },
62 | {
63 | "type": "file",
64 | "source": "{{user `config_dir`}}/.",
65 | "destination": "/ops/{{user `config_dir`}}"
66 | },
67 | {
68 | "type": "shell",
69 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
70 | "inline": [
71 | "sh /ops/{{user `scripts_dir`}}/haproxy.sh {{user `config_dir`}} {{user `scripts_dir`}}",
72 | "sh /ops/{{user `scripts_dir`}}/cleanup.sh"
73 | ]
74 | }
75 | ],
76 | "post-processors": [
77 | {
78 | "type": "atlas",
79 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
80 | "artifact_type": "amazon.image",
81 | "metadata": {
82 | "created_at": "{{timestamp}}"
83 | }
84 | }
85 | ]
86 | }
87 |
--------------------------------------------------------------------------------
/packer/aws/ubuntu/nodejs.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
5 | "aws_region": "{{env `AWS_DEFAULT_REGION`}}",
6 | "base_ami": "{{env `ATLAS_BASE_ARTIFACT_AMAZON_IMAGE_ID`}}",
7 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
8 | "name": "aws-{{env `AWS_DEFAULT_REGION`}}-ubuntu-nodejs",
9 | "ssh_username": "ubuntu",
10 | "scripts_dir": "scripts/ubuntu",
11 | "config_dir": "config",
12 | "host_app_dir": "/application"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../.",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/upstart/*",
20 | "{{user `scripts_dir`}}/nodejs_app/*",
21 | "{{user `config_dir`}}/*",
22 | "{{user `config_dir`}}/consul/*",
23 | "{{user `config_dir`}}/consul_template/*",
24 | "{{user `config_dir`}}/consul_template/templates/*",
25 | "{{user `config_dir`}}/envconsul/*",
26 | "{{user `config_dir`}}/vault/*",
27 | "{{user `config_dir`}}/vault/policies/*"
28 | ],
29 | "vcs": false
30 | },
31 | "builders": [
32 | {
33 | "type": "amazon-ebs",
34 | "access_key": "{{user `aws_access_key`}}",
35 | "secret_key": "{{user `aws_secret_key`}}",
36 | "region": "{{user `aws_region`}}",
37 | "vpc_id": "",
38 | "subnet_id": "",
39 | "source_ami": "{{user `base_ami`}}",
40 | "instance_type": "c3.large",
41 | "ssh_username": "{{user `ssh_username`}}",
42 | "ssh_timeout": "10m",
43 | "ami_name": "{{user `name`}} {{timestamp}}",
44 | "ami_description": "{{user `name`}} AMI",
45 | "run_tags": { "ami-create": "{{user `name`}}" },
46 | "tags": { "ami": "{{user `name`}}" },
47 | "ssh_private_ip": false,
48 | "associate_public_ip_address": true
49 | }
50 | ],
51 | "provisioners": [
52 | {
53 | "type": "shell",
54 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
55 | "inline": [
56 | "mkdir -p /ops/{{user `scripts_dir`}}",
57 | "chmod a+w /ops/{{user `scripts_dir`}}",
58 | "mkdir -p /ops/{{user `config_dir`}}",
59 | "chmod a+w /ops/{{user `config_dir`}}"
60 | ]
61 | },
62 | {
63 | "type": "file",
64 | "source": "{{user `scripts_dir`}}/.",
65 | "destination": "/ops/{{user `scripts_dir`}}"
66 | },
67 | {
68 | "type": "file",
69 | "source": "{{user `config_dir`}}/.",
70 | "destination": "/ops/{{user `config_dir`}}"
71 | },
72 | {
73 | "type": "shell",
74 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
75 | "inline": [
76 | "mkdir -p {{user `host_app_dir`}}",
77 | "chmod a+w {{user `host_app_dir`}}"
78 | ]
79 | },
80 | {
81 | "type": "file",
82 | "source": "{{user `scripts_dir`}}/nodejs_app/",
83 | "destination": "{{user `host_app_dir`}}"
84 | },
85 | {
86 | "type": "shell",
87 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
88 | "inline": [
89 | "sh /ops/{{user `scripts_dir`}}/nodejs.sh {{user `config_dir`}} {{user `scripts_dir`}}",
90 | "sh /ops/{{user `scripts_dir`}}/cleanup.sh"
91 | ]
92 | }
93 | ],
94 | "post-processors": [
95 | {
96 | "type": "atlas",
97 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
98 | "artifact_type": "amazon.image",
99 | "metadata": {
100 | "created_at": "{{timestamp}}"
101 | }
102 | }
103 | ]
104 | }
105 |
--------------------------------------------------------------------------------
/packer/aws/ubuntu/vault.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY_ID`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_ACCESS_KEY`}}",
5 | "aws_region": "{{env `AWS_DEFAULT_REGION`}}",
6 | "base_ami": "{{env `ATLAS_BASE_ARTIFACT_AMAZON_IMAGE_ID`}}",
7 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
8 | "name": "aws-{{env `AWS_DEFAULT_REGION`}}-ubuntu-vault",
9 | "ssh_username": "ubuntu",
10 | "scripts_dir": "scripts/ubuntu",
11 | "config_dir": "config"
12 | },
13 | "push": {
14 | "name": "{{user `atlas_username`}}/{{user `name`}}",
15 | "base_dir": "../../.",
16 | "include": [
17 | "{{user `scripts_dir`}}/*",
18 | "{{user `scripts_dir`}}/upstart/*",
19 | "{{user `config_dir`}}/*",
20 | "{{user `config_dir`}}/consul/*",
21 | "{{user `config_dir`}}/vault/*",
22 | "{{user `config_dir`}}/vault/policies/*",
23 | "{{user `config_dir`}}/vault/scripts/*"
24 | ],
25 | "vcs": false
26 | },
27 | "builders": [
28 | {
29 | "type": "amazon-ebs",
30 | "access_key": "{{user `aws_access_key`}}",
31 | "secret_key": "{{user `aws_secret_key`}}",
32 | "region": "{{user `aws_region`}}",
33 | "vpc_id": "",
34 | "subnet_id": "",
35 | "source_ami": "{{user `base_ami`}}",
36 | "instance_type": "c3.large",
37 | "ssh_username": "{{user `ssh_username`}}",
38 | "ssh_timeout": "10m",
39 | "ami_name": "{{user `name`}} {{timestamp}}",
40 | "ami_description": "{{user `name`}} AMI",
41 | "run_tags": { "ami-create": "{{user `name`}}" },
42 | "tags": { "ami": "{{user `name`}}" },
43 | "ssh_private_ip": false,
44 | "associate_public_ip_address": true
45 | }
46 | ],
47 | "provisioners": [
48 | {
49 | "type": "shell",
50 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
51 | "inline": [
52 | "mkdir -p /ops/{{user `scripts_dir`}}",
53 | "chmod a+w /ops/{{user `scripts_dir`}}",
54 | "mkdir -p /ops/{{user `config_dir`}}",
55 | "chmod a+w /ops/{{user `config_dir`}}"
56 | ]
57 | },
58 | {
59 | "type": "file",
60 | "source": "{{user `scripts_dir`}}/.",
61 | "destination": "/ops/{{user `scripts_dir`}}"
62 | },
63 | {
64 | "type": "file",
65 | "source": "{{user `config_dir`}}/.",
66 | "destination": "/ops/{{user `config_dir`}}"
67 | },
68 | {
69 | "type": "shell",
70 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
71 | "inline": [
72 | "sh /ops/{{user `scripts_dir`}}/vault.sh {{user `config_dir`}} {{user `scripts_dir`}}",
73 | "sh /ops/{{user `scripts_dir`}}/cleanup.sh"
74 | ]
75 | }
76 | ],
77 | "post-processors": [
78 | {
79 | "type": "atlas",
80 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
81 | "artifact_type": "amazon.image",
82 | "metadata": {
83 | "created_at": "{{timestamp}}"
84 | }
85 | }
86 | ]
87 | }
88 |
--------------------------------------------------------------------------------
/packer/aws/windows/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_KEY`}}",
5 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
6 | "name": "aws-windows-base",
7 | "region": "us-east-1",
8 | "vpc_id": "",
9 | "subnet_id": "",
10 | "source_ami": "ami-cd9339a6",
11 | "instance_type": "t2.micro",
12 | "winrm_username": "Administrator",
13 | "user_data_file": "packer/scripts/windows/config/ec2_user_data.conf",
14 | "scripts_dir": "packer/scripts/windows",
15 | "consul_config_dir": "C:\\etc\\consul.d"
16 | },
17 | "push": {
18 | "name": "{{user `atlas_username`}}/{{user `name`}}",
19 | "base_dir": "../../../.",
20 | "include": [
21 | "{{user `user_data_file`}}",
22 | "{{user `scripts_dir`}}/*"
23 | ],
24 | "vcs": false
25 | },
26 | "builders": [
27 | {
28 | "type": "amazon-ebs",
29 | "access_key": "{{user `aws_access_key`}}",
30 | "secret_key": "{{user `aws_secret_key`}}",
31 | "region": "{{user `region`}}",
32 | "vpc_id": "{{user `vpc_id`}}",
33 | "subnet_id": "{{user `subnet_id`}}",
34 | "source_ami": "{{user `source_ami`}}",
35 | "instance_type": "{{user `instance_type`}}",
36 | "communicator": "winrm",
37 | "winrm_username": "{{user `winrm_username`}}",
38 | "winrm_timeout": "60m",
39 | "user_data_file": "{{user `user_data_file`}}",
40 | "ami_name": "{{user `name`}} {{timestamp}}",
41 | "ami_description": "{{user `name`}} AMI",
42 | "run_tags": { "ami-create": "{{user `name`}}" },
43 | "tags": { "ami": "{{user `name`}}" },
44 | "associate_public_ip_address": true
45 | }
46 | ],
47 | "provisioners": [
48 | {
49 | "type": "powershell",
50 | "scripts": [
51 | "{{user `scripts_dir`}}/install_web_server.ps1",
52 | "{{user `scripts_dir`}}/install_windows_updates.ps1"
53 | ]
54 | },
55 | {
56 | "type": "windows-restart",
57 | "restart_command": "powershell \"& {(Get-WmiObject win32_operatingsystem).LastBootUpTime > C:\\ProgramData\\lastboot.txt; Restart-Computer -force}\"",
58 | "restart_check_command": "powershell -command \"& {if ((get-content C:\\ProgramData\\lastboot.txt) -eq (Get-WmiObject win32_operatingsystem).LastBootUpTime) {Write-Output 'Waiting for restart'; start-sleep 600} else {Write-Output 'Restart complete'}}\""
59 | },
60 | {
61 | "type": "powershell",
62 | "scripts": [
63 | "{{user `scripts_dir`}}/install_windows_updates.ps1"
64 | ]
65 | },
66 | {
67 | "type": "windows-restart",
68 | "restart_command": "powershell \"& {(Get-WmiObject win32_operatingsystem).LastBootUpTime > C:\\ProgramData\\lastboot.txt; Restart-Computer -force}\"",
69 | "restart_check_command": "powershell -command \"& {if ((get-content C:\\ProgramData\\lastboot.txt) -eq (Get-WmiObject win32_operatingsystem).LastBootUpTime) {Write-Output 'Waiting for restart'; start-sleep 600} else {Write-Output 'Restart complete'}}\""
70 | },
71 | {
72 | "type": "powershell",
73 | "scripts": [
74 | "{{user `scripts_dir`}}/set_ec2_config.ps1"
75 | ]
76 | },
77 | {
78 | "type": "powershell",
79 | "inline": [
80 | "New-Item -Path {{user `consul_config_dir`}} -ItemType Directory -Force"
81 | ]
82 | },
83 | {
84 | "type": "file",
85 | "source": "{{user `scripts_dir`}}/consul_client.json",
86 | "destination": "{{user `consul_config_dir`}}\\config.json"
87 | },
88 | {
89 | "type": "powershell",
90 | "scripts": [
91 | "{{user `scripts_dir`}}/install_consul.ps1"
92 | ]
93 | }
94 | ],
95 | "post-processors": [
96 | {
97 | "type": "atlas",
98 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
99 | "artifact_type": "amazon.ami",
100 | "metadata": {
101 | "created_at": "{{timestamp}}"
102 | }
103 | }
104 | ]
105 | }
106 |
--------------------------------------------------------------------------------
/packer/aws/windows/web.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "aws_access_key": "{{env `AWS_ACCESS_KEY`}}",
4 | "aws_secret_key": "{{env `AWS_SECRET_KEY`}}",
5 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
6 | "base_ami": "{{env `ATLAS_BASE_ARTIFACT_AMAZON_AMI_ID`}}",
7 | "name": "aws-windows-web",
8 | "region": "us-east-1",
9 | "vpc_id": "",
10 | "subnet_id": "",
11 | "instance_type": "t2.micro",
12 | "winrm_username": "Administrator",
13 | "user_data_file": "packer/scripts/windows/config/ec2_user_data.conf",
14 | "scripts_dir": "packer/scripts/windows",
15 | "slug_app_dir": "app/"
16 | },
17 | "push": {
18 | "name": "{{user `atlas_username`}}/{{user `name`}}",
19 | "base_dir": "../../../.",
20 | "include": [
21 | "{{user `scripts_dir`}}/*"
22 | ],
23 | "vcs": false
24 | },
25 | "builders": [
26 | {
27 | "type": "amazon-ebs",
28 | "access_key": "{{user `aws_access_key`}}",
29 | "secret_key": "{{user `aws_secret_key`}}",
30 | "region": "{{user `region`}}",
31 | "vpc_id": "{{user `vpc_id`}}",
32 | "subnet_id": "{{user `subnet_id`}}",
33 | "source_ami": "{{user `base_ami`}}",
34 | "instance_type": "{{user `instance_type`}}",
35 | "communicator": "winrm",
36 | "winrm_username": "{{user `winrm_username`}}",
37 | "winrm_timeout": "30m",
38 | "user_data_file": "{{user `user_data_file`}}",
39 | "ami_name": "{{user `name`}} {{timestamp}}",
40 | "ami_description": "{{user `name`}} AMI",
41 | "run_tags": { "ami-create": "{{user `name`}}" },
42 | "tags": { "ami": "{{user `name`}}" },
43 | "associate_public_ip_address": true
44 | }
45 | ],
46 | "provisioners": [
47 | {
48 | "type": "powershell",
49 | "scripts": [
50 | "{{user `scripts_dir`}}/set_ec2_config.ps1"
51 | ]
52 | },
53 | {
54 | "type": "powershell",
55 | "inline": [
56 | "New-Item C:\\{{user `name`}} -type Directory"
57 | ]
58 | },
59 | {
60 | "type": "file",
61 | "source": "{{user `slug_app_dir`}}",
62 | "destination": "C:\\{{user `name`}}"
63 | },
64 | {
65 | "type": "powershell",
66 | "inline": [
67 | "Import-Module WebAdministration",
68 | "Clear-ItemProperty \"IIS:\\Sites\\Default Web Site\" -Name bindings",
69 | "Remove-Website -Name \"Default Web Site\"",
70 | "New-Item \"IIS:\\AppPools\\{{user `name`}} AppPool\"",
71 | "New-Item IIS:\\Sites\\{{user `name`}} -physicalPath C:\\{{user `name`}} -bindings @{protocol=\"http\";bindingInformation=\":80:\"}",
72 | "Set-ItemProperty IIS:\\Sites\\{{user `name`}} -name applicationPool -value \"{{user `name`}} AppPool\""
73 | ]
74 | }
75 | ],
76 | "post-processors": [
77 | {
78 | "type": "atlas",
79 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
80 | "artifact_type": "amazon.ami",
81 | "metadata": {
82 | "created_at": "{{timestamp}}"
83 | }
84 | }
85 | ]
86 | }
87 |
--------------------------------------------------------------------------------
/packer/config/consul/consul_client.json:
--------------------------------------------------------------------------------
1 | {
2 | "log_level": "INFO",
3 | "data_dir": "/opt/consul/data",
4 | "ui_dir": "/opt/consul/ui",
5 | "client_addr": "0.0.0.0",
6 | "bind_addr": "0.0.0.0",
7 | "atlas_join": true,
8 | "atlas_infrastructure": "{{ atlas_username }}/{{ atlas_environment }}",
9 | "atlas_token": "{{ atlas_token }}",
10 | "datacenter": "{{ datacenter }}",
11 | "node_name": "{{ node_name }}",
12 | "skip_leave_on_interrupt": true,
13 | "leave_on_terminate": true
14 | }
15 |
--------------------------------------------------------------------------------
/packer/config/consul/consul_server.json:
--------------------------------------------------------------------------------
1 | {
2 | "log_level": "INFO",
3 | "server": true,
4 | "data_dir": "/opt/consul/data",
5 | "ui_dir": "/opt/consul/ui",
6 | "client_addr": "0.0.0.0",
7 | "bind_addr": "0.0.0.0",
8 | "atlas_join": true,
9 | "atlas_infrastructure": "{{ atlas_username }}/{{ atlas_environment }}",
10 | "atlas_token": "{{ atlas_token }}",
11 | "bootstrap_expect": {{ consul_server_count }},
12 | "datacenter": "{{ datacenter }}",
13 | "node_name": "{{ node_name }}",
14 | "skip_leave_on_interrupt": true,
15 | "leave_on_terminate": true,
16 | "service": {
17 | "name": "consul",
18 | "tags": ["{{ node_name }}"]
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/packer/config/consul/haproxy.json:
--------------------------------------------------------------------------------
1 | {
2 | "service": {
3 | "name": "haproxy"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/packer/config/consul/nodejs.json:
--------------------------------------------------------------------------------
1 | {
2 | "recursors": ["localhost:8600"],
3 | "service": {
4 | "name": "web",
5 | "port": 8888,
6 | "tags": ["nodejs", "{{ deploy }}"]
7 | },
8 | "check": {
9 | "id": "nodejs",
10 | "service_id": "web",
11 | "name": "Running on port 8888",
12 | "http": "http://localhost:8888",
13 | "interval": "10s",
14 | "timeout": "1s"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/packer/config/consul/vault.json:
--------------------------------------------------------------------------------
1 | {
2 | "service": {
3 | "name": "vault",
4 | "port": 8200,
5 | "tags": ["{{ node_name }}"]
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/packer/config/consul_template/base.hcl:
--------------------------------------------------------------------------------
1 | consul = "127.0.0.1:8500"
2 | max_stale = "10m"
3 | retry = "5s"
4 | log_level = "warn"
5 |
--------------------------------------------------------------------------------
/packer/config/consul_template/haproxy.hcl:
--------------------------------------------------------------------------------
1 | template {
2 | source = "/opt/consul_template/haproxy.ctmpl"
3 | destination = "/etc/haproxy/haproxy.cfg"
4 | command = "service haproxy restart"
5 | }
6 |
--------------------------------------------------------------------------------
/packer/config/consul_template/nodejs.hcl:
--------------------------------------------------------------------------------
1 | vault {
2 | address = "https://vault.service.consul:8200"
3 | token = "{{ vault_token }}"
4 | renew = true
5 |
6 | ssl {
7 | enabled = true
8 | verify = true
9 | ca_cert = "{{ cert_path }}"
10 | }
11 | }
12 |
13 | template {
14 | source = "/opt/consul_template/vault_generic.ctmpl"
15 | destination = "/application/vault/generic.html"
16 | command = "service nodejs restart"
17 | }
18 |
--------------------------------------------------------------------------------
/packer/config/consul_template/nodejs_aws.hcl:
--------------------------------------------------------------------------------
1 | template {
2 | source = "/opt/consul_template/vault_aws.ctmpl"
3 | destination = "/application/vault/aws.html"
4 | command = "service nodejs restart"
5 | }
6 |
--------------------------------------------------------------------------------
/packer/config/consul_template/templates/haproxy.ctmpl:
--------------------------------------------------------------------------------
1 | global
2 | maxconn 4
3 | log 127.0.0.1 local0 notice
4 | user haproxy
5 | group haproxy
6 |
7 | defaults
8 | log global
9 | retries 2
10 | timeout connect 3000
11 | timeout server 5000
12 | timeout client 5000
13 |
14 | listen localnodes
15 | bind *:80
16 | mode http
17 | default_backend webs
18 |
19 | backend webs
20 | balance roundrobin
21 | mode http{{range service "nodejs.web"}}
22 | server {{.Node}} {{.Address}}:{{.Port}}{{end}}
23 |
24 | listen stats *:1936
25 | mode http
26 | stats enable
27 | stats uri /haproxy?stats
28 | stats hide-version
29 |
--------------------------------------------------------------------------------
/packer/config/consul_template/templates/vault_aws.ctmpl:
--------------------------------------------------------------------------------
1 | {{with vault "{{ cred_path }}"}}
2 |
3 | Consul Template is setup with the Vault AWS backend!
4 |
5 | The dynamically generated AWS IAM credentials for {{ node_name }} are...
6 |
7 | Access Key: {{.Data.access_key}}
8 | Secret Key: {{.Data.secret_key}}
9 | {{end}}
10 |
--------------------------------------------------------------------------------
/packer/config/consul_template/templates/vault_generic.ctmpl:
--------------------------------------------------------------------------------
1 | {{with vault "{{ secret_path }}"}}
2 |
3 | Consul Template is setup with the Vault Generic Secret backend!
4 |
5 | The Vault secret for {{ node_name }} is: "{{.Data.{{ secret_key }}}}"
6 | {{end}}
7 |
--------------------------------------------------------------------------------
/packer/config/envconsul/base.hcl:
--------------------------------------------------------------------------------
1 | consul = "127.0.0.1:8500"
2 | max_stale = "10m"
3 | timeout = "5s"
4 | retry = "5s"
5 | splay = "5s"
6 | sanitize = true
7 | upcase = true
8 | log_level = "warn"
9 |
--------------------------------------------------------------------------------
/packer/config/envconsul/nodejs.hcl:
--------------------------------------------------------------------------------
1 | prefix {
2 | path = "service/nodejs"
3 | }
4 |
--------------------------------------------------------------------------------
/packer/config/vault/policies/aws_nodejs.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": {
4 | "Effect": "Allow",
5 | "Action": "iam:*",
6 | "Resource": "*"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packer/config/vault/policies/nodejs.hcl:
--------------------------------------------------------------------------------
1 | # Allow renewal of leases for secrets
2 | path "sys/renew/*" {
3 | policy = "write"
4 | }
5 |
6 | # Allow renewal of token leases
7 | path "auth/token/renew/*" {
8 | policy = "write"
9 | }
10 |
11 | # Transit backend
12 | path "transit/encrypt/nodejs_*" {
13 | policy = "write"
14 | }
15 |
16 | path "transit/decrypt/nodejs_*" {
17 | policy = "write"
18 | }
19 |
20 | # Secrets backend
21 | path "secret/nodejs/*" {
22 | policy = "read"
23 | }
24 |
25 | # AWS backend
26 | path "aws/creds/*" {
27 | policy = "read"
28 | }
29 |
--------------------------------------------------------------------------------
/packer/config/vault/policies/nodejs.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": {
3 | "sys/renew/*": {
4 | "policy": "write"
5 | },
6 | "auth/token/renew/*": {
7 | "policy": "write"
8 | },
9 | "transit/encrypt/nodejs_*": {
10 | "policy": "write"
11 | },
12 | "transit/decrypt/nodejs_*": {
13 | "policy": "write"
14 | },
15 | "secret/nodejs/*": {
16 | "policy": "read"
17 | },
18 | "aws/creds/*": {
19 | "policy": "read"
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/packer/config/vault/scripts/setup_aws.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | usage() {
5 | cat <
17 |
18 | Where ACCESS_KEY is your Vault AWS Access Key ID, SECRET_KEY is your Vault AWS Secret Access Key, and REGION is the AWS region for API calls.
19 | EOF
20 |
21 | exit 1
22 | }
23 |
24 | if ! which vault > /dev/null; then
25 | echo
26 | echo "ERROR: The vault executable was not found. This script requires vault"
27 | echo
28 | usage
29 | fi
30 |
31 | ACCESSKEY=$1
32 |
33 | if [ -z "${ACCESSKEY}" ]; then
34 | echo
35 | echo "ERROR: Specify the Vault AWS Access Key ID as the first argument"
36 | echo
37 | usage
38 | fi
39 |
40 | SECRETKEY=$2
41 |
42 | if [ -z "${SECRETKEY}" ]; then
43 | echo
44 | echo "ERROR: Specify the Vault AWS Secret Access Key as the second argument"
45 | echo
46 | usage
47 | fi
48 |
49 | REGION=$3
50 |
51 | if [ -z "${REGION}" ]; then
52 | echo
53 | echo "ERROR: Specify the AWS region as the third argument, e.g. us-east-1"
54 | echo
55 | usage
56 | fi
57 |
58 | if vault status | grep standby > /dev/null; then
59 | echo "Mounts only run on the leader. Exiting."
60 | exit 0
61 | fi
62 |
63 | echo "Authenticating as root..."
64 |
65 | cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
66 | cget root-token | vault auth -
67 |
68 | if vault mounts | grep aws > /dev/null; then
69 | echo "AWS backend already mounted."
70 | else
71 | echo "Mounting AWS backend..."
72 | vault mount aws
73 | fi
74 |
75 | echo "Writing root AWS IAM credentials..."
76 |
77 | vault write aws/config/root \
78 | access_key=$ACCESSKEY \
79 | secret_key=$SECRETKEY \
80 | region=$REGION
81 |
82 | echo "Writing lease settings for generated credentials..."
83 |
84 | vault write aws/config/lease \
85 | lease="1m" \
86 | lease_max="2m"
87 |
88 | shred -u -z ~/.vault-token
89 |
--------------------------------------------------------------------------------
/packer/config/vault/scripts/setup_transit.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | usage() {
5 | cat < /dev/null; then
19 | echo
20 | echo "ERROR: The vault executable was not found. This script requires vault"
21 | echo
22 | usage
23 | fi
24 |
25 | if vault status | grep standby > /dev/null; then
26 | echo "Mounts only run on the leader. Exiting."
27 | exit 0
28 | fi
29 |
30 | echo "Authenticating as root..."
31 |
32 | cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
33 | cget root-token | vault auth -
34 |
35 | if vault mounts | grep transit > /dev/null; then
36 | echo "Transit backend already mounted."
37 | else
38 | echo "Mounting Transit backend."
39 | vault mount transit
40 | fi
41 |
42 | shred -u -z ~/.vault-token
43 |
--------------------------------------------------------------------------------
/packer/config/vault/scripts/setup_vault.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cr=`echo '\n.'`
5 | cr=${cr%.}
6 | read -p "Running this script will initialize & unseal Vault,${cr}then put your unseal keys and root token into Consul KV.${cr}${cr}If you're sure you want to continue, type 'yes': `echo '\n> '`" ANSWER
7 |
8 | if [ "$ANSWER" != "yes" ]; then
9 | echo
10 | echo "Exiting without intializing & unsealing Vault, no keys or tokens were stored."
11 | echo
12 | exit 1
13 | fi
14 |
15 | cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
16 |
17 | if [ ! $(cget root-token) ]; then
18 | echo "Initialize Vault"
19 | vault init | tee /tmp/vault.init > /dev/null
20 |
21 | # Store master keys in consul for operator to retrieve and remove
22 | COUNTER=1
23 | cat /tmp/vault.init | grep '^Unseal' | awk '{print $4}' | for key in $(cat -); do
24 | curl -fX PUT 127.0.0.1:8500/v1/kv/service/vault/unseal-key-$COUNTER -d $key
25 | COUNTER=$((COUNTER + 1))
26 | done
27 |
28 | export ROOT_TOKEN=$(cat /tmp/vault.init | grep '^Initial' | awk '{print $4}')
29 | curl -fX PUT 127.0.0.1:8500/v1/kv/service/vault/root-token -d $ROOT_TOKEN
30 |
31 | echo "Remove master keys from disk"
32 | shred /tmp/vault.init
33 |
34 | echo "Setup Vault demo"
35 | curl -fX PUT 127.0.0.1:8500/v1/kv/service/nodejs/show_vault -d "true"
36 | curl -fX PUT 127.0.0.1:8500/v1/kv/service/nodejs/vault_files -d "aws.html,generic.html"
37 | else
38 | echo "Vault has already been initialized, skipping."
39 | fi
40 |
41 | echo "Unsealing Vault"
42 | vault unseal $(cget unseal-key-1)
43 | vault unseal $(cget unseal-key-2)
44 | vault unseal $(cget unseal-key-3)
45 |
46 | echo "Vault setup complete."
47 |
48 | instructions() {
49 | cat <
17 |
18 | Where POLICY_NAME is the name of the policy you wish to create, and POLICY_PATH is the path to the policy.
19 | EOF
20 |
21 | exit 1
22 | }
23 |
24 | if ! which vault > /dev/null; then
25 | echo
26 | echo "ERROR: The vault executable was not found. This script requires vault"
27 | echo
28 | usage
29 | fi
30 |
31 | POLICYNAME=$1
32 |
33 | if [ -z "${POLICYNAME}" ]; then
34 | echo
35 | echo "ERROR: Specify the name of your policy as the first argument, e.g. nodejs"
36 | echo
37 | usage
38 | fi
39 |
40 | POLICYPATH=$2
41 |
42 | if [ -z "${POLICYPATH}" ]; then
43 | echo
44 | echo "ERROR: Specify the path to your policy as the second argument, e.g. /opt/vault/policies/nodejs.hcl"
45 | echo
46 | usage
47 | fi
48 |
49 | echo "Authenticating as root..."
50 |
51 | cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
52 | cget root-token | vault auth -
53 |
54 | echo "Writing Vault $POLICYNAME policy..."
55 |
56 | vault policy-write "${POLICYNAME}" $POLICYPATH
57 |
58 | shred -u -z ~/.vault-token
59 |
--------------------------------------------------------------------------------
/packer/config/vault/scripts/write_role.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | usage() {
5 | cat <
17 |
18 | Where ROLE_NAME is the name of the role you wish to create, and POLICY_PATH is the path to the policy for this role.
19 | EOF
20 |
21 | exit 1
22 | }
23 |
24 | if ! which vault > /dev/null; then
25 | echo
26 | echo "ERROR: The vault executable was not found. This script requires vault"
27 | echo
28 | usage
29 | fi
30 |
31 | ROLENAME=$1
32 |
33 | if [ -z "${ROLENAME}" ]; then
34 | echo
35 | echo "ERROR: Specify the name of your role as the first argument, e.g. nodejs/my_app"
36 | echo
37 | usage
38 | fi
39 |
40 | POLICYPATH=$2
41 |
42 | if [ -z "${POLICYPATH}" ]; then
43 | echo
44 | echo "ERROR: Specify the path to your policy as the second argument, e.g. /opt/vault/policies/aws_nodejs.json"
45 | echo
46 | usage
47 | fi
48 |
49 | echo "Authenticating as root..."
50 |
51 | cget() { curl -sf "http://127.0.0.1:8500/v1/kv/service/vault/$1?raw"; }
52 | cget root-token | vault auth -
53 |
54 | echo "Writing Vault $ROLENAME role..."
55 |
56 | vault write aws/roles/$ROLENAME policy=@$POLICYPATH
57 |
58 | shred -u -z ~/.vault-token
59 |
--------------------------------------------------------------------------------
/packer/config/vault/vault.hcl:
--------------------------------------------------------------------------------
1 | backend "consul" {
2 | path = "vault"
3 | address = "127.0.0.1:8500"
4 | advertise_addr = "https://{{ node_name }}.node.consul:8200"
5 | }
6 |
7 | listener "atlas" {
8 | infrastructure = "{{ atlas_username }}/{{ atlas_environment }}"
9 | token = "{{ atlas_token }}"
10 | node_id = "{{ node_name }}"
11 | tls_cert_file = "{{ tls_cert_file }}"
12 | tls_key_file = "{{ tls_key_file }}"
13 | }
14 |
15 | cluster_name = "{{ datacenter }}"
16 |
17 | listener "tcp" {
18 | address = "0.0.0.0:8200"
19 | tls_cert_file = "{{ tls_cert_file }}"
20 | tls_key_file = "{{ tls_key_file }}"
21 | }
22 |
--------------------------------------------------------------------------------
/packer/google/ubuntu/base.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
4 | "gce_credentials": "{{env `GCE_CREDENTIALS`}}",
5 | "gce_project_id": "{{env `GCE_PROJECT_ID`}}",
6 | "gce_zone": "{{env `GCE_DEFAULT_ZONE`}}",
7 | "gce_source_image": "{{env `GCE_SOURCE_IMAGE`}}",
8 | "name": "google-ubuntu-base",
9 | "scripts_dir": "scripts",
10 | "config_dir": "config",
11 | "ssh_username": "ubuntu",
12 | "dns_listen_addr": "127.0.0.1"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../../packer",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/ubuntu/*",
20 | "{{user `scripts_dir`}}/ubuntu/upstart/*",
21 | "{{user `config_dir`}}/*",
22 | "{{user `config_dir`}}/consul/*",
23 | "{{user `config_dir`}}/consul_template/*",
24 | "{{user `config_dir`}}/consul_template/templates/*",
25 | "{{user `config_dir`}}/envconsul/*",
26 | "{{user `config_dir`}}/vault/*",
27 | "{{user `config_dir`}}/vault/policies/*",
28 | "{{user `config_dir`}}/vault/scripts/*"
29 | ],
30 | "vcs": false
31 | },
32 | "builders": [
33 | {
34 | "type": "googlecompute",
35 | "project_id": "{{user `gce_project_id`}}",
36 | "account_file": "{{user `gce_credentials`}}",
37 | "zone": "{{user `gce_zone`}}",
38 | "network": "default",
39 | "source_image": "{{user `gce_source_image`}}",
40 | "ssh_username": "{{user `ssh_username`}}",
41 | "image_name": "packer-{{user `name`}}-{{timestamp}}",
42 | "image_description": "packer-{{user `name`}}-image",
43 | "use_internal_ip": false,
44 | "tags": [
45 | "{{user `name`}}"
46 | ]
47 | }
48 | ],
49 | "provisioners": [
50 | {
51 | "type": "shell",
52 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
53 | "inline": [
54 | "mkdir -p /ops/{{user `scripts_dir`}}",
55 | "chmod a+w /ops/{{user `scripts_dir`}}",
56 | "mkdir -p /ops/{{user `config_dir`}}",
57 | "chmod a+w /ops/{{user `config_dir`}}"
58 | ]
59 | },
60 | {
61 | "type": "file",
62 | "source": "{{user `scripts_dir`}}/",
63 | "destination": "/ops/{{user `scripts_dir`}}"
64 | },
65 | {
66 | "type": "file",
67 | "source": "{{user `config_dir`}}/",
68 | "destination": "/ops/{{user `config_dir`}}"
69 | },
70 | {
71 | "type": "shell",
72 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
73 | "inline": [
74 | "sh /ops/{{user `scripts_dir`}}/ubuntu/dependencies.sh",
75 | "sh /ops/{{user `scripts_dir`}}/ubuntu/consul.sh {{user `config_dir`}} {{user `scripts_dir`}}/ubuntu",
76 | "sh /ops/{{user `scripts_dir`}}/ubuntu/consul_template.sh {{user `config_dir`}} {{user `scripts_dir`}}/ubuntu",
77 | "sh /ops/{{user `scripts_dir`}}/ubuntu/envconsul.sh {{user `config_dir`}}",
78 | "sh /ops/{{user `scripts_dir`}}/ubuntu/dnsmasq.sh {{user `dns_listen_addr`}}",
79 | "sh /ops/{{user `scripts_dir`}}/ubuntu/cleanup.sh"
80 | ]
81 | }
82 | ],
83 | "post-processors": [
84 | {
85 | "type": "atlas",
86 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
87 | "artifact_type": "google.image",
88 | "metadata": {
89 | "created_at": "{{timestamp}}",
90 | "zone": "{{user `gce_zone`}}"
91 | }
92 | }
93 | ]
94 | }
95 |
--------------------------------------------------------------------------------
/packer/google/ubuntu/consul.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
4 | "gce_project_id": "{{env `GCE_PROJECT_ID`}}",
5 | "gce_zone": "{{env `GCE_DEFAULT_ZONE`}}",
6 | "gce_source_image": "{{env `ATLAS_BASE_ARTIFACT_GOOGLE_IMAGE_ID`}}",
7 | "gce_credentials": "{{env `GCE_CREDENTIALS`}}",
8 | "name": "google-ubuntu-consul",
9 | "scripts_dir": "scripts",
10 | "config_dir": "config",
11 | "ssh_username": "ubuntu",
12 | "dns_listen_addr": "127.0.0.1"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../../packer",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/ubuntu/*",
20 | "{{user `scripts_dir`}}/ubuntu/upstart/*",
21 | "{{user `config_dir`}}/*",
22 | "{{user `config_dir`}}/consul/*",
23 | "{{user `config_dir`}}/consul_template/*",
24 | "{{user `config_dir`}}/consul_template/templates/*",
25 | "{{user `config_dir`}}/envconsul/*",
26 | "{{user `config_dir`}}/vault/*",
27 | "{{user `config_dir`}}/vault/policies/*",
28 | "{{user `config_dir`}}/vault/scripts/*"
29 | ],
30 | "vcs": false
31 | },
32 | "builders": [
33 | {
34 | "type": "googlecompute",
35 | "project_id": "{{user `gce_project_id`}}",
36 | "account_file": "{{user `gce_credentials`}}",
37 | "zone": "{{user `gce_zone`}}",
38 | "network": "default",
39 | "source_image": "{{user `gce_source_image`}}",
40 | "ssh_username": "{{user `ssh_username`}}",
41 | "image_name": "packer-{{user `name`}}-{{timestamp}}",
42 | "image_description": "packer-{{user `name`}}-image",
43 | "use_internal_ip": false,
44 | "tags": [
45 | "{{user `name`}}"
46 | ]
47 | }
48 | ],
49 | "provisioners": [
50 | {
51 | "type": "shell",
52 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
53 | "inline": [
54 | "mkdir -p /ops/{{user `scripts_dir`}}",
55 | "chmod a+w /ops/{{user `scripts_dir`}}",
56 | "mkdir -p /ops/{{user `config_dir`}}",
57 | "chmod a+w /ops/{{user `config_dir`}}"
58 | ]
59 | },
60 | {
61 | "type": "file",
62 | "source": "{{user `scripts_dir`}}/",
63 | "destination": "/ops/{{user `scripts_dir`}}"
64 | },
65 | {
66 | "type": "file",
67 | "source": "{{user `config_dir`}}/",
68 | "destination": "/ops/{{user `config_dir`}}"
69 | },
70 | {
71 | "type": "shell",
72 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
73 | "inline": [
74 | "cp /ops/{{user `config_dir`}}/consul/consul_server.json /etc/consul.d/base.json",
75 | "sh /ops/{{user `scripts_dir`}}/ubuntu/dnsmasq.sh {{user `dns_listen_addr`}}",
76 | "sh /ops/{{user `scripts_dir`}}/ubuntu/cleanup.sh"
77 | ]
78 | }
79 | ],
80 | "post-processors": [
81 | {
82 | "type": "atlas",
83 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
84 | "artifact_type": "google.image",
85 | "metadata": {
86 | "created_at": "{{timestamp}}",
87 | "zone": "{{user `gce_zone`}}"
88 | }
89 | }
90 | ]
91 | }
92 |
--------------------------------------------------------------------------------
/packer/google/ubuntu/haproxy.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
4 | "gce_project_id": "{{env `GCE_PROJECT_ID`}}",
5 | "gce_zone": "{{env `GCE_DEFAULT_ZONE`}}",
6 | "gce_source_image": "{{env `ATLAS_BASE_ARTIFACT_GOOGLE_IMAGE_ID`}}",
7 | "gce_credentials": "{{env `GCE_CREDENTIALS`}}",
8 | "name": "google-ubuntu-haproxy",
9 | "scripts_dir": "scripts",
10 | "config_dir": "config",
11 | "ssh_username": "ubuntu",
12 | "dns_listen_addr": "127.0.0.1"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../../packer",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/ubuntu/*",
20 | "{{user `scripts_dir`}}/ubuntu/upstart/*",
21 | "{{user `config_dir`}}/*",
22 | "{{user `config_dir`}}/consul/*",
23 | "{{user `config_dir`}}/consul_template/*",
24 | "{{user `config_dir`}}/consul_template/templates/*",
25 | "{{user `config_dir`}}/envconsul/*",
26 | "{{user `config_dir`}}/vault/*",
27 | "{{user `config_dir`}}/vault/policies/*",
28 | "{{user `config_dir`}}/vault/scripts/*"
29 | ],
30 | "vcs": false
31 | },
32 | "builders": [
33 | {
34 | "type": "googlecompute",
35 | "project_id": "{{user `gce_project_id`}}",
36 | "account_file": "{{user `gce_credentials`}}",
37 | "zone": "{{user `gce_zone`}}",
38 | "network": "default",
39 | "source_image": "{{user `gce_source_image`}}",
40 | "ssh_username": "{{user `ssh_username`}}",
41 | "image_name": "packer-{{user `name`}}-{{timestamp}}",
42 | "image_description": "packer-{{user `name`}}-image",
43 | "use_internal_ip": false,
44 | "tags": [
45 | "{{user `name`}}"
46 | ]
47 | }
48 | ],
49 | "provisioners": [
50 | {
51 | "type": "shell",
52 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
53 | "inline": [
54 | "mkdir -p /ops/{{user `scripts_dir`}}",
55 | "chmod a+w /ops/{{user `scripts_dir`}}",
56 | "mkdir -p /ops/{{user `config_dir`}}",
57 | "chmod a+w /ops/{{user `config_dir`}}"
58 | ]
59 | },
60 | {
61 | "type": "file",
62 | "source": "{{user `scripts_dir`}}/",
63 | "destination": "/ops/{{user `scripts_dir`}}"
64 | },
65 | {
66 | "type": "file",
67 | "source": "{{user `config_dir`}}/",
68 | "destination": "/ops/{{user `config_dir`}}"
69 | },
70 | {
71 | "type": "shell",
72 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
73 | "inline": [
74 | "sh /ops/{{user `scripts_dir`}}/ubuntu/haproxy.sh {{user `config_dir`}} {{user `scripts_dir`}}/ubuntu",
75 | "sh /ops/{{user `scripts_dir`}}/ubuntu/cleanup.sh"
76 | ]
77 | }
78 | ],
79 | "post-processors": [
80 | {
81 | "type": "atlas",
82 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
83 | "artifact_type": "google.image",
84 | "metadata": {
85 | "created_at": "{{timestamp}}",
86 | "zone": "{{user `gce_zone`}}"
87 | }
88 | }
89 | ]
90 | }
91 |
--------------------------------------------------------------------------------
/packer/google/ubuntu/nodejs.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
4 | "gce_project_id": "{{env `GCE_PROJECT_ID`}}",
5 | "gce_zone": "{{env `GCE_DEFAULT_ZONE`}}",
6 | "gce_source_image": "{{env `ATLAS_BASE_ARTIFACT_GOOGLE_IMAGE_ID`}}",
7 | "gce_credentials": "{{env `GCE_CREDENTIALS`}}",
8 | "name": "google-ubuntu-nodejs",
9 | "scripts_dir": "scripts",
10 | "config_dir": "config",
11 | "ssh_username": "ubuntu",
12 | "host_app_dir": "/application"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../../packer",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/ubuntu/*",
20 | "{{user `scripts_dir`}}/ubuntu/upstart/*",
21 | "{{user `scripts_dir`}}/ubuntu/nodejs_app/*",
22 | "{{user `config_dir`}}/*",
23 | "{{user `config_dir`}}/consul/*",
24 | "{{user `config_dir`}}/consul_template/*",
25 | "{{user `config_dir`}}/consul_template/templates/*",
26 | "{{user `config_dir`}}/envconsul/*",
27 | "{{user `config_dir`}}/vault/*",
28 | "{{user `config_dir`}}/vault/policies/*",
29 | "{{user `config_dir`}}/vault/scripts/*"
30 | ],
31 | "vcs": false
32 | },
33 | "builders": [
34 | {
35 | "type": "googlecompute",
36 | "project_id": "{{user `gce_project_id`}}",
37 | "account_file": "{{user `gce_credentials`}}",
38 | "zone": "{{user `gce_zone`}}",
39 | "network": "default",
40 | "source_image": "{{user `gce_source_image`}}",
41 | "ssh_username": "{{user `ssh_username`}}",
42 | "image_name": "packer-{{user `name`}}-{{timestamp}}",
43 | "image_description": "packer-{{user `name`}}-image",
44 | "use_internal_ip": false,
45 | "tags": [
46 | "{{user `name`}}"
47 | ]
48 | }
49 | ],
50 | "provisioners": [
51 | {
52 | "type": "shell",
53 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
54 | "inline": [
55 | "mkdir -p /ops/{{user `scripts_dir`}}",
56 | "chmod a+w /ops/{{user `scripts_dir`}}",
57 | "mkdir -p /ops/{{user `config_dir`}}",
58 | "chmod a+w /ops/{{user `config_dir`}}"
59 | ]
60 | },
61 | {
62 | "type": "file",
63 | "source": "{{user `scripts_dir`}}/",
64 | "destination": "/ops/{{user `scripts_dir`}}"
65 | },
66 | {
67 | "type": "file",
68 | "source": "{{user `config_dir`}}/",
69 | "destination": "/ops/{{user `config_dir`}}"
70 | },
71 | {
72 | "type": "shell",
73 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
74 | "inline": [
75 | "mkdir -p {{user `host_app_dir`}}",
76 | "chmod a+w {{user `host_app_dir`}}"
77 | ]
78 | },
79 | {
80 | "type": "file",
81 | "source": "{{user `scripts_dir`}}/ubuntu/nodejs_app/",
82 | "destination": "{{user `host_app_dir`}}"
83 | },
84 | {
85 | "type": "shell",
86 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
87 | "inline": [
88 | "sh /ops/{{user `scripts_dir`}}/ubuntu/nodejs.sh {{user `config_dir`}} {{user `scripts_dir`}}/ubuntu",
89 | "sh /ops/{{user `scripts_dir`}}/ubuntu/cleanup.sh"
90 | ]
91 | }
92 | ],
93 | "post-processors": [
94 | {
95 | "type": "atlas",
96 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
97 | "artifact_type": "google.image",
98 | "metadata": {
99 | "created_at": "{{timestamp}}",
100 | "zone": "{{user `gce_zone`}}"
101 | }
102 | }
103 | ]
104 | }
105 |
--------------------------------------------------------------------------------
/packer/google/ubuntu/vault.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "atlas_username": "{{env `ATLAS_USERNAME`}}",
4 | "gce_project_id": "{{env `GCE_PROJECT_ID`}}",
5 | "gce_zone": "{{env `GCE_DEFAULT_ZONE`}}",
6 | "gce_source_image": "{{env `ATLAS_BASE_ARTIFACT_GOOGLE_IMAGE_ID`}}",
7 | "gce_credentials": "{{env `GCE_CREDENTIALS`}}",
8 | "name": "google-ubuntu-vault",
9 | "scripts_dir": "scripts",
10 | "config_dir": "config",
11 | "ssh_username": "ubuntu",
12 | "dns_listen_addr": "127.0.0.1"
13 | },
14 | "push": {
15 | "name": "{{user `atlas_username`}}/{{user `name`}}",
16 | "base_dir": "../../../packer",
17 | "include": [
18 | "{{user `scripts_dir`}}/*",
19 | "{{user `scripts_dir`}}/ubuntu/*",
20 | "{{user `scripts_dir`}}/ubuntu/upstart/*",
21 | "{{user `config_dir`}}/*",
22 | "{{user `config_dir`}}/consul/*",
23 | "{{user `config_dir`}}/consul_template/*",
24 | "{{user `config_dir`}}/consul_template/templates/*",
25 | "{{user `config_dir`}}/envconsul/*",
26 | "{{user `config_dir`}}/vault/*",
27 | "{{user `config_dir`}}/vault/policies/*",
28 | "{{user `config_dir`}}/vault/scripts/*"
29 | ],
30 | "vcs": false
31 | },
32 | "builders": [
33 | {
34 | "type": "googlecompute",
35 | "project_id": "{{user `gce_project_id`}}",
36 | "account_file": "{{user `gce_credentials`}}",
37 | "zone": "{{user `gce_zone`}}",
38 | "network": "default",
39 | "source_image": "{{user `gce_source_image`}}",
40 | "ssh_username": "{{user `ssh_username`}}",
41 | "image_name": "packer-{{user `name`}}-{{timestamp}}",
42 | "image_description": "packer-{{user `name`}}-image",
43 | "use_internal_ip": false,
44 | "tags": [
45 | "{{user `name`}}"
46 | ]
47 | }
48 | ],
49 | "provisioners": [
50 | {
51 | "type": "shell",
52 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
53 | "inline": [
54 | "mkdir -p /ops/{{user `scripts_dir`}}",
55 | "chmod a+w /ops/{{user `scripts_dir`}}",
56 | "mkdir -p /ops/{{user `config_dir`}}",
57 | "chmod a+w /ops/{{user `config_dir`}}"
58 | ]
59 | },
60 | {
61 | "type": "file",
62 | "source": "{{user `scripts_dir`}}/",
63 | "destination": "/ops/{{user `scripts_dir`}}"
64 | },
65 | {
66 | "type": "file",
67 | "source": "{{user `config_dir`}}/",
68 | "destination": "/ops/{{user `config_dir`}}"
69 | },
70 | {
71 | "type": "shell",
72 | "execute_command": "echo {{user `ssh_username`}} | {{ .Vars }} sudo -E -S sh '{{ .Path }}'",
73 | "inline": [
74 | "sh /ops/{{user `scripts_dir`}}/ubuntu/vault.sh {{user `config_dir`}} {{user `scripts_dir`}}/ubuntu",
75 | "sh /ops/{{user `scripts_dir`}}/ubuntu/cleanup.sh"
76 | ]
77 | }
78 | ],
79 | "post-processors": [
80 | {
81 | "type": "atlas",
82 | "artifact": "{{user `atlas_username`}}/{{user `name`}}",
83 | "artifact_type": "google.image",
84 | "metadata": {
85 | "created_at": "{{timestamp}}",
86 | "zone": "{{user `gce_zone`}}"
87 | }
88 | }
89 | ]
90 | }
91 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/cleanup.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo Cleanup...
5 | apt-get -y autoremove
6 | apt-get -y clean
7 |
8 | rm -rf /tmp/*
9 | rm -rf /ops
10 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/consul.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cd /tmp
5 |
6 | CONSULVERSION=0.7.0
7 | CONFIGDIR=/ops/$1
8 | SCRIPTSDIR=/ops/$2
9 | CONSULDOWNLOAD=https://releases.hashicorp.com/consul/${CONSULVERSION}/consul_${CONSULVERSION}_linux_amd64.zip
10 | CONSULWEBUI=https://releases.hashicorp.com/consul/${CONSULVERSION}/consul_${CONSULVERSION}_web_ui.zip
11 | CONSULCONFIGDIR=/etc/consul.d
12 | CONSULDIR=/opt/consul
13 |
14 | echo Fetching Consul...
15 | curl -L $CONSULDOWNLOAD > consul.zip
16 |
17 | echo Installing Consul...
18 | unzip consul.zip -d /usr/local/bin
19 | chmod 0755 /usr/local/bin/consul
20 | chown root:root /usr/local/bin/consul
21 |
22 | echo Configuring Consul...
23 | mkdir -p $CONSULCONFIGDIR
24 | chmod 755 $CONSULCONFIGDIR
25 | mkdir -p $CONSULDIR
26 | chmod 755 $CONSULDIR
27 |
28 | # Consul config
29 | cp $CONFIGDIR/consul/consul_client.json $CONSULCONFIGDIR/base.json
30 |
31 | # Upstart config
32 | cp $SCRIPTSDIR/upstart/consul.conf /etc/init/consul.conf
33 |
34 | curl -L $CONSULWEBUI > ui.zip
35 | unzip ui.zip -d $CONSULDIR/ui
36 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/consul_template.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cd /tmp
5 |
6 | CTVERSION=0.16.0
7 | CONFIGDIR=/ops/$1
8 | SCRIPTSDIR=/ops/$2
9 | CTDOWNLOAD=https://releases.hashicorp.com/consul-template/${CTVERSION}/consul-template_${CTVERSION}_linux_amd64.zip
10 | CTCONFIGDIR=/etc/consul_template.d
11 | CTDIR=/opt/consul_template
12 |
13 | echo Fetching Consul Template...
14 | curl -L $CTDOWNLOAD > consul_template.zip
15 |
16 | echo Installing Consul Template...
17 | unzip consul_template.zip -d /usr/local/bin
18 | chmod 0755 /usr/local/bin/consul-template
19 | chown root:root /usr/local/bin/consul-template
20 |
21 | echo Configuring Consul Template...
22 | mkdir -p $CTCONFIGDIR
23 | chmod 755 $CTCONFIGDIR
24 | mkdir -p $CTDIR
25 | chmod 755 $CTDIR
26 |
27 | # Consul Template config
28 | cp $CONFIGDIR/consul_template/base.hcl $CTCONFIGDIR/base.hcl
29 |
30 | # Upstart config
31 | cp $SCRIPTSDIR/upstart/consul_template.conf /etc/init/consul_template.conf
32 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/dependencies.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo Install dependencies...
5 | # Update the box
6 | apt-get -y update
7 | apt-get -y upgrade
8 |
9 | # Install dependencies
10 | apt-get -y install curl unzip jq
11 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/dnsmasq.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | DNSLISTENADDR=$1
5 |
6 | echo Installing Dnsmasq...
7 |
8 | apt-get -y update
9 | apt-get -y upgrade
10 | apt-get -y install dnsmasq-base dnsmasq
11 |
12 | echo Configuring Dnsmasq...
13 |
14 | cat </etc/dnsmasq.d/consul
15 | server=/consul/127.0.0.1#8600
16 | listen-address=$DNSLISTENADDR
17 | bind-interfaces
18 | EOF
19 |
20 | cat /etc/dnsmasq.d/consul
21 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/envconsul.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cd /tmp
5 |
6 | ECVERSION=0.6.1
7 | CONFIGDIR=/ops/$1
8 | ECDOWNLOAD=https://releases.hashicorp.com/envconsul/${ECVERSION}/envconsul_${ECVERSION}_linux_amd64.zip
9 | ECCONFIGDIR=/etc/envconsul.d
10 |
11 | echo Fetching envconsul...
12 | curl -L $ECDOWNLOAD > envconsul.zip
13 |
14 | echo Installing envconsul...
15 | unzip envconsul.zip -d /usr/local/bin
16 | chmod 0755 /usr/local/bin/envconsul
17 | chown root:root /usr/local/bin/envconsul
18 |
19 | echo Configuring envconsul...
20 | mkdir -p $ECCONFIGDIR
21 | chmod 755 $ECCONFIGDIR
22 |
23 | # envconsul config
24 | cp $CONFIGDIR/envconsul/base.hcl $ECCONFIGDIR/base.hcl
25 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/haproxy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | CONFIGDIR=/ops/$1
5 | SCRIPTSDIR=/ops/$2
6 | RSYSLOG=/etc/rsyslog.conf
7 |
8 | echo Installing HAProxy...
9 |
10 | apt-get -y update
11 | apt-get install -y haproxy
12 | chmod a+w /etc/rsyslog.conf
13 |
14 | echo '$ModLoad imudp' >> $RSYSLOG
15 | echo '$UDPServerAddress 127.0.0.1' >> $RSYSLOG
16 | echo '$UDPServerRun 514' >> $RSYSLOG
17 |
18 | echo Configuring HAProxy...
19 |
20 | # Consul config
21 | cp $CONFIGDIR/consul/haproxy.json /etc/consul.d/haproxy.json
22 |
23 | # Consul Template config
24 | cp $CONFIGDIR/consul_template/haproxy.hcl /etc/consul_template.d/haproxy.hcl
25 | cp $CONFIGDIR/consul_template/templates/haproxy.ctmpl /opt/consul_template/haproxy.ctmpl
26 |
27 | # Upstart config
28 | cp $SCRIPTSDIR/upstart/haproxy.conf /etc/init/haproxy.conf
29 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/nodejs.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | CONFIGDIR=/ops/$1
5 | SCRIPTSDIR=/ops/$2
6 | VAULTPOLICIES=/opt/vault/policies
7 |
8 | echo Installing Node.js...
9 |
10 | # Setup a proper node PPA
11 | curl -sL https://deb.nodesource.com/setup_4.x — Node.js v4 LTS "Argon" | sudo bash -
12 |
13 | apt-get -y update
14 | apt-get install -y -qq nodejs
15 |
16 | echo Configuring Node.js application...
17 | mkdir -p $VAULTPOLICIES
18 | chmod 755 $VAULTPOLICIES
19 |
20 | # Consul config
21 | cp $CONFIGDIR/consul/nodejs.json /etc/consul.d/nodejs.json
22 |
23 | # Consul Template config
24 | cp $CONFIGDIR/consul_template/nodejs.hcl /etc/consul_template.d/nodejs.hcl
25 | cp $CONFIGDIR/consul_template/nodejs_aws.hcl /etc/consul_template.d/nodejs_aws.hcl
26 | cp $CONFIGDIR/consul_template/templates/vault_aws.ctmpl /opt/consul_template/vault_aws.ctmpl
27 | cp $CONFIGDIR/consul_template/templates/vault_generic.ctmpl /opt/consul_template/vault_generic.ctmpl
28 |
29 | # envconsul config
30 | cp $CONFIGDIR/envconsul/nodejs.hcl /etc/envconsul.d/nodejs.hcl
31 |
32 | # Vault Policy config
33 | cp $CONFIGDIR/vault/policies/nodejs.json $VAULTPOLICIES/nodejs.json
34 | cp $CONFIGDIR/vault/policies/aws_nodejs.json $VAULTPOLICIES/aws_nodejs.json
35 |
36 | # Upstart config
37 | cp $SCRIPTSDIR/upstart/nodejs.conf /etc/init/nodejs.conf
38 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/nodejs_app/compile.json:
--------------------------------------------------------------------------------
1 | {
2 | "variables": {
3 | "app_slug": "{{ env `ATLAS_APPLICATION_SLUG` }}"
4 | },
5 | "builders": [
6 | {
7 | "type": "docker",
8 | "image": "progrium/cedarish:cedar14",
9 | "commit": true
10 | }
11 | ],
12 | "provisioners": [
13 | {
14 | "type": "shell",
15 | "inline": [
16 | "curl --silent http://dl.gliderlabs.com/herokuish/latest/linux_x86_64.tgz | tar -xzC /bin"
17 | ]
18 | },
19 | {
20 | "type": "file",
21 | "source": ".",
22 | "destination": "/tmp/app"
23 | },
24 | {
25 | "type": "shell",
26 | "inline": [
27 | "ls -lRa /tmp/app"
28 | ]
29 | },
30 | {
31 | "type": "shell",
32 | "inline": [
33 | "herokuish buildpack install https://github.com/heroku/heroku-buildpack-nodejs",
34 | "herokuish buildpack build",
35 | "cd /app",
36 | "tar czvf /tmp/slug.tar.gz .",
37 | "sleep 10"
38 | ]
39 | },
40 | {
41 | "type": "file",
42 | "source": "/tmp/slug.tar.gz",
43 | "destination": "slug.tar.gz",
44 | "direction": "download"
45 | }
46 | ],
47 | "post-processors": [
48 | [
49 | {
50 | "type": "artifice",
51 | "files": ["slug.tar.gz"]
52 | },
53 | {
54 | "type": "atlas",
55 | "artifact": "{{user `app_slug` }}",
56 | "artifact_type": "archive"
57 | }
58 | ]
59 | ]
60 | }
61 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/nodejs_app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "demo-app",
3 | "description": "Node.js Application",
4 | "version": "1.0.0",
5 | "engines": {
6 | "node": "4.1.2"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/nodejs_app/server.js:
--------------------------------------------------------------------------------
1 | var http = require("http"),
2 | fs = require("fs"),
3 | vaultDir = "/application/vault/",
4 | showVault = process.env.SHOW_VAULT,
5 | vaultFiles = process.env.VAULT_FILES,
6 | vaultSecret = process.env.SECRET_KEY,
7 | files = [],
8 | port = 8888;
9 |
10 | function handleRequest(req, res) {
11 | res.writeHead(200, {"Content-type":"text/html"});
12 | res.write("Hello, World! This is Node.js app v99.");
13 |
14 | // Only show Vault files if the SHOW_VAULT KV is set to true in Consul
15 | if (fs.existsSync(vaultDir) && showVault && (showVault.toUpperCase() === "TRUE" || showVault === "1")) {
16 | files = fs.readdirSync(vaultDir);
17 |
18 | for (var i = 0; i < files.length; i++) {
19 | file = files[i];
20 |
21 | // Only show this file if included in the VAULT_FILES KV in Consul
22 | if (vaultFiles && vaultFiles.indexOf(file) > -1) {
23 | res.write(fs.readFileSync(vaultDir + file, "binary"));
24 | }
25 | }
26 | }
27 |
28 | res.end();
29 | }
30 |
31 | http.createServer(handleRequest).listen(port);
32 |
33 | console.log("Static file server running at\n => http://localhost:" + port);
34 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/upstart/consul.conf:
--------------------------------------------------------------------------------
1 | description "Consul"
2 |
3 | start on runlevel [2345]
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 |
8 | console log
9 |
10 | script
11 | if [ -f "/etc/service/consul" ]; then
12 | . /etc/service/consul
13 | fi
14 |
15 | # Make sure to use all our CPUs, because Consul can block a scheduler thread
16 | export GOMAXPROCS=`nproc`
17 |
18 | exec /usr/local/bin/consul agent \
19 | -config-dir="/etc/consul.d" \
20 | \$${CONSUL_FLAGS} \
21 | >>/var/log/consul.log 2>&1
22 | end script
23 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/upstart/consul_template.conf:
--------------------------------------------------------------------------------
1 | description "Consul Template"
2 |
3 | start on vagrant-ready or runlevel [2345]
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 |
8 | console log
9 |
10 | script
11 | exec /usr/local/bin/consul-template \
12 | -config "/etc/consul_template.d" \
13 | >>/var/log/consul_template.log 2>&1
14 | end script
15 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/upstart/haproxy.conf:
--------------------------------------------------------------------------------
1 | description "HAProxy"
2 |
3 | start on runlevel [2345]
4 | stop on runlevel [016]
5 |
6 | respawn
7 |
8 | env CONF=/etc/haproxy/haproxy.cfg
9 |
10 | post-stop script
11 | sleep 5
12 | end script
13 |
14 | pre-start script
15 | [ -r $CONF ]
16 | end script
17 |
18 | exec /usr/sbin/haproxy -f $CONF >> /var/log/haproxy_start.log 2>&1
19 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/upstart/nodejs.conf:
--------------------------------------------------------------------------------
1 | description "nodejs"
2 |
3 | start on vagrant-ready or runlevel [2345]
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 |
8 | script
9 | envconsul \
10 | -config /etc/envconsul.d \
11 | /usr/bin/node /application/server.js >> /var/log/nodejs.log 2>&1
12 | end script
13 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/upstart/vault.conf:
--------------------------------------------------------------------------------
1 | description "Vault"
2 |
3 | start on runlevel [2345]
4 | stop on runlevel [!2345]
5 |
6 | respawn
7 |
8 | console log
9 |
10 | script
11 | if [ -f "/etc/service/vault" ]; then
12 | . /etc/service/vault
13 | fi
14 |
15 | # Make sure to use all our CPUs, because Vault can block a scheduler thread
16 | export GOMAXPROCS=`nproc`
17 |
18 | exec /usr/local/bin/vault server \
19 | -config="/etc/vault.d/vault.hcl" \
20 | \$${VAULT_FLAGS} \
21 | >>/var/log/vault.log 2>&1
22 | end script
23 |
--------------------------------------------------------------------------------
/packer/scripts/ubuntu/vault.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | cd /tmp
5 |
6 | VAULTVERSION=0.6.2
7 | CONFIGDIR=/ops/$1
8 | SCRIPTSDIR=/ops/$2
9 | VAULTDOWNLOAD=https://releases.hashicorp.com/vault/${VAULTVERSION}/vault_${VAULTVERSION}_linux_amd64.zip
10 | VAULTCONFIGDIR=/etc/vault.d
11 | VAULTDIR=/opt/vault
12 | VAULTPOLICIES=$VAULTDIR/policies
13 | VAULTSCRIPTS=$VAULTDIR/scripts
14 |
15 | echo Fetching Vault...
16 | curl -L $VAULTDOWNLOAD > vault.zip
17 |
18 | echo Installing Vault...
19 | unzip vault.zip -d /usr/local/bin
20 | chmod 0755 /usr/local/bin/vault
21 | chown root:root /usr/local/bin/vault
22 |
23 | echo Creating Vault configuration...
24 | mkdir -p $VAULTCONFIGDIR
25 | chmod 755 $VAULTCONFIGDIR
26 | mkdir -p $VAULTPOLICIES
27 | chmod 755 $VAULTPOLICIES
28 | mkdir -p $VAULTSCRIPTS
29 | chmod 755 $VAULTSCRIPTS
30 |
31 | # Consul config
32 | cp $CONFIGDIR/consul/vault.json /etc/consul.d/vault.json
33 |
34 | # Vault config
35 | cp $CONFIGDIR/vault/vault.hcl $VAULTCONFIGDIR/vault.hcl
36 |
37 | # Vault setup scripts & policies
38 | cp -R $CONFIGDIR/vault/policies/* $VAULTPOLICIES/.
39 | cp -R $CONFIGDIR/vault/scripts/* $VAULTSCRIPTS/.
40 |
41 | # Upstart config
42 | cp $SCRIPTSDIR/upstart/vault.conf /etc/init/vault.conf
43 |
--------------------------------------------------------------------------------
/packer/scripts/windows/config/ec2_user_data.conf:
--------------------------------------------------------------------------------
1 |
2 | write-output "Starting instance userdata script"
3 |
4 | Set-ExecutionPolicy -ExecutionPolicy Bypass -Force
5 |
6 | # WinRM
7 | write-output "Setting up WinRM"
8 |
9 | & winrm quickconfig `-q
10 | & winrm set winrm/config '@{MaxTimeoutms="1800000"}'
11 | & winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="1024"}'
12 | & winrm set winrm/config/client/auth '@{Basic="true"}'
13 | & winrm set winrm/config/service/auth '@{Basic="true"}'
14 | & winrm set winrm/config/client '@{AllowUnencrypted="true"}'
15 | & winrm set winrm/config/service '@{AllowUnencrypted="true"}'
16 |
17 | # Firewall
18 | write-output "Setting up Firewall"
19 |
20 | netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public new remoteip=any
21 |
22 | write-output "Ending instance userdata script"
23 |
24 |
--------------------------------------------------------------------------------
/packer/scripts/windows/consul_client.json:
--------------------------------------------------------------------------------
1 | {
2 | "log_level": "INFO",
3 | "datacenter": "{{ datacenter }}",
4 | "data_dir": "C:\\opt\\consul\\data",
5 | "ui_dir": "C:\\opt\\consul\\ui",
6 | "client_addr": "0.0.0.0",
7 | "bind_addr": "0.0.0.0",
8 | "atlas_infrastructure": "{{ atlas_username }}/{{ atlas_environment }}",
9 | "atlas_join": true,
10 | "atlas_token": "{{ atlas_token }}",
11 | "node_name": "{{ node_name }}",
12 | "skip_leave_on_interrupt": true,
13 | "leave_on_terminate": true
14 | }
15 |
--------------------------------------------------------------------------------
/packer/scripts/windows/install_consul.ps1:
--------------------------------------------------------------------------------
1 | write-output "Creating Consul directories"
2 | foreach ($dir in @('log', 'data')) {
3 | New-Item -Path "C:\opt\consul\$dir" -ItemType Directory -Force
4 | }
5 |
6 | write-output "Creating nssm directory"
7 | New-Item -Path "C:\opt\nssm" -ItemType Directory -Force
8 |
9 | write-output "Setting urls"
10 | $nssmUrl = "http://nssm.cc/release/nssm-2.24.zip"
11 | $consulUrl = "https://releases.hashicorp.com/consul/0.6.0-rc1/consul_0.6.0-rc1_windows_amd64.zip"
12 | $uiUrl = "https://releases.hashicorp.com/consul/0.6.0-rc1/consul_0.6.0-rc1_web_ui.zip"
13 |
14 | write-output "Setting file paths"
15 | $nssmFilePath = "$($env:TEMP)\nssm.zip"
16 | $consulFilePath = "$($env:TEMP)\consul.zip"
17 | $uiFilePath = "$($env:TEMP)\consulwebui.zip"
18 |
19 | write-output "Downloading nssm"
20 | (New-Object System.Net.WebClient).DownloadFile($nssmUrl, $nssmFilePath)
21 | write-output "Downloading Consul"
22 | (New-Object System.Net.WebClient).DownloadFile($consulUrl, $consulFilePath)
23 | write-output "Downloading Consul Web UI"
24 | (New-Object System.Net.WebClient).DownloadFile($uiUrl, $uiFilePath)
25 |
26 | write-output "Creating shell object"
27 | $shell = New-Object -ComObject Shell.Application
28 |
29 | write-output "Setting namespaces"
30 | $nssmZip = $shell.NameSpace($nssmFilePath)
31 | $consulZip = $shell.NameSpace($consulFilePath)
32 | $uiZip = $shell.NameSpace($uiFilePath)
33 |
34 | write-output "Setting destinations"
35 | $nssmDestination = $shell.NameSpace("C:\opt\nssm")
36 | $consulDestination = $shell.NameSpace("C:\opt\consul")
37 | $uiDestination = $shell.NameSpace("C:\opt\consul")
38 |
39 | write-output "Setting copy flags"
40 | $copyFlags = 0x00
41 | $copyFlags += 0x04 # Hide progress dialogs
42 | $copyFlags += 0x10 # Overwrite existing files
43 |
44 | write-output "Copying nssm"
45 | $nssmDestination.CopyHere($nssmZip.Items(), $copyFlags)
46 | write-output "Copying Consul"
47 | $consulDestination.CopyHere($consulZip.Items(), $copyFlags)
48 | write-output "Copying Consul Web UI"
49 | $uiDestination.CopyHere($uiZip.Items(), $copyFlags)
50 |
51 | # Alternative way to unzip
52 | # cmd /c "7z e C:\install\consul\0.5.2_windows_386.zip -oC:\opt\consul > C:\install_log\consul.log"
53 |
54 | # Move nssm exe to /opt
55 | write-output "Moving nssm"
56 | Move-Item -Path "C:\opt\nssm\nssm-2.24\win32\nssm.exe" "C:\opt" -Force
57 | write-output "Moving Consul Web UI"
58 | Move-Item -Path "C:\opt\consul\dist" "C:\opt\consul\ui" -Force
59 |
60 | # Clean up
61 | write-output "Cleanup"
62 | #Remove-Item -Force -Path "C:\opt\nssm"
63 | Remove-Item -Force -Path $consulFilePath
64 | Remove-Item -Force -Path $uiFilePath
65 | Remove-Item -Force -Path $nssmFilePath
66 |
67 | # Create the Consul service and set its options
68 | write-output "Creating Consul service"
69 | C:\opt\nssm.exe install consul "C:\opt\consul\consul.exe" agent -config-dir "C:\etc\consul.d"
70 | write-output "Setting Consul options"
71 | C:\opt\nssm.exe set consul AppEnvironmentExtra "GOMAXPROCS=%NUMBER_OF_PROCESSORS%"
72 | C:\opt\nssm.exe set consul AppRotateFiles 1
73 | C:\opt\nssm.exe set consul AppRotateOnline 1
74 | C:\opt\nssm.exe set consul AppRotateBytes 10485760
75 | C:\opt\nssm.exe set consul AppStdout C:\opt\consul\log\consul.log
76 | C:\opt\nssm.exe set consul AppStderr C:\opt\consul\log\consul.log
77 |
78 | write-output "Stopping Consul service"
79 | Stop-Service consul -EA silentlycontinue
80 | Set-Service consul -StartupType Manual
81 |
82 | # Disable negative DNS response caching
83 | write-output "Disable negative DNS response caching"
84 | Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters -Name MaxNegativeCacheTtl -Value 0 -Type DWord
85 |
86 | # Allow Consul Serf traffic through the firewall
87 | write-output "Set firewall"
88 | netsh advfirewall firewall add rule name="Consul Serf LAN TCP" dir=in action=allow protocol=TCP localport=8301
89 | netsh advfirewall firewall add rule name="Consul Serf LAN UDP" dir=in action=allow protocol=UDP localport=8301
90 |
--------------------------------------------------------------------------------
/packer/scripts/windows/install_web_server.ps1:
--------------------------------------------------------------------------------
1 | # Silence progress bars in PowerShell, which can sometimes feed back strange
2 | # XML data to the Packer output.
3 | $ProgressPreference = "SilentlyContinue"
4 |
5 | Write-Output "Starting IIS Installation"
6 |
7 | Import-Module ServerManager
8 |
9 | # IIS
10 |
11 | # Only needed for .NET 3, .NET 4/4.5 is already installed.
12 | #Add-WindowsFeature NET-Framework-Core
13 |
14 | Add-WindowsFeature Web-Server -IncludeAllSubFeature
15 |
16 | Write-Output "Ended IIS Installation"
17 |
18 | # WebDeploy
19 | Write-Output "Starting WebDeploy Installation"
20 |
21 | # Install Microsoft Web Deploy to be able to deploy website packages easily
22 | $webDeployURL = "http://download.microsoft.com/download/D/4/4/D446D154-2232-49A1-9D64-F5A9429913A4/WebDeploy_amd64_en-US.msi"
23 | $filePath = "$($env:TEMP)\WebDeploy_amd64_en-US.msi"
24 |
25 | (New-Object System.Net.WebClient).DownloadFile($webDeployURL, $filePath)
26 |
27 | Start-Process -FilePath msiexec -ArgumentList /i, $filePath, /qn -Wait
28 |
29 | # Clean up
30 | Remove-Item -Force -Path $filePath
31 |
32 | Write-Output "Ended WebDeploy Installation"
33 |
--------------------------------------------------------------------------------
/packer/scripts/windows/install_windows_updates.ps1:
--------------------------------------------------------------------------------
1 | # Silence progress bars in PowerShell, which can sometimes feed back strange
2 | # XML data to the Packer output.
3 | $ProgressPreference = "SilentlyContinue"
4 |
5 | Write-Output "Starting PSWindowsUpdate Installation"
6 | # Install PSWindowsUpdate for scriptable Windows Updates
7 | $webDeployURL = "https://gallery.technet.microsoft.com/scriptcenter/2d191bcd-3308-4edd-9de2-88dff796b0bc/file/66095/1/PSWindowsUpdate_1.4.5.zip"
8 | $filePath = "$($env:TEMP)\PSWindowsUpdate.zip"
9 |
10 | (New-Object System.Net.WebClient).DownloadFile($webDeployURL, $filePath)
11 |
12 | # Older versions of Powershell do not have 'Expand Archive'
13 | # Use Shell.Application custom object to unzip
14 | # https://stackoverflow.com/questions/27768303/how-to-unzip-a-file-in-powershell
15 | $shell = New-Object -ComObject Shell.Application
16 | $zipFile = $shell.NameSpace($filePath)
17 | $destinationFolder = $shell.NameSpace("C:\Program Files\WindowsPowerShell\Modules")
18 |
19 | $copyFlags = 0x00
20 | $copyFlags += 0x04 # Hide progress dialogs
21 | $copyFlags += 0x10 # Overwrite existing files
22 |
23 | $destinationFolder.CopyHere($zipFile.Items(), $copyFlags)
24 | # Clean up
25 | Remove-Item -Force -Path $filePath
26 |
27 | Write-Output "Ended PSWindowsUpdate Installation"
28 |
29 | Write-Output "Starting Windows Update Installation"
30 |
31 | Try
32 | {
33 | Import-Module PSWindowsUpdate -ErrorAction Stop
34 | }
35 | Catch
36 | {
37 | Write-Error "Unable to install PSWindowsUpdate"
38 | exit 1
39 | }
40 |
41 | if (Test-Path C:\Windows\Temp\PSWindowsUpdate.log) {
42 | # Save old logs
43 | Rename-Item -Path C:\Windows\Temp\PSWindowsUpdate.log -NewName PSWindowsUpdate-$((Get-Date).Ticks).log
44 |
45 | # Uncomment the line below to delete old logs instead
46 | #Remove-Item -Path C:\Windows\Temp\PSWindowsUpdate.log
47 | }
48 |
49 | try {
50 | $updateCommand = {ipmo PSWindowsUpdate; Get-WUInstall -AcceptAll -IgnoreReboot | Out-File C:\Windows\Temp\PSWindowsUpdate.log}
51 | $TaskName = "PackerUpdate"
52 |
53 | $User = [Security.Principal.WindowsIdentity]::GetCurrent()
54 | $Scheduler = New-Object -ComObject Schedule.Service
55 |
56 | $Task = $Scheduler.NewTask(0)
57 |
58 | $RegistrationInfo = $Task.RegistrationInfo
59 | $RegistrationInfo.Description = $TaskName
60 | $RegistrationInfo.Author = $User.Name
61 |
62 | $Settings = $Task.Settings
63 | $Settings.Enabled = $True
64 | $Settings.StartWhenAvailable = $True
65 | $Settings.Hidden = $False
66 |
67 | $Action = $Task.Actions.Create(0)
68 | $Action.Path = "powershell"
69 | $Action.Arguments = "-Command $updateCommand"
70 |
71 | $Task.Principal.RunLevel = 1
72 |
73 | $Scheduler.Connect()
74 | $RootFolder = $Scheduler.GetFolder("\")
75 | $RootFolder.RegisterTaskDefinition($TaskName, $Task, 6, "SYSTEM", $Null, 1) | Out-Null
76 | $RootFolder.GetTask($TaskName).Run(0) | Out-Null
77 |
78 | Write-Output "The Windows Update log will be displayed below this message. No additional output indicates no updates were needed."
79 | do {
80 | sleep 1
81 | if ((Test-Path C:\Windows\Temp\PSWindowsUpdate.log) -and $script:reader -eq $null) {
82 | $script:stream = New-Object System.IO.FileStream -ArgumentList "C:\Windows\Temp\PSWindowsUpdate.log", "Open", "Read", "ReadWrite"
83 | $script:reader = New-Object System.IO.StreamReader $stream
84 | }
85 | if ($script:reader -ne $null) {
86 | $line = $Null
87 | do {$script:reader.ReadLine()
88 | $line = $script:reader.ReadLine()
89 | Write-Output $line
90 | } while ($line -ne $null)
91 | }
92 | } while ($Scheduler.GetRunningTasks(0) | Where-Object {$_.Name -eq $TaskName})
93 | } finally {
94 | $RootFolder.DeleteTask($TaskName,0)
95 | [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Scheduler) | Out-Null
96 | if ($script:reader -ne $null) {
97 | $script:reader.Close()
98 | $script:stream.Dispose()
99 | }
100 | }
101 | Write-Output "Ended Windows Update Installation"
102 |
--------------------------------------------------------------------------------
/packer/scripts/windows/set_ec2_config.ps1:
--------------------------------------------------------------------------------
1 | # This script will set up the system to request a password reset on the next boot.
2 | # The new password will be exposed via the EC2 console.
3 | # It will also make the system handle any new userdata passed in.
4 | $EC2SettingsFile="C:\\Program Files\\Amazon\\Ec2ConfigService\\Settings\\Config.xml"
5 | $xml = [xml](get-content $EC2SettingsFile)
6 | $xmlElement = $xml.get_DocumentElement()
7 | $xmlElementToModify = $xmlElement.Plugins
8 |
9 | foreach ($element in $xmlElementToModify.Plugin)
10 | {
11 | if ($element.name -eq "Ec2SetPassword")
12 | {
13 | $element.State="Enabled"
14 | }
15 | elseif ($element.name -eq "Ec2SetComputerName")
16 | {
17 | $element.State="Disabled"
18 | }
19 | elseif ($element.name -eq "Ec2HandleUserData")
20 | {
21 | $element.State="Enabled"
22 | }
23 | }
24 | $xml.Save($EC2SettingsFile)
25 |
26 | Write-Output "Set EC2 Machine Configuration"
27 |
--------------------------------------------------------------------------------
/setup/gen_cert.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | usage() {
6 | cat <
16 |
17 | Where DOMAIN is the domain to be deployed and COMPANY is your companies name.
18 |
19 | This will generate a self-signed site cert with the following subjectAltNames in the directory specified.
20 |
21 | * DOMAIN
22 | * vault.DOMAIN
23 | * vpn.DOMAIN
24 | * nodejs.DOMAIN
25 | * haproxy.DOMAIN
26 | * private.haproxy.DOMAIN
27 |
28 | And a self-signed cert for Consul/Vault with the following subjectAltNames in the directory specified.
29 |
30 | * DOMAIN
31 | * *.node.consul
32 | * *.service.consul
33 |
34 | * IP
35 | * 0.0.0.0
36 | * 127.0.0.1
37 | EOF
38 |
39 | exit 1
40 | }
41 |
42 | create_cert() {
43 | local base="$1"
44 | local domain="$2"
45 | local company="$3"
46 | local sslconf="$4"
47 |
48 | echo "Creating $base cert"
49 |
50 | local os="$(uname -s)"
51 | local csr="${base}.csr"
52 | local key="${base}.key"
53 | local crt="${base}.crt"
54 |
55 | # MinGW/MSYS issue: http://stackoverflow.com/questions/31506158/running-openssl-from-a-bash-script-on-windows-subject-does-not-start-with
56 | local subj="/C=US/ST=California/L=San Francisco/O=${company}/OU=${base}/CN=${domain}"
57 | if [[ "${os}" == "MINGW32"* || "${os}" == "MINGW64"* || "${os}" == "MSYS"* ]]; then
58 | subj="//C=US\ST=California\L=San Francisco\O=${company}\OU=${base}\CN=${domain}"
59 | fi
60 |
61 | openssl genrsa -out "$key" 2048
62 | openssl req -new -out "$csr" -key "$key" -subj "${subj}" -config "$sslconf"
63 | openssl x509 -req -days 3650 -in "$csr" -signkey "$key" -out "$crt" -extensions v3_req -extfile "$sslconf"
64 | }
65 |
66 | main() {
67 | local domain="$1"
68 | local company="$2"
69 |
70 | if ! which openssl > /dev/null; then
71 | echo
72 | echo "ERROR: The openssl executable was not found. This script requires openssl."
73 | echo
74 | usage
75 | fi
76 |
77 | if [[ -z "$domain" ]]; then
78 | echo
79 | echo "ERROR: Specify base domain as the first argument, e.g. mycompany.com"
80 | echo
81 | usage
82 | fi
83 |
84 | if [[ -z "$company" ]]; then
85 | echo
86 | echo "ERROR: Specify company as the third argument, e.g. HashiCorp"
87 | echo
88 | usage
89 | fi
90 |
91 | umask 077
92 |
93 | # Create a temporary build dir and make sure we clean it up. For
94 | # debugging, comment out the trap line.
95 | local builddir="$(mktemp -d /tmp/ssl-XXXXXX)"
96 | trap "rm -rf '$builddir'" INT TERM EXIT
97 |
98 | local sslconf="${builddir}/site_selfsigned_openssl.cnf"
99 | cp openssl.cnf "${sslconf}"
100 | (cat <> "$sslconf"
110 | create_cert "site" "$domain" "$company" "$sslconf"
111 |
112 | domain="consul"
113 | sslconf=${builddir}/vault_selfsigned_openssl.cnf
114 | cp openssl.cnf "${sslconf}"
115 | (cat <> "$sslconf"
123 | create_cert "vault" "$domain" "$company" "$sslconf"
124 | }
125 |
126 | main "$@"
127 |
128 |
--------------------------------------------------------------------------------
/setup/gen_key.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | set -e
4 |
5 | usage() {
6 | cat < [EXISTING KEY]
12 |
13 | Where ENVIRONMENT is the Atlas Environment specified in terraform.tfvars. There
14 | is an optional second argument you can include that uses an existing private
15 | key.
16 |
17 | This will generate a .pem private key and a .pub public key in the directory
18 | specified.
19 | EOF
20 | }
21 |
22 | main() {
23 | local environment="$1"
24 | local existingkey="$2"
25 | local key="$environment"
26 |
27 | if [[ -z "$environment" || $# -eq 0 ]]; then
28 | printf "ERROR: Specify environment as the second argument, e.g. aws-us-east-1-prod\n\n" >&2
29 | usage
30 | exit 1
31 | fi
32 |
33 | if [[ -s "$key.pem" && -s "$key.pub" && -z "$existingkey" ]]; then
34 | echo "Using existing key pair"
35 | return 0
36 | fi
37 |
38 | umask 277
39 |
40 | if [[ -z "$existingkey" ]]; then
41 | echo "No key pair exists and no private key arg was passed, generating new keys..."
42 | rm -f "${key}.pem"
43 | openssl genrsa -out "$key.pem" 1024
44 |
45 | elif [[ -s "$existingkey" ]]; then
46 | echo "Using private key $existingkey for key pair..."
47 | cp "$existingkey" "$key.pem"
48 |
49 | else
50 | echo "ERROR: Missing or empty existing private key $existingkey!"
51 | exit 1
52 | fi
53 |
54 | rm -f "${key}.pub"
55 | ssh-keygen -y -f "$key.pem" > "$key.pub"
56 | }
57 |
58 | main "$@"
59 |
60 |
--------------------------------------------------------------------------------
/setup/openssl.cnf:
--------------------------------------------------------------------------------
1 | # OpenSSL example configuration file.
2 | # This is mostly being used for generation of certificate requests.
3 | #
4 |
5 | # This definition stops the following lines choking if HOME isn't
6 | # defined.
7 | HOME = .
8 | RANDFILE = $ENV::HOME/.rnd
9 |
10 | # Extra OBJECT IDENTIFIER info:
11 | #oid_file = $ENV::HOME/.oid
12 | oid_section = new_oids
13 |
14 | # To use this configuration file with the "-extfile" option of the
15 | # "openssl x509" utility, name here the section containing the
16 | # X.509v3 extensions to use:
17 | # extensions =
18 | # (Alternatively, use a configuration file that has only
19 | # X.509v3 extensions in its main [= default] section.)
20 |
21 | [ new_oids ]
22 |
23 | # We can add new OIDs in here for use by 'ca' and 'req'.
24 | # Add a simple OID like this:
25 | # testoid1=1.2.3.4
26 | # Or use config file substitution like this:
27 | # testoid2=${testoid1}.5.6
28 |
29 | ####################################################################
30 | [ ca ]
31 | default_ca = CA_default # The default ca section
32 |
33 | ####################################################################
34 | [ CA_default ]
35 |
36 | dir = ./demoCA # Where everything is kept
37 | certs = $dir/certs # Where the issued certs are kept
38 | crl_dir = $dir/crl # Where the issued crl are kept
39 | database = $dir/index.txt # database index file.
40 | #unique_subject = no # Set to 'no' to allow creation of
41 | # several ctificates with same subject.
42 | new_certs_dir = $dir/newcerts # default place for new certs.
43 |
44 | certificate = $dir/cacert.pem # The CA certificate
45 | serial = $dir/serial # The current serial number
46 | crlnumber = $dir/crlnumber # the current crl number
47 | # must be commented out to leave a V1 CRL
48 | crl = $dir/crl.pem # The current CRL
49 | private_key = $dir/private/cakey.pem# The private key
50 | RANDFILE = $dir/private/.rand # private random number file
51 |
52 | x509_extensions = usr_cert # The extentions to add to the cert
53 |
54 | # Comment out the following two lines for the "traditional"
55 | # (and highly broken) format.
56 | name_opt = ca_default # Subject Name options
57 | cert_opt = ca_default # Certificate field options
58 |
59 | # Extension copying option: use with caution.
60 | copy_extensions = copy
61 |
62 | # Extensions to add to a CRL. Note: Netscape communicator chokes on V2 CRLs
63 | # so this is commented out by default to leave a V1 CRL.
64 | # crlnumber must also be commented out to leave a V1 CRL.
65 | # crl_extensions = crl_ext
66 |
67 | default_days = 365 # how long to certify for
68 | default_crl_days= 30 # how long before next CRL
69 | default_md = sha1 # which md to use.
70 | preserve = no # keep passed DN ordering
71 |
72 | # A few difference way of specifying how similar the request should look
73 | # For type CA, the listed attributes must be the same, and the optional
74 | # and supplied fields are just that :-)
75 | policy = policy_match
76 |
77 | # For the CA policy
78 | [ policy_match ]
79 | countryName = match
80 | stateOrProvinceName = match
81 | organizationName = match
82 | organizationalUnitName = optional
83 | commonName = supplied
84 | emailAddress = optional
85 |
86 | # For the 'anything' policy
87 | # At this point in time, you must list all acceptable 'object'
88 | # types.
89 | [ policy_anything ]
90 | countryName = optional
91 | stateOrProvinceName = optional
92 | localityName = optional
93 | organizationName = optional
94 | organizationalUnitName = optional
95 | commonName = supplied
96 | emailAddress = optional
97 |
98 | ####################################################################
99 | [ req ]
100 | default_bits = 1024
101 | default_keyfile = privkey.pem
102 | distinguished_name = req_distinguished_name
103 | attributes = req_attributes
104 | x509_extensions = v3_ca # The extentions to add to the self signed cert
105 |
106 | # Passwords for private keys if not present they will be prompted for
107 | # input_password = secret
108 | # output_password = secret
109 |
110 | # This sets a mask for permitted string types. There are several options.
111 | # default: PrintableString, T61String, BMPString.
112 | # pkix : PrintableString, BMPString.
113 | # utf8only: only UTF8Strings.
114 | # nombstr : PrintableString, T61String (no BMPStrings or UTF8Strings).
115 | # MASK:XXXX a literal mask value.
116 | # WARNING: current versions of Netscape crash on BMPStrings or UTF8Strings
117 | # so use this option with caution!
118 | string_mask = nombstr
119 |
120 | req_extensions = v3_req # The extensions to add to a certificate request
121 |
122 | [ req_distinguished_name ]
123 | countryName = Country Name (2 letter code)
124 | countryName_default = AU
125 | countryName_min = 2
126 | countryName_max = 2
127 |
128 | stateOrProvinceName = State or Province Name (full name)
129 | stateOrProvinceName_default = Some-State
130 |
131 | localityName = Locality Name (eg, city)
132 |
133 | 0.organizationName = Organization Name (eg, company)
134 | 0.organizationName_default = Internet Widgits Pty Ltd
135 |
136 | # we can do this but it is not needed normally :-)
137 | #1.organizationName = Second Organization Name (eg, company)
138 | #1.organizationName_default = World Wide Web Pty Ltd
139 |
140 | organizationalUnitName = Organizational Unit Name (eg, section)
141 | #organizationalUnitName_default =
142 |
143 | commonName = Common Name (e.g. server FQDN or YOUR name)
144 | commonName_max = 64
145 |
146 | emailAddress = Email Address
147 | emailAddress_max = 64
148 |
149 | # SET-ex3 = SET extension number 3
150 |
151 | [ req_attributes ]
152 | challengePassword = A challenge password
153 | challengePassword_min = 4
154 | challengePassword_max = 20
155 |
156 | unstructuredName = An optional company name
157 |
158 | [ usr_cert ]
159 |
160 | # These extensions are added when 'ca' signs a request.
161 |
162 | # This goes against PKIX guidelines but some CAs do it and some software
163 | # requires this to avoid interpreting an end user certificate as a CA.
164 |
165 | basicConstraints=CA:TRUE
166 |
167 | # Here are some examples of the usage of nsCertType. If it is omitted
168 | # the certificate can be used for anything *except* object signing.
169 |
170 | # This is OK for an SSL server.
171 | # nsCertType = server
172 |
173 | # For an object signing certificate this would be used.
174 | # nsCertType = objsign
175 |
176 | # For normal client use this is typical
177 | # nsCertType = client, email
178 |
179 | # and for everything including object signing:
180 | # nsCertType = client, email, objsign
181 |
182 | # This is typical in keyUsage for a client certificate.
183 | # keyUsage = nonRepudiation, digitalSignature, keyEncipherment
184 |
185 | # This will be displayed in Netscape's comment listbox.
186 | nsComment = "OpenSSL Generated Certificate"
187 |
188 | # PKIX recommendations harmless if included in all certificates.
189 | subjectKeyIdentifier=hash
190 | authorityKeyIdentifier=keyid,issuer
191 |
192 | # This stuff is for subjectAltName and issuerAltname.
193 | # Import the email address.
194 | # subjectAltName=email:copy
195 | # An alternative to produce certificates that aren't
196 | # deprecated according to PKIX.
197 | # subjectAltName=email:move
198 |
199 | # Copy subject details
200 | # issuerAltName=issuer:copy
201 |
202 | #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
203 | #nsBaseUrl
204 | #nsRevocationUrl
205 | #nsRenewalUrl
206 | #nsCaPolicyUrl
207 | #nsSslServerName
208 |
209 | [ v3_req ]
210 |
211 | # Extensions to add to a certificate request
212 |
213 | basicConstraints = CA:TRUE
214 | # keyUsage = nonRepudiation, digitalSignature, keyEncipherment
215 | subjectAltName = @alt_names
216 |
217 | [ v3_ca ]
218 |
219 |
220 | # Extensions for a typical CA
221 |
222 |
223 | # PKIX recommendation.
224 |
225 | subjectKeyIdentifier=hash
226 |
227 | authorityKeyIdentifier=keyid:always,issuer:always
228 |
229 | # This is what PKIX recommends but some broken software chokes on critical
230 | # extensions.
231 | #basicConstraints = critical,CA:true
232 | # So we do this instead.
233 | basicConstraints = CA:TRUE
234 |
235 | # Key usage: this is typical for a CA certificate. However since it will
236 | # prevent it being used as an test self-signed certificate it is best
237 | # left out by default.
238 | keyUsage = cRLSign, keyCertSign
239 |
240 | # Some might want this also
241 | # nsCertType = sslCA, emailCA
242 |
243 | # Include email address in subject alt name: another PKIX recommendation
244 | # subjectAltName=email:copy
245 | # Copy issuer details
246 | # issuerAltName=issuer:copy
247 |
248 | # DER hex encoding of an extension: beware experts only!
249 | # obj=DER:02:03
250 | # Where 'obj' is a standard or added object
251 | # You can even override a supported extension:
252 | # basicConstraints= critical, DER:30:03:01:01:FF
253 |
254 | [ crl_ext ]
255 |
256 | # CRL extensions.
257 | # Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
258 |
259 | # issuerAltName=issuer:copy
260 | authorityKeyIdentifier=keyid:always,issuer:always
261 |
262 | [ proxy_cert_ext ]
263 | # These extensions should be added when creating a proxy certificate
264 |
265 | # This goes against PKIX guidelines but some CAs do it and some software
266 | # requires this to avoid interpreting an end user certificate as a CA.
267 |
268 | basicConstraints=CA:FALSE
269 |
270 | # Here are some examples of the usage of nsCertType. If it is omitted
271 | # the certificate can be used for anything *except* object signing.
272 |
273 | # This is OK for an SSL server.
274 | # nsCertType = server
275 |
276 | # For an object signing certificate this would be used.
277 | # nsCertType = objsign
278 |
279 | # For normal client use this is typical
280 | # nsCertType = client, email
281 |
282 | # and for everything including object signing:
283 | # nsCertType = client, email, objsign
284 |
285 | # This is typical in keyUsage for a client certificate.
286 | # keyUsage = nonRepudiation, digitalSignature, keyEncipherment
287 |
288 | # This will be displayed in Netscape's comment listbox.
289 | nsComment = "OpenSSL Generated Certificate"
290 |
291 | # PKIX recommendations harmless if included in all certificates.
292 | subjectKeyIdentifier=hash
293 | authorityKeyIdentifier=keyid,issuer:always
294 |
295 | # This stuff is for subjectAltName and issuerAltname.
296 | # Import the email address.
297 | # subjectAltName=email:copy
298 | # An alternative to produce certificates that aren't
299 | # deprecated according to PKIX.
300 | # subjectAltName=email:move
301 |
302 | # Copy subject details
303 | # issuerAltName=issuer:copy
304 |
305 | #nsCaRevocationUrl = http://www.domain.dom/ca-crl.pem
306 | #nsBaseUrl
307 | #nsRevocationUrl
308 | #nsRenewalUrl
309 | #nsCaPolicyUrl
310 | #nsSslServerName
311 |
312 | # This really needs to be in place for it to be a proxy certificate.
313 | proxyCertInfo=critical,language:id-ppl-anyLanguage,pathlen:3,policy:foo
314 |
--------------------------------------------------------------------------------
/terraform/empty.tf:
--------------------------------------------------------------------------------
1 | /**
2 | * Intentionally empty. Required to allow Terraform push
3 | * commands from the top-level terraform directory.
4 | */
5 |
--------------------------------------------------------------------------------
/terraform/modules/aws/compute/compute.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all compute resources
3 | #--------------------------------------------------------------
4 |
5 | variable "name" { }
6 | variable "region" { }
7 | variable "vpc_id" { }
8 | variable "vpc_cidr" { }
9 | variable "key_name" { }
10 | variable "azs" { }
11 | variable "private_subnet_ids" { }
12 | variable "public_subnet_ids" { }
13 | variable "site_ssl_cert" { }
14 | variable "site_ssl_key" { }
15 | variable "vault_ssl_cert" { }
16 | variable "atlas_username" { }
17 | variable "atlas_environment" { }
18 | variable "atlas_aws_global" { }
19 | variable "atlas_token" { }
20 | variable "sub_domain" { }
21 | variable "route_zone_id" { }
22 | variable "vault_token" { default = "" }
23 |
24 | variable "haproxy_amis" { }
25 | variable "haproxy_node_count" { }
26 | variable "haproxy_instance_type" { }
27 |
28 | variable "nodejs_blue_ami" { }
29 | variable "nodejs_blue_node_count" { }
30 | variable "nodejs_blue_instance_type" { }
31 | variable "nodejs_blue_weight" { }
32 | variable "nodejs_green_ami" { }
33 | variable "nodejs_green_node_count" { }
34 | variable "nodejs_green_instance_type" { }
35 | variable "nodejs_green_weight" { }
36 |
37 | module "haproxy" {
38 | source = "./haproxy"
39 |
40 | name = "${var.name}-haproxy"
41 | vpc_id = "${var.vpc_id}"
42 | vpc_cidr = "${var.vpc_cidr}"
43 | key_name = "${var.key_name}"
44 | subnet_ids = "${var.public_subnet_ids}"
45 | atlas_username = "${var.atlas_username}"
46 | atlas_environment = "${var.atlas_environment}"
47 | atlas_token = "${var.atlas_token}"
48 | amis = "${var.haproxy_amis}"
49 | nodes = "${var.haproxy_node_count}"
50 | instance_type = "${var.haproxy_instance_type}"
51 | sub_domain = "${var.sub_domain}"
52 | route_zone_id = "${var.route_zone_id}"
53 | }
54 |
55 | module "nodejs" {
56 | source = "./nodejs"
57 |
58 | name = "${var.name}-nodejs"
59 | region = "${var.region}"
60 | vpc_id = "${var.vpc_id}"
61 | vpc_cidr = "${var.vpc_cidr}"
62 | key_name = "${var.key_name}"
63 | azs = "${var.azs}"
64 | private_subnet_ids = "${var.private_subnet_ids}"
65 | public_subnet_ids = "${var.public_subnet_ids}"
66 | site_ssl_cert = "${var.site_ssl_cert}"
67 | site_ssl_key = "${var.site_ssl_key}"
68 | vault_ssl_cert = "${var.vault_ssl_cert}"
69 | atlas_username = "${var.atlas_username}"
70 | atlas_environment = "${var.atlas_environment}"
71 | atlas_aws_global = "${var.atlas_aws_global}"
72 | atlas_token = "${var.atlas_token}"
73 | blue_weight = "${var.nodejs_blue_weight}"
74 | blue_ami = "${var.nodejs_blue_ami}"
75 | blue_nodes = "${var.nodejs_blue_node_count}"
76 | blue_instance_type = "${var.nodejs_blue_instance_type}"
77 | green_ami = "${var.nodejs_green_ami}"
78 | green_nodes = "${var.nodejs_green_node_count}"
79 | green_instance_type = "${var.nodejs_green_instance_type}"
80 | green_weight = "${var.nodejs_green_weight}"
81 | sub_domain = "${var.sub_domain}"
82 | route_zone_id = "${var.route_zone_id}"
83 | vault_token = "${var.vault_token}"
84 | }
85 |
86 | output "haproxy_private_ips" { value = "${module.haproxy.private_ips}" }
87 | output "haproxy_public_ips" { value = "${module.haproxy.public_ips}" }
88 | output "haproxy_private_fqdn" { value = "${module.haproxy.private_fqdn}" }
89 | output "haproxy_public_fqdn" { value = "${module.haproxy.public_fqdn}" }
90 |
91 | output "nodejs_blue_elb_zone_id" { value = "${module.nodejs.blue_elb_zone_id}" }
92 | output "nodejs_blue_private_fqdn" { value = "${module.nodejs.blue_private_fqdn}" }
93 | output "nodejs_blue_elb_dns" { value = "${module.nodejs.blue_elb_dns}" }
94 | output "nodejs_green_elb_zone_id" { value = "${module.nodejs.green_elb_zone_id}" }
95 | output "nodejs_green_private_fqdn" { value = "${module.nodejs.green_private_fqdn}" }
96 | output "nodejs_green_elb_dns" { value = "${module.nodejs.green_elb_dns}" }
97 |
--------------------------------------------------------------------------------
/terraform/modules/aws/compute/haproxy/haproxy.sh.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | NODENAME="${node_name}-$(hostname)"
5 |
6 | echo "Configuring Consul..."
7 |
8 | sed -i -- "s/{{ atlas_username }}/${atlas_username}/g" /etc/consul.d/base.json
9 | sed -i -- "s/{{ atlas_environment }}/${atlas_environment}/g" /etc/consul.d/base.json
10 | sed -i -- "s/{{ atlas_token }}/${atlas_token}/g" /etc/consul.d/base.json
11 | sed -i -- "s/{{ datacenter }}/${atlas_environment}/g" /etc/consul.d/base.json
12 | sed -i -- "s/{{ node_name }}/$NODENAME/g" /etc/consul.d/base.json
13 |
14 | service consul restart
15 |
16 | exit 0
17 |
--------------------------------------------------------------------------------
/terraform/modules/aws/compute/haproxy/haproxy.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all resources necessary for HAProxy
3 | #--------------------------------------------------------------
4 |
5 | variable "name" { default = "haproxy" }
6 | variable "vpc_id" { }
7 | variable "vpc_cidr" { }
8 | variable "key_name" { }
9 | variable "subnet_ids" { }
10 | variable "atlas_username" { }
11 | variable "atlas_environment" { }
12 | variable "atlas_token" { }
13 | variable "amis" { }
14 | variable "nodes" { }
15 | variable "instance_type" { }
16 | variable "sub_domain" { }
17 | variable "route_zone_id" { }
18 |
19 | resource "aws_security_group" "haproxy" {
20 | name = "${var.name}"
21 | vpc_id = "${var.vpc_id}"
22 | description = "HAProxy security group"
23 |
24 | tags {
25 | Name = "${var.name}"
26 | Demo = "true"
27 | }
28 | lifecycle { create_before_destroy = true }
29 |
30 | ingress {
31 | protocol = "tcp"
32 | from_port = 80
33 | to_port = 80
34 | cidr_blocks = ["0.0.0.0/0"]
35 | }
36 |
37 | ingress {
38 | protocol = "tcp"
39 | from_port = 443
40 | to_port = 443
41 | cidr_blocks = ["0.0.0.0/0"]
42 | }
43 |
44 | ingress {
45 | protocol = -1
46 | from_port = 0
47 | to_port = 0
48 | cidr_blocks = ["${var.vpc_cidr}"]
49 | }
50 |
51 | egress {
52 | protocol = -1
53 | from_port = 0
54 | to_port = 0
55 | cidr_blocks = ["0.0.0.0/0"]
56 | }
57 | }
58 |
59 | resource "template_file" "user_data" {
60 | template = "${path.module}/haproxy.sh.tpl"
61 | count = "${var.nodes}"
62 |
63 | lifecycle { create_before_destroy = true }
64 |
65 | vars {
66 | atlas_username = "${var.atlas_username}"
67 | atlas_environment = "${var.atlas_environment}"
68 | atlas_token = "${var.atlas_token}"
69 | node_name = "${var.name}-${count.index+1}"
70 | }
71 | }
72 |
73 | resource "aws_instance" "haproxy" {
74 | ami = "${element(split(",", var.amis), count.index)}"
75 | count = "${var.nodes}"
76 | instance_type = "${var.instance_type}"
77 | key_name = "${var.key_name}"
78 | subnet_id = "${element(split(",", var.subnet_ids), count.index)}"
79 | user_data = "${element(template_file.user_data.*.rendered, count.index)}"
80 |
81 | vpc_security_group_ids = ["${aws_security_group.haproxy.id}"]
82 |
83 | tags { Name = "${var.name}" }
84 | lifecycle { create_before_destroy = true }
85 | }
86 |
87 | resource "aws_route53_record" "haproxy_public" {
88 | zone_id = "${var.route_zone_id}"
89 | name = "haproxy.${var.sub_domain}"
90 | type = "A"
91 | ttl = "300"
92 | records = ["${aws_instance.haproxy.*.public_ip}"]
93 | }
94 |
95 | resource "aws_route53_record" "haproxy_private" {
96 | zone_id = "${var.route_zone_id}"
97 | name = "private.haproxy.${var.sub_domain}"
98 | type = "A"
99 | ttl = "300"
100 | records = ["${aws_instance.haproxy.*.private_ip}"]
101 | }
102 |
103 | output "public_ips" { value = "${join(",", aws_instance.haproxy.*.public_ip)}" }
104 | output "private_ips" { value = "${join(",", aws_instance.haproxy.*.private_ip)}" }
105 | output "public_fqdn" { value = "${aws_route53_record.haproxy_public.fqdn}" }
106 | output "private_fqdn" { value = "${aws_route53_record.haproxy_private.fqdn}" }
107 |
--------------------------------------------------------------------------------
/terraform/modules/aws/compute/nodejs/nodejs.sh.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | NAME="${node_name}-$(hostname)"
4 | SANITIZEDNAME=$${NAME//-/_} # Replace hyphens with underscores, Consul Template doesn't like hyphens
5 | SSLCERTDIR=/usr/local/etc
6 | SSLSITECERTPATH=$SSLCERTDIR/site.crt
7 | SSLVAULTCERTPATH=$SSLCERTDIR/vault.crt
8 | NODEJSPOLICYNAME=${vault_policy}
9 | NODEJSPOLICY=/opt/vault/policies/$NODEJSPOLICYNAME.json
10 | GENERICSECRETPATH=secret/$NODEJSPOLICYNAME/$SANITIZEDNAME
11 | GENERICSECRETKEY=secret_key
12 | GENERICSECRET="This is a secret stored in Vault for $NAME using the $NODEJSPOLICYNAME policy"
13 | AWSROLEPOLICY=/opt/vault/policies/aws_$NODEJSPOLICYNAME.json
14 | AWSROLEPATH=aws/roles/$NODEJSPOLICYNAME
15 | AWSCREDPATH=aws/creds/$NODEJSPOLICYNAME
16 | VAULT=https://vault.service.consul:8200
17 | CONSUL=http://127.0.0.1:8500
18 | LOGS=/var/log/user_data.log
19 |
20 | logger() {
21 | DT=$(date '+%Y/%m/%d %H:%M:%S')
22 | echo "$DT nodejs.sh: $1" | sudo tee -a $LOGS > /dev/null
23 | }
24 |
25 | preparepolicy() {
26 | FILEPATH=$1
27 | PARAMETER=$2
28 |
29 | sed -i -- 's/\"/\\"/g' $FILEPATH
30 | sed -i '1s/^/{"{{ parameter }}": "/' $FILEPATH
31 | sed -i '$s|$|"}|' $FILEPATH
32 | sed -i -- "s/{{ parameter }}/$PARAMETER/g" $FILEPATH
33 | }
34 |
35 | logger "Configuring Consul..."
36 |
37 | sed -i -- "s/{{ atlas_username }}/${atlas_username}/g" /etc/consul.d/base.json
38 | sed -i -- "s/{{ atlas_environment }}/${atlas_environment}/g" /etc/consul.d/base.json
39 | sed -i -- "s/{{ atlas_token }}/${atlas_token}/g" /etc/consul.d/base.json
40 | sed -i -- "s/{{ datacenter }}/${atlas_environment}/g" /etc/consul.d/base.json
41 | sed -i -- "s/{{ node_name }}/$NAME/g" /etc/consul.d/base.json
42 | sed -i -- "s/{{ deploy }}/${deploy}/g" /etc/consul.d/nodejs.json
43 |
44 | service consul restart
45 |
46 | logger "Updating certs..."
47 |
48 | mkdir -p $SSLCERTDIR
49 | chmod -R 0600 $SSLCERTDIR
50 |
51 | echo "${site_ssl_cert}" | sudo tee $SSLSITECERTPATH > /dev/null
52 | echo "${vault_ssl_cert}" | sudo tee $SSLVAULTCERTPATH > /dev/null
53 |
54 | cp $SSLSITECERTPATH /usr/local/share/ca-certificates/.
55 | cp $SSLVAULTCERTPATH /usr/local/share/ca-certificates/.
56 | update-ca-certificates
57 |
58 | logger "Checking for Vault token..."
59 |
60 | if [[ "x${vault_token}" == "x" || "${vault_token}" == "REPLACE_IN_ATLAS" ]]; then
61 | logger "Setting consul_template retry to 1h and stopping service."
62 | sed -i -- "s/retry = \"5s\"/retry = \"1h\"/g" /etc/consul_template.d/base.hcl
63 | service consul_template stop
64 |
65 | logger "Setting envconsul retry to 1h."
66 | sed -i -- "s/retry = \"5s\"/retry = \"1h\"/g" /etc/envconsul.d/base.hcl
67 | service nodejs restart
68 |
69 | logger "Exiting without setting Vault policy due to no Vault token."
70 |
71 | exit 1
72 | fi
73 |
74 | logger "Waiting for Vault to become ready..."
75 |
76 | SLEEPTIME=1
77 | cget() { curl -sf "$VAULT/v1/sys/health?standbyok"; }
78 |
79 | while ! cget | grep "\"initialized\":true,\"sealed\":false"; do
80 | if [ $SLEEPTIME -gt 15 ]; then
81 | logger "ERROR: VAULT SETUP NOT COMPLETE! Manual intervention required."
82 | exit 2
83 | else
84 | logger "Blocking until Vault is ready, waiting $SLEEPTIME second(s)..."
85 | sleep $SLEEPTIME
86 | SLEEPTIME=$((SLEEPTIME + 1))
87 | fi
88 | done
89 |
90 | logger "--- Vault Policy Setup ---"
91 | logger "Preparing Vault $NODEJSPOLICYNAME policy..."
92 |
93 | preparepolicy $NODEJSPOLICY rules
94 |
95 | logger "Generating Vault $NODEJSPOLICYNAME policy..."
96 |
97 | logger $(
98 | curl \
99 | -H "X-Vault-Token: ${vault_token}" \
100 | -H "Content-Type: application/json" \
101 | -LX PUT \
102 | -d @$NODEJSPOLICY \
103 | $VAULT/v1/sys/policy/$NODEJSPOLICYNAME
104 | )
105 |
106 | logger "Generating Vault $NODEJSPOLICYNAME token..."
107 |
108 | (cat < /tmp/$NODEJSPOLICYNAME-token.json
119 |
120 | TOKEN=$(
121 | curl \
122 | -H "X-Vault-Token: ${vault_token}" \
123 | -H "Content-Type: application/json" \
124 | -LX POST \
125 | -d @/tmp/$NODEJSPOLICYNAME-token.json \
126 | $VAULT/v1/auth/token/create \
127 | | grep -Po '"client_token":.*?[^\\]",' | awk -F\" '{print $4}'
128 | )
129 |
130 | rm -rf /tmp/$NODEJSPOLICYNAME-token.json
131 |
132 | SSLVAULTCERTPATH=$${SSLVAULTCERTPATH//\//\\/}
133 |
134 | logger "Update /etc/consul_template.d/nodejs.hcl with vault_token and cert_path"
135 |
136 | sed -i -- "s/{{ vault_token }}/$TOKEN/g" /etc/consul_template.d/nodejs.hcl
137 | sed -i -- "s/{{ cert_path }}/$SSLVAULTCERTPATH/g" /etc/consul_template.d/nodejs.hcl
138 |
139 | logger "Update /etc/envconsul.d/nodejs.hcl with vault_token and cert_path"
140 |
141 | sed -i -- "s/{{ vault_token }}/$TOKEN/g" /etc/envconsul.d/nodejs.hcl
142 | sed -i -- "s/{{ cert_path }}/$SSLVAULTCERTPATH/g" /etc/envconsul.d/nodejs.hcl
143 |
144 | logger "--- Generic Secret Backend Setup ---"
145 | logger "Writing $NAME secret..."
146 |
147 | logger $(
148 | curl \
149 | -H "X-Vault-Token: ${vault_token}" \
150 | -H "Content-Type: application/json" \
151 | -LX POST \
152 | -d "{\"$GENERICSECRETKEY\": \"$GENERICSECRET\", \"ttl\": \"1m\"}" \
153 | $VAULT/v1/$GENERICSECRETPATH
154 | )
155 |
156 | GENERICSECRETPATH=$${GENERICSECRETPATH//\//\\/}
157 |
158 | logger "Update /opt/consul_template/vault_generic.ctmpl"
159 |
160 | sed -i -- "s/{{ node_name }}/$NAME/g" /opt/consul_template/vault_generic.ctmpl
161 | sed -i -- "s/{{ secret_path }}/$GENERICSECRETPATH/g" /opt/consul_template/vault_generic.ctmpl
162 | sed -i -- "s/{{ secret_key }}/$GENERICSECRETKEY/g" /opt/consul_template/vault_generic.ctmpl
163 |
164 | logger "Update /etc/envconsul.d/nodejs.hcl with secret_path"
165 |
166 | sed -i -- "s/{{ secret_path }}/$GENERICSECRETPATH/g" /etc/envconsul.d/nodejs.hcl
167 |
168 | logger "--- AWS Backend Setup ---"
169 | logger "Checking if AWS backend is mounted..."
170 |
171 | AWSMOUNTED=$(
172 | curl \
173 | -H "X-Vault-Token: ${vault_token}" \
174 | -LX GET \
175 | $VAULT/v1/sys/mounts \
176 | | grep -c "aws"
177 | )
178 |
179 | echo "AWS backend mount status: $AWSMOUNTED"
180 |
181 | if [ $AWSMOUNTED -eq 0 ]; then
182 | logger "Mounting AWS backend..."
183 |
184 | logger $(
185 | curl \
186 | -H "X-Vault-Token: ${vault_token}" \
187 | -H "Content-Type: application/json" \
188 | -LX POST \
189 | -d "{\"type\":\"aws\", \"description\":\"dynamic aws iam credentials\"}" \
190 | $VAULT/v1/sys/mounts/aws
191 | )
192 |
193 | logger "AWS backend mounted."
194 | else
195 | logger "AWS backend already mounted."
196 | fi
197 |
198 | logger "Writing root IAM credentials..."
199 |
200 | logger $(
201 | curl \
202 | -H "X-Vault-Token: ${vault_token}" \
203 | -H "Content-Type: application/json" \
204 | -LX POST \
205 | -d "{\"access_key\":\"${aws_access_id}\", \"secret_key\":\"${aws_secret_key}\", \"region\":\"${aws_region}\"}" \
206 | $VAULT/v1/aws/config/root
207 | )
208 |
209 | logger "Writing lease settings for generated credentials..."
210 |
211 | logger $(
212 | curl \
213 | -H "X-Vault-Token: ${vault_token}" \
214 | -H "Content-Type: application/json" \
215 | -LX POST \
216 | -d "{\"lease\": \"1m\", \"lease_max\": \"2m\"}" \
217 | $VAULT/v1/aws/config/lease
218 | )
219 |
220 | logger "Preparing Vault AWS $NODEJSPOLICYNAME policy..."
221 |
222 | preparepolicy $AWSROLEPOLICY policy
223 |
224 | logger "Generating Vault AWS $NODEJSPOLICYNAME role..."
225 |
226 | logger $(
227 | curl \
228 | -H "X-Vault-Token: ${vault_token}" \
229 | -H "Content-Type: application/json" \
230 | -LX PUT \
231 | -d @$AWSROLEPOLICY \
232 | $VAULT/v1/$AWSROLEPATH
233 | )
234 |
235 | logger "Update /opt/consul_template/vault_aws.ctmpl"
236 |
237 | AWSCREDPATH=$${AWSCREDPATH//\//\\/}
238 |
239 | sed -i -- "s/{{ node_name }}/$NAME/g" /opt/consul_template/vault_aws.ctmpl
240 | sed -i -- "s/{{ cred_path }}/$AWSCREDPATH/g" /opt/consul_template/vault_aws.ctmpl
241 |
242 | service nodejs restart
243 | service consul_template restart
244 |
245 | logger "Create Consul KV envconsul watches to display Vault secret"
246 |
247 | curl -X PUT -d '1' $CONSUL/v1/kv/service/nodejs/show_vault
248 | curl -X PUT -d 'aws.html,generic.html' $CONSUL/v1/kv/service/nodejs/vault_files
249 |
250 | logger "Node.js configuration complete"
251 |
252 | exit 0
253 |
--------------------------------------------------------------------------------
/terraform/modules/aws/compute/nodejs/nodejs.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all resources necessary for the
3 | # Node.js application
4 | #--------------------------------------------------------------
5 |
6 | variable "name" { default = "nodejs" }
7 | variable "region" { }
8 | variable "vpc_id" { }
9 | variable "vpc_cidr" { }
10 | variable "key_name" { }
11 | variable "azs" { }
12 | variable "private_subnet_ids" { }
13 | variable "public_subnet_ids" { }
14 | variable "site_ssl_cert" { }
15 | variable "site_ssl_key" { }
16 | variable "vault_ssl_cert" { }
17 | variable "atlas_username" { }
18 | variable "atlas_environment" { }
19 | variable "atlas_aws_global" { }
20 | variable "atlas_token" { }
21 | variable "blue_ami" { }
22 | variable "blue_nodes" { }
23 | variable "blue_instance_type" { }
24 | variable "blue_weight" { }
25 | variable "green_ami" { }
26 | variable "green_nodes" { }
27 | variable "green_instance_type" { }
28 | variable "green_weight" { }
29 | variable "sub_domain" { }
30 | variable "route_zone_id" { }
31 | variable "vault_token" { default = "" }
32 | variable "vault_policy" { default = "nodejs" }
33 |
34 | resource "aws_security_group" "elb" {
35 | name = "${var.name}.elb"
36 | vpc_id = "${var.vpc_id}"
37 | description = "Security group for Nodejs ELB"
38 |
39 | tags { Name = "${var.name}-elb" }
40 | lifecycle { create_before_destroy = true }
41 |
42 | ingress {
43 | protocol = "tcp"
44 | from_port = 80
45 | to_port = 80
46 | cidr_blocks = ["0.0.0.0/0"]
47 | }
48 |
49 | ingress {
50 | protocol = "tcp"
51 | from_port = 443
52 | to_port = 443
53 | cidr_blocks = ["0.0.0.0/0"]
54 | }
55 |
56 | egress {
57 | protocol = -1
58 | from_port = 0
59 | to_port = 0
60 | cidr_blocks = ["0.0.0.0/0"]
61 | }
62 | }
63 |
64 | resource "aws_iam_server_certificate" "nodejs" {
65 | name = "${var.region}-${var.name}"
66 | certificate_body = "${var.site_ssl_cert}"
67 | private_key = "${var.site_ssl_key}"
68 |
69 | lifecycle { create_before_destroy = true }
70 |
71 | provisioner "local-exec" {
72 | command = < /dev/null
25 | echo "${ssl_key}" | sudo tee $SSLKEYPATH > /dev/null
26 |
27 | cp "$SSLCERTPATH" /usr/local/share/ca-certificates/.
28 | update-ca-certificates
29 |
30 | echo "Configuring Vault..."
31 |
32 | SSLCERTPATH=$${SSLCERTPATH//\//\\/}
33 | SSLKEYPATH=$${SSLKEYPATH//\//\\/}
34 |
35 | sed -i -- "s/{{ node_name }}/${node_name}/g" /etc/vault.d/vault.hcl
36 | sed -i -- "s/{{ atlas_username }}/${atlas_username}/g" /etc/vault.d/vault.hcl
37 | sed -i -- "s/{{ atlas_environment }}/${atlas_environment}/g" /etc/vault.d/vault.hcl
38 | sed -i -- "s/{{ atlas_token }}/${atlas_token}/g" /etc/vault.d/vault.hcl
39 | sed -i -- "s/{{ tls_cert_file }}/$SSLCERTPATH/g" /etc/vault.d/vault.hcl
40 | sed -i -- "s/{{ tls_key_file }}/$SSLKEYPATH/g" /etc/vault.d/vault.hcl
41 | sed -i -- "s/{{ datacenter }}/${atlas_environment}/g" /etc/vault.d/vault.hcl
42 |
43 | service vault restart
44 |
45 | exit 0
46 |
--------------------------------------------------------------------------------
/terraform/modules/aws/data/vault/vault.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all resources necessary for Vault
3 | #--------------------------------------------------------------
4 |
5 | variable "name" { default = "vault" }
6 | variable "region" { }
7 | variable "vpc_id" { }
8 | variable "vpc_cidr" { }
9 | variable "private_subnet_ids" { }
10 | variable "public_subnet_ids" { }
11 | variable "ssl_cert" { }
12 | variable "ssl_key" { }
13 | variable "key_name" { }
14 | variable "atlas_username" { }
15 | variable "atlas_environment" { }
16 | variable "atlas_token" { }
17 | variable "amis" { }
18 | variable "nodes" { }
19 | variable "instance_type" { }
20 | variable "sub_domain" { }
21 | variable "route_zone_id" { }
22 |
23 | resource "aws_security_group" "vault" {
24 | name = "${var.name}"
25 | vpc_id = "${var.vpc_id}"
26 | description = "Security group for Vault"
27 |
28 | tags { Name = "${var.name}" }
29 | lifecycle { create_before_destroy = true }
30 |
31 | ingress {
32 | protocol = -1
33 | from_port = 0
34 | to_port = 0
35 | cidr_blocks = ["${var.vpc_cidr}"]
36 | }
37 |
38 | egress {
39 | protocol = -1
40 | from_port = 0
41 | to_port = 0
42 | cidr_blocks = ["0.0.0.0/0"]
43 | }
44 | }
45 |
46 | resource "template_file" "user_data" {
47 | count = "${var.nodes}"
48 | template = "${path.module}/vault.sh.tpl"
49 |
50 | lifecycle { create_before_destroy = true }
51 |
52 | vars {
53 | atlas_username = "${var.atlas_username}"
54 | atlas_environment = "${var.atlas_environment}"
55 | atlas_token = "${var.atlas_token}"
56 | node_name = "${var.name}-${count.index+1}"
57 | ssl_cert = "${var.ssl_cert}"
58 | ssl_key = "${var.ssl_key}"
59 | }
60 | }
61 |
62 | resource "aws_instance" "vault" {
63 | count = "${var.nodes}"
64 | ami = "${element(split(",", var.amis), count.index)}"
65 | instance_type = "${var.instance_type}"
66 | key_name = "${var.key_name}"
67 | subnet_id = "${element(split(",", var.private_subnet_ids), count.index)}"
68 | user_data = "${element(template_file.user_data.*.rendered, count.index)}"
69 |
70 | vpc_security_group_ids = ["${aws_security_group.vault.id}"]
71 |
72 | tags { Name = "${var.name}.${count.index+1}" }
73 | }
74 |
75 | resource "aws_security_group" "elb" {
76 | name = "${var.name}-elb"
77 | vpc_id = "${var.vpc_id}"
78 | description = "Security group for Vault ELB"
79 |
80 | tags { Name = "${var.name}-elb" }
81 |
82 | ingress {
83 | protocol = "tcp"
84 | from_port = 80
85 | to_port = 80
86 | cidr_blocks = ["${var.vpc_cidr}"]
87 | }
88 |
89 | ingress {
90 | protocol = "tcp"
91 | from_port = 443
92 | to_port = 443
93 | cidr_blocks = ["${var.vpc_cidr}"]
94 | }
95 |
96 | egress {
97 | protocol = -1
98 | from_port = 0
99 | to_port = 0
100 | cidr_blocks = ["0.0.0.0/0"]
101 | }
102 | }
103 |
104 | resource "aws_iam_server_certificate" "vault" {
105 | name = "${var.region}-${var.name}"
106 | certificate_body = "${var.ssl_cert}"
107 | private_key = "${var.ssl_key}"
108 |
109 | provisioner "local-exec" {
110 | command = <
72 | # https://docs.openvpn.net/how-to-tutorialsguides/virtual-platforms/amazon-ec2-appliance-ami-quick-start-guide/
73 | user_data = < /dev/null",
90 | "echo '${var.ssl_key}' | sudo tee /usr/local/openvpn_as/etc/web-ssl/server.key > /dev/null",
91 | # Set VPN network info
92 | "sudo /usr/local/openvpn_as/scripts/sacli -k vpn.daemon.0.client.network -v ${element(split("/", var.vpn_cidr), 0)} ConfigPut",
93 | "sudo /usr/local/openvpn_as/scripts/sacli -k vpn.daemon.0.client.netmask_bits -v ${element(split("/", var.vpn_cidr), 1)} ConfigPut",
94 | # Do a warm restart so the config is picked up
95 | "sudo /usr/local/openvpn_as/scripts/sacli start",
96 | ]
97 | }
98 | }
99 |
100 | resource "aws_route53_record" "openvpn" {
101 | zone_id = "${var.route_zone_id}"
102 | name = "vpn.${var.sub_domain}"
103 | type = "A"
104 | ttl = "300"
105 | records = ["${aws_instance.openvpn.public_ip}"]
106 | }
107 |
108 | output "private_ip" { value = "${aws_instance.openvpn.private_ip}" }
109 | output "public_ip" { value = "${aws_instance.openvpn.public_ip}" }
110 | output "public_fqdn" { value = "${aws_route53_record.openvpn.fqdn}" }
111 |
--------------------------------------------------------------------------------
/terraform/modules/aws/network/private_subnet/private_subnet.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all resources necessary for a private
3 | # subnet
4 | #--------------------------------------------------------------
5 |
6 | variable "name" { default = "private"}
7 | variable "vpc_id" { }
8 | variable "cidrs" { }
9 | variable "azs" { }
10 | variable "nat_gateway_ids" { }
11 |
12 | resource "aws_subnet" "private" {
13 | vpc_id = "${var.vpc_id}"
14 | cidr_block = "${element(split(",", var.cidrs), count.index)}"
15 | availability_zone = "${element(split(",", var.azs), count.index)}"
16 | count = "${length(split(",", var.cidrs))}"
17 |
18 | tags { Name = "${var.name}.${element(split(",", var.azs), count.index)}" }
19 | lifecycle { create_before_destroy = true }
20 | }
21 |
22 | resource "aws_route_table" "private" {
23 | vpc_id = "${var.vpc_id}"
24 | count = "${length(split(",", var.cidrs))}"
25 |
26 | route {
27 | cidr_block = "0.0.0.0/0"
28 | nat_gateway_id = "${element(split(",", var.nat_gateway_ids), count.index)}"
29 | }
30 |
31 | tags { Name = "${var.name}.${element(split(",", var.azs), count.index)}" }
32 | lifecycle { create_before_destroy = true }
33 | }
34 |
35 | resource "aws_route_table_association" "private" {
36 | count = "${length(split(",", var.cidrs))}"
37 | subnet_id = "${element(aws_subnet.private.*.id, count.index)}"
38 | route_table_id = "${element(aws_route_table.private.*.id, count.index)}"
39 |
40 | lifecycle { create_before_destroy = true }
41 | }
42 |
43 | output "subnet_ids" { value = "${join(",", aws_subnet.private.*.id)}" }
44 |
--------------------------------------------------------------------------------
/terraform/modules/aws/network/public_subnet/public_subnet.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all resources necessary for a public
3 | # subnet
4 | #--------------------------------------------------------------
5 |
6 | variable "name" { default = "public" }
7 | variable "vpc_id" { }
8 | variable "cidrs" { }
9 | variable "azs" { }
10 |
11 | resource "aws_internet_gateway" "public" {
12 | vpc_id = "${var.vpc_id}"
13 |
14 | tags { Name = "${var.name}" }
15 | }
16 |
17 | resource "aws_subnet" "public" {
18 | vpc_id = "${var.vpc_id}"
19 | cidr_block = "${element(split(",", var.cidrs), count.index)}"
20 | availability_zone = "${element(split(",", var.azs), count.index)}"
21 | count = "${length(split(",", var.cidrs))}"
22 |
23 | tags { Name = "${var.name}.${element(split(",", var.azs), count.index)}" }
24 | lifecycle { create_before_destroy = true }
25 |
26 | map_public_ip_on_launch = true
27 | }
28 |
29 | resource "aws_route_table" "public" {
30 | vpc_id = "${var.vpc_id}"
31 |
32 | route {
33 | cidr_block = "0.0.0.0/0"
34 | gateway_id = "${aws_internet_gateway.public.id}"
35 | }
36 |
37 | tags { Name = "${var.name}.${element(split(",", var.azs), count.index)}" }
38 | }
39 |
40 | resource "aws_route_table_association" "public" {
41 | count = "${length(split(",", var.cidrs))}"
42 | subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
43 | route_table_id = "${aws_route_table.public.id}"
44 | }
45 |
46 | output "subnet_ids" { value = "${join(",", aws_subnet.public.*.id)}" }
47 |
--------------------------------------------------------------------------------
/terraform/modules/aws/network/vpc/vpc.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module creates all resources necessary for a VPC
3 | #--------------------------------------------------------------
4 |
5 | variable "name" { default = "vpc" }
6 | variable "cidr" { }
7 |
8 | resource "aws_vpc" "vpc" {
9 | cidr_block = "${var.cidr}"
10 | enable_dns_support = true
11 | enable_dns_hostnames = true
12 |
13 | tags { Name = "${var.name}" }
14 | lifecycle { create_before_destroy = true }
15 | }
16 |
17 | output "vpc_id" { value = "${aws_vpc.vpc.id}" }
18 | output "vpc_cidr" { value = "${aws_vpc.vpc.cidr_block}" }
19 |
--------------------------------------------------------------------------------
/terraform/modules/aws/util/artifact/artifact.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module is used to for creating Atlas artifacts
3 | #--------------------------------------------------------------
4 |
5 | variable "type" { default = "amazon.ami" }
6 | variable "region" { }
7 | variable "atlas_username" { }
8 | variable "artifact_name" { }
9 | variable "artifact_version" { default = "latest" }
10 |
11 | resource "atlas_artifact" "artifact" {
12 | name = "${var.atlas_username}/${var.artifact_name}"
13 | type = "${var.type}"
14 | count = "${length(split(",", var.artifact_version))}"
15 | version = "${element(split(",", var.artifact_version), count.index)}"
16 |
17 | lifecycle { create_before_destroy = true }
18 | metadata { region = "${var.region}" }
19 | }
20 |
21 | output "amis" { value = "${join(",", atlas_artifact.artifact.*.metadata_full.ami_id)}" }
22 |
--------------------------------------------------------------------------------
/terraform/modules/aws/util/deploy/deploy.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module is used to achieve a blue/green deploy strategy
3 | #--------------------------------------------------------------
4 |
5 | variable "name" { default = "deploy" }
6 | variable "vpc_id" { }
7 | variable "vpc_cidr" { }
8 | variable "key_name" { }
9 | variable "azs" { }
10 | variable "private_subnet_ids" { }
11 | variable "blue_elb_id" { }
12 | variable "blue_ami" { }
13 | variable "blue_nodes" { }
14 | variable "blue_instance_type" { }
15 | variable "blue_user_data" { }
16 | variable "green_elb_id" { }
17 | variable "green_ami" { }
18 | variable "green_nodes" { }
19 | variable "green_instance_type" { }
20 | variable "green_user_data" { }
21 |
22 | resource "aws_security_group" "deploy" {
23 | vpc_id = "${var.vpc_id}"
24 | description = "Security group for ${var.name} Blue/Green deploy Launch Configuration"
25 |
26 | tags { Name = "${var.name}" }
27 | lifecycle { create_before_destroy = true }
28 |
29 | ingress {
30 | protocol = -1
31 | from_port = 0
32 | to_port = 0
33 | cidr_blocks = ["${var.vpc_cidr}"]
34 | }
35 |
36 | egress {
37 | protocol = -1
38 | from_port = 0
39 | to_port = 0
40 | cidr_blocks = ["0.0.0.0/0"]
41 | }
42 | }
43 |
44 | resource "aws_launch_configuration" "blue" {
45 | name_prefix = "${var.name}.blue."
46 | image_id = "${var.blue_ami}"
47 | instance_type = "${var.blue_instance_type}"
48 | key_name = "${var.key_name}"
49 | security_groups = ["${aws_security_group.deploy.id}"]
50 | user_data = "${var.blue_user_data}"
51 |
52 | lifecycle { create_before_destroy = true }
53 | }
54 |
55 | resource "aws_autoscaling_group" "blue" {
56 | name = "${aws_launch_configuration.blue.name}"
57 | launch_configuration = "${aws_launch_configuration.blue.name}"
58 | desired_capacity = "${var.blue_nodes}"
59 | min_size = "${var.blue_nodes}"
60 | max_size = "${var.blue_nodes}"
61 | wait_for_elb_capacity = "${var.blue_nodes}"
62 | availability_zones = ["${split(",", var.azs)}"]
63 | vpc_zone_identifier = ["${split(",", var.private_subnet_ids)}"]
64 | load_balancers = ["${var.blue_elb_id}"]
65 |
66 | lifecycle { create_before_destroy = true }
67 |
68 | tag {
69 | key = "Name"
70 | value = "${var.name}.blue"
71 | propagate_at_launch = true
72 | }
73 | }
74 |
75 | resource "aws_launch_configuration" "green" {
76 | name_prefix = "${var.name}.green."
77 | image_id = "${var.green_ami}"
78 | instance_type = "${var.green_instance_type}"
79 | key_name = "${var.key_name}"
80 | security_groups = ["${aws_security_group.deploy.id}"]
81 | user_data = "${var.green_user_data}"
82 |
83 | lifecycle { create_before_destroy = true }
84 | }
85 |
86 | resource "aws_autoscaling_group" "green" {
87 | name = "${aws_launch_configuration.green.name}"
88 | launch_configuration = "${aws_launch_configuration.green.name}"
89 | desired_capacity = "${var.green_nodes}"
90 | min_size = "${var.green_nodes}"
91 | max_size = "${var.green_nodes}"
92 | wait_for_elb_capacity = "${var.green_nodes}"
93 | availability_zones = ["${split(",", var.azs)}"]
94 | vpc_zone_identifier = ["${split(",", var.private_subnet_ids)}"]
95 | load_balancers = ["${var.green_elb_id}"]
96 |
97 | lifecycle { create_before_destroy = true }
98 |
99 | tag {
100 | key = "Name"
101 | value = "${var.name}.green"
102 | propagate_at_launch = true
103 | }
104 | }
105 |
--------------------------------------------------------------------------------
/terraform/modules/aws/util/iam/iam.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module is used to create an AWS IAM group and its users
3 | #--------------------------------------------------------------
4 |
5 | variable "name" { default = "iam" }
6 | variable "users" { }
7 | variable "policy" { }
8 |
9 | resource "aws_iam_group" "group" {
10 | name = "${var.name}"
11 | }
12 |
13 | resource "aws_iam_group_policy" "policy" {
14 | name = "${var.name}"
15 | group = "${aws_iam_group.group.id}"
16 | policy = "${var.policy}"
17 | }
18 |
19 | resource "aws_iam_user" "user" {
20 | count = "${length(split(",", var.users))}"
21 | name = "${element(split(",", var.users), count.index)}"
22 | }
23 |
24 | resource "aws_iam_access_key" "key" {
25 | count = "${length(split(",", var.users))}"
26 | user = "${element(aws_iam_user.user.*.name, count.index)}"
27 | }
28 |
29 | resource "aws_iam_group_membership" "membership" {
30 | name = "${var.name}"
31 | group = "${aws_iam_group.group.name}"
32 | users = ["${aws_iam_user.user.*.name}"]
33 | }
34 |
35 | output "users" { value = "${join(",", aws_iam_access_key.key.*.user)}" }
36 | output "access_ids" { value = "${join(",", aws_iam_access_key.key.*.id)}" }
37 | output "secret_keys" { value = "${join(",", aws_iam_access_key.key.*.secret)}" }
38 |
--------------------------------------------------------------------------------
/terraform/modules/aws/util/website/website.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 | # This module is used to create an S3 bucket website
3 | #--------------------------------------------------------------
4 |
5 | variable "fqdn" { }
6 | variable "sub_domain" { }
7 | variable "route_zone_id" { }
8 | variable "index_page" { default = "index.html" }
9 | variable "error_page" { default = "error.html" }
10 |
11 | resource "aws_s3_bucket" "website" {
12 | bucket = "${var.fqdn}"
13 | acl = "public-read"
14 | force_destroy = true
15 |
16 | website {
17 | index_document = "${var.index_page}"
18 | error_document = "${var.error_page}"
19 | }
20 |
21 | policy = < /dev/null
20 | }
21 |
22 | preparepolicy() {
23 | FILEPATH=$1
24 | PARAMETER=$2
25 |
26 | sed -i -- 's/\"/\\"/g' $FILEPATH
27 | sed -i '1s/^/{"{{ parameter }}": "/' $FILEPATH
28 | sed -i '$s|$|"}|' $FILEPATH
29 | sed -i -- "s/{{ parameter }}/$PARAMETER/g" $FILEPATH
30 | }
31 |
32 | logger "Configuring Consul..."
33 |
34 | sed -i -- "s/{{ atlas_username }}/${atlas_username}/g" /etc/consul.d/base.json
35 | sed -i -- "s/{{ atlas_environment }}/${atlas_environment}/g" /etc/consul.d/base.json
36 | sed -i -- "s/{{ atlas_token }}/${atlas_token}/g" /etc/consul.d/base.json
37 | sed -i -- "s/{{ datacenter }}/${atlas_environment}/g" /etc/consul.d/base.json
38 | sed -i -- "s/{{ node_name }}/${node_name}/g" /etc/consul.d/base.json
39 | sed -i -- "s/{{ deploy }}/${deploy}/g" /etc/consul.d/nodejs.json
40 |
41 | service consul restart
42 |
43 | logger "Updating certs..."
44 |
45 | mkdir -p $SSLCERTDIR
46 | chmod -R 0600 $SSLCERTDIR
47 |
48 | echo "${site_ssl_cert}" | sudo tee $SSLSITECERTPATH > /dev/null
49 | echo "${vault_ssl_cert}" | sudo tee $SSLVAULTCERTPATH > /dev/null
50 |
51 | cp $SSLSITECERTPATH /usr/local/share/ca-certificates/.
52 | cp $SSLVAULTCERTPATH /usr/local/share/ca-certificates/.
53 | update-ca-certificates
54 |
55 | logger "Checking for Vault token..."
56 |
57 | if [[ "x${vault_token}" == "x" || "${vault_token}" == "REPLACE_IN_ATLAS" ]]; then
58 | logger "Setting consul_template retry to 1h and stopping service."
59 | sed -i -- "s/retry = \"5s\"/retry = \"1h\"/g" /etc/consul_template.d/base.hcl
60 | service consul_template stop
61 |
62 | logger "Setting envconsul retry to 1h."
63 | sed -i -- "s/retry = \"5s\"/retry = \"1h\"/g" /etc/envconsul.d/base.hcl
64 | service nodejs restart
65 |
66 | logger "Exiting without setting Vault policy due to no Vault token."
67 |
68 | exit 1
69 | fi
70 |
71 | logger "Waiting for Vault to become ready..."
72 |
73 | SLEEPTIME=1
74 | cget() { curl -sf "$VAULT/v1/sys/health?standbyok"; }
75 |
76 | while ! cget | grep "\"initialized\":true,\"sealed\":false"; do
77 | if [ $SLEEPTIME -gt 15 ]; then
78 | logger "ERROR: VAULT SETUP NOT COMPLETE! Manual intervention required."
79 | exit 2
80 | else
81 | logger "Blocking until Vault is ready, waiting $SLEEPTIME second(s)..."
82 | sleep $SLEEPTIME
83 | SLEEPTIME=$((SLEEPTIME + 1))
84 | fi
85 | done
86 |
87 | logger "--- Vault Policy Setup ---"
88 | logger "Preparing Vault $NODEJSPOLICYNAME policy..."
89 |
90 | preparepolicy $NODEJSPOLICY rules
91 |
92 | logger "Generating Vault $NODEJSPOLICYNAME policy..."
93 |
94 | logger $(
95 | curl \
96 | -H "X-Vault-Token: ${vault_token}" \
97 | -H "Content-Type: application/json" \
98 | -LX PUT \
99 | -d @$NODEJSPOLICY \
100 | $VAULT/v1/sys/policy/$NODEJSPOLICYNAME
101 | )
102 |
103 | logger "Generating Vault $NODEJSPOLICYNAME token..."
104 |
105 | (cat < /tmp/$NODEJSPOLICYNAME-token.json
116 |
117 | TOKEN=$(
118 | curl \
119 | -H "X-Vault-Token: ${vault_token}" \
120 | -H "Content-Type: application/json" \
121 | -LX POST \
122 | -d @/tmp/$NODEJSPOLICYNAME-token.json \
123 | $VAULT/v1/auth/token/create \
124 | | grep -Po '"client_token":.*?[^\\]",' | awk -F\" '{print $4}'
125 | )
126 |
127 | rm -rf /tmp/$NODEJSPOLICYNAME-token.json
128 |
129 | SSLVAULTCERTPATH=$${SSLVAULTCERTPATH//\//\\/}
130 |
131 | logger "Update /etc/consul_template.d/nodejs.hcl with vault_token and cert_path"
132 |
133 | sed -i -- "s/{{ vault_token }}/$TOKEN/g" /etc/consul_template.d/nodejs.hcl
134 | sed -i -- "s/{{ cert_path }}/$SSLVAULTCERTPATH/g" /etc/consul_template.d/nodejs.hcl
135 |
136 | logger "Remove AWS specific config from /etc/consul_template.d/"
137 |
138 | rm /etc/consul_template.d/nodejs_aws.hcl
139 |
140 | logger "Update /etc/envconsul.d/nodejs.hcl with vault_token and cert_path"
141 |
142 | sed -i -- "s/{{ vault_token }}/$TOKEN/g" /etc/envconsul.d/nodejs.hcl
143 | sed -i -- "s/{{ cert_path }}/$SSLVAULTCERTPATH/g" /etc/envconsul.d/nodejs.hcl
144 |
145 | logger "--- Generic Secret Backend Setup ---"
146 | logger "Writing $NAME secret..."
147 |
148 | logger $(
149 | curl \
150 | -H "X-Vault-Token: ${vault_token}" \
151 | -H "Content-Type: application/json" \
152 | -LX POST \
153 | -d "{\"$GENERICSECRETKEY\": \"$GENERICSECRET\", \"ttl\": \"1m\"}" \
154 | $VAULT/v1/$GENERICSECRETPATH
155 | )
156 |
157 | GENERICSECRETPATH=$${GENERICSECRETPATH//\//\\/}
158 |
159 | logger "Update /opt/consul_template/vault_generic.ctmpl"
160 |
161 | sed -i -- "s/{{ node_name }}/$NAME/g" /opt/consul_template/vault_generic.ctmpl
162 | sed -i -- "s/{{ secret_path }}/$GENERICSECRETPATH/g" /opt/consul_template/vault_generic.ctmpl
163 | sed -i -- "s/{{ secret_key }}/$GENERICSECRETKEY/g" /opt/consul_template/vault_generic.ctmpl
164 |
165 | logger "Update /etc/envconsul.d/nodejs.hcl with secret_path"
166 |
167 | sed -i -- "s/{{ secret_path }}/$GENERICSECRETPATH/g" /etc/envconsul.d/nodejs.hcl
168 |
169 | service nodejs restart
170 | service consul_template restart
171 |
172 | logger "Create Consul KV envconsul watches to display Vault secret"
173 |
174 | curl -X PUT -d '1' $CONSUL/v1/kv/service/nodejs/show_vault
175 | curl -X PUT -d 'generic.html' $CONSUL/v1/kv/service/nodejs/vault_files
176 |
177 | logger "Node.js configuration complete"
178 |
179 | exit 0
180 |
--------------------------------------------------------------------------------
/terraform/modules/google/compute/nodejs/nodejs.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 |
3 | # This module creates all resources necessary for the
4 |
5 | # Node.js application
6 |
7 | #--------------------------------------------------------------
8 |
9 | variable "name" {}
10 |
11 | variable "zones" {
12 | type = "list"
13 | }
14 |
15 | variable "atlas_username" {}
16 |
17 | variable "atlas_environment" {}
18 |
19 | variable "atlas_token" {}
20 |
21 | variable "private_subnet_names" {
22 | type = "list"
23 | }
24 |
25 | variable "public_subnet_names" {
26 | type = "list"
27 | }
28 |
29 | variable "image" {}
30 |
31 | variable "nodes" {}
32 |
33 | variable "instance_type" {}
34 |
35 | variable "site_ssl_cert" {}
36 |
37 | variable "site_ssl_key" {}
38 |
39 | variable "vault_ssl_cert" {}
40 |
41 | variable "vault_token" {
42 | default = ""
43 | }
44 |
45 | variable "vault_policy" {
46 | default = "nodejs"
47 | }
48 |
49 | variable "ssh_keys" {}
50 |
51 | resource "template_file" "nodejs_config" {
52 | template = "${file("${path.module}/nodejs.sh.tpl")}"
53 | count = "${var.nodes}"
54 |
55 | lifecycle { create_before_destroy = true }
56 |
57 | vars {
58 | atlas_username = "${var.atlas_username}"
59 | atlas_environment = "${var.atlas_environment}"
60 | atlas_token = "${var.atlas_token}"
61 | node_name = "${var.name}-${count.index}"
62 | deploy = "deploy"
63 | site_ssl_cert = "${var.site_ssl_cert}"
64 | vault_ssl_cert = "${var.vault_ssl_cert}"
65 | vault_token = "${var.vault_token}"
66 | vault_policy = "${var.vault_policy}"
67 | }
68 | }
69 |
70 | resource "google_compute_instance" "nodejs" {
71 | name = "${var.name}-${count.index}"
72 | count = "${var.nodes}"
73 | machine_type = "${var.instance_type}"
74 | zone = "${element(var.zones, count.index)}"
75 |
76 | metadata_startup_script = "${element(template_file.nodejs_config.*.rendered, count.index)}"
77 |
78 | metadata {
79 | sshKeys = "${var.ssh_keys}"
80 | }
81 |
82 | disk {
83 | image = "${var.image}"
84 | }
85 |
86 | network_interface {
87 | subnetwork = "${element(var.private_subnet_names, count.index)}"
88 |
89 | access_config {
90 | # ephemeral
91 | }
92 | }
93 |
94 | tags = ["nodejs"]
95 | }
96 |
97 | output "private_ips" {
98 | value = ["${google_compute_instance.nodejs.*.network_interface.0.address}"]
99 | }
100 |
--------------------------------------------------------------------------------
/terraform/modules/google/data/consul/consul.sh.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | echo "Configuring Consul..."
5 |
6 | sed -i -- "s/{{ atlas_username }}/${atlas_username}/g" /etc/consul.d/base.json
7 | sed -i -- "s/{{ atlas_environment }}/${atlas_environment}/g" /etc/consul.d/base.json
8 | sed -i -- "s/{{ atlas_token }}/${atlas_token}/g" /etc/consul.d/base.json
9 | sed -i -- "s/{{ consul_server_count }}/${consul_server_count}/g" /etc/consul.d/base.json
10 | sed -i -- "s/{{ datacenter }}/${atlas_environment}/g" /etc/consul.d/base.json
11 | sed -i -- "s/{{ node_name }}/${node_name}/g" /etc/consul.d/base.json
12 |
13 | service consul restart
14 |
15 | exit 0
16 |
--------------------------------------------------------------------------------
/terraform/modules/google/data/consul/consul.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 |
3 | # This module creates all resources necessary for Consul
4 |
5 | #--------------------------------------------------------------
6 |
7 | variable "name" {}
8 |
9 | variable "project" {}
10 |
11 | variable "region" {}
12 |
13 | variable "zones" {
14 | type = "list"
15 | }
16 |
17 | variable "atlas_username" {}
18 |
19 | variable "atlas_environment" {}
20 |
21 | variable "atlas_token" {}
22 |
23 | variable "private_subnet_names" {
24 | type = "list"
25 | }
26 |
27 | variable "image" {}
28 |
29 | variable "nodes" {}
30 |
31 | variable "instance_type" {}
32 |
33 | variable "ssh_keys" {}
34 |
35 | resource "template_file" "consul_config" {
36 | template = "${file("${path.module}/consul.sh.tpl")}"
37 | count = "${var.nodes}"
38 |
39 | vars {
40 | atlas_username = "${var.atlas_username}"
41 | atlas_environment = "${var.atlas_environment}"
42 | atlas_token = "${var.atlas_token}"
43 | consul_server_count = "${var.nodes}"
44 | node_name = "${var.name}-${count.index}"
45 | }
46 |
47 | lifecycle {
48 | create_before_destroy = true
49 | }
50 | }
51 |
52 | resource "google_compute_instance" "consul" {
53 | name = "${var.name}-${count.index}"
54 | count = "${var.nodes}"
55 | machine_type = "${var.instance_type}"
56 | zone = "${element(var.zones, count.index)}"
57 |
58 | metadata_startup_script = "${element(template_file.consul_config.*.rendered, count.index)}"
59 |
60 | metadata {
61 | sshKeys = "${var.ssh_keys}"
62 | }
63 |
64 | disk {
65 | image = "${var.image}"
66 | }
67 |
68 | network_interface {
69 | subnetwork = "${element(var.private_subnet_names, count.index)}"
70 |
71 | access_config {
72 | # ephemeral
73 | }
74 | }
75 |
76 | tags = ["consul"]
77 | }
78 |
79 | output "private_ips" {
80 | value = ["${google_compute_instance.consul.*.network_interface.0.address}"]
81 | }
82 |
--------------------------------------------------------------------------------
/terraform/modules/google/data/data.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 |
3 | # This module creates all data resources
4 |
5 | #--------------------------------------------------------------
6 |
7 | variable "name" {}
8 |
9 | variable "project" {}
10 |
11 | variable "region" {}
12 |
13 | variable "zones" {
14 | type = "list"
15 | }
16 |
17 | variable "atlas_username" {}
18 |
19 | variable "atlas_environment" {}
20 |
21 | variable "atlas_token" {}
22 |
23 | variable "private_subnet_names" {
24 | type = "list"
25 | }
26 |
27 | variable "public_subnet_names" {
28 | type = "list"
29 | }
30 |
31 | variable "consul_image" {}
32 |
33 | variable "consul_node_count" {}
34 |
35 | variable "consul_instance_type" {}
36 |
37 | variable "vault_ssl_cert" {}
38 |
39 | variable "vault_ssl_key" {}
40 |
41 | variable "vault_image" {}
42 |
43 | variable "vault_node_count" {}
44 |
45 | variable "vault_instance_type" {}
46 |
47 | variable "ssh_keys" {}
48 |
49 | module "consul" {
50 | source = "./consul"
51 |
52 | name = "${var.name}-consul"
53 | project = "${var.project}"
54 | region = "${var.region}"
55 | zones = "${var.zones}"
56 | atlas_username = "${var.atlas_username}"
57 | atlas_environment = "${var.atlas_environment}"
58 | atlas_token = "${var.atlas_token}"
59 | private_subnet_names = "${var.private_subnet_names}"
60 | image = "${var.consul_image}"
61 | nodes = "${var.consul_node_count}"
62 | instance_type = "${var.consul_instance_type}"
63 | ssh_keys = "${var.ssh_keys}"
64 | }
65 |
66 | module "vault" {
67 | source = "./vault"
68 |
69 | name = "${var.name}-vault"
70 | project = "${var.project}"
71 | region = "${var.region}"
72 | zones = "${var.zones}"
73 |
74 | atlas_username = "${var.atlas_username}"
75 | atlas_environment = "${var.atlas_environment}"
76 | atlas_token = "${var.atlas_token}"
77 | private_subnet_names = "${var.private_subnet_names}"
78 | public_subnet_names = "${var.public_subnet_names}"
79 | ssl_cert = "${var.vault_ssl_cert}"
80 | ssl_key = "${var.vault_ssl_key}"
81 | image = "${var.vault_image}"
82 | nodes = "${var.vault_node_count}"
83 | instance_type = "${var.vault_instance_type}"
84 | ssh_keys = "${var.ssh_keys}"
85 | }
86 |
87 | # Consul
88 | output "consul_private_ips" {
89 | value = "${module.consul.private_ips}"
90 | }
91 |
92 | # Vault
93 | output "vault_private_ips" {
94 | value = "${module.vault.private_ips}"
95 | }
96 |
--------------------------------------------------------------------------------
/terraform/modules/google/data/vault/vault.sh.tpl:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | SSLDIR=/usr/local/etc
5 | SSLCERTPATH=$SSLDIR/vault.crt
6 | SSLKEYPATH=$SSLDIR/vault.key
7 |
8 | echo "Configuring Consul..."
9 |
10 | sed -i -- "s/{{ atlas_username }}/${atlas_username}/g" /etc/consul.d/base.json
11 | sed -i -- "s/{{ atlas_environment }}/${atlas_environment}/g" /etc/consul.d/base.json
12 | sed -i -- "s/{{ atlas_token }}/${atlas_token}/g" /etc/consul.d/base.json
13 | sed -i -- "s/{{ datacenter }}/${atlas_environment}/g" /etc/consul.d/base.json
14 | sed -i -- "s/{{ node_name }}/${node_name}/g" /etc/consul.d/base.json
15 | sed -i -- "s/{{ node_name }}/${node_name}/g" /etc/consul.d/vault.json
16 |
17 | service consul restart
18 |
19 | echo "Updating cert..."
20 |
21 | mkdir -p $SSLDIR
22 | chmod -R 0600 $SSLDIR
23 |
24 | echo "${ssl_cert}" | sudo tee $SSLCERTPATH > /dev/null
25 | echo "${ssl_key}" | sudo tee $SSLKEYPATH > /dev/null
26 |
27 | cp "$SSLCERTPATH" /usr/local/share/ca-certificates/.
28 | update-ca-certificates
29 |
30 | echo "Configuring Vault..."
31 |
32 | SSLCERTPATH=$${SSLCERTPATH//\//\\/}
33 | SSLKEYPATH=$${SSLKEYPATH//\//\\/}
34 |
35 | sed -i -- "s/{{ node_name }}/${node_name}/g" /etc/vault.d/vault.hcl
36 | sed -i -- "s/{{ tls_cert_file }}/$SSLCERTPATH/g" /etc/vault.d/vault.hcl
37 | sed -i -- "s/{{ tls_key_file }}/$SSLKEYPATH/g" /etc/vault.d/vault.hcl
38 |
39 | service vault restart
40 |
41 | exit 0
42 |
--------------------------------------------------------------------------------
/terraform/modules/google/data/vault/vault.tf:
--------------------------------------------------------------------------------
1 | # This module creates all resources necessary for Vault
2 |
3 | variable "name" {}
4 |
5 | variable "project" {}
6 |
7 | variable "region" {}
8 |
9 | variable "zones" {
10 | type = "list"
11 | }
12 |
13 | variable "atlas_username" {}
14 |
15 | variable "atlas_environment" {}
16 |
17 | variable "atlas_token" {}
18 |
19 | variable "private_subnet_names" {
20 | type = "list"
21 | }
22 |
23 | variable "public_subnet_names" {
24 | type = "list"
25 | }
26 |
27 | variable "image" {}
28 |
29 | variable "nodes" {}
30 |
31 | variable "instance_type" {}
32 |
33 | variable "ssl_cert" {}
34 |
35 | variable "ssl_key" {}
36 |
37 | variable "ssh_keys" {}
38 |
39 | resource "template_file" "vault_config" {
40 | template = "${file("${path.module}/vault.sh.tpl")}"
41 | count = "${var.nodes}"
42 |
43 | vars {
44 | atlas_username = "${var.atlas_username}"
45 | atlas_environment = "${var.atlas_environment}"
46 | atlas_token = "${var.atlas_token}"
47 | node_name = "${var.name}-${count.index}"
48 | ssl_cert = "${var.ssl_cert}"
49 | ssl_key = "${var.ssl_key}"
50 | }
51 |
52 | lifecycle {
53 | create_before_destroy = true
54 | }
55 | }
56 |
57 | resource "google_compute_instance" "vault" {
58 | name = "${var.name}-${count.index}"
59 | count = "${var.nodes}"
60 | machine_type = "${var.instance_type}"
61 | zone = "${element(var.zones, count.index)}"
62 |
63 | metadata_startup_script = "${element(template_file.vault_config.*.rendered, count.index)}"
64 |
65 | metadata {
66 | sshKeys = "${var.ssh_keys}"
67 | }
68 |
69 | disk {
70 | image = "${var.image}"
71 | }
72 |
73 | network_interface {
74 | subnetwork = "${element(var.private_subnet_names, count.index)}"
75 |
76 | access_config {
77 | # ephemeral
78 | }
79 | }
80 |
81 | tags = ["vault"]
82 | }
83 |
84 | output "private_ips" {
85 | value = ["${google_compute_instance.vault.*.network_interface.0.address}"]
86 | }
87 |
--------------------------------------------------------------------------------
/terraform/modules/google/network/bastion/bastion.tf:
--------------------------------------------------------------------------------
1 | #--------------------------------------------------------------
2 |
3 | # This module creates all resources necessary for a Bastion
4 |
5 | # host
6 |
7 | #--------------------------------------------------------------
8 |
9 | variable "name" {}
10 |
11 | variable "zones" {
12 | type = "list"
13 | }
14 |
15 | variable "public_subnet_names" {
16 | type = "list"
17 | }
18 |
19 | variable "image" {}
20 |
21 | variable "instance_type" {}
22 |
23 | variable "ssh_keys" {}
24 |
25 | resource "google_compute_instance" "bastion" {
26 | name = "${var.name}"
27 | machine_type = "${var.instance_type}"
28 | zone = "${element(var.zones, 0)}"
29 |
30 | metadata {
31 | sshKeys = "${var.ssh_keys}"
32 | }
33 |
34 | disk {
35 | image = "${var.image}"
36 | }
37 |
38 | network_interface {
39 | subnetwork = "${element(var.public_subnet_names, 0)}"
40 |
41 | access_config {
42 | # ephemeral
43 | }
44 | }
45 |
46 | tags = ["bastion"]
47 | }
48 |
49 | output "private_ip" {
50 | value = "${google_compute_instance.bastion.network_interface.0.address}"
51 | }
52 |
53 | output "public_ip" {
54 | value = "${google_compute_instance.bastion.network_interface.0.access_config.0.assigned_nat_ip}"
55 | }
56 |
--------------------------------------------------------------------------------
/terraform/modules/google/network/network.tf:
--------------------------------------------------------------------------------
1 | variable "name" {}
2 |
3 | variable "region" {}
4 |
5 | variable "zones" {
6 | type = "list"
7 | }
8 |
9 | variable "cidr" {}
10 |
11 | variable "public_subnets" {
12 | type = "list"
13 | }
14 |
15 | variable "private_subnets" {
16 | type = "list"
17 | }
18 |
19 | variable "bastion_image" {}
20 |
21 | variable "bastion_instance_type" {}
22 |
23 | variable "ssh_keys" {}
24 |
25 | resource "google_compute_network" "network" {
26 | name = "${var.name}"
27 | }
28 |
29 | resource "google_compute_firewall" "allow-internal" {
30 | name = "${var.name}-allow-internal"
31 | network = "${google_compute_network.network.name}"
32 |
33 | allow {
34 | protocol = "icmp"
35 | }
36 |
37 | allow {
38 | protocol = "tcp"
39 | ports = ["0-65535"]
40 | }
41 |
42 | allow {
43 | protocol = "udp"
44 | ports = ["0-65535"]
45 | }
46 |
47 | source_ranges = [
48 | "${var.cidr}",
49 | ]
50 | }
51 |
52 | resource "google_compute_firewall" "allow-ssh" {
53 | name = "${var.name}-allow-ssh"
54 | network = "${google_compute_network.network.name}"
55 |
56 | allow {
57 | protocol = "tcp"
58 | ports = ["22"]
59 | }
60 |
61 | source_ranges = ["0.0.0.0/0"]
62 |
63 | # uncomment to restrict public ssh to the bastion host
64 | target_tags = ["bastion"]
65 | }
66 |
67 | module "public_subnet" {
68 | source = "./public_subnet"
69 |
70 | name = "${var.name}-public"
71 | region = "${var.region}"
72 | network = "${google_compute_network.network.self_link}"
73 | cidrs = "${var.public_subnets}"
74 | }
75 |
76 | module "private_subnet" {
77 | source = "./private_subnet"
78 |
79 | name = "${var.name}-private"
80 | region = "${var.region}"
81 | network = "${google_compute_network.network.self_link}"
82 | cidrs = "${var.private_subnets}"
83 | }
84 |
85 | module "bastion" {
86 | source = "./bastion"
87 |
88 | name = "${var.name}-bastion"
89 | zones = "${var.zones}"
90 | public_subnet_names = "${module.public_subnet.subnet_names}"
91 | image = "${var.bastion_image}"
92 | instance_type = "${var.bastion_instance_type}"
93 | ssh_keys = "${var.ssh_keys}"
94 | }
95 |
96 | output "name" {
97 | value = "${google_compute_network.network.name}"
98 | }
99 |
100 | output "public_subnet_names" {
101 | value = "${module.public_subnet.subnet_names}"
102 | }
103 |
104 | output "private_subnet_names" {
105 | value = "${module.private_subnet.subnet_names}"
106 | }
107 |
108 | output "bastion_public_ip" {
109 | value = "${module.bastion.public_ip}"
110 | }
111 |
--------------------------------------------------------------------------------
/terraform/modules/google/network/private_subnet/private_subnet.tf:
--------------------------------------------------------------------------------
1 | variable "name" {}
2 |
3 | variable "region" {}
4 |
5 | variable "network" {}
6 |
7 | variable "cidrs" {
8 | type = "list"
9 | }
10 |
11 | resource "google_compute_subnetwork" "private" {
12 | name = "${var.name}-${count.index}"
13 | count = "${length(var.cidrs)}"
14 | ip_cidr_range = "${element(var.cidrs, count.index)}"
15 | network = "${var.network}"
16 | region = "${var.region}"
17 | }
18 |
19 | output "subnet_names" {
20 | value = ["${google_compute_subnetwork.private.*.name}"]
21 | }
22 |
--------------------------------------------------------------------------------
/terraform/modules/google/network/public_subnet/public_subnet.tf:
--------------------------------------------------------------------------------
1 | variable "name" {}
2 |
3 | variable "region" {}
4 |
5 | variable "network" {}
6 |
7 | variable "cidrs" {
8 | type = "list"
9 | }
10 |
11 | resource "google_compute_subnetwork" "public" {
12 | name = "${var.name}-${count.index}"
13 | count = "${length(var.cidrs)}"
14 | ip_cidr_range = "${element(var.cidrs, count.index)}"
15 | network = "${var.network}"
16 | region = "${var.region}"
17 | }
18 |
19 | output "subnet_names" {
20 | value = ["${google_compute_subnetwork.public.*.name}"]
21 | }
22 |
--------------------------------------------------------------------------------
/terraform/providers/aws/global/global.tf:
--------------------------------------------------------------------------------
1 | variable "domain" { }
2 | variable "atlas_username" { }
3 | variable "atlas_environment" { }
4 | variable "name" { }
5 | variable "region" { }
6 | variable "iam_admins" { }
7 | variable "iam_vault_envs" { }
8 |
9 | provider "aws" {
10 | region = "${var.region}"
11 | }
12 |
13 | atlas {
14 | name = "${var.atlas_username}/${var.atlas_environment}"
15 | }
16 |
17 | module "iam_admin" {
18 | source = "../../../modules/aws/util/iam"
19 |
20 | name = "${var.name}-admin"
21 | users = "${var.iam_admins}"
22 | policy = <