~damien/infrastructure

18d2292418905b465b1f83e2c06d46800e0b2a99 — Damien Radtke 1 year, 7 months ago
Initial commit
A  => config/README.md +1 -0
@@ 1,1 @@
This folder contains various config files, notably for Consul, Vault, and Nomad.

A  => config/client/consul.d/consul.hcl.erb +16 -0
@@ 1,16 @@
bind_addr = "{{ GetInterfaceIP `eth0` }}"
datacenter = "<%= datacenter %>"
node_name = "<%= File.read('/etc/hostname').strip %>"
data_dir = "/var/lib/consul"

server = false
retry_join = [<% servers.split(",").each_with_index do |server, i| %><%= i > 0 ? ',' : '' %>"<%= server %>"<% end %>]

ca_file = "/etc/ssl/consul/ca.pem"
cert_file = "/etc/ssl/consul/consul.pem"
key_file = "/etc/ssl/consul/consul-key.pem"

ports {
        http = 8500
        https = 8501
}

A  => firewall/README.md +1 -0
@@ 1,1 @@
This folder contains `firewalld` configuration files.

A  => firewall/services/consul.xml +12 -0
@@ 1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Consul</short>
  <description>Ports needed by Consul.</description>
  <port port="8300" protocol="tcp"/>
  <port port="8301" protocol="tcp"/>
  <port port="8301" protocol="udp"/>
  <port port="8302" protocol="tcp"/>
  <port port="8302" protocol="udp"/>
  <port port="8600" protocol="tcp"/>
  <port port="8600" protocol="udp"/>
</service>

A  => firewall/services/fabio.xml +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Fabio</short>
  <description>Ports needed by Fabio.</description>
  <port port="9998" protocol="tcp"/>
  <port port="9999" protocol="tcp"/>
</service>

A  => firewall/services/nomad.xml +9 -0
@@ 1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Nomad</short>
  <description>Ports needed by Nomad.</description>
  <port port="4646" protocol="tcp"/>
  <port port="4647" protocol="tcp"/>
  <port port="4648" protocol="tcp"/>
  <port port="4648" protocol="udp"/>
</service>

A  => firewall/services/vault.xml +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<service>
  <short>Vault</short>
  <description>Ports needed by Vault.</description>
  <port port="8200" protocol="tcp"/>
  <port port="8201" protocol="tcp"/>
</service>

A  => firewall/zones/README +1 -0
@@ 1,1 @@
Zone definitions go in /etc/firewalld/zones

A  => firewall/zones/internal.xml +12 -0
@@ 1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<zone>
  <short>Internal</short>
  <description>For use on internal networks. You mostly trust the other computers on the networks to not harm your computer. Only selected incoming connections are accepted.</description>
  <source address="192.168.174.116"/> <!-- add more Consul/Nomad cluster IP addresses here -->
  <service name="ssh"/>
  <service name="mdns"/>
  <service name="samba-client"/>
  <service name="dhcpv6-client"/>
  <service name="consul"/>
  <service name="nomad"/>
</zone>

A  => firewall/zones/trusted.xml +7 -0
@@ 1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<zone target="ACCEPT">
  <short>Trusted</short>
  <description>All network connections are accepted.</description>
  <source address="192.168.255.0/24"/> <!-- Linode NodeBalancers: https://www.linode.com/docs/platform/nodebalancer/nodebalancer-reference-guide/#ip-address-range -->
  <service name="fabio"/>
</zone>

A  => jobs/.gitignore +1 -0
@@ 1,1 @@
.env

A  => jobs/README.md +10 -0
@@ 1,10 @@
This folder contains Nomad job definitions.

## Running

Jobs can be run from this repo using the `run.sh` script. Make sure that the `NOMAD_ADDR`
environment variable is set and any environment variables you need saved in `.env`, then just run:

```
$ ./run.sh <job>
```

