2023-11-30 18:23:43 +01:00
|
|
|
#!/usr/bin/env bash
|
2023-09-21 16:05:17 +02:00
|
|
|
set -o errexit
|
|
|
|
set -o nounset
|
|
|
|
set -o pipefail
|
|
|
|
|
|
|
|
function print_help_and_exit() {
|
|
|
|
printf "Usage: generate-server-certificate DOMAIN.. \n"
|
|
|
|
printf "\n"
|
|
|
|
printf "Arguments:\n"
|
|
|
|
printf " DOMAIN..\n"
|
|
|
|
printf " The domains to generate a certificate for"
|
|
|
|
printf "Options:\n"
|
|
|
|
printf " -H, --host\n"
|
|
|
|
printf " Host where the service will run, required for sops operations\n"
|
|
|
|
printf " -p, --password-path\n"
|
|
|
|
printf " Path inside pass to find the ca.crt and ca.key files in\n"
|
|
|
|
printf " -r, --root\n"
|
|
|
|
printf " Repository root\n"
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
function mk_safe() {
|
|
|
|
echo "${1//./-}"
|
|
|
|
}
|
|
|
|
|
|
|
|
domain_names=()
|
|
|
|
host=
|
|
|
|
password_path=
|
|
|
|
root="$(git rev-parse --show-toplevel)"
|
|
|
|
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
|
case $1 in
|
2023-11-30 18:23:43 +01:00
|
|
|
-h | --help)
|
|
|
|
print_help_and_exit
|
|
|
|
;;
|
|
|
|
-H | --host)
|
|
|
|
shift # past argument
|
|
|
|
host=$1
|
|
|
|
shift # past value
|
|
|
|
;;
|
|
|
|
-p | --password-path)
|
|
|
|
shift # past argument
|
|
|
|
password_path=$1
|
|
|
|
shift # past value
|
|
|
|
;;
|
|
|
|
-r | --root)
|
|
|
|
shift # past argument
|
|
|
|
root=$1
|
|
|
|
shift # past value
|
|
|
|
;;
|
|
|
|
-*)
|
|
|
|
echo "Unknown option $1"
|
|
|
|
print_help_and_exit
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
domain_names+=("$1") # save domain name
|
|
|
|
shift # past argument
|
|
|
|
;;
|
2023-09-21 16:05:17 +02:00
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
2023-11-30 18:23:43 +01:00
|
|
|
if [[ -z $host ]]; then
|
2023-09-21 16:05:17 +02:00
|
|
|
printf -- "--host required\n"
|
|
|
|
print_help_and_exit
|
2023-11-30 18:23:43 +01:00
|
|
|
elif [[ -z $password_path ]]; then
|
2023-09-21 16:05:17 +02:00
|
|
|
printf -- "--password_path required\n"
|
|
|
|
print_help_and_exit
|
|
|
|
fi
|
|
|
|
|
2023-11-30 18:23:43 +01:00
|
|
|
if [[ ${#domain_names[@]} -eq 0 ]]; then
|
2023-09-21 16:05:17 +02:00
|
|
|
print_help_and_exit
|
|
|
|
fi
|
|
|
|
|
|
|
|
first_safe=$(mk_safe "${domain_names[0]}")
|
|
|
|
|
|
|
|
pushd "$(mktemp -d)"
|
|
|
|
|
2023-11-30 18:23:43 +01:00
|
|
|
cat <<EOF >openssl.cnf
|
2023-09-21 16:05:17 +02:00
|
|
|
[req]
|
|
|
|
req_extensions = v3_req
|
|
|
|
distinguished_name = req_distinguished_name
|
|
|
|
|
|
|
|
[req_distinguished_name]
|
|
|
|
|
|
|
|
[v3_req]
|
|
|
|
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
|
|
|
|
extendedKeyUsage = serverAuth
|
|
|
|
subjectAltName = @alt_names
|
|
|
|
|
|
|
|
[alt_names]
|
|
|
|
EOF
|
|
|
|
|
|
|
|
for key in "${!domain_names[@]}"; do
|
2023-11-30 18:23:43 +01:00
|
|
|
echo "DNS.$((key + 1)) = ${domain_names[$key]}" >>openssl.cnf
|
2023-09-21 16:05:17 +02:00
|
|
|
done
|
|
|
|
|
|
|
|
# Get ca.key and ca.crt from pass
|
2023-11-30 18:23:43 +01:00
|
|
|
pass "$password_path/ca.key" >ca.key
|
|
|
|
pass "$password_path/ca.crt" >ca.crt
|
2023-09-21 16:05:17 +02:00
|
|
|
|
|
|
|
# Generate private key for certificate
|
|
|
|
openssl ecparam -name prime256v1 -genkey -out server.key
|
|
|
|
# Generate certificate signing request (CSR) for server certificate
|
|
|
|
openssl req -new -sha256 -key server.key -out server.csr -subj "/CN=*.home"
|
|
|
|
# Generate server certificate using CA
|
|
|
|
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256 -extfile openssl.cnf -extensions v3_req
|
|
|
|
|
|
|
|
# Copy server.crt to final destination
|
|
|
|
mkdir -p "$root/secrets/pub"
|
|
|
|
cp server.crt "$root/secrets/pub/${first_safe}.crt"
|
|
|
|
|
|
|
|
# Safe the server key to sops
|
|
|
|
server_key=$(awk -v ORS='\\n' '1' server.key)
|
|
|
|
key="[\"certificate-key-${first_safe}\"] \"$server_key\""
|
|
|
|
sops --set "$key" "$root/secrets/hosts/$host/secrets.yaml"
|
|
|
|
|
|
|
|
# Clean Up
|
|
|
|
shred -u openssl.cnf server.key ca.crt ca.key server.crt server.csr ca.srl
|
|
|
|
|
|
|
|
popd
|