From 4feec7a93aa9a215e7986674e0ebc5ee70fa18b0 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Thu, 23 May 2024 09:02:11 -0500 Subject: [PATCH] Update PKI server container The PKI server container (which is the base for all PKI subsystem containers) has been updated to install the ROOT webapp (which provides Web UI files) and PKI webapp (which provides common PKI services), and store the default config files. The startup script has been modified to install the default config files if it doesn't exist already, use PKI NSS CLI instead of certutil to prepare the certs, and run the server as pkiuser in Docker/Podman so that the log files will be owned by pkiuser as well. The test has been updated to check the files created by the container and to verify that the container can be restarted successfully. --- .github/workflows/acme-container-test.yml | 11 +- .github/workflows/server-container-test.yml | 160 ++++++++++++++++++-- Dockerfile | 29 +++- base/server/bin/pki-server-run | 130 +++++++++++++--- 4 files changed, 283 insertions(+), 47 deletions(-) diff --git a/.github/workflows/acme-container-test.yml b/.github/workflows/acme-container-test.yml index 6eb9e7cd889..3fcf6cb3491 100644 --- a/.github/workflows/acme-container-test.yml +++ b/.github/workflows/acme-container-test.yml @@ -156,11 +156,12 @@ jobs: # TODO: review owners/permissions cat > expected << EOF drwxrwx--- 17 root backup - -rw-rw-rw- root root catalina.$DATE.log - -rw-rw-rw- root root host-manager.$DATE.log - -rw-rw-rw- root root localhost.$DATE.log - -rw-rw-rw- root root localhost_access_log.$DATE.txt - -rw-rw-rw- root root manager.$DATE.log + -rw-rw-rw- 17 root catalina.$DATE.log + -rw-rw-rw- 17 root host-manager.$DATE.log + -rw-rw-rw- 17 root localhost.$DATE.log + -rw-rw-rw- 17 root localhost_access_log.$DATE.txt + -rw-rw-rw- 17 root manager.$DATE.log + drwxrwxrwx 17 root pki EOF diff expected output diff --git a/.github/workflows/server-container-test.yml b/.github/workflows/server-container-test.yml index 20b1dfd2aa3..c8ebf7f5a15 100644 --- a/.github/workflows/server-container-test.yml +++ b/.github/workflows/server-container-test.yml @@ -6,6 +6,7 @@ env: DB_IMAGE: ${{ vars.DB_IMAGE || 'quay.io/389ds/dirsrv' }} jobs: + # https://github.com/dogtagpki/pki/wiki/Deploying-PKI-Server-Container test: name: Test runs-on: ubuntu-latest @@ -27,12 +28,10 @@ jobs: - name: Create network run: docker network create example - - name: Set up server container + - name: Create shared folders run: | - docker run --name pki --detach pki-server - - - name: Connect server container to network - run: docker network connect example pki --alias pki.example.com + mkdir certs + mkdir data - name: Set up client container run: | @@ -43,8 +42,19 @@ jobs: - name: Connect client container to network run: docker network connect example client --alias client.example.com - - name: Wait for server container to start + - name: Set up server container run: | + docker run \ + --name server \ + --hostname pki.example.com \ + --network example \ + --network-alias pki.example.com \ + -v $PWD/certs:/certs \ + -v $PWD/data:/data \ + --detach \ + pki-server + + # wait for server to start docker exec client curl \ --retry 60 \ --retry-delay 0 \ @@ -54,18 +64,140 @@ jobs: -o /dev/null \ https://pki.example.com:8443 - - name: Gather artifacts from server container + - name: Check data dir + if: always() + run: | + ls -l data \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\(\S*\) *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3 \4/' \ + | tee output + + # everything should be owned by pkiuser:root (UID=17, GID=0) + # TODO: review owners/permissions + cat > expected << EOF + drwxrwxrwx 17 root conf + drwxrwxrwx 17 root logs + EOF + + diff expected output + + - name: Check data/conf dir if: always() run: | - mkdir -p /tmp/artifacts/server - docker logs pki > /tmp/artifacts/server/container.out 2> /tmp/artifacts/server/container.err - mkdir -p /tmp/artifacts/server/var/lib - docker cp pki:/var/lib/tomcats /tmp/artifacts/server/var/lib + ls -l data/conf \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\(\S*\) *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3 \4/' \ + | tee output + + # everything should be owned by pkiuser:root (UID=17, GID=0) + # TODO: review owners/permissions + cat > expected << EOF + drwxrwxrwx 17 root Catalina + drwxrwxrwx 17 root alias + -rw-rw-rw- 17 root catalina.policy + lrwxrwxrwx 17 root catalina.properties -> /usr/share/pki/server/conf/catalina.properties + drwxrwxrwx 17 root certs + lrwxrwxrwx 17 root context.xml -> /etc/tomcat/context.xml + -rw-rw-rw- 17 root jss.conf + lrwxrwxrwx 17 root logging.properties -> /usr/share/pki/server/conf/logging.properties + -rw-rw-rw- 17 root password.conf + -rw-rw-rw- 17 root server.xml + -rw-rw-rw- 17 root tomcat.conf + lrwxrwxrwx 17 root web.xml -> /etc/tomcat/web.xml + EOF + + diff expected output + + - name: Check data/logs dir + if: always() + run: | + ls -l data/logs \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\(\S*\) *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3 \4/' \ + | tee output + + DATE=$(date +'%Y-%m-%d') + + # everything should be owned by pkiuser:root (UID=17, GID=0) + # TODO: review owners/permissions + cat > expected << EOF + drwxrwx--- 17 root backup + -rw-rw-rw- 17 root catalina.$DATE.log + -rw-rw-rw- 17 root host-manager.$DATE.log + -rw-rw-rw- 17 root localhost.$DATE.log + -rw-rw-rw- 17 root localhost_access_log.$DATE.txt + -rw-rw-rw- 17 root manager.$DATE.log + drwxrwxrwx 17 root pki + EOF + + diff expected output + + - name: Check server info locally + run: | + docker exec server pki info + + - name: Install CA signing cert + run: | + docker exec client pki nss-cert-import \ + --cert $SHARED/certs/ca_signing.crt \ + --trust CT,C,C \ + ca_signing + + - name: Check server info remotely + run: | + docker exec client pki \ + -U https://pki.example.com:8443 \ + info + + - name: Restart server + run: | + docker restart server + sleep 5 + + # wait for server to restart + docker exec client curl \ + --retry 60 \ + --retry-delay 0 \ + --retry-connrefused \ + -s \ + -k \ + -o /dev/null \ + https://pki.example.com:8443 + + - name: Check server info remotely again + run: | + docker exec client pki \ + -U https://pki.example.com:8443 \ + info + + - name: Check server container logs + if: always() + run: | + docker logs server 2>&1 + + - name: Gather artifacts + if: always() + run: | + docker exec server ls -la /etc/pki + mkdir -p /tmp/artifacts/server/etc + docker cp server:/etc/pki /tmp/artifacts/server/etc + + docker exec server ls -la /var/log/pki + mkdir -p /tmp/artifacts/server/var/log + docker cp server:/var/log/pki /tmp/artifacts/server/var/log + + docker logs server > /tmp/artifacts/server/container.out 2> /tmp/artifacts/server/container.err + + mkdir -p /tmp/artifacts/client + docker logs client > /tmp/artifacts/client/container.out 2> /tmp/artifacts/client/container.err continue-on-error: true - - name: Upload artifacts from server container + - name: Upload artifacts if: always() uses: actions/upload-artifact@v4 with: - name: server-container-test - path: /tmp/artifacts/server + name: server-container + path: /tmp/artifacts diff --git a/Dockerfile b/Dockerfile index f13ab881a10..a433c6c8ef2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -158,6 +158,19 @@ RUN pki-server http-connector-cert-add \ --keystoreType pkcs11 \ --keystoreProvider Mozilla-JSS +# Deploy ROOT webapp +RUN pki-server webapp-deploy \ + --descriptor /usr/share/pki/server/conf/Catalina/localhost/ROOT.xml \ + ROOT + +# Deploy PKI webapp +RUN pki-server webapp-deploy \ + --descriptor /usr/share/pki/server/conf/Catalina/localhost/pki.xml \ + pki + +# Store default config files +RUN cp -r /data/conf /var/lib/pki/pki-tomcat/conf.default + # Grant the root group the full access to PKI server files # https://www.openshift.com/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id RUN chgrp -Rf root /var/lib/pki/pki-tomcat @@ -188,8 +201,8 @@ RUN pki-server ca-create # Deploy CA subsystem RUN pki-server ca-deploy -# Store default config files -RUN mv /data/conf /var/lib/pki/pki-tomcat/conf.default +# Store additional default config files +RUN cp -r /data/conf/* /var/lib/pki/pki-tomcat/conf.default # Grant the root group the full access to PKI server files # https://www.openshift.com/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id @@ -219,8 +232,8 @@ RUN pki-server kra-create # Deploy KRA subsystem RUN pki-server kra-deploy -# Store default config files -RUN mv /data/conf /var/lib/pki/pki-tomcat/conf.default +# Store additional default config files +RUN cp -r /data/conf/* /var/lib/pki/pki-tomcat/conf.default # Grant the root group the full access to PKI server files # https://www.openshift.com/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id @@ -250,8 +263,8 @@ RUN pki-server ocsp-create # Deploy OCSP subsystem RUN pki-server ocsp-deploy -# Store default config files -RUN mv /data/conf /var/lib/pki/pki-tomcat/conf.default +# Store additional default config files +RUN cp -r /data/conf/* /var/lib/pki/pki-tomcat/conf.default # Grant the root group the full access to PKI server files # https://www.openshift.com/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id @@ -299,8 +312,8 @@ RUN rm -f /usr/share/pki/acme/webapps/acme/WEB-INF/classes/logging.properties # Deploy PKI ACME application RUN pki-server acme-deploy -# Store default config files -RUN mv /data/conf /var/lib/pki/pki-tomcat/conf.default +# Store additional default config files +RUN cp -r /data/conf/* /var/lib/pki/pki-tomcat/conf.default # Grant the root group the full access to PKI ACME files # https://www.openshift.com/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id diff --git a/base/server/bin/pki-server-run b/base/server/bin/pki-server-run index 5fc518694aa..fde969b8b76 100755 --- a/base/server/bin/pki-server-run +++ b/base/server/bin/pki-server-run @@ -7,6 +7,34 @@ . /usr/share/pki/scripts/config +# Allow the owner of the container (who might not be in the root group) +# to manage the config and log files. +umask 000 + +echo "################################################################################" + +if [ -d /data/conf ] +then + echo "info: Reusing /data/conf" +else + echo "INFO: Creating /data/conf" + cp -r /var/lib/pki/pki-tomcat/conf.default /data/conf + chown -Rf pkiuser:root /data/conf + find /data/conf -type f -exec chmod +rw -- {} + + find /data/conf -type d -exec chmod +rwx -- {} + +fi + +echo "################################################################################" + +if [ -d /data/logs ] +then + echo "INFO: Reusing /data/logs" +else + echo "INFO: Creating /data/logs" + mkdir /data/logs + chown -Rf pkiuser:root /data/logs +fi + echo "################################################################################" # import ca_signing.cert and ca_signing.key if available @@ -25,14 +53,22 @@ then -name ca_signing \ -passout file:/tmp/password + # trust CA signing cert in PKCS #12 file + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + pkcs12-cert-mod \ + --pkcs12 /tmp/certs.p12 \ + --password-file /tmp/password \ + --trust-flags CT,C,C \ + ca_signing + # import PKCS #12 file into NSS database - pki -d /var/lib/pki/pki-tomcat/conf/alias pkcs12-import \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + pkcs12-import \ --pkcs12 /tmp/certs.p12 \ --password-file /tmp/password - # trust imported CA signing cert - certutil -M -d /var/lib/pki/pki-tomcat/conf/alias -n ca_signing -t CT,C,C - rm /tmp/certs.p12 rm /tmp/password fi @@ -43,28 +79,38 @@ then echo "INFO: Importing Certificates and Keys from PKCS #12 File" # import PKCS #12 file into NSS database - pki -d /var/lib/pki/pki-tomcat/conf/alias pkcs12-import \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + pkcs12-import \ --pkcs12 /certs/certs.p12 \ --password-file /certs/password fi # check whether CA signing certificate is available rc=0 -certutil -L -d /var/lib/pki/pki-tomcat/conf/alias -n ca_signing -a > /dev/null 2>&1 || rc=$? +pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-export \ + --output-file /certs/ca_signing.crt \ + ca_signing || rc=$? # generate a CA signing certificate if not available if [ $rc -ne 0 ] then - echo "INFO: Issuing Self-signed CA Signing Certificate" + echo "INFO: Creating CA signing cert" # generate CA signing CSR - pki -d /var/lib/pki/pki-tomcat/conf/alias nss-cert-request \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-request \ --subject "CN=CA Signing Certificate" \ --ext /usr/share/pki/server/certs/ca_signing.conf \ --csr /certs/ca_signing.csr # issue self-signed CA signing cert - pki -d /var/lib/pki/pki-tomcat/conf/alias nss-cert-issue \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-issue \ --csr /certs/ca_signing.csr \ --ext /usr/share/pki/server/certs/ca_signing.conf \ --validity-length 1 \ @@ -72,49 +118,93 @@ then --cert /certs/ca_signing.crt # import and trust CA signing cert into NSS database - pki -d /var/lib/pki/pki-tomcat/conf/alias nss-cert-import \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-import \ --cert /certs/ca_signing.crt \ --trust CT,C,C \ ca_signing fi -echo "INFO: CA Signing Certificate:" -certutil -L -d /var/lib/pki/pki-tomcat/conf/alias -n ca_signing +echo "INFO: CA signing cert:" +pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-show \ + ca_signing echo "################################################################################" # check whether SSL server certificate is available rc=0 -certutil -L -d /var/lib/pki/pki-tomcat/conf/alias -n sslserver -a > /dev/null 2>&1 || rc=$? +pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-export \ + --output-file /certs/sslserver.crt \ + sslserver || rc=$? # generate a SSL server certificate if not available if [ $rc -ne 0 ] then - echo "INFO: Issuing SSL Server Certificate" + echo "INFO: Creating SSL server cert" # generate SSL server CSR - pki -d /var/lib/pki/pki-tomcat/conf/alias nss-cert-request \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-request \ --subject "CN=$HOSTNAME" \ --ext /usr/share/pki/server/certs/sslserver.conf \ --csr /certs/sslserver.csr # issue SSL server cert - pki -d /var/lib/pki/pki-tomcat/conf/alias nss-cert-issue \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-issue \ --issuer ca_signing \ --csr /certs/sslserver.csr \ --ext /usr/share/pki/server/certs/sslserver.conf \ --cert /certs/sslserver.crt # import SSL server cert into NSS database - pki -d /var/lib/pki/pki-tomcat/conf/alias nss-cert-import \ + pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-import \ --cert /certs/sslserver.crt \ sslserver fi -echo "INFO: SSL Server Certificate:" -certutil -L -d /var/lib/pki/pki-tomcat/conf/alias -n sslserver +echo "INFO: SSL server cert:" +pki \ + -d /var/lib/pki/pki-tomcat/conf/alias \ + nss-cert-show \ + sslserver + +echo "################################################################################" + +# check whether CA signing cert exists in default NSS database +rc=0 +pki nss-cert-export ca_signing > /dev/null || rc=$? + +if [ $rc -ne 0 ] +then + echo "INFO: Importing CA signing cert" + pki nss-cert-import \ + --cert /certs/ca_signing.crt \ + --trust CT,C,C \ + ca_signing +fi echo "################################################################################" echo "INFO: Starting PKI server" -pki-server run --as-current-user +if [ "$UID" = "0" ]; then + # In Docker/Podman the server runs as pkiuser (UID=17) that + # belongs to the root group (GID=0). + pki-server run + +else + # In OpenShift the server runs as an OpenShift-assigned user + # (with a random UID) that belongs to the root group (GID=0). + # + # https://www.redhat.com/en/blog/jupyter-on-openshift-part-6-running-as-an-assigned-user-id + pki-server run --as-current-user +fi