From b319edbe19b1f7deacdd10d19e822c98f6087a80 Mon Sep 17 00:00:00 2001 From: grindsa Date: Sat, 20 Jul 2024 15:34:10 +0200 Subject: [PATCH 01/81] [feat] eab-profiling in msca handlers --- examples/ca_handler/mscertsrv_ca_handler.py | 40 +++++++---- examples/ca_handler/mswcce_ca_handler.py | 80 ++++++++++++--------- 2 files changed, 71 insertions(+), 49 deletions(-) diff --git a/examples/ca_handler/mscertsrv_ca_handler.py b/examples/ca_handler/mscertsrv_ca_handler.py index 438b6d7c..2029a57a 100644 --- a/examples/ca_handler/mscertsrv_ca_handler.py +++ b/examples/ca_handler/mscertsrv_ca_handler.py @@ -9,7 +9,7 @@ from cryptography.hazmat.primitives.serialization.pkcs7 import load_pem_pkcs7_certificates, load_der_pkcs7_certificates # pylint: disable=e0401, e0611 from examples.ca_handler.certsrv import Certsrv -from acme_srv.helper import load_config, b64_url_recode, convert_byte_to_string, proxy_check, convert_string_to_byte, header_info_get, allowed_domainlist_check # pylint: disable=e0401 +from acme_srv.helper import load_config, b64_url_recode, convert_byte_to_string, proxy_check, convert_string_to_byte, header_info_get, allowed_domainlist_check, eab_profile_header_info_check # pylint: disable=e0401 class CAhandler(object): @@ -28,6 +28,9 @@ def __init__(self, _debug: bool = False, logger: object = None): self.allowed_domainlist = [] self.header_info_field = False self.verify = True + self.eab_handler = None + self.eab_profiling = False + def __enter__(self): """ Makes CAhandler a Context Manager """ @@ -266,10 +269,11 @@ def _parameter_overwrite(self, csr: str): os.environ['KRB5_CONFIG'] = self.krb5_config # lookup http header information from request - if self.header_info_field: - user_template = self._template_name_get(csr) - if user_template: - self.template = user_template + # if self.header_info_field: + # user_template = self._template_name_get(csr) + # if user_template: + # self.template = user_template + def _domainlist_check(self, csr: str) -> bool: """ check if domain is in allowed domainlist """ @@ -298,23 +302,31 @@ def enroll(self, csr: str) -> Tuple[str, str, str, bool]: if self.host and self.user and self.password and self.template: + # check if domain is in allowed domainlis result = self._domainlist_check(csr) if result: - # setup certserv - ca_server = Certsrv(self.host, self.user, self.password, self.auth_method, self.ca_bundle, verify=self.verify, proxies=self.proxy) - # check connection and credentials - auth_check = self._check_credentials(ca_server) + # check for eab profiling and header_info + error = eab_profile_header_info_check(self.logger, self, csr, 'profile_id') + + if not error: + # setup certserv + ca_server = Certsrv(self.host, self.user, self.password, self.auth_method, self.ca_bundle, verify=self.verify, proxies=self.proxy) + + # check connection and credentials + auth_check = self._check_credentials(ca_server) - if auth_check: + if auth_check: - # enroll certificate - (error, cert_bundle, cert_raw) = self._csr_process(ca_server, csr) + # enroll certificate + (error, cert_bundle, cert_raw) = self._csr_process(ca_server, csr) + else: + self.logger.error('Connection or Credentialcheck failed') + error = 'Connection or Credentialcheck failed.' else: - self.logger.error('Connection or Credentialcheck failed') - error = 'Connection or Credentialcheck failed.' + self.logger.error('EAB profile check failed') else: self.logger.error('SAN/CN check failed') error = 'SAN/CN check failed' diff --git a/examples/ca_handler/mswcce_ca_handler.py b/examples/ca_handler/mswcce_ca_handler.py index e7755439..215b8317 100644 --- a/examples/ca_handler/mswcce_ca_handler.py +++ b/examples/ca_handler/mswcce_ca_handler.py @@ -17,7 +17,8 @@ proxy_check, build_pem_file, header_info_get, - allowed_domainlist_check + allowed_domainlist_check, + eab_profile_header_info_check ) @@ -39,6 +40,8 @@ def __init__(self, _debug: bool = False, logger: object = None): self.allowed_domainlist = [] self.header_info_field = None self.timeout = 5 + self.eab_handler = None + self.eab_profiling = False def __enter__(self): """Makes CAhandler a Context Manager""" @@ -225,10 +228,10 @@ def _csr_check(self, csr: str) -> bool: self.logger.debug('CAhandler._csr_check()') # lookup http header information from request - if self.header_info_field: - user_template = self._template_name_get(csr) - if user_template: - self.template = user_template + #if self.header_info_field: + # user_template = self._template_name_get(csr) + # if user_template: + # self.template = user_template if self.allowed_domainlist: if self.allowed_domainlist != 'ADLFAILURE': @@ -257,39 +260,46 @@ def enroll(self, csr: str) -> Tuple[str, str, str, str]: result = self._csr_check(csr) if result: - # create request - request = self.request_create() - # recode csr - csr = build_pem_file(self.logger, None, csr, 64, True) - - # pylint: disable=W0511 - # currently getting certificate chain is not supported - ca_pem = self._file_load(self.ca_bundle) - - try: - # request certificate - cert_raw = convert_byte_to_string( - request.get_cert(convert_string_to_byte(csr)) - ) - # replace crlf with lf - cert_raw = cert_raw.replace("\r\n", "\n") - except Exception as err_: - cert_raw = None - self.logger.error("ca_server.get_cert() failed with error: %s", err_) - - if cert_raw: - if ca_pem: - cert_bundle = cert_raw + ca_pem + # check for eab profiling and header_info + error = eab_profile_header_info_check(self.logger, self, csr, 'profile_id') + + if not error: + # create request + request = self.request_create() + + # recode csr + csr = build_pem_file(self.logger, None, csr, 64, True) + + # pylint: disable=W0511 + # currently getting certificate chain is not supported + ca_pem = self._file_load(self.ca_bundle) + + try: + # request certificate + cert_raw = convert_byte_to_string( + request.get_cert(convert_string_to_byte(csr)) + ) + # replace crlf with lf + cert_raw = cert_raw.replace("\r\n", "\n") + except Exception as err_: + cert_raw = None + self.logger.error("ca_server.get_cert() failed with error: %s", err_) + + if cert_raw: + if ca_pem: + cert_bundle = cert_raw + ca_pem + else: + cert_bundle = cert_raw + + cert_raw = cert_raw.replace("-----BEGIN CERTIFICATE-----\n", "") + cert_raw = cert_raw.replace("-----END CERTIFICATE-----\n", "") + cert_raw = cert_raw.replace("\n", "") else: - cert_bundle = cert_raw - - cert_raw = cert_raw.replace("-----BEGIN CERTIFICATE-----\n", "") - cert_raw = cert_raw.replace("-----END CERTIFICATE-----\n", "") - cert_raw = cert_raw.replace("\n", "") + self.logger.error("cert bundling failed") + error = "cert bundling failed" else: - self.logger.error("cert bundling failed") - error = "cert bundling failed" + self.logger.error('EAB profile check failed') else: self.logger.error('SAN/CN check failed') error = 'SAN/CN check failed' From d8bec52e96f8cc08b6d6df78b144669f29e9f193 Mon Sep 17 00:00:00 2001 From: grindsa Date: Sun, 21 Jul 2024 19:39:56 +0200 Subject: [PATCH 02/81] [fix] profiling support in microsoft handlers --- .github/workflows/ca_handler_tests_msca.yml | 489 ++++++++++++++++++++ acme_srv/helper.py | 2 +- examples/ca_handler/mscertsrv_ca_handler.py | 15 +- examples/ca_handler/mswcce_ca_handler.py | 13 +- 4 files changed, 500 insertions(+), 19 deletions(-) diff --git a/.github/workflows/ca_handler_tests_msca.yml b/.github/workflows/ca_handler_tests_msca.yml index e79ff00b..2d151e66 100644 --- a/.github/workflows/ca_handler_tests_msca.yml +++ b/.github/workflows/ca_handler_tests_msca.yml @@ -304,6 +304,241 @@ jobs: name: mscertsrv_handler_tests-${{ matrix.websrv }}-${{ matrix.dbhandler }}.tar.gz path: ${{ github.workspace }}/artifact/upload/ + mscertsrv_handler_profiling_tests: + name: "mscertsrv_handler_profiling_tests" + runs-on: ubuntu-latest + needs: mscertsrv_handler_tests + strategy: + fail-fast: false + # max-parallel: 1 + matrix: + websrv: ['apache2', 'nginx'] + dbhandler: ['wsgi', 'django'] + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "create folders and networks" + run: | + docker network create local + mkdir lego + mkdir acme-sh + mkdir certbot + + - name: "Get runner ip" + run: | + echo RUNNER_IP=$(ip addr show eth0 | grep -i "inet " | cut -d ' ' -f 6 | cut -d '/' -f 1) >> $GITHUB_ENV + echo RUNNER_PATH=$(pwd | sed 's_/_\\/_g') >> $GITHUB_ENV + + - run: echo "runner IP is ${{ env.RUNNER_IP }}" + + - name: "Prepare ssh environment on ramdisk " + run: | + sudo mkdir -p /tmp/rd + sudo mount -t tmpfs -o size=5M none /tmp/rd + sudo echo "$SSH_KEY" > /tmp/rd/ak.tmp + sudo chmod 600 /tmp/rd/ak.tmp + sudo echo "$KNOWN_HOSTS" > /tmp/rd/known_hosts + env: + SSH_KEY: ${{ secrets.WCCE_SSH_ACCESS_KEY }} + KNOWN_HOSTS: ${{ secrets.WCCE_SSH_KNOWN_HOSTS }} + + - name: "Setup ssh forwarder" + run: | + docker run -d --rm --network local --name=$WCCE_FQDN_WOTLD -e "MAPPINGS=445:$WCCE_HOST:445; 443:$WCCE_HOST:443; 88:$WCCE_HOST:88" -e "SSH_HOST=$SSH_HOST" -e "SSH_PORT=$SSH_PORT" -e "SSH_USER=$SSH_USER" -p 443:443 -p 445:445 -p 88:88 -v "/tmp/rd/ak.tmp:/ssh_key:ro" davidlor/ssh-port-forward-client:dev + env: + SSH_USER: ${{ secrets.WCCE_SSH_USER }} + SSH_HOST: ${{ secrets.WCCE_SSH_HOST }} + SSH_PORT: ${{ secrets.WCCE_SSH_PORT }} + WCCE_HOST: ${{ secrets.WCCE_HOST }} + WCCE_FQDN_WOTLD: ${{ secrets.WCCE_FQDN_WOTLD }} + + - name: "Sleep for 10s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 10s + + - name: "Test conection to mscertsrv via ssh tunnel" + run: | + docker run -i --rm --network local curlimages/curl --insecure -f https://$WCCE_FQDN + env: + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + + - name: "Build docker-compose (${{ matrix.websrv }}_${{ matrix.dbhandler }})" + working-directory: examples/Docker/ + run: | + sudo mkdir -p data + sed -i "s/wsgi/$DB_HANDLER/g" .env + sed -i "s/apache2/$WEB_SRV/g" .env + cat .env + sed -i "s/name: acme/name: local/g" docker-compose.yml + docker-compose up -d + docker-compose logs + env: + WEB_SRV: ${{ matrix.websrv }} + DB_HANDLER: ${{ matrix.dbhandler }} + + - name: "EAB with headerinfo - Setup a2c with mscertsrv_ca_handler using kerberos" + run: | + sudo cp .github/acme2certifier.pem examples/Docker/data/acme2certifier.pem + sudo cp .github/acme2certifier_cert.pem examples/Docker/data/acme2certifier_cert.pem + sudo cp .github/acme2certifier_key.pem examples/Docker/data/acme2certifier_key.pem + sudo cp .github/django_settings.py examples/Docker/data/settings.py + sudo touch examples/Docker/data/ca_certs.pem + sudo chmod 777 examples/Docker/data/ca_certs.pem + sudo cp test/ca/certsrv_ca_certs.pem examples/Docker/data/ca_certs.pem + sudo touch examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/mscertsrv_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "host: $WCCE_FQDN" >> examples/Docker/data/acme_srv.cfg + sudo echo "user: $WES_USER" >> examples/Docker/data/acme_srv.cfg + sudo echo "password: $WES_PASSWORD" >> examples/Docker/data/acme_srv.cfg + sudo echo "auth_method: gssapi" >> examples/Docker/data/acme_srv.cfg + sudo echo "template: $WES_TEMPLATE" >> examples/Docker/data/acme_srv.cfg + sudo echo "ca_bundle: /var/www/acme2certifier/volume/ca_certs.pem" >> examples/Docker/data/acme_srv.cfg + sudo echo "krb5_config: /var/www/acme2certifier/volume/krb5.conf" >> examples/Docker/data/acme_srv.cfg + sudo echo "verify: False" >> examples/Docker/data/acme_srv.cfg + sudo echo "request_timeout: 30" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" examples/Docker/data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout: 40/g" examples/Docker/data/acme_srv.cfg + + sudo echo "eab_profiling: True" >> examples/Docker/data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> examples/Docker/data/acme_srv.cfg + sudo echo "eab_handler_file: /var/www/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "key_file: volume/kid_profiles.json" >> examples/Docker/data/acme_srv.cfg + + sudo touch examples/Docker/data/krb5.conf + sudo chmod 777 examples/Docker/data/krb5.conf + cat < examples/Docker/data/krb5.conf + $WES_KRB5_CONF + EOF + + sudo cp examples/eab_handler/kid_profiles.json examples/Docker/data/kid_profiles.json + sudo chmod 777 examples/eab_handler/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"template\"\: \[\"WebServerModified\"\, \"WebServer\"]/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"template\"\: \"WebServerModified\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/example.net/local/g" examples/Docker/data/kid_profiles.json + sudo sed -i '18,19d' examples/Docker/data/kid_profiles.json + sudo sed -i '8,9d' examples/Docker/data/kid_profiles.json + + cd examples/Docker/ + docker-compose restart + docker-compose logs + env: + WES_HOST: ${{ secrets.WES_HOST }} + WES_USER: ${{ secrets.WES_USER }} + WES_PASSWORD: ${{ secrets.WES_PASSWORD }} + WES_TEMPLATE: ${{ secrets.WES_TEMPLATE }} + WES_AUTHMETHOD: ${{ secrets.WES_AUTHMETHOD }} + WCCE_HOST: ${{ secrets.WCCE_HOST }} + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WES_KRB5_CONF: ${{ secrets.WES_KRB5_CONF }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + WCCE_FQDN_WOTLD: ${{ secrets.WCCE_FQDN_WOTLD }} + + - name: "Sleep for 10s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 10s + + - name: "EAB with headerinfo - Test http://acme-srv/directory is accessible" + run: docker run -i --rm --network local curlimages/curl -f http://acme-srv/directory + + - name: "EAB with headerinfo - Test if https://acme-srv/directory is accessible" + run: docker run -i --rm --network local curlimages/curl --insecure -f https://acme-srv/directory + + - name: "EAB with headerinfo - 01a - enrollment without header-info field (first value in list)" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Client" + + - name: "EAB with headerinfo - 01b - enrollment with header-info field (pick value from list)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=WebServer --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Server" + + - name: "EAB with headerinfo - 01c - enrollment with header-info field containing value not included in list (to fail)" + id: legofail02 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=Unknown --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + + - name: EAB with headerinfo 01c - check result " + if: steps.legofail02.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail02.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 01d - enrollment with header-info field cotaining an invalid parameter (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent ca_name=foo --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 01e - enrollment with header-info field containing parameter not in json (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent user=user --key-type=rsa2048 -d lego.local --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 02 - template from profile" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 03 - domainlist validation fails (to fail)" + id: legofail03 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM --http run + + - name: "EAB with headerinfo - 03 - check result " + if: steps.legofail03.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail03.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 04 - Settings from acme_srv.cfg" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_03 --hmac YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Server" + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + sudo cp -rp examples/Docker/data/ ${{ github.workspace }}/artifact/data/ + sudo cp /etc/hosts ${{ github.workspace }}/artifact/data/ + sudo cp /etc/resolv.conf ${{ github.workspace }}/artifact/data/ + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + sudo cp -rp certbot/ ${{ github.workspace }}/artifact/certbot/ + sudo cp -rp lego/ ${{ github.workspace }}/artifact/lego/ + cd examples/Docker + docker-compose logs > ${{ github.workspace }}/artifact/docker-compose.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz docker-compose.log data acme-sh certbot lego dnsmasq + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: mscertsrv_handler_profiling_tests-${{ matrix.websrv }}-${{ matrix.dbhandler }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ + mswcce_handler_tests: name: "mswcce_handler_tests" runs-on: ubuntu-latest @@ -619,6 +854,260 @@ jobs: name: mswcce_handler_tests-${{ matrix.websrv }}-${{ matrix.dbhandler }}.tar.gz path: ${{ github.workspace }}/artifact/upload/ + mswcce_handler_profiling_tests: + name: "mswcce_handler_profiling_tests" + runs-on: ubuntu-latest + needs: mscertsrv_handler_tests + strategy: + fail-fast: false + # max-parallel: 1 + matrix: + websrv: ['apache2', 'nginx'] + dbhandler: ['wsgi', 'django'] + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "create folders" + run: | + mkdir lego + mkdir acme-sh + mkdir certbot + + - name: "[ PREPARE ] get runner ip" + run: | + echo RUNNER_IP=$(ip addr show eth0 | grep -i "inet " | cut -d ' ' -f 6 | cut -d '/' -f 1) >> $GITHUB_ENV + echo RUNNER_PATH=$(pwd | sed 's_/_\\/_g') >> $GITHUB_ENV + + - run: echo "runner IP is ${{ env.RUNNER_IP }}" + + - name: "Install dnsmasq" + run: | + sudo apt-get update + sudo apt-get install -y dnsmasq + sudo systemctl disable systemd-resolved + sudo systemctl stop systemd-resolved + sudo mkdir -p dnsmasq + sudo cp .github/dnsmasq.conf dnsmasq/ + sudo chmod -R 777 dnsmasq/dnsmasq.conf + sudo sed -i "s/RUNNER_IP/$RUNNER_IP/g" dnsmasq/dnsmasq.conf + sudo echo "address=/$WCCE_FQDN/$RUNNER_IP" >> dnsmasq/dnsmasq.conf + sudo echo "address=/$WCCE_ADS_DOMAIN/$RUNNER_IP" >> dnsmasq/dnsmasq.conf + sudo echo "address=/$WES_HOST/$RUNNER_IP" >> dnsmasq/dnsmasq.conf + cat dnsmasq/dnsmasq.conf + sudo cp dnsmasq/dnsmasq.conf /etc/ + sudo systemctl enable dnsmasq + sudo systemctl start dnsmasq + env: + RUNNER_IP: ${{ env.RUNNER_IP }} + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + WES_HOST: ${{ secrets.WES_HOST }} + + - name: "[ PREPARE ] test dns resulution" + run: | + host $WCCE_ADS_DOMAIN 127.0.0.1 + host $WCCE_FQDN 127.0.0.1 + host $WES_HOST 127.0.0.1 + env: + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + WES_HOST: ${{ secrets.WES_HOST }} + + - name: "Build docker-compose (${{ matrix.websrv }}_${{ matrix.dbhandler }})" + working-directory: examples/Docker/ + run: | + sudo mkdir -p data + sed -i "s/wsgi/$DB_HANDLER/g" .env + sed -i "s/apache2/$WEB_SRV/g" .env + cat .env + docker network create acme + docker-compose up -d + docker-compose logs + env: + WEB_SRV: ${{ matrix.websrv }} + DB_HANDLER: ${{ matrix.dbhandler }} + + - name: "Prepare ssh environment on ramdisk " + run: | + sudo mkdir -p /tmp/rd + sudo mount -t tmpfs -o size=5M none /tmp/rd + sudo echo "$SSH_KEY" > /tmp/rd/ak.tmp + sudo chmod 600 /tmp/rd/ak.tmp + sudo echo "$KNOWN_HOSTS" > /tmp/rd/known_hosts + env: + SSH_KEY: ${{ secrets.WCCE_SSH_ACCESS_KEY }} + KNOWN_HOSTS: ${{ secrets.WCCE_SSH_KNOWN_HOSTS }} + + - name: "Establish SSH connection" + run: sudo ssh $SSH_USER@$SSH_HOST -fN -i /tmp/rd/ak.tmp -p $SSH_PORT -o UserKnownHostsFile=/tmp/rd/known_hosts -L 445:$WCCE_HOST:445 -L 88:$WCCE_HOST:88 -L 443:$WES_IP:443 -g + env: + SSH_USER: ${{ secrets.WCCE_SSH_USER }} + SSH_HOST: ${{ secrets.WCCE_SSH_HOST }} + SSH_PORT: ${{ secrets.WCCE_SSH_PORT }} + WCCE_HOST: ${{ secrets.WCCE_HOST }} + WES_IP: ${{ secrets.WES_IP }} + CMP_HOST: ${{ secrets.CMP_HOST }} + + - name: "Sleep for 5s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 5s + + - name: "EAB with headerinfo - Setup a2c with ms_wcce_ca_handler (Kerboros)" + run: | + sudo cp .github/acme2certifier.pem examples/Docker/data/acme2certifier.pem + sudo cp .github/acme2certifier_cert.pem examples/Docker/data/acme2certifier_cert.pem + sudo cp .github/acme2certifier_key.pem examples/Docker/data/acme2certifier_key.pem + sudo cp .github/django_settings.py examples/Docker/data/settings.py + sudo touch examples/Docker/data/ca_certs.pem + sudo chmod 777 examples/Docker/data/ca_certs.pem + sudo echo "$WCCE_CA_BUNDLE" > examples/Docker/data/ca_certs.pem + sudo touch examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: /var/www/acme2certifier/examples/ca_handler/mswcce_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "host: $WCCE_FQDN" >> examples/Docker/data/acme_srv.cfg + sudo echo "user: $WCCE_USER" >> examples/Docker/data/acme_srv.cfg + sudo echo "password: $WCCE_PASSWORD" >> examples/Docker/data/acme_srv.cfg + sudo echo "template: $WCCE_TEMPLATE" >> examples/Docker/data/acme_srv.cfg + sudo echo "ca_name: $WCCE_CA_NAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "target_domain: $WCCE_ADS_DOMAIN" >> examples/Docker/data/acme_srv.cfg + sudo echo "domain_controller: $RUNNER_IP" >> examples/Docker/data/acme_srv.cfg + sudo echo "ca_bundle: volume/ca_certs.pem" >> examples/Docker/data/acme_srv.cfg + sudo echo "timeout: 20" >> examples/Docker/data/acme_srv.cfg + sudo echo "use_kerberos: True" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" examples/Docker/data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout: 40/g" examples/Docker/data/acme_srv.cfg + + sudo echo "eab_profiling: True" >> examples/Docker/data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> examples/Docker/data/acme_srv.cfg + sudo echo "eab_handler_file: /var/www/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "key_file: volume/kid_profiles.json" >> examples/Docker/data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json examples/Docker/data/kid_profiles.json + sudo chmod 777 examples/eab_handler/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"template\"\: \[\"WebServerModified\"\, \"WebServer\"]/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"template\"\: \"WebServerModified\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/example.net/acme/g" examples/Docker/data/kid_profiles.json + sudo sed -i '18,19d' examples/Docker/data/kid_profiles.json + sudo sed -i '8,9d' examples/Docker/data/kid_profiles.json + + cd examples/Docker/ + docker-compose restart + docker-compose logs + env: + RUNNER_IP: ${{ env.RUNNER_IP }} + DNSMASQ_IP: ${{ env.DNSMASQ_IP }} + WCCE_USER: ${{ secrets.WCCE_USER }} + WCCE_PASSWORD: ${{ secrets.WCCE_PASSWORD }} + WCCE_TEMPLATE: ${{ secrets.WCCE_TEMPLATE }} + WCCE_CA_NAME: ${{ secrets.WCCE_CA_NAME }} + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WCCE_CA_BUNDLE: ${{ secrets.WCCE_CA_BUNDLE }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + + - name: "EAB with headerinfo - Sleep for 10s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 10s + + - name: "EAB with headerinfo - Test http://acme-srv/directory is accessible" + run: docker run -i --rm --network acme curlimages/curl -f http://acme-srv/directory + + - name: "EAB with headerinfo - Test https://acme-srv/directory is accessible" + run: docker run -i --rm --network acme curlimages/curl -f https://acme-srv/directory --insecure + + - name: "EAB with headerinfo - 01a - enrollment without header-info field (first value in list)" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Client" + + - name: "EAB with headerinfo - 01b - enrollment with header-info field (pick value from list)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=WebServer --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Server" + + - name: "EAB with headerinfo - 01c - enrollment with header-info field containing value not included in list (to fail)" + id: legofail02 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=Unknown --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + + - name: EAB with headerinfo 01c - check result " + if: steps.legofail02.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail02.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 01d - enrollment with header-info field cotaining an invalid parameter (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent ca_name=foo --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 01e - enrollment with header-info field containing parameter not in json (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent user=user --key-type=rsa2048 -d lego.acme --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 02 - template from profile" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 03 - domainlist validation fails (to fail)" + id: legofail03 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM --http run + + - name: "EAB with headerinfo - 03 - check result " + if: steps.legofail03.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail03.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 04 - Settings from acme_srv.cfg" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_03 --hmac YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Server" + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + sudo cp -rp examples/Docker/data/ ${{ github.workspace }}/artifact/data/ + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + sudo cp -rp certbot/ ${{ github.workspace }}/artifact/certbot/ + sudo cp -rp lego/ ${{ github.workspace }}/artifact/lego/ + sudo cp -rp dnsmasq/ ${{ github.workspace }}/artifact/dnsmasq/ + cd examples/Docker + docker-compose logs > ${{ github.workspace }}/artifact/docker-compose.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz docker-compose.log data acme-sh certbot lego dnsmasq + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: mswcce_handler_profiling_tests-${{ matrix.websrv }}-${{ matrix.dbhandler }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ + mscertsrv_handler_tests_rpm: name: "mscertsrv_handler_tests_rpm" runs-on: ubuntu-latest diff --git a/acme_srv/helper.py b/acme_srv/helper.py index ea924412..e2633c9b 100644 --- a/acme_srv/helper.py +++ b/acme_srv/helper.py @@ -1703,7 +1703,7 @@ def eab_profile_list_check(logger, cahandler, eab_handler, csr, key, value): logger.debug('Helper.eab_profile_list_check(): list: key: %s, value: %s', key, value) result = None - if hasattr(cahandler, key): + if hasattr(cahandler, key) and key != 'allowed_domainlist': new_value, error = header_info_field_validate(logger, csr, cahandler.header_info_field, key, value) if new_value: logger.debug('Helper.eab_profile_list_check(): setting attribute: %s to %s', key, new_value) diff --git a/examples/ca_handler/mscertsrv_ca_handler.py b/examples/ca_handler/mscertsrv_ca_handler.py index 2029a57a..33c0dbd5 100644 --- a/examples/ca_handler/mscertsrv_ca_handler.py +++ b/examples/ca_handler/mscertsrv_ca_handler.py @@ -9,7 +9,7 @@ from cryptography.hazmat.primitives.serialization.pkcs7 import load_pem_pkcs7_certificates, load_der_pkcs7_certificates # pylint: disable=e0401, e0611 from examples.ca_handler.certsrv import Certsrv -from acme_srv.helper import load_config, b64_url_recode, convert_byte_to_string, proxy_check, convert_string_to_byte, header_info_get, allowed_domainlist_check, eab_profile_header_info_check # pylint: disable=e0401 +from acme_srv.helper import load_config, b64_url_recode, convert_byte_to_string, proxy_check, convert_string_to_byte, header_info_get, allowed_domainlist_check, eab_profile_header_info_check, config_eab_profile_load # pylint: disable=e0401 class CAhandler(object): @@ -176,6 +176,8 @@ def _config_load(self): self._config_user_load(config_dic) self._config_password_load(config_dic) self._config_parameters_load(config_dic) + # load profiling + self.eab_profiling, self.eab_handler = config_eab_profile_load(self.logger, config_dic) self._config_headerinfo_load(config_dic) # load proxy config @@ -262,19 +264,12 @@ def _csr_process(self, ca_server, csr: str) -> Tuple[str, str, str]: return (error, cert_bundle, cert_raw) - def _parameter_overwrite(self, csr: str): + def _parameter_overwrite(self, _csr: str): """ overwrite overwrite krb5.conf or user-template """ if self.krb5_config: self.logger.info('CAhandler.enroll(): load krb5config from %s', self.krb5_config) os.environ['KRB5_CONFIG'] = self.krb5_config - # lookup http header information from request - # if self.header_info_field: - # user_template = self._template_name_get(csr) - # if user_template: - # self.template = user_template - - def _domainlist_check(self, csr: str) -> bool: """ check if domain is in allowed domainlist """ self.logger.debug('CAhandler._domainlist_check()') @@ -308,7 +303,7 @@ def enroll(self, csr: str) -> Tuple[str, str, str, bool]: if result: # check for eab profiling and header_info - error = eab_profile_header_info_check(self.logger, self, csr, 'profile_id') + error = eab_profile_header_info_check(self.logger, self, csr, 'template') if not error: # setup certserv diff --git a/examples/ca_handler/mswcce_ca_handler.py b/examples/ca_handler/mswcce_ca_handler.py index 215b8317..9f3f8e4f 100644 --- a/examples/ca_handler/mswcce_ca_handler.py +++ b/examples/ca_handler/mswcce_ca_handler.py @@ -18,7 +18,8 @@ build_pem_file, header_info_get, allowed_domainlist_check, - eab_profile_header_info_check + eab_profile_header_info_check, + config_eab_profile_load ) @@ -164,6 +165,8 @@ def _config_load(self): self._config_host_load(config_dic) self._config_credentials_load(config_dic) self._config_parameters_load(config_dic) + # load profiling + self.eab_profiling, self.eab_handler = config_eab_profile_load(self.logger, config_dic) self._config_headerinfo_load(config_dic) self._config_proxy_load(config_dic) @@ -227,12 +230,6 @@ def _csr_check(self, csr: str) -> bool: """ check if csr is allowed """ self.logger.debug('CAhandler._csr_check()') - # lookup http header information from request - #if self.header_info_field: - # user_template = self._template_name_get(csr) - # if user_template: - # self.template = user_template - if self.allowed_domainlist: if self.allowed_domainlist != 'ADLFAILURE': # check sans / cn against list of allowed comains from config @@ -262,7 +259,7 @@ def enroll(self, csr: str) -> Tuple[str, str, str, str]: if result: # check for eab profiling and header_info - error = eab_profile_header_info_check(self.logger, self, csr, 'profile_id') + error = eab_profile_header_info_check(self.logger, self, csr, 'template') if not error: # create request From cf079676fcac75744226d3eedabdf83b3f901d4e Mon Sep 17 00:00:00 2001 From: grindsa Date: Mon, 22 Jul 2024 10:19:31 +0200 Subject: [PATCH 03/81] [doc] documentation update --- .github/workflows/ca_handler_tests_msca.yml | 531 ++++++++++++++++++++ docs/eab_profiling.md | 2 + docs/mscertsrv.md | 47 ++ docs/mswcce.md | 47 ++ 4 files changed, 627 insertions(+) diff --git a/.github/workflows/ca_handler_tests_msca.yml b/.github/workflows/ca_handler_tests_msca.yml index 2d151e66..7126173e 100644 --- a/.github/workflows/ca_handler_tests_msca.yml +++ b/.github/workflows/ca_handler_tests_msca.yml @@ -1403,6 +1403,259 @@ jobs: name: mscertsrv_handler_tests_rpm-rh${{ matrix.rhversion }}.tar.gz path: ${{ github.workspace }}/artifact/upload/ + mscertsrv_handler_profile_tests_rpm: + name: "mscertsrv_handler_profile_tests_rpm" + runs-on: ubuntu-latest + needs: mscertsrv_handler_tests_rpm + strategy: + # max-parallel: 1 + fail-fast: false + matrix: + rhversion: [8, 9] + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "create folders and networks" + run: | + docker network create local + mkdir lego + mkdir acme-sh + mkdir certbot + + - name: "Get runner ip" + run: | + echo RUNNER_IP=$(ip addr show eth0 | grep -i "inet " | cut -d ' ' -f 6 | cut -d '/' -f 1) >> $GITHUB_ENV + echo RUNNER_PATH=$(pwd | sed 's_/_\\/_g') >> $GITHUB_ENV + + - run: echo "runner IP is ${{ env.RUNNER_IP }}" + + - name: "Prepare ssh environment on ramdisk " + run: | + sudo mkdir -p /tmp/rd + sudo mount -t tmpfs -o size=5M none /tmp/rd + sudo echo "$SSH_KEY" > /tmp/rd/ak.tmp + sudo chmod 600 /tmp/rd/ak.tmp + sudo echo "$KNOWN_HOSTS" > /tmp/rd/known_hosts + env: + SSH_KEY: ${{ secrets.WCCE_SSH_ACCESS_KEY }} + KNOWN_HOSTS: ${{ secrets.WCCE_SSH_KNOWN_HOSTS }} + + - name: "Setup ssh forwarder" + run: | + docker run -d --rm --network local --name=$WCCE_FQDN_WOTLD -e "MAPPINGS=445:$WCCE_HOST:445; 443:$WCCE_HOST:443; 88:$WCCE_HOST:88" -e "SSH_HOST=$SSH_HOST" -e "SSH_PORT=$SSH_PORT" -e "SSH_USER=$SSH_USER" -p 443:443 -p 445:445 -p 88:88 -v "/tmp/rd/ak.tmp:/ssh_key:ro" davidlor/ssh-port-forward-client:dev + env: + SSH_USER: ${{ secrets.WCCE_SSH_USER }} + SSH_HOST: ${{ secrets.WCCE_SSH_HOST }} + SSH_PORT: ${{ secrets.WCCE_SSH_PORT }} + WCCE_HOST: ${{ secrets.WCCE_HOST }} + WCCE_FQDN_WOTLD: ${{ secrets.WCCE_FQDN_WOTLD }} + + - name: "Sleep for 10s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 10s + + - name: "Test conection to mscertsrv via ssh tunnel" + run: | + docker run -i --rm --network local curlimages/curl --insecure -f https://$WCCE_FQDN + env: + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + + - name: Retrieve Version from version.py + run: | + echo TAG_NAME=$(cat acme_srv/version.py | grep -i __version__ | head -n 1 | sed 's/__version__ = //g' | sed s/\'//g) >> $GITHUB_ENV + + - run: echo "Latest tag is ${{ env.TAG_NAME }}" + + - name: update version number in spec file + run: | + # sudo sed -i "s/Source0:.*/Source0: %{name}-%{version}.tar.gz/g" examples/install_scripts/rpm/acme2certifier.spec + sudo sed -i "s/__version__/${{ env.TAG_NAME }}/g" examples/install_scripts/rpm/acme2certifier.spec + cat examples/install_scripts/rpm/acme2certifier.spec + + - name: build RPM package + id: rpm + uses: grindsa/rpmbuild@alma9 + with: + spec_file: "examples/install_scripts/rpm/acme2certifier.spec" + + - run: echo "path is ${{ steps.rpm.outputs.rpm_dir_path }}" + + - name: "Setup environment for alma installation" + run: | + docker network create acme + sudo mkdir -p data + sudo chmod -R 777 data + sudo cp ${{ steps.rpm.outputs.rpm_dir_path }}noarch/acme2certifier-${{ env.TAG_NAME }}-1.0.noarch.rpm data + sudo cp examples/Docker/almalinux-systemd/rpm_tester.sh data + + - name: "Retrieve rpms from SBOM repo" + run: | + git clone https://$GH_SBOM_USER:$GH_SBOM_TOKEN@github.com/$GH_SBOM_USER/sbom /tmp/sbom + cp /tmp/sbom/rpm-repo/RPMs/rhel${{ matrix.rhversion }}/*.rpm data + env: + GH_SBOM_USER: ${{ secrets.GH_SBOM_USER }} + GH_SBOM_TOKEN: ${{ secrets.GH_SBOM_TOKEN }} + + - name: "EAB with headerinfo - Prepare Almalinux instance" + run: | + sudo cp examples/Docker/almalinux-systemd/Dockerfile data + sudo sed -i "s/FROM almalinux:9/FROM almalinux:${{ matrix.rhversion }}/g" data/Dockerfile + cat data/Dockerfile | docker build -t almalinux-systemd -f - . --no-cache + docker run -d -id --privileged --network local --name=acme-srv -v "$(pwd)/data":/tmp/acme2certifier almalinux-systemd + + - name: "EAB with headerinfo - Setup a2c with mscertsrv_ca_handler using kerberos" + run: | + mkdir -p data/acme_ca + sudo cp test/ca/certsrv_ca_certs.pem data/acme_ca/ca_certs.pem + sudo touch data/acme_srv.cfg + sudo chmod 777 data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/acme_srv.cfg + sudo echo "handler_file: /opt/acme2certifier/examples/ca_handler/mscertsrv_ca_handler.py" >> data/acme_srv.cfg + sudo echo "host: $WCCE_FQDN" >> data/acme_srv.cfg + sudo echo "user: $WES_USER" >> data/acme_srv.cfg + sudo echo "password: $WES_PASSWORD" >> data/acme_srv.cfg + sudo echo "auth_method: gssapi" >> data/acme_srv.cfg + sudo echo "template: $WES_TEMPLATE" >> data/acme_srv.cfg + sudo echo "ca_bundle: volume/acme_ca/ca_certs.pem" >> data/acme_srv.cfg + sudo echo "krb5_config: volume/acme_ca/krb5.conf" >> data/acme_srv.cfg + sudo echo "verify: False" >> data/acme_srv.cfg + sudo echo "request_timeout: 30" >> data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout: 40/g" data/acme_srv.cfg + + sudo echo "eab_profiling: True" >> data/acme_srv.cfg + sudo echo -e "\n[EABhandler]" >> data/acme_srv.cfg + sudo echo "eab_handler_file: /opt/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> data/acme_srv.cfg + sudo echo "key_file: /opt/acme2certifier/volume/acme_ca/kid_profiles.json" >> data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json data/acme_ca/kid_profiles.json + sudo chmod 777 data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"template\"\: \[\"WebServerModified\"\, \"WebServer\"]/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"template\"\: \"WebServerModified\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/example.net/local/g" data/acme_ca/kid_profiles.json + sudo sed -i '18,19d' data/acme_ca/kid_profiles.json + sudo sed -i '8,9d' data/acme_ca/kid_profiles.json + + sudo touch data/acme_ca/krb5.conf + sudo chmod 777 data/acme_ca/krb5.conf + cat < data/acme_ca/krb5.conf + $WES_KRB5_CONF + EOF + + env: + WES_HOST: ${{ secrets.WES_HOST }} + WES_USER: ${{ secrets.WES_USER }} + WES_PASSWORD: ${{ secrets.WES_PASSWORD }} + WES_AUTHMETHOD: ${{ secrets.WES_AUTHMETHOD }} + WES_TEMPLATE: ${{ secrets.WES_TEMPLATE }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + WES_KRB5_CONF: ${{ secrets.WES_KRB5_CONF }} + + - name: "KRB - Execute install scipt" + run: | + docker exec acme-srv sh /tmp/acme2certifier/rpm_tester.sh + docker exec acme-srv yum install -y krb5-libs + + - name: "EAB with headerinfo - Sleep for 10s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 10s + + - name: "EAB with headerinfo - Test http://acme-srv/directory is accessible" + run: docker run -i --rm --network local curlimages/curl -f http://acme-srv/directory + + - name: "EAB with headerinfo - 01a - enrollment without header-info field (first value in list)" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Client" + + - name: "EAB with headerinfo - 01b - enrollment with header-info field (pick value from list)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=WebServer --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Server" + + - name: "EAB with headerinfo - 01c - enrollment with header-info field containing value not included in list (to fail)" + id: legofail02 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=Unknown --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + + - name: EAB with headerinfo 01c - check result " + if: steps.legofail02.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail02.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 01d - enrollment with header-info field cotaining an invalid parameter (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent ca_name=foo --key-type=rsa2048 -d lego.local --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 01e - enrollment with header-info field containing parameter not in json (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent user=user --key-type=rsa2048 -d lego.local --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 02 - template from profile" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 03 - domainlist validation fails (to fail)" + id: legofail03 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM --http run + + - name: "EAB with headerinfo - 03 - check result " + if: steps.legofail03.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail03.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 04 - Settings from acme_srv.cfg" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network local goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.local --eab --kid keyid_03 --hmac YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr --http run + sudo openssl x509 -in lego/certificates/lego.local.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.local.crt -ext extendedKeyUsage -noout | grep "TLS Web Server" + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + docker exec acme-srv tar cvfz /tmp/acme2certifier/a2c.tgz /opt/acme2certifier + sudo rm -rf data/*.rpm + sudo cp -rp data/ ${{ github.workspace }}/artifact/data/ + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + docker exec acme-srv ls -la /tmp > ${{ github.workspace }}/artifact/data/tmp_list + docker exec acme-srv ls -la /tmp + docker exec acme-srv cat /var/log/messages > ${{ github.workspace }}/artifact/acme-srv.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz data acme-srv.log acme-sh + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: mscertsrv_handler_profile_tests_rpm-rh${{ matrix.rhversion }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ + mswcce_handler_tests_rpm: name: "mswcce_handler_tests_rpm" runs-on: ubuntu-latest @@ -1721,3 +1974,281 @@ jobs: name: mswcce_handler_tests_rpm-rh${{ matrix.rhversion }}.tar.gz path: ${{ github.workspace }}/artifact/upload/ + mswcce_handler_profile_tests_rpm: + name: "mswcce_handler_profile_tests_rpm" + runs-on: ubuntu-latest + needs: mscertsrv_handler_tests_rpm + strategy: + # max-parallel: 1 + fail-fast: false + matrix: + rhversion: [8, 9] + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "Get runner ip" + run: | + echo RUNNER_IP=$(ip addr show eth0 | grep -i "inet " | cut -d ' ' -f 6 | cut -d '/' -f 1) >> $GITHUB_ENV + echo RUNNER_PATH=$(pwd | sed 's_/_\\/_g') >> $GITHUB_ENV + + - run: echo "runner IP is ${{ env.RUNNER_IP }}" + + - name: "Install dnsmasq" + run: | + sudo apt-get update + sudo apt-get install -y dnsmasq + sudo systemctl disable systemd-resolved + sudo systemctl stop systemd-resolved + # sudo chmod -R 777 /etc/resolv.conf + # sudo echo "nameserver 8.8.8.8" > /etc/resolv.conf + sudo mkdir -p dnsmasq + sudo cp .github/dnsmasq.conf dnsmasq/ + sudo chmod -R 777 dnsmasq/dnsmasq.conf + sudo sed -i "s/RUNNER_IP/$RUNNER_IP/g" dnsmasq/dnsmasq.conf + sudo echo "address=/$WCCE_FQDN/$RUNNER_IP" >> dnsmasq/dnsmasq.conf + sudo echo "address=/$WCCE_ADS_DOMAIN/$RUNNER_IP" >> dnsmasq/dnsmasq.conf + sudo echo "address=/$WES_HOST/$RUNNER_IP" >> dnsmasq/dnsmasq.conf + cat dnsmasq/dnsmasq.conf + sudo cp dnsmasq/dnsmasq.conf /etc/ + sudo sed -i "s/ --local-service/ /g" /etc/init.d/dnsmasq + sudo systemctl enable dnsmasq + sudo systemctl start dnsmasq + env: + RUNNER_IP: ${{ env.RUNNER_IP }} + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + WES_HOST: ${{ secrets.WES_HOST }} + + - name: "Test dns resulution" + run: | + host $WCCE_ADS_DOMAIN ${{ env.RUNNER_IP }} + host $WCCE_FQDN ${{ env.RUNNER_IP }} + host $WES_HOST 127.0.0.1 + env: + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + WES_HOST: ${{ secrets.WES_HOST }} + + - name: Retrieve Version from version.py + run: | + echo TAG_NAME=$(cat acme_srv/version.py | grep -i __version__ | head -n 1 | sed 's/__version__ = //g' | sed s/\'//g) >> $GITHUB_ENV + + - run: echo "Latest tag is ${{ env.TAG_NAME }}" + + - name: update version number in spec file + run: | + # sudo sed -i "s/Source0:.*/Source0: %{name}-%{version}.tar.gz/g" examples/install_scripts/rpm/acme2certifier.spec + sudo sed -i "s/__version__/${{ env.TAG_NAME }}/g" examples/install_scripts/rpm/acme2certifier.spec + cat examples/install_scripts/rpm/acme2certifier.spec + + - name: build RPM package + id: rpm + uses: grindsa/rpmbuild@alma9 + with: + spec_file: "examples/install_scripts/rpm/acme2certifier.spec" + + - run: echo "path is ${{ steps.rpm.outputs.rpm_dir_path }}" + + - name: "Setup environment for alma installation" + run: | + docker network create acme + sudo mkdir -p data + sudo chmod -R 777 data + sudo cp ${{ steps.rpm.outputs.rpm_dir_path }}noarch/acme2certifier-${{ env.TAG_NAME }}-1.0.noarch.rpm data + sudo cp examples/Docker/almalinux-systemd/rpm_tester.sh data + + - name: "Retrieve rpms from SBOM repo" + run: | + git clone https://$GH_SBOM_USER:$GH_SBOM_TOKEN@github.com/$GH_SBOM_USER/sbom /tmp/sbom + cp /tmp/sbom/rpm-repo/RPMs/rhel${{ matrix.rhversion }}/*.rpm data + env: + GH_SBOM_USER: ${{ secrets.GH_SBOM_USER }} + GH_SBOM_TOKEN: ${{ secrets.GH_SBOM_TOKEN }} + + - name: "Create letsencrypt and lego folder" + run: | + mkdir certbot + mkdir lego + mkdir acme-sh + + - name: "Ssh environment on ramdisk " + run: | + sudo mkdir -p /tmp/rd + sudo mount -t tmpfs -o size=5M none /tmp/rd + sudo echo "$SSH_KEY" > /tmp/rd/ak.tmp + sudo chmod 600 /tmp/rd/ak.tmp + sudo echo "$KNOWN_HOSTS" > /tmp/rd/known_hosts + env: + SSH_KEY: ${{ secrets.WCCE_SSH_ACCESS_KEY }} + KNOWN_HOSTS: ${{ secrets.WCCE_SSH_KNOWN_HOSTS }} + + - name: "Establish SSH connection" + run: sudo ssh $SSH_USER@$SSH_HOST -fN -i /tmp/rd/ak.tmp -p $SSH_PORT -o UserKnownHostsFile=/tmp/rd/known_hosts -L 445:$WCCE_HOST:445 -L 88:$WCCE_HOST:88 -L 443:$WES_IP:443 -g + env: + SSH_USER: ${{ secrets.WCCE_SSH_USER }} + SSH_HOST: ${{ secrets.WCCE_SSH_HOST }} + SSH_PORT: ${{ secrets.WCCE_SSH_PORT }} + WCCE_HOST: ${{ secrets.WCCE_HOST }} + WES_IP: ${{ secrets.WES_IP }} + CMP_HOST: ${{ secrets.CMP_HOST }} + + - name: "Sleep for 5s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 5s + + - name: "EAB with headerinfo - Setup a2c with ms_wcce_ca_handler (Kerberos)" + run: | + mkdir -p data/acme_ca + sudo touch data/acme_ca/ca_certs.pem + sudo chmod 777 data/acme_ca/ca_certs.pem + sudo echo "$WCCE_CA_BUNDLE" > data/acme_ca/ca_certs.pem + sudo touch data/acme_ca/acme_srv.cfg + sudo chmod 777 data/acme_ca/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/acme_srv.cfg + sudo echo "handler_file: /opt/acme2certifier/examples/ca_handler/mswcce_ca_handler.py" >> data/acme_srv.cfg + sudo echo "host: $WCCE_FQDN" >> data/acme_srv.cfg + sudo echo "user: $WCCE_USER" >> data/acme_srv.cfg + sudo echo "password: $WCCE_PASSWORD" >> data/acme_srv.cfg + sudo echo "template: $WCCE_TEMPLATE" >> data/acme_srv.cfg + sudo echo "ca_name: $WCCE_CA_NAME" >> data/acme_srv.cfg + sudo echo "target_domain: $WCCE_ADS_DOMAIN" >> data/acme_srv.cfg + sudo echo "domain_controller: $RUNNER_IP" >> data/acme_srv.cfg + sudo echo "ca_bundle: /opt/acme2certifier/volume/acme_ca/ca_certs.pem" >> data/acme_srv.cfg + sudo echo "timeout: 20" >> data/acme_srv.cfg + sudo echo "use_kerberos: True" >> data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout: 40/g" data/acme_srv.cfg + + sudo echo "eab_profiling: True" >> data/acme_srv.cfg + sudo echo -e "\n[EABhandler]" >> data/acme_srv.cfg + sudo echo "eab_handler_file: /opt/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> data/acme_srv.cfg + sudo echo "key_file: /opt/acme2certifier/volume/acme_ca/kid_profiles.json" >> data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json data/acme_ca/kid_profiles.json + sudo chmod 777 data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"template\"\: \[\"WebServerModified\"\, \"WebServer\"]/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"template\"\: \"WebServerModified\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/example.net/acme/g" data/acme_ca/kid_profiles.json + sudo sed -i '18,19d' data/acme_ca/kid_profiles.json + sudo sed -i '8,9d' data/acme_ca/kid_profiles.json + + env: + RUNNER_IP: ${{ env.RUNNER_IP }} + WCCE_USER: ${{ secrets.WCCE_USER }} + WCCE_PASSWORD: ${{ secrets.WCCE_PASSWORD }} + WCCE_TEMPLATE: ${{ secrets.WCCE_TEMPLATE }} + WCCE_CA_NAME: ${{ secrets.WCCE_CA_NAME }} + WCCE_ADS_DOMAIN: ${{ secrets.WCCE_ADS_DOMAIN }} + WCCE_CA_BUNDLE: ${{ secrets.WCCE_CA_BUNDLE }} + WCCE_FQDN: ${{ secrets.WCCE_FQDN }} + + - name: "EAB with headerinfo - Prepare Almalinux instance" + run: | + sudo cp examples/Docker/almalinux-systemd/Dockerfile data + sudo sed -i "s/FROM almalinux:9/FROM almalinux:${{ matrix.rhversion }}/g" data/Dockerfile + cat data/Dockerfile | docker build -t almalinux-systemd -f - . --no-cache + docker run -d -id --privileged --network acme --name=acme-srv -v "$(pwd)/data":/tmp/acme2certifier almalinux-systemd + + - name: "EAB with headerinfo - Execute install scipt" + run: | + docker exec acme-srv sh /tmp/acme2certifier/rpm_tester.sh + + + - name: "EAB with headerinfo - Sleep for 5s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 5s + + - name: "EAB with headerinfo - 01a - enrollment without header-info field (first value in list)" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Client" + + - name: "EAB with headerinfo - 01b - enrollment with header-info field (pick value from list)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=WebServer --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep -i "TLS Web Server" + + - name: "EAB with headerinfo - 01c - enrollment with header-info field containing value not included in list (to fail)" + id: legofail02 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent template=Unknown --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + + - name: EAB with headerinfo 01c - check result " + if: steps.legofail02.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail02.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 01d - enrollment with header-info field cotaining an invalid parameter (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent ca_name=foo --key-type=rsa2048 -d lego.acme --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 01e - enrollment with header-info field containing parameter not in json (silent overwrite)" + run: | + sudo rm -rf lego/* + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --user-agent user=user --key-type=rsa2048 -d lego.acme --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 02 - template from profile" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Client" + + - name: "EAB with headerinfo - 03 - domainlist validation fails (to fail)" + id: legofail03 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM --http run + + - name: "EAB with headerinfo - 03 - check result " + if: steps.legofail03.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail03.outcome }}" + exit 1 + + - name: "EAB with headerinfo - 04 - Settings from acme_srv.cfg" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 -d lego.acme --eab --kid keyid_03 --hmac YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr --http run + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + sudo openssl x509 -in lego/certificates/lego.acme.crt -ext extendedKeyUsage -noout | grep "TLS Web Server" + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + docker exec acme-srv tar cvfz /tmp/acme2certifier/a2c.tgz /opt/acme2certifier + sudo rm -rf data/*.rpm + sudo cp -rp data/ ${{ github.workspace }}/artifact/data/ + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + sudo cp -rp dnsmasq/ ${{ github.workspace }}/artifact/dnsmasq/ + # docker exec acme-srv cat /etc/nginx/nginx.conf.orig > ${{ github.workspace }}/artifact/data/nginx.conf.orig + # docker exec acme-srv cat /etc/nginx/nginx.conf > ${{ github.workspace }}/artifact/data/nginx.conf + docker exec acme-srv cat /var/log/messages > ${{ github.workspace }}/artifact/acme-srv.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz data acme-srv.log acme-sh dnsmasq + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: mswcce_handler_profile_tests_rpm-rh${{ matrix.rhversion }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ + diff --git a/docs/eab_profiling.md b/docs/eab_profiling.md index 2603b3a5..a5a27c16 100644 --- a/docs/eab_profiling.md +++ b/docs/eab_profiling.md @@ -10,6 +10,8 @@ Currently the following ca-handlers had been modified and do support this featur - [EJBCA](ejbca.md) - [Insta ActiveCMS](asa.md) - [Insta certifier/NetGuard Certificate manager](certifier.md) +- [Microsoft Certificate Enrollment Web Services](mscertsrv.md) +- [Microsoft Windows Client Certificate Enrollment Protocol (MS-WCCE) via RPC/DCOM](mswcce.md) - [XCA](xca.md) In case you need support for a different ca-handler feel free to raise an [issue](https://github.com/grindsa/acme2certifier/issues/new). diff --git a/docs/mscertsrv.md b/docs/mscertsrv.md index 81347fe2..c5566ca8 100644 --- a/docs/mscertsrv.md +++ b/docs/mscertsrv.md @@ -80,6 +80,7 @@ auth_method: template: allowed_domainlist: ["example.com", "*.example2.com"] krb5_config: /krb5.conf +eab_profiling: False ``` - host - hostname of the system providing the Web enrollment service @@ -93,6 +94,7 @@ krb5_config: /krb5.conf - krb5_config - *optional* - path to individual krb5.conf - template - certificate template used for enrollment - allowed_domainlist - *optional* - list of domain-names allowed for enrollment in json format example: ["bar.local$, bar.foo.local] +- eab_profiling - optional - [activate eab profiling](eab_profiling.md) (default: False) ## Passing a template from client to server @@ -117,3 +119,48 @@ Example for lego: ```bash docker run -i -v $PWD/lego:/.lego/ --rm --name lego goacme/lego -s http:// -a --email "lego@example.com" --user-agent template=foo -d --http run ``` + +# eab profiling + +This handler can use the [eab profiling feture](eab_profiling.md) to allow individual enrollment configuration per acme-account as well as restriction of CN and SANs to be submitted within the CSR. The feature is disabled by default and must be activated in `acme_srv.cfg` + +```cfg +[EABhandler] +eab_handler_file: examples/eab_handler/kid_profile_handler.py +key_file: + +[CAhandler] +eab_profiling: True +``` + +below an example key-file used during regression testing: + +```json +{ + "keyid_00": { + "hmac": "V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw", + "cahandler": { + "template": ["WebServerModified", "WebServer"], + "allowed_domainlist": ["www.example.com", "www.example.org", "*.local"], + "unknown_key": "unknown_value" + } + }, + "keyid_01": { + "hmac": "YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg", + "cahandler": { + "template": "WebServerModified", + "allowed_domainlist": ["www.example.com", "www.example.org", "*.local"], + "unknown_key": "unknown_value" + } + }, + "keyid_02": { + "hmac": "dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM", + "cahandler": { + "allowed_domainlist": ["www.example.com", "www.example.org"] + } + }, + "keyid_03": { + "hmac": "YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr" + } +} +``` diff --git a/docs/mswcce.md b/docs/mswcce.md index 8c85d16a..3b63b084 100644 --- a/docs/mswcce.md +++ b/docs/mswcce.md @@ -40,6 +40,7 @@ template: