将内部CA导入Jenkins

时间:2018-05-22 15:32:13

标签: java ssl jenkins jenkins-pipeline self-signed

我正在尝试使用Jenkins作业(管道)从json端点读取一些信息,然后根据该信息执行某些操作。

它正在读取的端点是内部端点,应用程序可以通过https访问,其证书由我们的内部CA自签名。

这是示例代码,由管道运行以解析json:

[Route(...)]

为了使它更复杂一点,我也在管道中使用来自全局工具配置的Java二进制文件。

当我运行管道时,我得到了以下错误:

new JsonSlurper().parse(new URL('https://my.internal.url/info'))?.application?.git?.commit

所以现在我正在尝试让运行此代码的JVM知道这个CA,但我无法弄清楚如何做到这一点。

我尝试下载根CA的pem文件,将其添加到系统证书中,然后通过执行以下操作将其导入到java(sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280) at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:392) Caused: sun.security.validator.ValidatorException: PKIX path building failed at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:397) at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:302) at sun.security.validator.Validator.validate(Validator.java:260) at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:324) at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:229) at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:124) at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1496) Caused: javax.net.ssl.SSLHandshakeException at sun.security.ssl.Alerts.getSSLException(Alerts.java:192) at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1959) ... Caused: groovy.json.JsonException: Unable to process url: https://my.internal.url/info at groovy.json.JsonSlurper.parseURL(JsonSlurper.java:416) at groovy.json.JsonSlurper.parse(JsonSlurper.java:379) ... )的系统默认cacerts文件中:

/etc/ssl/certs/java/cacerts

之后,当我使用类测试java中的ssl连接(如https://gist.github.com/4ndrej/4547029)并运行curl -Lso /etc/ssl/certs/rootca1.pem "<DOWNLOAD LINK>" \ && chmod 777 /etc/ssl/certs/rootca1.pem \ && mkdir -p /usr/share/ca-certificates/projectname \ && cp /etc/ssl/certs/rootca1.pem /usr/share/ca-certificates/projectname/rootca1.crt \ && echo "projectname/rootca1.crt" >> /etc/ca-certificates.conf \ && update-ca-certificates -f 时,我可以成功连接。 Jenkins管道仍然出现相同的错误。

然后我想,也许管道使用由全局工具配置(即使在Jenkins文件中尚未完成)复制到工作区的java二进制文件,因此我将CA添加到java SSLPoke https://my.internal.url/info 443 工具的密钥库,复制到工作区(cacerts)。

之后我再次使用SSLPoke类的二进制文件成功连接到URL,但管道仍然失败......

所以我现在没有想法......有没有人遇到类似的问题并设法解决它们?没有转移到正式签名的证书(由于各种原因,它们不是内部网址的选项,甚至不是让我们加密)。

提前致谢!

2 个答案:

答案 0 :(得分:1)

所以我们设法解决了这个问题。问题是,我们没有让我们的代理提供整个证书链。除了浏览器之外,openssl二进制文件(例如Java实现)也无法即时加载缺少的中间证书。

所以我们创建了一个包含整个证书链的证书(从leaf到root证书),现在一切正常。

答案 1 :(得分:0)

我没有解决此问题,但是我们有一个解决方法。我们将证书放入从属容器中,并在所有节点上的所有Java安装中进行常规安装:

def jdksJava8 = ['Java 8', 'Java 8 Oracle']
def jdksJava11 = ['Java 11']

def nodeNames = env.'NODE_NAME' ? [env.'NODE_NAME'] : getNodeNames().sort().findAll { it.startsWith('my-node') }

stage 'Install myRootCA', {

    currentBuild.displayName = "${env.'BUILD_NUMBER'}: ${env.'NODE_NAME' ?: 'all nodes'}"

    parallel nodeNames.collectEntries { nodeName ->
        [
            (nodeName): {
                node nodeName, {
                    jdksJava8.each { jdkName ->
                        withEnv(["JAVA_HOME=${tool jdkName}"]) {
                            sh '$JAVA_HOME/bin/java -version'
                            sh script: '$JAVA_HOME/bin/keytool -delete -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias myRootCA', returnStatus: true
                            sh script: '$JAVA_HOME/bin/keytool -import -trustcacerts -noprompt -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit -alias myRootCA -file /usr/share/ca-certificates/myCompany/myRootCA.crt', returnStatus: true
                        }
                    }

                    jdksJava11.each { jdkName ->
                        withEnv(["JAVA_HOME=${tool jdkName}"]) {
                            sh script: '$JAVA_HOME/bin/keytool -delete -cacerts -storepass changeit -noprompt -alias myRootCA', returnStatus: true
                            sh script: '$JAVA_HOME/bin/keytool -importcert -cacerts -storepass changeit -noprompt -alias myRootCA -file /usr/share/ca-certificates/myCompany/myRootCA.crt', returnStatus: true
                        }
                    }
                }
            }
        ]
    }

}

@NonCPS
def getNodeNames() {
    jenkins.model.Jenkins.instance.nodes.collect { node -> node.name }
}

带有此脚本的作业现在每天晚上运行。如果必须重新启动节点,我们会在以后手动运行它以重新安装证书。