A  => jobs/acme-renewer.nomad +54 -0
@@ 1,54 @@
job "acme-renewer" {
	region = "us"

	datacenters = ["us-central"]
	type = "batch"

	#periodic {
	# 	cron = "7 10 * * *"
	# 	time_zone = "America/Chicago"
	#}

	group "acme-renewer" {
		task "renew" {
			driver = "exec"
			config {
				command = "acme.sh"
				args = [
					"--force",
					"--staging",
					"--issue",
					"--dns", "dns_linode_v4",
					"--dnssleep", "900",
					"--cert-file", "${NOMAD_SECRETS_DIR}/cert.pem",
					"--key-file", "${NOMAD_SECRETS_DIR}/key.pem",
					"--ca-file", "${NOMAD_SECRETS_DIR}/ca.pem",
					"--fullchain-file", "${NOMAD_SECRETS_DIR}/fullchain.pem",
					"--reloadcmd", "vault write kv/cert public=@'${NOMAD_SECRETS_DIR}/cert.pem' private=@'${NOMAD_SECRETS_DIR}/key.pem'",
					"--domain", "damienradtke.com",
					"--domain", "*.damienradtke.com",
				]
			}

			artifact {
				source = "https://github.com/Neilpang/acme.sh/archive/2.8.2.tar.gz"
				options {
					checksum = "sha256:9c97ae15db3fc65200db462b3304aa082b1367f1ba4af5a86693b014a991c990"
				}
			}

			resources {
				cpu = 20  # MHz, the minimum value
				memory = 30  # MB
			}

			vault {
				policies = ["acme-renewer"]
			}

			env {
				LINODE_TOKEN = "af53c271d591561eec8c78e88830fbac2c102e0f36796745ac3ff0fb442c7ebd"
			}
		}
	}
}

A  => jobs/cat-facts.nomad +37 -0
@@ 1,37 @@
job "cat-facts" {
	region = "us"

	datacenters = ["us-central"]
	type = "batch"

	periodic {
	 	cron = "7 10 * * *"
	 	time_zone = "America/Chicago"
	}

	group "cat-facts" {
		task "cat-fact" {
			driver = "exec"
			config {
				command = "rusty-cat-fact"
			}

			artifact {
				source = "s3::http://${MINIO_HOST}:9000/artifacts/rusty-cat-fact/target/debug/rusty-cat-fact"
				options {
					aws_access_key_id = "${MINIO_ACCESS_KEY}"
					aws_access_key_secret = "${MINIO_SECRET_KEY}"
				}
			}

			env {
				WEBHOOK_URL = "${CATFACTS_WEBHOOK}"
			}

			resources {
				cpu = 20  # MHz, the minimum value
				memory = 30  # MB
			}
		}
	}
}

A  => jobs/damienradtkecom.nomad +111 -0
@@ 1,111 @@
job "damienradtkecom" {
	region = "us"

	datacenters = ["us-central"]
	type = "service"

	group "server" {
		count = 1

		task "server" {
			driver = "exec"
			config {
				command = "hugo"
				args = [
					"server",
					"--config=local/blog/config.toml",
					"--baseURL=https://damienradtke.com/",
					"--appendPort=false",
					"--watch=false",
					"--bind=0.0.0.0",
					"--port=${NOMAD_PORT_http}",
					"--contentDir=local/blog/content",
					"--layoutDir=local/blog/layouts",
					"--themesDir=local/blog/themes",
				]
			}

			service {
				name = "${JOB}-${TASK}"
				port = "http"

				check {
				      type = "http"
				      protocol = "http"
				      port = "http"
				      interval = "10s"
				      timeout = "2s"
				      path = "/"
				}

				tags = ["urlprefix-damienradtke.com/"]
			}


			resources {
				cpu = 20  # MHz, the minimum value
				memory = 50  # MB
				network {
					port "http" {}
				}
			}

			artifact {
				source = "github.com/dradtke/blog"
				destination = "local/blog/"
				options {
					ref = "d60dd4a75d7d4015e6d0109e15e3fb46d31cd6bc"
				}
			}

			artifact {
				source = "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz"
				options {
					checksum = "sha256:558cd6d492562cf7bc2a24a683cdc2608043a4f593077442480944cc7c1f8665"
				}
			}
		}
	}

	group "certrenewer" {
		count = 1

		task "certrenewer" {
			driver = "exec"
			config {
				command = "cert-renewer"
				args = [
					"--frequency=24h",
					"--balancer=damienradtkecom",
					"--domain=damienradtke.com",
					"--email=me@damienradtke.com",
					"--port=${NOMAD_PORT_http}",
					"--cache-dir=${NOMAD_SECRETS_DIR}",
					"--linode-token=${CERTRENEWER_TOKEN}",
					"--production",
					"--init",
				]
			}

			service {
				name = "${JOB}-${TASK}"
				port = "http"
			}

			resources {
				cpu = 20  # MHz, the minimum value
				memory = 20  # MB
				network {
					port "http" {}
				}
			}

			artifact {
				source = "https://github.com/dradtke/linode-certrenewer/releases/download/v0.1.0/cert-renewer"
				options {
					checksum = "sha256:295224e5135e7c2688d1ede7e253a36ed9178aaafa38771e1914d6f4e48cb449"
				}
			}
		}
	}
}

