commit 3a72024bfa73f802efb0e59e166a95457daed0e3
parent c37679b5eed3efcb95ff32bf67fe169689c70a6d
Author: Andreas Gruhler <andreas.gruhler@adfinis.com>
Date:   Sat, 27 Jul 2024 13:55:46 +0200
feat(nomad): tls and gossip encryption
Diffstat:
5 files changed, 138 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,2 +1,3 @@
 **.swp
 **auto.pkrvars.hcl
+tls
diff --git a/README.md b/README.md
@@ -74,11 +74,31 @@ The Packer JSON supports a few arguments for Bao server certificates:
 * `vault_tls_subj_alt_name`: Comma seperated list of Subject Alternative Names
   (SAN) for the self-signed certificates, e.g., `DNS:vault.example.com`
 
+### Nomad
+The steps to create a set of self-signed certificates for Nomad are not fully
+automated to have control over the certificate generation process.
+
+TLS is a prerequisite for workload identities with JWT:
+* https://developer.hashicorp.com/nomad/docs/concepts/workload-identity
+
+A `nomad` binary on the Packer build host is required to create the initial CA
+certificate (trust anchor):
+```bash
+# create nomad CA
+mkdir -p tls/nomad && cd tls/nomad
+nomad tls ca create
+```
+
+Then run the script from the projects root directory to create a new set of
+certificates in the directory `./tls/nomad/certs`:
+```bash
+./nomad-tls.sh
+```
+
 ## ACL's
 tbd
 
 * ACLs for Nomad
-* TLS and Gossip encryption for Nomad
 
 ## Authorized Keys
 Copy the contents of an openssh pubkey to `authorized_keys` Packer variable.
diff --git a/hashi-pi.pkr.hcl b/hashi-pi.pkr.hcl
@@ -28,6 +28,22 @@ variable "img_url" {
   default = "https://downloads.raspberrypi.org/raspios_lite_arm64/images/raspios_lite_arm64-2024-03-15/2024-03-15-raspios-bookworm-arm64-lite.img.xz"
 }
 
