Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

multiple environments + droneci #63

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions terraform/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Run terraform init.

```
make init
```
```

Plan terraform changes, to verify.

Expand All @@ -33,7 +33,7 @@ make plan

```
make plan
```
```

verify your changes are executed as you'd like.

Expand All @@ -48,3 +48,26 @@ follow the stream, and verify your changes have been applied using the AWS Conso
```
make ${your_action_here}
```

### Secrets

Secrets in AWS are managed via KMS

Each project should have a unique key

#### Generate Key
```
aws kms create-key \
--profile hashbang \
--description "some-app" \
--region us-west-2
```

#### Encrypt Secret
```
aws kms encrypt \
--profile hashbang \
--key-id fe5d40fe-dcf6-1558-4080-096648020239 \
--plaintext "$(pass Hashbang/someapp | head -n1)" \
--output text --query CiphertextBlob
```
33 changes: 33 additions & 0 deletions terraform/environments/ci/drone.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module "drone_balancer" {
source = "../../modules/route53_balancer"
domain = "ci.hashbang.sh"
name = "droneci-balancer"
asg = "${module.drone_asg.id}"
launch_topic = "${module.drone_asg.launch_topic}"
terminate_topic = "${module.drone_asg.terminate_topic}"
}

module "drone_asg" {
source = "../../modules/coreos_asg"
name = "drone"
key_name = "admin"
subnets = "${module.vpc.public_subnets}"
vpc_id = "${module.vpc.vpc_id}"
kms_key_id = "8c2d565d-1998-4c82-baba-50c98fc2841e"
cloud_config = "${data.template_file.cloud_config.rendered}"
}

data "template_file" "cloud_config" {
template = "${file("${path.module}/files/drone-cloud-config.yml")}"
vars {
aws_region = "us-west-2"
kms_drone_github_client = "AQICAHgdKTQKPCVSxRc0j0autqD7bCgQSjpitnlAfGw9dPM7RwFyqCRmVD71lSGwEOCO2EepAAAAcjBwBgkqhkiG9w0BBwagYzBhAgEAMFwGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQM4Ct8bkQtrK2s1m4EAgEQgC8rNab4vAJuzTxrB6/2O3q+Z4QnDQ6YJGPMY1pIWP9RXPMZ45lPmDpwiouKO9TcPg=="
kms_drone_github_secret = "AQICAHgdKTQKPCVSxRc0j0autqD7bCgQSjpitnlAfGw9dPM7RwHuoOEi30zJqK76A1SsLI5aAAAAhzCBhAYJKoZIhvcNAQcGoHcwdQIBADBwBgkqhkiG9w0BBwEwHgYJYIZIAWUDBAEuMBEEDEI8ORtXn4gamHlUbgIBEIBD5GIJ//Fr8XRmvmy1Zht+04HIkXnNqnPwPJNlHEGPmop8K63WYxuDEZpZAtY7dY1c+E7omAUNCS5vKSPBQ1zePjDpzQ=="
kms_drone_secret = "AQICAHgdKTQKPCVSxRc0j0autqD7bCgQSjpitnlAfGw9dPM7RwEfn8AuPpq5mUHeHCd/Qe9SAAAAkjCBjwYJKoZIhvcNAQcGoIGBMH8CAQAwegYJKoZIhvcNAQcBMB4GCWCGSAFlAwQBLjARBAyxt5KAogGEsGdDiXwCARCATWFPSW/o0t5i9Qy72CeyYtYmTjM8Pq85VRJ3rc6jD52DAhYkp1lFgvMaV0UmPCU/awdQN55Kj+lQrvi6JWi7K75BvkVNDzBUP6F2vu+J"
drone_orgs = "hashbang"
decrypt_script = "${file("${path.module}/files/decrypt.sh")}"
efs_id = "${module.drone_asg.efs_id}"
domain = "ci.hashbang.sh"
drone_admins = "dpflug,daurnimator,deviavir,drgrove,kellerfuchs,lrvick,ryansquared,singlerider"
}
}
19 changes: 19 additions & 0 deletions terraform/environments/ci/files/decrypt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/bin/bash
Copy link
Member

Choose a reason for hiding this comment

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

#!/bin/sh
set -e

Copy link
Member Author

