#!/usr/bin/env bash # Verifies a generated Docker TLS cert bundle is internally consistent (CA signed both certs, # key/cert pairs match, SANs are correct) BEFORE deploying it — cheap, local, no real dockerd # needed. Once deployed, also verifies live mTLS against a real endpoint if given one. # # Usage: ./verify-docker-tls.sh [lab-host-ip:port] set -euo pipefail DIR="${1:?usage: verify-docker-tls.sh [lab-host-ip:port]}" ENDPOINT="${2:-}" fail() { echo "FAIL: $1" >&2; exit 1; } echo "==> Checking file presence" for f in ca.pem server-cert.pem server-key.pem provisioner-client-cert.pem provisioner-client-key.pem; do [ -f "$DIR/$f" ] || fail "missing $f" done echo "OK: all expected files present" echo "==> Checking key/cert pairs match (modulus comparison)" for pair in "server-cert.pem server-key.pem" "provisioner-client-cert.pem provisioner-client-key.pem"; do set -- $pair cert_mod=$(openssl x509 -noout -modulus -in "$DIR/$1" | openssl md5) key_mod=$(openssl rsa -noout -modulus -in "$DIR/$2" | openssl md5) [ "$cert_mod" = "$key_mod" ] || fail "$1 / $2 do not match" done echo "OK: cert/key pairs match" echo "==> Checking both certs are signed by the CA" openssl verify -CAfile "$DIR/ca.pem" "$DIR/server-cert.pem" | grep -q "OK" || fail "server-cert.pem not CA-signed" openssl verify -CAfile "$DIR/ca.pem" "$DIR/provisioner-client-cert.pem" | grep -q "OK" || fail "provisioner-client-cert.pem not CA-signed" echo "OK: both certs verify against ca.pem" echo "==> Checking private key permissions" for f in ca-key.pem server-key.pem provisioner-client-key.pem; do [ -f "$DIR/$f" ] || continue perm=$(stat -c '%a' "$DIR/$f" 2>/dev/null || stat -f '%Lp' "$DIR/$f") [ "$perm" = "400" ] || echo "WARNING: $f has permissions $perm, expected 400" done if [ -n "$ENDPOINT" ]; then echo "==> Testing live mTLS handshake against $ENDPOINT" echo | openssl s_client -connect "$ENDPOINT" \ -cert "$DIR/provisioner-client-cert.pem" -key "$DIR/provisioner-client-key.pem" \ -CAfile "$DIR/ca.pem" 2>&1 | grep -q "Verify return code: 0" \ && echo "OK: live mTLS handshake succeeded" \ || fail "live handshake against $ENDPOINT failed — check firewall/dockerd TLS config" else echo "(skipped live handshake test — no endpoint given; this only proves the cert bundle is internally consistent, not that dockerd is actually listening with it)" fi echo "==> All checks passed"