A  => jobs/fabio.nomad +71 -0
@@ 1,71 @@
job "fabio" {
	region = "us"

	datacenters = ["us-central"]
	type = "service"

	group "fabio" {
		task "fabio" {
			driver = "exec"
			config {
				command = "fabio-1.5.11-go1.11.5-linux_amd64",
				args = [
					"-proxy.cs", "cs=mycerts;type=vault;cert=secret/fabio/certs",
					"-proxy.addr", "0.0.0.0:9999;cs=mycerts",
				]
			}

			artifact {
				source = "https://github.com/fabiolb/fabio/releases/download/v1.5.11/fabio-1.5.11-go1.11.5-linux_amd64"
			}

			vault {
				policies = ["acme-renewer"]
			}

			env {
				VAULT_CAPATH = "/etc/ssl/vault/ca.pem"
			}

			resources {
				memory = 50  # MB
				network {
					port "ui" {
						static = 9998
					}
					port "balancer" {
						static = 9999
					}
				}
			}
		}

		task "porter" {
			driver = "raw_exec"
			config {
				command = "porter",
				args = ["-to", "localhost:9999"]
			}

			artifact {
				source = "s3::http://${MINIO_HOST}:9000/artifacts/porter/porter"
				options {
					aws_access_key_id = "${MINIO_ACCESS_KEY}"
					aws_access_key_secret = "${MINIO_SECRET_KEY}"
				}
			}

			resources {
				memory = 50  # MB
				network {
					port "http" {
						static = 80
					}
					port "https" {
						static = 443
					}
				}
			}
		}
	}
}

A  => jobs/hubot.nomad +40 -0
@@ 1,40 @@
job "hubot" {
	region = "us"

	datacenters = ["us-central"]
	type = "service"

	group "hubots" {
		count = 1

		task "hubot" {
			driver = "raw_exec"
			config {
				command = "bash"
				args = [
					"-c",
					"cd local && exec node_modules/hubot/bin/hubot --adapter slack --name carl",
				]
			}

			user = "nobody"

			env {
				PATH = "node_modules/coffeescript/bin:/usr/bin"

				HUBOT_LOG_LEVEL = "debug"
				HUBOT_SLACK_TOKEN = "${HUBOT_SLACK_TOKEN}"
				HUBOT_GOOGLE_CSE_ID = "${HUBOT_GOOGLE_CSE_ID}"
				HUBOT_GOOGLE_CSE_KEY = "${HUBOT_GOOGLE_CSE_KEY}"
			}

			artifact {
				source = "s3::http://${MINIO_HOST}:9000/artifacts/hubot/hubot.tar.gz"
				options {
					aws_access_key_id = "${MINIO_ACCESS_KEY}"
					aws_access_key_secret = "${MINIO_SECRET_KEY}"
				}
			}
		}
	}
}

A  => jobs/owncloud.nomad +87 -0
@@ 1,87 @@
job "owncloud" {
	region = "us"

	datacenters = ["us-central"]
	type = "service"

	constraint {
		attribute = "${meta.owncloud_mounted}"
		value = "true"
	}

	group "own-cloud" {
		count = 1

			task "server" {
				driver = "docker"
				config {
					image = "owncloud/server:10.2"
					volumes = [
						"/mnt/owncloud:/mnt/data",
					]

					port_map {
						http = 8080
					}
				}

				service {
					name = "${JOB}-${TASK}"
					port = "http"
				}

				resources {
					network {
						port "http" {}
					}
				}

				env {
					OWNCLOUD_ADMIN_USERNAME = "admin"
					OWNCLOUD_ADMIN_PASSWORD = "password"
				}
			}
	}

	//group "certrenewer" {
	//	count = 1

	//	task "certrenewer" {
	//		driver = "exec"
	//		config {
	//			command = "cert-renewer"
	//			args = [
	//				"--frequency=24h",
	//				"--balancer=damienradtkecom",
	//				"--domain=damienradtke.com",
	//				"--email=me@damienradtke.com",
	//				"--port=${NOMAD_PORT_http}",
	//				"--cache-dir=${NOMAD_SECRETS_DIR}",
	//				"--linode-token=${CERTRENEWER_TOKEN}",
	//				"--production",
	//				"--init",
	//			]
	//		}

	//		service {
	//			name = "${JOB}-${TASK}"
	//			port = "http"
	//		}

	//		resources {
	//			cpu = 20  # MHz, the minimum value
	//			memory = 20  # MB
	//			network {
	//				port "http" {}
	//			}
	//		}

	//		artifact {
	//			source = "https://github.com/dradtke/linode-certrenewer/releases/download/v0.1.0/cert-renewer"
	//			options {
	//				checksum = "sha256:295224e5135e7c2688d1ede7e253a36ed9178aaafa38771e1914d6f4e48cb449"
	//			}
	//		}
	//	}
	//}
}

