From 311d7b4c85fc4f5934f59bf8df43e9a1f9a618a5 Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Fri, 14 Jun 2024 10:34:41 -0500 Subject: [PATCH] Add test for CA container user service A new test has been added to run a CA container as a rootless systemd service in user space then perform a cert enrollment. --- .github/workflows/ca-container-tests.yml | 5 + .../ca-container-user-service-test.yml | 398 ++++++++++++++++++ 2 files changed, 403 insertions(+) create mode 100644 .github/workflows/ca-container-user-service-test.yml diff --git a/.github/workflows/ca-container-tests.yml b/.github/workflows/ca-container-tests.yml index 425a4e9d8b1..b0f53cfc0c2 100644 --- a/.github/workflows/ca-container-tests.yml +++ b/.github/workflows/ca-container-tests.yml @@ -28,6 +28,11 @@ jobs: needs: build uses: ./.github/workflows/ca-container-system-service-test.yml + ca-container-user-service-test: + name: CA container user service + needs: build + uses: ./.github/workflows/ca-container-user-service-test.yml + ca-container-migration-test: name: CA migration to container needs: build diff --git a/.github/workflows/ca-container-user-service-test.yml b/.github/workflows/ca-container-user-service-test.yml new file mode 100644 index 00000000000..b08c952b839 --- /dev/null +++ b/.github/workflows/ca-container-user-service-test.yml @@ -0,0 +1,398 @@ +name: CA container user service + +on: workflow_call + +env: + DB_IMAGE: ${{ vars.DB_IMAGE || 'quay.io/389ds/dirsrv' }} + +jobs: + test: + name: Test + runs-on: ubuntu-latest + env: + SHARED: /tmp/workdir/pki + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get -y install jq + + - name: Clone repository + uses: actions/checkout@v4 + + - name: Retrieve PKI images + uses: actions/cache@v4 + with: + key: pki-images-${{ github.sha }} + path: pki-images.tar + + - name: Load PKI images + run: docker load --input pki-images.tar + + - name: Create network + run: docker network create example + + - name: Set up DS container + run: | + tests/bin/ds-container-create.sh \ + --image=${{ env.DB_IMAGE }} \ + --hostname=ds.example.com \ + --network=example \ + --network-alias=ds.example.com \ + --password=Secret.123 \ + ds + + - name: Set up PKI container + run: | + tests/bin/runner-init.sh \ + --hostname=ca.example.com \ + --network=example \ + pki + + - name: Install Podman + run: | + docker exec pki dnf install -y podman fuse-overlayfs + docker exec pki podman info + + - name: Configure rootless container + run: | + # enable SETUID and SETGID capabilities + # https://github.com/containers/podman/discussions/21739 + docker exec pki setcap cap_setuid+ep /usr/bin/newuidmap + docker exec pki setcap cap_setgid+ep /usr/bin/newgidmap + + # enable login shell + docker exec pki usermod -s /bin/bash pkiuser + + # enable access to systemd journal + docker exec pki usermod -a -G systemd-journal pkiuser + + # add subordinate UID and GID ranges + # https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md + docker exec pki usermod --add-subuids 100000-165535 --add-subgids 100000-165535 pkiuser + + # enable systemd linger + # https://blog.christophersmart.com/2021/02/20/rootless-podman-containers-under-system-accounts-managed-and-enabled-at-boot-with-systemd/ + docker exec pki loginctl enable-linger pkiuser + + # use fuse-overlayfs + # https://github.com/containers/podman/issues/8705#issuecomment-744357805 + docker exec -u pkiuser pki mkdir -p /home/pkiuser/.config/containers + docker exec -i -u pkiuser pki tee /home/pkiuser/.config/containers/storage.conf << EOF + [storage] + driver = "overlay" + + [storage.options.overlay] + mount_program = "/usr/bin/fuse-overlayfs" + EOF + + docker exec -u pkiuser pki podman system info --format=json | tee output + + # rootless should be enabled + echo "true" > expected + jq -r '.host.security.rootless' output > actual + diff expected actual + + - name: Load PKI images into PKI user's space + run: | + docker cp pki-images.tar pki:/home/pkiuser + docker exec pki chown pkiuser /home/pkiuser/pki-images.tar + + docker exec -u pkiuser pki podman load --input /home/pkiuser/pki-images.tar + docker exec -u pkiuser pki podman images + + - name: Create shared folders in PKI user's home directory + run: | + # create folders with default owner and permissions + docker exec -u pkiuser pki mkdir -p /home/pkiuser/.dogtag/pki-ca/conf + docker exec -u pkiuser pki mkdir -p /home/pkiuser/.dogtag/pki-ca/logs + + docker exec pki ls -laR /home/pkiuser + + - name: Create CA user service + run: | + # create container unit file + # https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html + docker exec -u pkiuser pki mkdir -p /home/pkiuser/.config/containers/systemd + docker exec -i -u pkiuser pki tee /home/pkiuser/.config/containers/systemd/pki-ca.container << EOF + [Unit] + Description=PKI CA + + [Container] + Image=pki-ca + Network=host + + # run container as PKI user + User=pkiuser + Group=pkiuser + UserNS=keep-id + + # use shared folders in home directory + Volume=/home/pkiuser/.dogtag/pki-ca/conf:/conf + Volume=/home/pkiuser/.dogtag/pki-ca/logs:/logs + + # configure DS connection + Environment=PKI_DS_URL=ldap://ds.example.com:3389 + Environment=PKI_DS_PASSWORD=Secret.123 + + [Install] + WantedBy=multi-user.target + EOF + + # check service unit file generated by Quadlet + docker exec -u pkiuser pki /usr/libexec/podman/quadlet -dryrun -user + + # reload service unit files using login shell + docker exec pki sudo -i -u pkiuser systemctl --user daemon-reload + + - name: Run CA user service + run: | + # start service using login shell + docker exec pki sudo -i -u pkiuser systemctl --user start pki-ca.service + docker exec -u pkiuser pki podman ps + + # wait for CA to start + docker exec -u pkiuser pki curl \ + --retry 180 \ + --retry-delay 0 \ + --retry-connrefused \ + -s \ + -k \ + -o /dev/null \ + https://ca.example.com:8443 + + - name: Check conf dir + if: always() + run: | + docker exec -u pkiuser pki ls -l /home/pkiuser/.dogtag/pki-ca/conf \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\S* *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3/' \ + | tee output + + # everything should be owned by pkiuser group + # TODO: review owners/permissions + cat > expected << EOF + drwxrwxrwx pkiuser Catalina + drwxrwxrwx pkiuser alias + drwxrwxrwx pkiuser ca + -rw-rw-rw- pkiuser catalina.policy + lrwxrwxrwx pkiuser catalina.properties -> /usr/share/pki/server/conf/catalina.properties + drwxrwxrwx pkiuser certs + lrwxrwxrwx pkiuser context.xml -> /etc/tomcat/context.xml + -rw-rw-rw- pkiuser jss.conf + lrwxrwxrwx pkiuser logging.properties -> /usr/share/pki/server/conf/logging.properties + -rw-rw-rw- pkiuser password.conf + -rw-rw-rw- pkiuser server.xml + -rw-rw-rw- pkiuser serverCertNick.conf + -rw-rw-rw- pkiuser tomcat.conf + lrwxrwxrwx pkiuser web.xml -> /etc/tomcat/web.xml + EOF + + diff expected output + + - name: Check conf/alias dir + if: always() + run: | + docker exec -u pkiuser pki ls -l /home/pkiuser/.dogtag/pki-ca/conf/alias \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\S* *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3/' \ + | tee output + + # everything should be owned by pkiuser group + # TODO: review owners/permissions + cat > expected << EOF + -rw-rw-rw- pkiuser ca.crt + -rw-rw-rw- pkiuser cert9.db + -rw-rw-rw- pkiuser key4.db + -rw-rw-rw- pkiuser pkcs11.txt + EOF + + diff expected output + + - name: Check conf/ca dir + if: always() + run: | + docker exec -u pkiuser pki ls -l /home/pkiuser/.dogtag/pki-ca/conf/ca \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\S* *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3/' \ + -e '/^\S* *\S* *\S* *CS.cfg.bak /d' \ + | tee output + + # everything should be owned by pkiuser group + # TODO: review owners/permissions + cat > expected << EOF + -rw-rw-rw- pkiuser CS.cfg + -rw-rw-rw- pkiuser adminCert.profile + drwxrwxrwx pkiuser archives + -rw-rw-rw- pkiuser caAuditSigningCert.profile + -rw-rw-rw- pkiuser caCert.profile + -rw-rw-rw- pkiuser caOCSPCert.profile + drwxrwxrwx pkiuser emails + -rw-rw-rw- pkiuser flatfile.txt + drwxrwxrwx pkiuser profiles + -rw-rw-rw- pkiuser proxy.conf + -rw-rw-rw- pkiuser registry.cfg + -rw-rw-rw- pkiuser serverCert.profile + -rw-rw-rw- pkiuser subsystemCert.profile + EOF + + diff expected output + + - name: Check logs dir + if: always() + run: | + docker exec -u pkiuser pki ls -l /home/pkiuser/.dogtag/pki-ca/logs \ + | sed \ + -e '/^total/d' \ + -e 's/^\(\S*\) *\S* *\S* *\(\S*\) *\S* *\S* *\S* *\S* *\(.*\)$/\1 \2 \3/' \ + | tee output + + DATE=$(date +'%Y-%m-%d') + + # everything should be owned by pkiuser group + # TODO: review owners/permissions + cat > expected << EOF + drwxrwx--- pkiuser backup + drwxrwxrwx pkiuser ca + -rw-rw-rw- pkiuser catalina.$DATE.log + -rw-rw-rw- pkiuser host-manager.$DATE.log + -rw-rw-rw- pkiuser localhost.$DATE.log + -rw-rw-rw- pkiuser localhost_access_log.$DATE.txt + -rw-rw-rw- pkiuser manager.$DATE.log + drwxrwxrwx pkiuser pki + EOF + + diff expected output + + - name: Check CA info + run: | + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server cert-export \ + --cert-file /conf/certs/ca_signing.crt \ + ca_signing + + docker exec -u pkiuser pki pki nss-cert-import \ + --cert /home/pkiuser/.dogtag/pki-ca/conf/certs/ca_signing.crt \ + --trust CT,C,C \ + ca_signing + + docker exec -u pkiuser pki pki info + + # https://github.com/dogtagpki/pki/wiki/Setting-up-CA-Database + - name: Initialize CA database + run: | + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-db-init -v + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-db-index-add -v + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-db-index-rebuild -v + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-db-vlv-add -v + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-db-vlv-reindex -v + + - name: Create admin cert + run: | + docker exec -u pkiuser pki pki \ + nss-cert-request \ + --subject "CN=Administrator" \ + --ext /usr/share/pki/server/certs/admin.conf \ + --csr /home/pkiuser/.dogtag/pki-ca/conf/certs/admin.csr + + docker exec -u pkiuser pki podman exec systemd-pki-ca pki \ + -d /conf/alias \ + -f /conf/password.conf \ + nss-cert-issue \ + --issuer "ca_signing" \ + --csr /conf/certs/admin.csr \ + --ext /usr/share/pki/server/certs/admin.conf \ + --cert /conf/certs/admin.crt + + docker exec -u pkiuser pki pki \ + nss-cert-import \ + --cert /home/pkiuser/.dogtag/pki-ca/conf/certs/admin.crt \ + admin + + # https://github.com/dogtagpki/pki/wiki/Setting-up-CA-Admin-User + - name: Add CA admin user + run: | + # create CA admin user + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-user-add \ + --full-name Administrator \ + --type adminType \ + --cert /conf/certs/admin.crt \ + admin + + # add CA admin user into CA groups + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-user-role-add admin "Administrators" + docker exec -u pkiuser pki podman exec systemd-pki-ca \ + pki-server ca-user-role-add admin "Certificate Manager Agents" + + - name: Check CA admin user + run: | + docker exec -u pkiuser pki pki \ + -n admin \ + ca-user-show \ + admin + + - name: Check cert enrollment + run: | + docker exec -u pkiuser pki pki \ + client-cert-request \ + uid=testuser | tee output + + REQUEST_ID=$(sed -n -e 's/^ *Request ID: *\(.*\)$/\1/p' output) + echo "REQUEST_ID: $REQUEST_ID" + + docker exec -u pkiuser pki pki \ + -n admin \ + ca-cert-request-approve \ + $REQUEST_ID \ + --force + + - name: Check DS server systemd journal + if: always() + run: | + docker exec ds journalctl -x --no-pager -u dirsrv@localhost.service + + - name: Check DS container logs + if: always() + run: | + docker logs ds + + - name: Check CA container systemd journal + if: always() + run: | + docker exec -u pkiuser pki journalctl --user -x --no-pager -u pki-ca.service + + - name: Check CA container logs + if: always() + run: | + docker exec -u pkiuser pki podman logs systemd-pki-ca 2>&1 + + - name: Check CA debug logs + if: always() + run: | + docker exec -u pkiuser pki find /home/pkiuser/.dogtag/pki-ca/logs/ca -name "debug.*" -exec cat {} \; + + - name: Gather artifacts + if: always() + run: | + tests/bin/ds-artifacts-save.sh ds + tests/bin/pki-artifacts-save.sh pki + + docker cp pki:/home/pkiuser/.dogtag/pki-ca /tmp/artifacts/ca + docker exec -u pkiuser pki podman logs systemd-pki-ca > /tmp/artifacts/ca/container.out 2> /tmp/artifacts/ca/container.err + + - name: Upload artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: ca-container-user-service + path: /tmp/artifacts