locals {
extra_provisions_for_class = lookup({
"load-balancer" = [
"groupadd fabio",
"useradd --gid fabio fabio",
"mkdir -p --mode=0500 /etc/ssl/fabio",
"chown fabio:fabio /etc/ssl/fabio",
"/usr/local/bin/issue-cert.sh --user fabio --ca consul --name consul",
"/usr/local/bin/issue-cert.sh --user fabio --ca vault --name vault",
"firewall-cmd --zone=public --add-service=fabio --permanent",
"firewall-cmd --zone=public --add-service=web --permanent",
"firewall-cmd --reload",
]
}, var.node_class, [])
}
resource "linode_instance" "clients" {
count = var.clients
label = "nomad-client-${random_id.clients[count.index].keepers.datacenter}-${replace(random_id.clients[count.index].b64_url, "-", "_")}"
region = random_id.clients[count.index].keepers.datacenter
image = random_id.clients[count.index].keepers.image
type = random_id.clients[count.index].keepers.instance_type
// private_ip = true
authorized_users = var.authorized_users
group = terraform.workspace
stackscript_id = var.stackscript_id
stackscript_data = {
hostname = "nomad-client-${random_id.clients[count.index].keepers.datacenter}-${replace(random_id.clients[count.index].b64_url, "-", "_")}"
consul_version = random_id.clients[count.index].keepers.consul_version
nomad_version = random_id.clients[count.index].keepers.nomad_version
}
lifecycle {
create_before_destroy = true
}
// wait for stackscript to complete
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"while ! [[ -f /root/StackScript.complete ]]; do echo 'waiting for stackscript to complete...'; sleep 3; done",
]
}
// systemd service files
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/systemd/system/"
source = "../services/"
}
// cfssl config
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/ssl/cfssl.json"
content = data.template_file.cfssl_config.rendered
}
// consul config
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/consul.d"
source = "../config/consul"
}
// consul client config
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/consul.d/client.hcl"
content = <<-EOT
datacenter = "${var.datacenter}"
server = false
retry_join = [
%{for ip in var.consul_server_ips~}
"${split("/", ip)[0]}",
%{endfor~}
]
EOT
}
// nomad config
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/nomad.d"
source = "../config/nomad"
}
// nomad client config
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/nomad.d/client.hcl"
content = <<-EOT
datacenter = "${var.datacenter}"
client {
enabled = true
# This is Nomad's default chroot + SSL certs.
chroot_env {
"/bin" = "/bin"
"/etc" = "/etc"
"/lib" = "/lib"
"/lib32" = "/lib32"
"/lib64" = "/lib64"
"/run/resolvconf" = "/run/resolvconf"
"/sbin" = "/sbin"
"/usr" = "/usr"
# This is where SSL certs actually live on openSUSE. /etc/ssl/certs is symlinked to here
"/var/lib/ca-certificates/pem" = "/var/lib/ca-certificates/pem"
}
node_class = "${var.node_class}"
meta {
%{for key, value in var.meta~}
"${key}" = "${value}"
%{endfor~}
}
}
plugin "raw_exec" {
config {
enabled = true
}
}
EOT
}
// firewall services
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/firewalld/services"
source = "../firewall/services/"
}
// firewall zones
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/firewalld/zones"
source = "../firewall/zones/"
}
// issue-cert script
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/usr/local/bin/issue-cert.sh"
source = "../scripts/issue-cert.sh"
}
// healthcheck script
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/usr/local/bin/healthcheck-nomad.sh"
source = "../scripts/healthcheck-nomad.sh"
}
// Consul certificate authority
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/ssl/consul/ca.pem"
source = "/etc/ssl/consul/ca.pem"
}
// Nomad certificate authority
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/ssl/nomad/ca.pem"
source = "/etc/ssl/nomad/ca.pem"
}
// Vault certificate authority
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/ssl/vault/ca.pem"
source = "/etc/ssl/vault/ca.pem"
}
// set global environment variables
provisioner "file" {
connection { host = split("/", self.ipv6)[0] }
destination = "/etc/profile.local"
content = <<-EOT
export CONSUL_HTTP_ADDR=unix:///var/run/consul/consul_https.sock
export NOMAD_ADDR=https://localhost:4646
export NOMAD_CACERT=/etc/ssl/nomad/ca.pem
export NOMAD_CLIENT_CERT=/etc/ssl/nomad/cli.pem
export NOMAD_CLIENT_KEY=/etc/ssl/nomad/cli-key.pem
EOT
}
// install additional base packages needed for running tasks
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = ["zypper --non-interactive install git docker"]
}
// reload firewall
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = ["service firewalld reload"]
}
// fix permissions
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"chown -R consul:consul /etc/consul.d",
"chown -R nomad:nomad /etc/nomad.d",
"chmod +x /usr/local/bin/issue-cert.sh",
"chmod 0400 /etc/ssl/cfssl.json",
]
}
// issue certs
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"/usr/local/bin/issue-cert.sh --user consul --ca consul --name consul",
"/usr/local/bin/issue-cert.sh --user nomad --ca nomad --name nomad --hostnames client.global.nomad",
"/usr/local/bin/issue-cert.sh --user nomad --ca nomad --name cli",
"/usr/local/bin/issue-cert.sh --user nomad --ca nomad --name nomad --hostnames client.global.nomad",
"/usr/local/bin/issue-cert.sh --user nomad --ca consul --name consul",
"/usr/local/bin/issue-cert.sh --user nomad --ca vault --name vault",
]
}
// fix CLI key permissions
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"chmod g+r /etc/ssl/nomad/cli-key.pem",
]
}
// start services
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"systemctl enable consul && service consul start",
"systemctl enable nomad && service nomad start",
]
}
// install autocompletion
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"sudo -u damien /usr/local/bin/consul -autocomplete-install",
"sudo -u damien /usr/local/bin/nomad -autocomplete-install",
]
}
// run extra provisions based on the node class
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = local.extra_provisions_for_class
}
// run healthcheck script to ensure the node comes up
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"chmod +x /usr/local/bin/healthcheck-nomad.sh",
"/usr/local/bin/healthcheck-nomad.sh",
]
}
// disable further root ssh
provisioner "remote-exec" {
connection { host = split("/", self.ipv6)[0] }
inline = [
"sed -i 's/PermitRootLogin .*/PermitRootLogin no/' /etc/ssh/sshd_config",
"service sshd reload",
]
}
}
resource "random_id" "clients" {
count = var.clients
keepers = {
datacenter = var.datacenter
image = var.image
instance_type = var.instance_type
consul_version = var.consul_version
nomad_version = var.nomad_version
}
byte_length = 4
}
data "template_file" "cfssl_config" {
template = file("${path.module}/../../config/cfssl.json")
vars = {
ca_host = var.ca_host
ca_key = var.ca_key
}
}
// vim: set expandtab shiftwidth=2 tabstop=2: