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