A  => jobs/radtkefamily.nomad +69 -0
@@ 1,69 @@
job "radtkefamily" {
	region = "us"

	datacenters = ["us-central"]
	type = "service"

	group "server" {
		count = 1

		task "server" {
			driver = "exec"
			config {
				command = "hugo"
				args = [
					"server",
					"--config=local/site/config.toml",
					"--baseURL=https://radtke.family/",
					"--appendPort=false",
					"--watch=false",
					"--bind=0.0.0.0",
					"--port=${NOMAD_PORT_http}",
					"--contentDir=local/site/content",
					"--layoutDir=local/site/layouts",
					"--themesDir=local/site/themes",
				]
			}

			service {
				name = "${JOB}-${TASK}"
				port = "http"

				check {
				      type = "http"
				      protocol = "http"
				      port = "http"
				      interval = "10s"
				      timeout = "2s"
				      path = "/"
				}

				tags = ["urlprefix-radtke.family/"]
			}


			resources {
				cpu = 20  # MHz, the minimum value
				memory = 50  # MB
				network {
					port "http" {}
				}
			}

			artifact {
				source = "git::https://git.sr.ht/~damien/radtke-family-site"
				destination = "local/site/"
				options {
					ref = "eb80412984895814038a82a397e73deee2ca73b1"
				}
			}

			artifact {
				source = "https://github.com/gohugoio/hugo/releases/download/v0.58.2/hugo_extended_0.58.2_Linux-64bit.tar.gz"
				options {
					checksum = "sha256:7ac65f7ee6dd30f6c3667e0c2fa22a0034c0945e0614447c6b2b4d7795d192d2"
				}
			}
		}
	}
}

A  => jobs/renew-certs.nomad +33 -0
@@ 1,33 @@
job "renew-certs" {
	region = "us"

	datacenters = ["us-central"]
	type = "batch"

	periodic {
	 	cron = "0 9 * * *"
	 	time_zone = "America/Chicago"
	}

	group "renew-certs" {
		task "renew" {
			driver = "exec"
			config {
				command = "rusty-cat-fact"
			}

			artifact {
				source = "s3::http://${MINIO_HOST}:9000/artifacts/rusty-cat-fact/target/debug/rusty-cat-fact"
				options {
					aws_access_key_id = "${MINIO_ACCESS_KEY}"
					aws_access_key_secret = "${MINIO_SECRET_KEY}"
				}
			}

			resources {
				cpu = 20  # MHz, the minimum value
				memory = 30  # MB
			}
		}
	}
}

A  => jobs/run.sh +45 -0
@@ 1,45 @@
#!/bin/bash

set -o pipefail

