diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 285c35e..39acbd8 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - image-name: ["secret-generation"] + image-name: ["secret-generation", "certificates-generation"] steps: - name: Checkout uses: actions/checkout@v4 diff --git a/certificates-generation/Dockerfile b/certificates-generation/Dockerfile new file mode 100644 index 0000000..7f3aad4 --- /dev/null +++ b/certificates-generation/Dockerfile @@ -0,0 +1,32 @@ +FROM debian:latest + +# Install necessary packages +RUN apt-get update && apt-get install -y \ + openssl \ + && rm -rf /var/lib/apt/lists/* + +# Create necessary CA directories +RUN mkdir -p /ca/certs && \ + mkdir -p /ca/private && \ + mkdir -p /ca/newcerts && \ + mkdir -p /ca/crl && \ + mkdir -p /ca/requests +RUN chmod 700 /ca/private && \ + touch /ca/index.txt && \ + echo 1000 > /ca/serial && \ + echo 1000 > /ca/crlnumber + +# Copy OpenSSL config file +COPY openssl_config_ca.cnf /ca/openssl_config_ca.cnf +COPY openssl_config_host.cnf /ca/openssl_config_host.cnf +COPY openssl_config_user.cnf /ca/openssl_config_user.cnf + +# Generate CA private key and certificate +RUN openssl genrsa -out /ca/private/ca.key 2048 +RUN openssl req -config /ca/openssl_config_ca.cnf -x509 -new -nodes -key /ca/private/ca.key -sha256 -days 365 -extensions v3_ca -out /ca/certs/ca.cert.pem + +# Entry point script to generate certs on startup +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +CMD ["/entrypoint.sh"] diff --git a/certificates-generation/entrypoint.sh b/certificates-generation/entrypoint.sh new file mode 100644 index 0000000..8aa9833 --- /dev/null +++ b/certificates-generation/entrypoint.sh @@ -0,0 +1,67 @@ +#!/bin/bash + +### CA + +echo "Generating DIRAC server certificate" +if ! openssl genrsa -out /ca/certs/hostkey.pem 2048; then + echo "Failed to generate DIRAC server private key" + exit 1 +fi +chmod 400 hostkey.pem + +### DIRAC Server + +if ! openssl req -config /ca/openssl_config_host.cnf \ + -new \ + -sha256 \ + -key /ca/certs/hostkey.pem \ + -out /ca/requests/server.csr; then + echo "Failed to generate DIRAC server certificate signing request" + exit 1 +fi +if ! openssl ca -config /ca/openssl_config_ca.cnf \ + -batch \ + -days 1 \ + -in /ca/requests/server.csr \ + -extensions server_cert \ + -out /ca/certs/hostcert.pem; then + echo "Failed to generate DIRAC server certificate" + exit 1 +fi + +### User + +if ! openssl genrsa -out /ca/certs/client.key 2048; then + echo "Failed to generate user private key" + exit 1 +fi +chmod 400 client.key + +if ! openssl req -config /ca/openssl_config_user.cnf \ + -key /ca/certs/client.key \ + -new \ + -out /ca/requests/client.req; then + echo "Failed to generate user certificate signing request" + exit 1 +fi + +if ! openssl ca -config /ca/openssl_config_ca.cnf \ + -extensions usr_cert \ + -batch \ + -days 1 \ + -in /ca/requests/client.req \ + -out /ca/certs/client.pem; then + echo "Failed to generate user certificate" + exit 1 +fi + +### + +echo "DIRAC Certificates generated and available in /ca/certs" + +if ! chmod -R o=u /ca/certs; then + echo "Failed to set read permissions on /ca/certs" + exit 1 +fi + +exit 0 diff --git a/certificates-generation/openssl_config_ca.cnf b/certificates-generation/openssl_config_ca.cnf new file mode 100644 index 0000000..32e46a4 --- /dev/null +++ b/certificates-generation/openssl_config_ca.cnf @@ -0,0 +1,107 @@ +# OpenSSL root CA configuration file + +[ ca ] +# `man ca` +default_ca = CA_default + +[ CA_default ] +# Directory and file locations. +dir = /ca +####### +certs = $dir/certs +crl_dir = $dir/crl +new_certs_dir = $dir/newcerts +database = $dir/index.txt +serial = $dir/serial +RANDFILE = $dir/private/.rand + +# The root key and root certificate. +private_key = $dir/private/ca.key +certificate = $dir/certs/ca.cert.pem + +# For certificate revocation lists. +crlnumber = $dir/crlnumber +crl = $dir/crl/ca.crl.pem +crl_extensions = crl_ext +default_crl_days = 30 +default_md = sha256 + +name_opt = ca_default +cert_opt = ca_default +default_days = 375 +preserve = no +policy = policy_loose + +# This option is dangerous, but allows to +# set subjectAlternativeName on the Request +# `man ca` is your friend +copy_extensions=copy + +[ policy_strict ] +# The root CA should only sign intermediate certificates that match. +# See the POLICY FORMAT section of `man ca`. +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ policy_loose ] +# Allow the intermediate CA to sign a more diverse range of certificates. +# See the POLICY FORMAT section of the `ca` man page. +countryName = optional +stateOrProvinceName = optional +localityName = optional +organizationName = optional +organizationalUnitName = optional +commonName = supplied +emailAddress = optional + +[ req ] +# Options for the `req` tool (`man req`). +default_bits = 2048 +distinguished_name = req_distinguished_name +string_mask = utf8only +prompt = no + + +# SHA-1 is deprecated, so use SHA-2 instead. +default_md = sha256 + +# Extension to add when the -x509 option is used. +x509_extensions = v3_ca + +[ req_distinguished_name ] +# See . +# EDIT HERE OPTIONALLY +O = DIRAC CI +CN = DIRAC CI Signing Certification Authority +######## + +[ v3_ca ] +# Extensions for a typical CA (`man x509v3_config`). +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical, CA:true +keyUsage = critical, digitalSignature, cRLSign, keyCertSign + +[ usr_cert ] +# Extensions for client certificates (`man x509v3_config`). +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth + + +# Whatever is in the request will be copied, unless it is already defined. +# So we have some double definitions here with the other ssl config files, +# but that's allright. The basicConstraints = CA:FALSE is a protection that MUST stay +[ server_cert ] +# Extensions for server certificates (`man x509v3_config`). +basicConstraints = CA:FALSE +nsComment = "OpenSSL Generated Server Certificate" +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +keyUsage = critical, digitalSignature, keyEncipherment +# Our servers need both serverAuth and clientAuth +extendedKeyUsage = serverAuth,clientAuth diff --git a/certificates-generation/openssl_config_host.cnf b/certificates-generation/openssl_config_host.cnf new file mode 100644 index 0000000..853d946 --- /dev/null +++ b/certificates-generation/openssl_config_host.cnf @@ -0,0 +1,37 @@ +# OpenSSL root CA configuration file + + +[ req ] +# Options for the `req` tool (`man req`). +default_bits = 2048 +distinguished_name = req_distinguished_name +string_mask = utf8only +prompt = no +encrypt_key = yes + +# SHA-1 is deprecated, so use SHA-2 instead. +default_md = sha256 + +# Extension to add in the request +req_extensions = v3_req + +[ req_distinguished_name ] +# CAUTION the name also needs to be in the alt_names as per RFC (don't remember the number) +# See . +C = ch +O = DIRAC +OU = DIRAC CI +CN = server + + +[ v3_req ] +# Extensions to ask for the cert (`man x509v3_config`). +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth,clientAuth +subjectKeyIdentifier = hash +subjectAltName = @alt_names + + +[ alt_names ] +DNS.1 = server +DNS.2 = localhost diff --git a/certificates-generation/openssl_config_user.cnf b/certificates-generation/openssl_config_user.cnf new file mode 100644 index 0000000..f767b58 --- /dev/null +++ b/certificates-generation/openssl_config_user.cnf @@ -0,0 +1,20 @@ +[ req ] +default_bits = 2048 +encrypt_key = yes +distinguished_name = req_dn +prompt = no +req_extensions = v3_req + +# Generates the following subject +# Subject: O=DIRAC CI, O=CERN, CN=ciuser +[ req_dn ] +C = ch +O = DIRAC +OU = DIRAC CI +CN = ciuser + +[ v3_req ] +# Extensions for client certificates (`man x509v3_config`). +nsComment = "OpenSSL Generated Client Certificate" +keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment +extendedKeyUsage = clientAuth