diff --git a/README.md b/README.md index 547203d94b..b6eb342214 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,10 @@ To potentially solve the issue, start the container specifying a DNS server (for docker run -p 8080:8080 -p 50000:50000 --restart=on-failure --dns 1.1.1.1 --dns 8.8.8.8 jenkins/jenkins:lts-jdk21 ``` +## Custom CA Certificates + +If your Jenkins instance needs to trust custom root CA certificates (for corporate proxies, internal services, or self-signed certificates), see the documentation on jenkins.io for detailed instructions on using init containers or building custom images at https://www.jenkins.io/doc/book/pipeline/docker/#custom-registry. + ## Passing Jenkins launcher parameters Arguments you pass to docker running the Jenkins image are passed to the Jenkins launcher, so for example you can run: diff --git a/tests/runtime.bats b/tests/runtime.bats index 82ef28a77e..758a7adf30 100644 --- a/tests/runtime.bats +++ b/tests/runtime.bats @@ -161,3 +161,50 @@ runInScriptConsole() { @test "[${SUT_DESCRIPTION}] ensure that 'ps' command is available" { command -v ps # Check for binary presence in the current PATH } + +@test "[${SUT_DESCRIPTION}] custom CA certificate is imported via init-container pattern" { + local container_name test_cert_dir cacerts_vol + container_name="$(get_sut_container_name)" + cleanup "${container_name}" + test_cert_dir="$(mktemp -d)" + cacerts_vol="${container_name}-cacerts" + + # Clean up any leftover volume + docker volume rm "${cacerts_vol}" 2>/dev/null || true + + # Generate a self-signed test CA certificate + docker run --rm --user root -v "${test_cert_dir}:/certs" "${SUT_IMAGE}" \ + bash -c '"${JAVA_HOME}/bin/keytool" -genkeypair -alias testca -keyalg RSA -keysize 2048 \ + -dname "CN=Test CA" -validity 1 -keypass changeit \ + -keystore /tmp/test.jks -storepass changeit 2>/dev/null && \ + "${JAVA_HOME}/bin/keytool" -exportcert -alias testca -rfc \ + -keystore /tmp/test.jks -storepass changeit \ + -file /certs/test-ca.crt 2>/dev/null && \ + chmod 644 /certs/test-ca.crt' + + # Run init container as root: copy system cacerts and import custom cert + docker run --rm --user root \ + -v "${test_cert_dir}:/certs:ro" \ + -v "${cacerts_vol}:/cacerts-volume" \ + "${SUT_IMAGE}" \ + sh -c 'cp "${JAVA_HOME}/lib/security/cacerts" /cacerts-volume/cacerts && "${JAVA_HOME}/bin/keytool" -importcert -noprompt -keystore /cacerts-volume/cacerts -storepass changeit -alias custom-test-ca -file /certs/test-ca.crt' + + # Start Jenkins with the custom truststore (read-only) + docker run -d --name "${container_name}" \ + -v "${cacerts_vol}:/cacerts:ro" \ + --env JAVA_OPTS="-Djavax.net.ssl.trustStore=/cacerts/cacerts" \ + "${SUT_IMAGE}" + + # Verify custom cert exists in custom truststore + retry 10 2 docker exec "${container_name}" \ + sh -c '"${JAVA_HOME}/bin/keytool" -list -keystore /cacerts/cacerts -storepass changeit -alias custom-test-ca' + + # Verify system truststore was NOT modified + run docker exec "${container_name}" \ + sh -c '"${JAVA_HOME}/bin/keytool" -list -keystore "${JAVA_HOME}/lib/security/cacerts" -storepass changeit -alias custom-test-ca' + assert_failure + + # Cleanup + rm -rf "${test_cert_dir}" + docker volume rm "${cacerts_vol}" 2>/dev/null || true +}