From 3723b0c4b622f93ea12c28976e651fa80f67558d Mon Sep 17 00:00:00 2001 From: "Endi S. Dewata" Date: Fri, 21 Jul 2023 13:54:50 -0500 Subject: [PATCH] Add test for CA clone with replicated DS A new test has been added to test installing CA with DS, cloning the DS, then cloning the CA using the existing DS clone. This process allows DS cloning to happen separately from CA cloning which could prevent pkispawn from timing out due to long DS cloning process with large database. https://github.com/dogtagpki/pki/wiki/Installing-CA-Clone-with-Replicated-DS --- .../workflows/ca-clone-replicated-ds-test.yml | 391 ++++++++++++++++++ .github/workflows/ca-clone-tests.yml | 7 + 2 files changed, 398 insertions(+) create mode 100644 .github/workflows/ca-clone-replicated-ds-test.yml diff --git a/.github/workflows/ca-clone-replicated-ds-test.yml b/.github/workflows/ca-clone-replicated-ds-test.yml new file mode 100644 index 00000000000..84fde901dcd --- /dev/null +++ b/.github/workflows/ca-clone-replicated-ds-test.yml @@ -0,0 +1,391 @@ +name: CA clone with replicated DS +# https://github.com/dogtagpki/pki/wiki/Installing-CA-Clone-with-Replicated-DS + +on: + workflow_call: + inputs: + db-image: + required: false + type: string + +jobs: + test: + name: Test + runs-on: ubuntu-latest + env: + SHARED: /tmp/workdir/pki + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Retrieve PKI images + uses: actions/cache@v3 + 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 primary DS container + run: | + tests/bin/ds-container-create.sh primaryds + env: + IMAGE: ${{ inputs.db-image }} + HOSTNAME: primaryds.example.com + PASSWORD: Secret.123 + + - name: Connect primary DS container to network + run: docker network connect example primaryds --alias primaryds.example.com + + - name: Set up primary PKI container + run: | + tests/bin/runner-init.sh primary + env: + HOSTNAME: primary.example.com + + - name: Connect primary PKI container to network + run: docker network connect example primary --alias primary.example.com + + # https://github.com/dogtagpki/pki/blob/master/docs/installation/ca/Installing_CA.md + - name: Install primary CA + run: | + docker exec primary pkispawn \ + -f /usr/share/pki/server/examples/installation/ca.cfg \ + -s CA \ + -D pki_ds_url=ldap://primaryds.example.com:3389 \ + -D pki_cert_id_generator=random \ + -D pki_request_id_generator=random \ + -D pki_client_admin_cert_p12=$SHARED/caadmin.p12 \ + -v + + - name: Check primary CA admin user + run: | + docker exec primary pki-server cert-export ca_signing \ + --cert-file $SHARED/ca_signing.crt + docker exec primary pki client-cert-import ca_signing \ + --ca-cert $SHARED/ca_signing.crt + docker exec primary pki pkcs12-import \ + --pkcs12 $SHARED/caadmin.p12 \ + --pkcs12-password Secret.123 + docker exec primary pki -n caadmin ca-user-show caadmin + + - name: Set up secondary DS container + run: | + tests/bin/ds-container-create.sh secondaryds + env: + IMAGE: ${{ inputs.db-image }} + HOSTNAME: secondaryds.example.com + PASSWORD: Secret.123 + + - name: Connect secondary DS container to network + run: docker network connect example secondaryds --alias secondaryds.example.com + + # https://github.com/dogtagpki/389-ds-base/wiki/Configuring-DS-Replication-with-DS-Tools + - name: Preparing DS backend + run: | + # check backends in primary DS + docker exec primaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://primaryds.example.com:3389 \ + backend suffix list + + # create backend for CA in secondary DS + docker exec secondaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://secondaryds.example.com:3389 \ + backend create \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + --be-name=ca + + - name: Enable replication on primary DS + run: | + docker exec primaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://primaryds.example.com:3389 \ + replication enable \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + --role=supplier \ + --replica-id=1 \ + --bind-dn="cn=Replication Manager,cn=config" \ + --bind-passwd=Secret.123 + + - name: Enable replication on secondary DS + run: | + docker exec secondaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://secondaryds.example.com:3389 \ + replication enable \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + --role=supplier \ + --replica-id=2 \ + --bind-dn="cn=Replication Manager,cn=config" \ + --bind-passwd=Secret.123 + + - name: Create replication manager on primary DS + run: | + docker exec primaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://primaryds.example.com:3389 \ + repl-agmt create \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + --host=secondaryds.example.com \ + --port=3389 \ + --conn-protocol=LDAP \ + --bind-dn="cn=Replication Manager,cn=config" \ + --bind-passwd=Secret.123 \ + --bind-method=SIMPLE \ + primaryds-to-secondaryds + + - name: Create replication manager on secondary DS + run: | + docker exec secondaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://secondaryds.example.com:3389 \ + repl-agmt create \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + --host=primaryds.example.com \ + --port=3389 \ + --conn-protocol=LDAP \ + --bind-dn="cn=Replication Manager,cn=config" \ + --bind-passwd=Secret.123 \ + --bind-method=SIMPLE \ + secondaryds-to-primaryds + + - name: Initializing replication agreement + run: | + # start initialization + docker exec primaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://primaryds.example.com:3389 \ + repl-agmt init \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + primaryds-to-secondaryds + + # wait for initialization to complete + counter=0 + while [[ "$counter" -lt 30 ]]; do + sleep 1 + + docker exec primaryds dsconf \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + ldap://primaryds.example.com:3389 \ + repl-agmt init-status \ + --suffix=dc=ca,dc=pki,dc=example,dc=com \ + primaryds-to-secondaryds \ + > >(tee stdout) 2> >(tee stderr >&2) || true + + STDOUT=$(cat stdout) + if [ "$STDOUT" = "Agreement successfully initialized." ]; then + break + fi + + counter=$((counter+1)) + done + + - name: Check entries in primary DS and secondary DS + run: | + # get DNs from primary DS + docker exec primaryds ldapsearch \ + -H ldap://primaryds.example.com:3389 \ + -x \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b "dc=ca,dc=pki,dc=example,dc=com" \ + -o ldif_wrap=no \ + -LLL \ + dn \ + | sed -ne 's/^dn: \(.*\)$/\1/p' | sort | tee primaryds.dn + + # get DNs from secondary DS + docker exec secondaryds ldapsearch \ + -H ldap://secondaryds.example.com:3389 \ + -x \ + -D "cn=Directory Manager" \ + -w Secret.123 \ + -b "dc=ca,dc=pki,dc=example,dc=com" \ + -o ldif_wrap=no \ + -LLL \ + dn \ + | sed -ne 's/^dn: \(.*\)$/\1/p' | sort > secondaryds.dn + + diff primaryds.dn secondaryds.dn + + - name: Export certs and keys from primary CA + run: | + docker exec primary pki-server ca-clone-prepare \ + --pkcs12-file $SHARED/ca-certs.p12 \ + --pkcs12-password Secret.123 + + docker exec primary pki-server cert-export ca_signing \ + --cert-file $SHARED/ca_signing.crt + + - name: Set up secondary PKI container + run: | + tests/bin/runner-init.sh secondary + env: + HOSTNAME: secondary.example.com + + - name: Connect secondary PKI container to network + run: docker network connect example secondary --alias secondary.example.com + + # https://github.com/dogtagpki/pki/wiki/Installing-CA-Clone-with-Existing-DS + - name: Install secondary CA + run: | + # get CS.cfg from primary CA before cloning + docker cp primary:/etc/pki/pki-tomcat/ca/CS.cfg CS.cfg.primary + + docker exec secondary pkispawn \ + -f /usr/share/pki/server/examples/installation/ca-clone.cfg \ + -s CA \ + -D pki_cert_chain_path=$SHARED/ca_signing.crt \ + -D pki_clone_pkcs12_path=$SHARED/ca-certs.p12 \ + -D pki_clone_pkcs12_password=Secret.123 \ + -D pki_ds_url=ldap://secondaryds.example.com:3389 \ + -D pki_ds_setup=False \ + -D pki_cert_id_generator=random \ + -D pki_request_id_generator=random \ + -v + + - name: Check system certs in primary CA and secondary CA + run: | + # get system certs from primary CA (except sslserver) + docker exec primary pki-server cert-show ca_signing > system-certs.primary + echo >> system-certs.primary + docker exec primary pki-server cert-show ca_ocsp_signing >> system-certs.primary + echo >> system-certs.primary + docker exec primary pki-server cert-show ca_audit_signing >> system-certs.primary + echo >> system-certs.primary + docker exec primary pki-server cert-show subsystem >> system-certs.primary + + # get system certs from secondary CA (except sslserver) + docker exec secondary pki-server cert-show ca_signing > system-certs.secondary + echo >> system-certs.secondary + docker exec secondary pki-server cert-show ca_ocsp_signing >> system-certs.secondary + echo >> system-certs.secondary + docker exec secondary pki-server cert-show ca_audit_signing >> system-certs.secondary + echo >> system-certs.secondary + docker exec secondary pki-server cert-show subsystem >> system-certs.secondary + + cat system-certs.primary + diff system-certs.primary system-certs.secondary + + - name: Check CS.cfg in primary CA after cloning + run: | + # get CS.cfg from primary CA after cloning + docker cp primary:/etc/pki/pki-tomcat/ca/CS.cfg CS.cfg.primary.after + + diff CS.cfg.primary CS.cfg.primary.after + + - name: Check CS.cfg in secondary CA + run: | + # get CS.cfg from secondary CA + docker cp secondary:/etc/pki/pki-tomcat/ca/CS.cfg CS.cfg.secondary + + # normalize expected result: + # - remove params that cannot be compared + # - replace primary.example.com with secondary.example.com + # - replace primaryds.example.com with secondaryds.example.com + # - set ca.crl.MasterCRL.enableCRLCache to false (automatically disabled in the clone) + # - set ca.crl.MasterCRL.enableCRLUpdates to false (automatically disabled in the clone) + # - add params for the clone + sed -e '/^installDate=/d' \ + -e '/^ca.sslserver.cert=/d' \ + -e '/^ca.sslserver.certreq=/d' \ + -e 's/primary.example.com/secondary.example.com/' \ + -e 's/primaryds.example.com/secondaryds.example.com/' \ + -e 's/^\(ca.crl.MasterCRL.enableCRLCache\)=.*$/\1=false/' \ + -e 's/^\(ca.crl.MasterCRL.enableCRLUpdates\)=.*$/\1=false/' \ + -e '$ a ca.certStatusUpdateInterval=0' \ + -e '$ a ca.listenToCloneModifications=false' \ + -e '$ a master.ca.agent.host=primary.example.com' \ + -e '$ a master.ca.agent.port=8443' \ + CS.cfg.primary.after \ + | sort > expected + + # normalize actual result: + # - remove params that cannot be compared + sed -e '/^installDate=/d' \ + -e '/^ca.sslserver.cert=/d' \ + -e '/^ca.sslserver.certreq=/d' \ + CS.cfg.secondary \ + | sort > actual + + diff expected actual + + - name: Check secondary CA admin user + run: | + docker exec secondary pki client-cert-import ca_signing \ + --ca-cert $SHARED/ca_signing.crt + docker exec secondary pki pkcs12-import \ + --pkcs12 $SHARED/caadmin.p12 \ + --pkcs12-password Secret.123 + docker exec secondary pki -n caadmin ca-user-show caadmin + + - name: Check users in primary CA and secondary CA + run: | + docker exec primary pki -n caadmin ca-user-find | tee ca-users.primary + docker exec secondary pki -n caadmin ca-user-find > ca-users.secondary + + diff ca-users.primary ca-users.secondary + + - name: Check certs in primary CA and secondary CA + run: | + docker exec primary pki ca-cert-find | tee ca-certs.primary + docker exec secondary pki ca-cert-find > ca-certs.secondary + + diff ca-certs.primary ca-certs.secondary + + - name: Check security domain in primary CA and secondary CA + run: | + docker exec primary pki securitydomain-show | tee sd.primary + docker exec secondary pki securitydomain-show > sd.secondary + + diff sd.primary sd.secondary + + - name: Gather artifacts from primary containers + if: always() + run: | + tests/bin/ds-artifacts-save.sh --output=/tmp/artifacts/primary primaryds + tests/bin/pki-artifacts-save.sh primary + continue-on-error: true + + - name: Gather artifacts from secondary containers + if: always() + run: | + tests/bin/ds-artifacts-save.sh --output=/tmp/artifacts/secondary secondaryds + tests/bin/pki-artifacts-save.sh secondary + continue-on-error: true + + - name: Remove CA from secondary PKI container + run: docker exec secondary pkidestroy -i pki-tomcat -s CA -v + + - name: Remove CA from primary PKI container + run: docker exec primary pkidestroy -i pki-tomcat -s CA -v + + - name: Upload artifacts from primary containers + if: always() + uses: actions/upload-artifact@v3 + with: + name: ca-clone-replicated-ds-primary + path: | + /tmp/artifacts/primary + + - name: Upload artifacts from secondary containers + if: always() + uses: actions/upload-artifact@v3 + with: + name: ca-clone-replicated-ds-secondary + path: | + /tmp/artifacts/secondary diff --git a/.github/workflows/ca-clone-tests.yml b/.github/workflows/ca-clone-tests.yml index 3879b8b49f7..79f0b4ef14f 100644 --- a/.github/workflows/ca-clone-tests.yml +++ b/.github/workflows/ca-clone-tests.yml @@ -41,3 +41,10 @@ jobs: uses: ./.github/workflows/ca-clone-shared-ds-test.yml with: db-image: ${{ needs.init.outputs.db-image }} + + ca-clone-replicated-ds-test: + name: CA clone with replicated DS + needs: [init, build] + uses: ./.github/workflows/ca-clone-replicated-ds-test.yml + with: + db-image: ${{ needs.init.outputs.db-image }}