Choose a reason for hiding this comment

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

Would that not list potentially logging plaintext secrets?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh -e != -x

unset IFS
out_path=${1:-/out/secrets.env}
rm "$out_path" 2> /dev/null
Copy link
Member

Choose a reason for hiding this comment

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

rm -f (so that set -e doesn't make it explode when $out_path doesn't exist yet).

for line in $(env | egrep '^KMS_'); do
kms_key="${line%%=*}"
key=${kms_key/KMS_/}
encrypted_value=${line#*=}
Copy link
Member

Choose a reason for hiding this comment

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

What does ${line%%=*} and ${line#*=} do? Is it POSIX?

Copy link
Member Author

@lrvick lrvick May 23, 2017

Choose a reason for hiding this comment

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

It is bash variable substitution %%=* says "strip the equals sign and anything after it" and #*= says "remove the equals sign and anything before it". When using bash there is little need for things like sed/awk for truncation and replacement.

I am only injecting the bash binary into the container so KISS.

decrypted_value_base64=$( \
aws kms decrypt \
--ciphertext-blob fileb://<(echo "$encrypted_value" | base64 -d) \
--query Plaintext \
--output text
)
decrypted_value=$(echo $decrypted_value_base64 | base64 -d)
echo "key=$key"
echo "encrypted_value=$encrypted_value"
echo "export $key=$decrypted_value" >> "$out_path"
done
122 changes: 122 additions & 0 deletions terraform/environments/ci/files/drone-cloud-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#cloud-config
hostname: "drone"
coreos:
units:
- name: update-engine.service
command: stop
- name: locksmithd.service
command: stop
- name: mnt-shared.mount
command: start
content: |
[Mount]
What=${efs_id}.efs.${aws_region}.amazonaws.com:/
Where=/mnt/shared
Type=nfs
- name: drone-server-secrets.service
enable: true
content: |
[Unit]
Description=DroneCI Server Secrets Writer
After=docker.service
Requires=docker.service
[Install]
WantedBy=multi-user.target
[Service]
TimeoutStartSec=0
ExecStart=/usr/bin/docker run \
--env "AWS_DEFAULT_REGION=${aws_region}" \
--env "KMS_DRONE_GITHUB_CLIENT=${kms_drone_github_client}" \
--env "KMS_DRONE_GITHUB_SECRET=${kms_drone_github_secret}" \
--env "KMS_DRONE_SECRET=${kms_drone_secret}" \
--volume drone-server-secrets:/secrets \
--volume /usr/bin/bash:/usr/bin/bash \
--volume /lib64:/lib64 \
--volume /home/core/scripts/decrypt.sh:/usr/bin/decrypt.sh \
--entrypoint /usr/bin/bash \
quay.io/coreos/awscli decrypt.sh "/secrets/secrets.env"
- name: drone-agent-secrets.service
enable: true
content: |
[Unit]
Description=DroneCI Agent Secrets Writer
Requires=docker.service
After=docker.service
[Install]
WantedBy=multi-user.target
[Service]
TimeoutStartSec=0
ExecStart=/usr/bin/docker run \
--env "AWS_DEFAULT_REGION=${aws_region}" \
--env "KMS_DRONE_SECRET=${kms_drone_secret}" \
--volume drone-agent-secrets:/secrets \
--volume /lib64:/lib64 \
--volume /usr/bin/bash:/usr/bin/bash \
--volume /home/core/scripts/decrypt.sh:/usr/bin/decrypt.sh \
--entrypoint /usr/bin/bash \
quay.io/coreos/awscli decrypt.sh "/secrets/secrets.env"
- name: drone-server.service
enable: true
command: start
content: |
[Unit]
Description=Drone CI Server
Requires=drone-server-secrets.service
After=drone-server-secrets.service
[Install]
WantedBy=multi-user.target
[Service]
Restart=always
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill %p
ExecStartPre=-/usr/bin/docker rm %p
ExecStartPre=/usr/bin/docker pull drone/drone:0.6
ExecStart=/usr/bin/docker run \
--name %p \
--volume /mnt/shared/drone:/var/lib/drone \
--volume drone-server-secrets:/secrets/ \
--volume /lib64:/lib64 \
--volume /usr/bin/bash:/usr/bin/bash \
--entrypoint="/usr/bin/bash" \
--publish 80:80 \
--publish 443:443 \
--env DRONE_OPEN=true \
--env DRONE_GITHUB=true \
--env DRONE_HOST=https://${domain} \
--env DRONE_ADMIN=${drone_admins} \
--env DRONE_LETS_ENCRYPT=true \
drone/drone -c 'source /secrets/secrets.env; /drone server'
ExecStop=/usr/bin/docker stop %p
- name: drone-agent.service
enable: true
command: start
content: |
[Unit]
Description=Drone CI Agent
Requires=drone-agent-secrets.service
After=drone-agent-secrets.service
[Install]
WantedBy=multi-user.target
[Service]
Restart=always
TimeoutStartSec=0
ExecStartPre=-/usr/bin/docker kill %p
ExecStartPre=-/usr/bin/docker rm %p
ExecStartPre=/usr/bin/docker pull drone/drone:0.6
ExecStart=/usr/bin/docker run \
--name %p \
--volumes-from drone-server \
--volume drone-agent-secrets:/secrets/ \
--volume /lib64:/lib64 \
--volume /usr/bin/bash:/usr/bin/bash \
--entrypoint="/usr/bin/bash" \
--volume /var/run/docker.sock:/var/run/docker.sock \
--env DRONE_SERVER=ws://drone-server:8000/ws/broker \
drone/drone -c 'source /secrets/secrets.env; /drone agent'
ExecStop=/usr/bin/docker stop %p
write_files:
- path: "/home/core/scripts/decrypt.sh"
permissions: "0755"
owner: "core"
encoding: base64
content: ${base64encode(decrypt_script)}
22 changes: 22 additions & 0 deletions terraform/environments/ci/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
terraform {
backend "s3" {
bucket = "hashbang-terraform-ci"
key = "state.tfstate"
region = "us-west-2"
lock_table = "hashbang-terraform-ci"
}
}

provider "aws" {
region = "us-west-2"
}

module "vpc" {
source = "github.com/terraform-community-modules/tf_aws_vpc?ref=v1.0.6"
Copy link
Member

Choose a reason for hiding this comment

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

Does that mean that anyone with push access to github.com/terraform-community-modules/tf_aws_vpc gets code execution as the admin running terraform (or as our CD infra, eventually)?

Copy link
Member Author

Choose a reason for hiding this comment

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

Could easily make this a submodule.

name = "ci"
cidr = "10.0.0.0/16"
Copy link
Member

Choose a reason for hiding this comment

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

Why are we allocating the whole of 10/16 to the CI?
What's actually in use there? Please document the network segmentation.

Copy link
Member Author

Choose a reason for hiding this comment

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

Just giving a 10/16 to each enviornment of which will initally only be Production and CI. Keeping them far apart to have plenty of addresses for throw-away workers etc in the future.

Copy link
Member Author

@lrvick lrvick May 23, 2017

Choose a reason for hiding this comment

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

To further clarify, we can later (with a bit more $) upgrade this with the drone agent containers in a dedicated autoscale group as dumb on-demand workers of which they will churn IP addresses pretty quick when doing a bunch of builds/jobs at once.

public_subnets = ["10.0.101.0/24", "10.0.102.0/24"]
azs = ["us-west-2a", "us-west-2b"]
enable_dns_hostnames = "true"
enable_dns_support = "true"
}
File renamed without changes.
23 changes: 23 additions & 0 deletions terraform/environments/production/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
terraform {
required_version = "> 0.8.4"
backend "s3" {
bucket = "hashbang-terraform-production"
key = "state.tfstate"
region = "us-west-2"
lock_table = "hashbang-terraform-production"
}
}

provider "aws" {
region = "us-west-2"
}

module "vpc" {
source = "github.com/terraform-community-modules/tf_aws_vpc?ref=v1.0.6"
name = "production"
cidr = "10.0.0.0/16"
public_subnets = ["10.0.103.0/24", "10.0.104.0/24"]
azs = ["us-west-2a", "us-west-2b"]
enable_dns_hostnames = "true"
enable_dns_support = "true"
}
21 changes: 0 additions & 21 deletions terraform/main.tf

This file was deleted.

Loading