+variable "nomad_tls_ca" {
+  type    = string
+  default = "./tls/nomad/nomad-agent-ca.pem"
+}
+
+variable "nomad_tls_certs" {
+  type    = string
+  default = "./tls/nomad/certs/"
+}
+
+variable "nomad_encrypt" {
+  type      = string
+  default   = ""
+  sensitive = true
+}
+
 variable "nomad_client" {
   type    = string
   default = "true"
@@ -174,6 +190,16 @@ build {
     inline = ["mkdir /tmp/tls"]
   }
 
+  provisioner "file" {
+    destination = "/tmp/tls/nomad-agent-ca.pem"
+    source      = "${var.nomad_tls_ca}"
+  }
+
+  provisioner "file" {
+    destination = "/tmp/tls/"
+    source      = "${var.nomad_tls_certs}"
+  }
+
   provisioner "shell" {
     script        = "nomad.sh"
     remote_folder = "/home/${var.username}"
@@ -182,6 +208,7 @@ build {
       "NFS_SERVER=${var.nomad_nfs_server}",
       "NFS_MOUNT=${var.nomad_nfs_mount}",
       "NFS_MOUNT_TARGET=${var.nomad_nfs_target}",
+      "NOMAD_ENCRYPT=${var.nomad_encrypt}",
       "NOMAD_SERVER=${var.nomad_server}",
       "NOMAD_CLIENT=${var.nomad_client}",
       "NOMAD_PODMAN_DRIVER_VERSION=${var.nomad_podman_driver_version}",
diff --git a/nomad-tls.sh b/nomad-tls.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+#
+# Creates a set of certificates for use with HashiCorp Nomad
+# https://developer.hashicorp.com/nomad/tutorials/transport-security/security-enable-tls
+
+# set -o errexit
+# set -o nounset
+# set -o xtrace
+
+# https://www.shellhacks.com/yes-no-bash-script-prompt-confirmation/
+read -p "Do you want to generate a new set of Nomad certicates in the directory \"./tls/nomad/\" [y/N]? " -n 1 -r
+echo    # (optional) move to a new line
+if [[ ! $REPLY =~ ^[Yy]$ ]]
+then
+    exit 1
+fi
+
+# Set working dir
+NOMAD_TLS_BASE_PATH="${NOMAD_TLS_BASE_PATH:-./tls/nomad/}"
+mkdir -p "$NOMAD_TLS_BASE_PATH"
+cd "$NOMAD_TLS_BASE_PATH"
+
+# Cleanup previously generated certificates
+rm -rf certs
+
+# Define cert types
+crt_types=("server" "cli" "client")
+
+for type in "${crt_types[@]}"; do
+  # Create certificate
+  nomad tls cert create -region dc1 -days 3560 -${type}
+  cert="dc1-$type-nomad.pem"
+  key="dc1-$type-nomad-key.pem"
+
+  # Show fingerprint
+  openssl x509 -in $cert -fingerprint -noout
+done;
+
+# Move to certs folder
+mkdir certs
+mv dc1-* certs/
diff --git a/nomad.sh b/nomad.sh
@@ -9,6 +9,15 @@ set -o xtrace
 
 cd "/home/${USERNAME}"
 
+# Move uploaded tls files
+TLS_DIR=/etc/nomad.d/tls
+mkdir -p $TLS_DIR
+mv /tmp/tls/* $TLS_DIR
+
+chmod 640 $TLS_DIR/*.pem
+chmod 644 $TLS_DIR/dc1-{cli,client,server}*
+chmod 644 $TLS_DIR/nomad-agent-ca.pem
+
 # Install podman driver for Nomad
 # https://developer.hashicorp.com/nomad/plugins/drivers/community/containerd
 curl -LO "https://releases.hashicorp.com/nomad-driver-podman/${NOMAD_PODMAN_DRIVER_VERSION}/nomad-driver-podman_${NOMAD_PODMAN_DRIVER_VERSION}_linux_arm64.zip"
@@ -58,6 +67,10 @@ if [[ "$NOMAD_SERVER" = true ]]; then
 cat << EOF > /etc/nomad.d/server.hcl 
 server {
   enabled = true
+
+  # Encrypt gossip communication
+  encrypt = "$NOMAD_ENCRYPT"
+
   bootstrap_expect = 3
   server_join {
     retry_join = [ "pi0", "pi2", "pi4" ]
@@ -86,6 +99,18 @@ server {
     }
   }
 }
+
+tls {
+  http = true
+  rpc  = true
+
+  ca_file   = "$TLS_DIR/nomad-agent-ca.pem"
+  cert_file = "$TLS_DIR/dc1-server-nomad.pem"
+  key_file  = "$TLS_DIR/dc1-server-nomad-key.pem"
+
+  verify_server_hostname = true
+  verify_https_client    = false
+}
 EOF
 
 # https://www.nomadproject.io/docs/integrations/vault-integration
@@ -94,12 +119,6 @@ fi # endif NOMAD_SERVER
 
 systemctl enable nomad
 
-# Configure .bashrc
-cat << EOF >> .bashrc
-
-complete -C /usr/bin/nomad nomad
-EOF
-
 if [[ "$NOMAD_CLIENT" = true ]]; then
 # this instance acts as a Nomad client agent
 cat << EOF > /etc/nomad.d/client.hcl
@@ -139,6 +158,18 @@ client {
   }
 }
 
+tls {
+  http = true
+  rpc  = true
+
+  ca_file   = "$TLS_DIR/nomad-agent-ca.pem"
+  cert_file = "$TLS_DIR/dc1-client-nomad.pem"
+  key_file  = "$TLS_DIR/dc1-client-nomad-key.pem"
+
+  verify_server_hostname = true
+  verify_https_client    = false
+}
+
 # Enable raw exec driver (jobs w/o isolation)
 plugin "raw_exec" {
   config {
@@ -193,3 +224,13 @@ systemctl --user -M jenkins@ enable podman.socket
 sudo -u jenkins mkdir /home/jenkins/workspace
 
 fi # endif NOMAD_CLIENT
+
+# Configure .bashrc
+cat << EOF >> "/home/${USERNAME}/.bashrc"
+
+complete -C /usr/bin/nomad nomad
+export NOMAD_ADDR=https://localhost:4646
+export NOMAD_CACERT=$TLS_DIR/nomad-agent-ca.pem
+export NOMAD_CLIENT_CERT=$TLS_DIR/dc1-cli-nomad.pem
+export NOMAD_CLIENT_KEY=$TLS_DIR/dc1-cli-nomad-key.pem
+EOF
+\ No newline at end of file