#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" OUT_DIR="${ROOT_DIR}/certs" TLS_DIR="${OUT_DIR}/tls" SSH_DIR="${OUT_DIR}/ssh" SERVER_DNS="localhost" FORCE=0 DO_TLS=1 DO_SSH=1 usage() { cat <<'USAGE' Generate local development TLS certificates and SSH keys for RTR Docker deploys. Usage: scripts/10_generate-certs.sh [options] Options: --out-dir DIR Output directory, default: ./certs --server-dns NAME TLS server dNSName SAN, default: localhost --tls-only Generate only TLS files --ssh-only Generate only SSH files --force Overwrite existing files -h, --help Show this help Generated TLS files: certs/tls/client-ca.crt certs/tls/client-ca.key certs/tls/server-dns.crt certs/tls/server-dns.key certs/tls/client-good.crt certs/tls/client-good.key Generated SSH files: certs/ssh/ssh_host_rsa_key certs/ssh/ssh_host_rsa_key.pub certs/ssh/rtr-client.key certs/ssh/rtr-client.key.pub certs/ssh/rtr-authorized_keys USAGE } die() { echo "error: $*" >&2 exit 1 } info() { echo "[generate-certs] $*" } need_cmd() { command -v "$1" >/dev/null 2>&1 || die "required command not found: $1" } run_quiet() { local log_file log_file="$(mktemp)" if "$@" >"${log_file}" 2>&1; then rm -f "${log_file}" return 0 fi cat "${log_file}" >&2 rm -f "${log_file}" return 1 } ensure_abs_out_dir() { case "${OUT_DIR}" in /*) ;; [A-Za-z]:*) ;; *) OUT_DIR="${ROOT_DIR}/${OUT_DIR}" ;; esac TLS_DIR="${OUT_DIR}/tls" SSH_DIR="${OUT_DIR}/ssh" } check_overwrite() { local path="$1" if [[ -e "${path}" && "${FORCE}" != "1" ]]; then die "${path} already exists; rerun with --force to overwrite" fi } write_tls_config_files() { local tmp_dir="$1" cat >"${tmp_dir}/ca.cnf" <<'EOF' [ req ] distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] CN = rpki-rtr-client-ca EOF cat >"${tmp_dir}/server.cnf" <"${tmp_dir}/client.cnf" <<'EOF' [ req ] distinguished_name = req_distinguished_name prompt = no [ req_distinguished_name ] CN = rpki-rtr-client EOF cat >"${tmp_dir}/server.ext" <"${tmp_dir}/client.ext" <<'EOF' basicConstraints=CA:FALSE keyUsage=digitalSignature,keyEncipherment extendedKeyUsage=clientAuth EOF } generate_tls() { need_cmd openssl mkdir -p "${TLS_DIR}" info "generating TLS certificates in ${TLS_DIR}" info "TLS server dNSName SAN: ${SERVER_DNS}" local files=( "${TLS_DIR}/client-ca.crt" "${TLS_DIR}/client-ca.key" "${TLS_DIR}/server-dns.crt" "${TLS_DIR}/server-dns.key" "${TLS_DIR}/client-good.crt" "${TLS_DIR}/client-good.key" ) for file in "${files[@]}"; do check_overwrite "${file}" done local tmp_dir tmp_dir="$(mktemp -d)" write_tls_config_files "${tmp_dir}" run_quiet openssl genrsa -out "${TLS_DIR}/client-ca.key" 2048 info "created TLS CA key: ${TLS_DIR}/client-ca.key" run_quiet openssl req -x509 -new -nodes \ -config "${tmp_dir}/ca.cnf" \ -key "${TLS_DIR}/client-ca.key" \ -sha256 -days 3650 \ -out "${TLS_DIR}/client-ca.crt" info "created TLS CA cert: ${TLS_DIR}/client-ca.crt" run_quiet openssl genrsa -out "${TLS_DIR}/server-dns.key" 2048 info "created TLS server key: ${TLS_DIR}/server-dns.key" run_quiet openssl req -new \ -config "${tmp_dir}/server.cnf" \ -key "${TLS_DIR}/server-dns.key" \ -out "${tmp_dir}/server-dns.csr" run_quiet openssl x509 -req \ -in "${tmp_dir}/server-dns.csr" \ -CA "${TLS_DIR}/client-ca.crt" \ -CAkey "${TLS_DIR}/client-ca.key" \ -CAcreateserial \ -out "${TLS_DIR}/server-dns.crt" \ -days 3650 -sha256 \ -extfile "${tmp_dir}/server.ext" info "created TLS server cert: ${TLS_DIR}/server-dns.crt" run_quiet openssl genrsa -out "${TLS_DIR}/client-good.key" 2048 info "created TLS client key: ${TLS_DIR}/client-good.key" run_quiet openssl req -new \ -config "${tmp_dir}/client.cnf" \ -key "${TLS_DIR}/client-good.key" \ -out "${tmp_dir}/client-good.csr" run_quiet openssl x509 -req \ -in "${tmp_dir}/client-good.csr" \ -CA "${TLS_DIR}/client-ca.crt" \ -CAkey "${TLS_DIR}/client-ca.key" \ -CAcreateserial \ -out "${TLS_DIR}/client-good.crt" \ -days 3650 -sha256 \ -extfile "${tmp_dir}/client.ext" info "created TLS client cert: ${TLS_DIR}/client-good.crt" rm -f "${TLS_DIR}/client-ca.srl" rm -rf "${tmp_dir}" chmod 600 "${TLS_DIR}"/*.key chmod 644 "${TLS_DIR}"/*.crt } generate_ssh_key() { local path="$1" local comment="$2" check_overwrite "${path}" check_overwrite "${path}.pub" rm -f "${path}" "${path}.pub" run_quiet ssh-keygen -q -t rsa -b 3072 -m PEM -N "" -C "${comment}" -f "${path}" } generate_ssh() { need_cmd ssh-keygen mkdir -p "${SSH_DIR}" info "generating SSH keys in ${SSH_DIR}" generate_ssh_key "${SSH_DIR}/ssh_host_rsa_key" "rpki-rtr-host" info "created SSH host key: ${SSH_DIR}/ssh_host_rsa_key" generate_ssh_key "${SSH_DIR}/rtr-client.key" "rpki-rtr-debug-client" info "created SSH client key: ${SSH_DIR}/rtr-client.key" check_overwrite "${SSH_DIR}/rtr-authorized_keys" cp "${SSH_DIR}/rtr-client.key.pub" "${SSH_DIR}/rtr-authorized_keys" info "created SSH authorized_keys: ${SSH_DIR}/rtr-authorized_keys" chmod 600 \ "${SSH_DIR}/ssh_host_rsa_key" \ "${SSH_DIR}/rtr-client.key" chmod 644 "${SSH_DIR}"/*.pub "${SSH_DIR}/rtr-authorized_keys" } while [[ $# -gt 0 ]]; do case "$1" in --out-dir) [[ $# -ge 2 ]] || die "--out-dir requires a value" OUT_DIR="$2" shift 2 ;; --server-dns) [[ $# -ge 2 ]] || die "--server-dns requires a value" SERVER_DNS="$2" shift 2 ;; --tls-only) DO_TLS=1 DO_SSH=0 shift ;; --ssh-only) DO_TLS=0 DO_SSH=1 shift ;; --force) FORCE=1 shift ;; -h|--help) usage exit 0 ;; *) die "unknown option: $1" ;; esac done ensure_abs_out_dir if [[ "${DO_TLS}" == "1" ]]; then generate_tls fi if [[ "${DO_SSH}" == "1" ]]; then generate_ssh fi info "done" info "generated files under ${OUT_DIR}" if [[ "${DO_TLS}" == "1" ]]; then cat <