if [[ $# -ne 1 ]]; then
	echo "usage: $0 <job>"
	exit 1
fi

JOB_SPEC="$(cat "$1" | env $(cat .env | xargs) envsubst "$(cat .env | awk 'BEGIN {FS="="; ORS=""} {print "${" $1 "} "}')")"

PARSE_REQ_BODY="$(jq -n --arg job "${JOB_SPEC}" '{"JobHCL": $job}')"
JOB_JSON=$(curl --silent --insecure --request POST --data "${PARSE_REQ_BODY}" "${NOMAD_ADDR}/v1/jobs/parse")

if [[ "${JOB_JSON}" != {* ]]; then
	echo "${JOB_JSON}"
	exit 1
fi

PLAN_REQ_BODY=$(jq -n --argjson job "${JOB_JSON}" '{"Job": $job, "Diff": true}')
PLAN=$(curl --silent --insecure --request POST --data "${PLAN_REQ_BODY}" \
	"${NOMAD_ADDR}/v1/job/$(echo "${JOB_JSON}" | jq -r .ID)/plan")

if [[ "${PLAN}" != {* ]]; then
	echo "${PLAN}"
	exit 1
fi

JOB_MODIFY_INDEX="$(echo "${PLAN}" | jq .JobModifyIndex)"
echo "Job Modify Index: ${JOB_MODIFY_INDEX}"

echo "Job Diff:"
echo "${PLAN}" | jq .Diff
echo ""
read -p "Continue? "

if [[ "${REPLY}" != y* ]]; then
	echo "Aborting"
	exit 2
fi

echo ""
CREATE_REQ_BODY="$(jq -n --argjson job "${JOB_JSON}" --argjson job_modify_index "${JOB_MODIFY_INDEX}" \
	'{"Job": $job, "EnforceIndex": true, "JobModifyIndex": $job_modify_index}')"
curl --silent --insecure --request POST --data "${CREATE_REQ_BODY}" "${NOMAD_ADDR}/v1/jobs?pretty"

A  => scripts/README.md +1 -0
@@ 1,1 @@
This folder contains various utility scripts, intended to be installed to /usr/local/bin.

A  => scripts/archive/README.md +1 -0
@@ 1,1 @@
These scripts shouldn't be used anymore, probably.

A  => scripts/archive/create-client-cert.sh +13 -0
@@ 1,13 @@
#!/bin/bash

set -eu -o pipefail

if [[ $# -ne 2 ]]; then
        echo "usage: $0 <app> <cert-name>"
        exit 1
fi

RESPONSE=$(echo '{}' | cfssl gencert -config /etc/ssl/cfssl.json -hostname "localhost,127.0.0.1" -remote "${CA_SERVER}" -label $1 -)
echo "${RESPONSE}" | jq --raw-output .cert > "$2.pem"
echo "${RESPONSE}" | jq --raw-output .key > "$2-key.pem"
chmod 0600 "$2-key.pem"

A  => scripts/archive/create-server-cert.sh +13 -0
@@ 1,13 @@
#!/bin/bash

set -eu -o pipefail

if [[ $# -ne 2 ]]; then
        echo "usage: $0 <app> <cert-name>"
        exit 1
fi

RESPONSE=$(echo '{}' | cfssl gencert -config /etc/ssl/cfssl.json -hostname "server.${REGION}.$1,localhost,127.0.0.1" -remote "${CA_SERVER}" -label $1 -)
echo "${RESPONSE}" | jq --raw-output .cert > "$2.pem"
echo "${RESPONSE}" | jq --raw-output .key > "$2-key.pem"
chmod 0600 "$2-key.pem"

A  => scripts/balance.rb +54 -0
@@ 1,54 @@
#!/usr/bin/env ruby
#
# This script is intended to be run as part of a Consul watch listening for services.
# It then uses Linode's API to remove nodes no longer available, and to add new ones.
#

require 'json'
require 'httparty'

BALANCER_NAME, CONFIG_PORT = ARGV
API_KEY = '62302a5b693c323d40a92183d673b461c74a43b68d01312d15a77591ecc41c44'
HEADERS = {"Authorization" => "Bearer #{API_KEY}"}

resp = HTTParty.get("https://api.linode.com/v4/nodebalancers", :headers => {"Authorization" => "Bearer #{API_KEY}"})
balancer = resp["data"].find do |node|
  node["label"] == BALANCER_NAME
end

resp = HTTParty.get("https://api.linode.com/v4/nodebalancers/#{balancer["id"]}/configs", :headers => {"Authorization" => "Bearer #{API_KEY}"})
config = resp["data"].find do |node|
  node["port"] == CONFIG_PORT.to_i
end

id_map = {}
resp = HTTParty.get("https://api.linode.com/v4/nodebalancers/#{balancer["id"]}/configs/#{config["id"]}/nodes", :headers => {"Authorization" => "Bearer #{API_KEY}"})
have = resp["data"].map do |node|
  id_map[node["address"]] = node["id"]
  node["address"]
end

want = JSON.load(STDIN).map do |service|
  "#{service["Node"]["Address"]}:#{service["Service"]["Port"]}"
end

# remove old servers
(have - want).each do |addr|
  puts "[-] #{addr}"
  resp = HTTParty.delete("https://api.linode.com/v4/nodebalancers/#{balancer["id"]}/configs/#{config["id"]}/nodes/#{id_map[addr]}", :headers => {"Authorization" => "Bearer #{API_KEY}"})
  if resp["errors"]
    puts "  errors found: #{resp["errors"]}"
  end
end

# add new servers
(want - have).each do |addr|
  puts "[+] #{addr}"
  resp = HTTParty.post("https://api.linode.com/v4/nodebalancers/#{balancer["id"]}/configs/#{config["id"]}/nodes", :headers => {"Authorization" => "Bearer #{API_KEY}", "Content-Type" => "application/json"}, :body => {
    :address => addr,
    :label => `uuidgen`.strip.gsub('-', ''),
  }.to_json)
  if resp["errors"]
    puts "  errors found: #{response["errors"]}"
  end
end

A  => scripts/install-cfssl.sh +21 -0
@@ 1,21 @@
#!/bin/bash

set -o pipefail

if [[ $# -ne 2 ]]; then
        echo "usage: $0 <program> <version>"
        exit 1
fi

PROGRAM="$1"
VERSION="$2"
DLROOT="https://pkg.cfssl.org/R${VERSION}"

pushd /tmp
	wget -O cfssl_SHA256SUMS "${DLROOT}/SHA256SUMS"
	wget "${DLROOT}/${PROGRAM}_linux-amd64"
	cat cfssl_SHA256SUMS | grep -E "${PROGRAM}_linux-amd64$" | sha256sum --check -
	chmod a+x "${PROGRAM}_linux-amd64"
	mv "${PROGRAM}_linux-amd64" "/usr/local/bin/${PROGRAM}-${VERSION}"
	ln -s "/usr/local/bin/${PROGRAM}-${VERSION}" "/usr/local/bin/${PROGRAM}"
popd

A  => scripts/install-hashicorp.sh +74 -0
@@ 1,74 @@
#!/bin/bash
#
# This script installs Hashicorp tools from their releases page,
# verifying them against Hashicorp's public key first.

if [[ $# -ne 2 ]]; then
        echo "usage: $0 <app> <version>"
        exit 1
fi

NAME="$1"
VERSION="$2"
OSARCH="linux_amd64"

cat >/tmp/hashicorp.asc <<EOF
-----BEGIN PGP PUBLIC KEY BLOCK-----
Version: GnuPG v1
mQENBFMORM0BCADBRyKO1MhCirazOSVwcfTr1xUxjPvfxD3hjUwHtjsOy/bT6p9f
W2mRPfwnq2JB5As+paL3UGDsSRDnK9KAxQb0NNF4+eVhr/EJ18s3wwXXDMjpIifq
fIm2WyH3G+aRLTLPIpscUNKDyxFOUbsmgXAmJ46Re1fn8uKxKRHbfa39aeuEYWFA
3drdL1WoUngvED7f+RnKBK2G6ZEpO+LDovQk19xGjiMTtPJrjMjZJ3QXqPvx5wca
KSZLr4lMTuoTI/ZXyZy5bD4tShiZz6KcyX27cD70q2iRcEZ0poLKHyEIDAi3TM5k
SwbbWBFd5RNPOR0qzrb/0p9ksKK48IIfH2FvABEBAAG0K0hhc2hpQ29ycCBTZWN1
cml0eSA8c2VjdXJpdHlAaGFzaGljb3JwLmNvbT6JATgEEwECACIFAlMORM0CGwMG
CwkIBwMCBhUIAgkKCwQWAgMBAh4BAheAAAoJEFGFLYc0j/xMyWIIAIPhcVqiQ59n
Jc07gjUX0SWBJAxEG1lKxfzS4Xp+57h2xxTpdotGQ1fZwsihaIqow337YHQI3q0i
SqV534Ms+j/tU7X8sq11xFJIeEVG8PASRCwmryUwghFKPlHETQ8jJ+Y8+1asRydi
psP3B/5Mjhqv/uOK+Vy3zAyIpyDOMtIpOVfjSpCplVRdtSTFWBu9Em7j5I2HMn1w
sJZnJgXKpybpibGiiTtmnFLOwibmprSu04rsnP4ncdC2XRD4wIjoyA+4PKgX3sCO
klEzKryWYBmLkJOMDdo52LttP3279s7XrkLEE7ia0fXa2c12EQ0f0DQ1tGUvyVEW
WmJVccm5bq25AQ0EUw5EzQEIANaPUY04/g7AmYkOMjaCZ6iTp9hB5Rsj/4ee/ln9
wArzRO9+3eejLWh53FoN1rO+su7tiXJA5YAzVy6tuolrqjM8DBztPxdLBbEi4V+j
2tK0dATdBQBHEh3OJApO2UBtcjaZBT31zrG9K55D+CrcgIVEHAKY8Cb4kLBkb5wM
skn+DrASKU0BNIV1qRsxfiUdQHZfSqtp004nrql1lbFMLFEuiY8FZrkkQ9qduixo
mTT6f34/oiY+Jam3zCK7RDN/OjuWheIPGj/Qbx9JuNiwgX6yRj7OE1tjUx6d8g9y
0H1fmLJbb3WZZbuuGFnK6qrE3bGeY8+AWaJAZ37wpWh1p0cAEQEAAYkBHwQYAQIA
CQUCUw5EzQIbDAAKCRBRhS2HNI/8TJntCAClU7TOO/X053eKF1jqNW4A1qpxctVc
z8eTcY8Om5O4f6a/rfxfNFKn9Qyja/OG1xWNobETy7MiMXYjaa8uUx5iFy6kMVaP
0BXJ59NLZjMARGw6lVTYDTIvzqqqwLxgliSDfSnqUhubGwvykANPO+93BBx89MRG
unNoYGXtPlhNFrAsB1VR8+EyKLv2HQtGCPSFBhrjuzH3gxGibNDDdFQLxxuJWepJ
EK1UbTS4ms0NgZ2Uknqn1WRU1Ki7rE4sTy68iZtWpKQXZEJa0IGnuI2sSINGcXCJ
oEIgXTMyCILo34Fa/C6VCm2WBgz9zZO8/rHIiQm1J5zqz0DrDwKBUM9C
=LYpS
-----END PGP PUBLIC KEY BLOCK-----
EOF

gpg --import /tmp/hashicorp.asc

pushd /tmp
        BASE="https://releases.hashicorp.com/${NAME}/${VERSION}"
        ARCHIVE="${NAME}_${VERSION}_${OSARCH}.zip"
        CHECKSUM="${NAME}_${VERSION}_SHA256SUMS"
        CHECKSUM_SIG="${CHECKSUM}.sig"

        # Download the checksum first and verify that it's signed by Hashicorp.
        wget "${BASE}/${CHECKSUM}"
        wget "${BASE}/${CHECKSUM_SIG}"
        sync

        # Verify that the checksum was signed by Hashicorp.
        gpg --verify "${CHECKSUM_SIG}" "${CHECKSUM}" || exit 13

        # Now download the release and verify that the checksum matches.
        # Note that the checksum comes with sums for every platform,
        # so we need to filter down to 64-bit Linux to avoid failures caused by
        # the other releases not being present.
        wget "${BASE}/${ARCHIVE}"
        sync
        cat "${CHECKSUM}" | grep -E "_${OSARCH}\\.zip$" | sha256sum --check - || exit 13

        # If we've reached this point, everything is good to go.
        unzip "${ARCHIVE}"
        mv ./${NAME} /usr/local/bin/${NAME}-${VERSION}
popd

A  => scripts/install-minio-client.sh +28 -0
@@ 1,28 @@
#!/bin/bash
#
# Following the advice given here:
# https://github.com/minio/cookbook/blob/master/docs/verifying-minio-binaries.md

# Import Minio's key.
echo "Importing Mino public key..."
gpg --with-fingerprint --keyserver pgp.mit.edu --recv-keys 12C74390F9AAC728

pushd /tmp
	DL_ROOT="https://dl.min.io/client/mc/release/linux-amd64"

	echo "Downloading files..."
	wget --quiet "${DL_ROOT}/mc.sha256sum"
	FILENAME=$(cat mc.sha256sum | cut -d' ' -f2)
	wget --quiet "${DL_ROOT}/${FILENAME}" \
	             "${DL_ROOT}/${FILENAME}.asc"

	echo "Verifying signature..."
	gpg --verify "${FILENAME}.asc" || exit 13

	echo "Verifying checksum..."
	sha256sum -c mc.sha256sum || exit 13

	echo "Done."
	mv "/tmp/${FILENAME}" /usr/local/bin/mc
	chmod +x /usr/local/bin/mc
popd 2>/dev/null

A  => scripts/issue-cert.sh +30 -0
@@ 1,30 @@
#!/bin/bash
#
# Examples:
# 
#   cd /etc/ssl/vault && issue-cert.sh vault <vault|cli|...>
#   cd /etc/ssl/nomad && issue-cert.sh nomad nomad <server|client>.<global|us-central|...>.nomad
#

set -eu -o pipefail

if [[ $# -lt 2 ]]; then
        echo "usage: $0 <ca> <cert-name>"
        exit 1
fi

CA=$1; shift
CERT_NAME=$1; shift
HOSTNAMES=("${CA}.service.consul" localhost 127.0.0.1)
while [[ $# -gt 0 ]]; do
	HOSTNAMES+=("$1"); shift
done

echo "Issuing new certificate for CA: ${CA}"
echo "Hostnames: ${HOSTNAMES[*]}"
echo ""

RESPONSE=$(echo '{}' | cfssl gencert -config /etc/ssl/cfssl.json -hostname "$(IFS=,; echo "${HOSTNAMES[*]}")" -remote "${CA_SERVER}" -label "${CA}" -)
echo "${RESPONSE}" | jq --raw-output .cert > "${CERT_NAME}.pem"
echo "${RESPONSE}" | jq --raw-output .key > "${CERT_NAME}-key.pem"
chmod 0600 "${CERT_NAME}-key.pem"

A  => services/README.md +1 -0
@@ 1,1 @@
This folder contains systemd service definitions.

A  => services/consul.service +18 -0
@@ 1,18 @@
[Unit]
Description="HashiCorp Consul - A service mesh solution"
Documentation=https://www.consul.io/
Requires=network-online.target
After=network-online.target

[Service]
User=consul
Group=consul
ExecStart=/usr/local/bin/consul agent -config-dir=/etc/consul.d/
ExecReload=/usr/local/bin/consul reload
KillMode=process
Restart=on-failure
LimitNOFILE=65536
WorkingDirectory=/var/lib/consul

[Install]
WantedBy=multi-user.target

A  => services/nomad.service +29 -0
@@ 1,29 @@
[Unit]
Description=Nomad
Documentation=https://nomadproject.io/docs/
Wants=network-online.target
After=network-online.target

# When using Nomad with Consul it is not necessary to start Consul first. These
# lines start Consul before Nomad as an optimization to avoid Nomad logging
# that Consul is unavailable at startup.
Wants=consul.service
After=consul.service

[Service]
#User=nomad
#Group=nomad
ExecReload=/bin/kill -HUP $MAINPID
ExecStart=/usr/local/bin/nomad agent -config /etc/nomad.d
KillMode=process
KillSignal=SIGINT
LimitNOFILE=infinity
LimitNPROC=infinity
Restart=on-failure
RestartSec=2
StartLimitBurst=3
StartLimitIntervalSec=10
TasksMax=infinity

[Install]
WantedBy=multi-user.target

A  => ssl/README.md +8 -0
@@ 1,8 @@
This directory contains two files:

- `ca-cfssl.json`: CFSSL configuration for the CA server.
- `cfssl.json.erb`: CFSSL configuration for servers making requests to the CA server.

## TODO

- Describe SSL layout in `/etc/ssl`.

A  => ssl/ca-cfssl.json +20 -0
@@ 1,20 @@
{
  "signing": {
    "default": {
      "expiry": "87600h",
      "usages": [
        "signing",
        "key encipherment",
        "server auth",
        "client auth"
      ],
      "auth_key": "primary"
    }
  },
  "auth_keys": {
    "primary": {
      "type": "standard",
      "key": "0123456789ABCDEF0123456789ABCDEF"
    }
  }
}

A  => ssl/cfssl.json.erb +26 -0
@@ 1,26 @@
{
  "signing": {
    "default": {
      "expiry": "87600h",
      "usages": [
        "signing",
        "key encipherment",
        "server auth",
        "client auth"
      ],
      "auth_remote": {
        "remote": "ca",
        "auth_key": "primary"
      }
    }
  },
  "auth_keys": {
    "primary": {
      "type": "standard",
      "key": "<%= ca_key %>"
    }
  },
  "remotes": {
    "ca": "<%= ca_server %>"
  }
}