本地sonar-scanner无法连接VPS部署的SonarQube服务器求助
VPS上部署了个人SonarQube实例,域名为https://sonar.pamwork.com,浏览器可正常访问,但本地Angular项目使用sonar-scanner扫描时提示「SonarQube server [https://sonar.pamwork.com] can not be reached」。
执行sonar-scanner -X的控制台输出:
> sonar-scanner -X 16:53:11.861 INFO: Scanner configuration file: C:\Users\TonkaIn-2022001\Documents\PAMWork Project\client\PAM Work Employees\node_modules\sonar-scanner\bin\..\conf\sonar-scanner.properties 16:53:11.869 INFO: Project root configuration file: C:\Users\TonkaIn-2022001\Documents\PAMWork Project\client\PAM Work Employees\sonar-project.properties 16:53:11.938 INFO: SonarQube Scanner 3.1.0.1141 16:53:11.939 INFO: Java 11.0.15.1 Oracle Corporation (64-bit) 16:53:11.939 INFO: Windows 10 10.0 amd64 16:53:12.183 DEBUG: keyStore is : 16:53:12.184 DEBUG: keyStore type is : pkcs12 16:53:12.185 DEBUG: keyStore provider is : 16:53:12.186 DEBUG: init keystore 16:53:12.187 DEBUG: init keymanager of type SunX509 16:53:12.877 DEBUG: Create: C:\Users\TonkaIn-2022001\.sonar\cache 16:53:12.879 INFO: User cache: C:\Users\TonkaIn-2022001\.sonar\cache 16:53:12.881 DEBUG: Create: C:\Users\TonkaIn-2022001\.sonar\cache\_tmp 16:53:12.886 DEBUG: Extract sonar-scanner-api-batch in temp... 16:53:12.903 DEBUG: Get bootstrap index... 16:53:12.903 DEBUG: Download: https://sonar.pamwork.com/batch/index 16:53:14.267 ERROR: SonarQube server [https://sonar.pamwork.com] can not be reached 16:53:14.268 INFO: ------------------------------------------------------------------------ 16:53:14.269 INFO: EXECUTION FAILURE 16:53:14.270 INFO: ------------------------------------------------------------------------ 16:53:14.271 INFO: Total time: 2.454s 16:53:14.290 INFO: Final Memory: 3M/14M 16:53:14.291 INFO: ------------------------------------------------------------------------ 16:53:14.291 ERROR: Error during SonarQube Scanner execution org.sonarsource.scanner.api.internal.ScannerException: Unable to execute SonarQube at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.lambda$createLauncher$0(IsolatedLauncherFactory.java:85) at java.base/java.security.AccessController.doPrivileged(Native Method) at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.createLauncher(IsolatedLauncherFactory.java:74) at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.createLauncher(IsolatedLauncherFactory.java:70) at org.sonarsource.scanner.api.EmbeddedScanner.doStart(EmbeddedScanner.java:167) at org.sonarsource.scanner.api.EmbeddedScanner.start(EmbeddedScanner.java:113) at org.sonarsource.scanner.cli.Main.execute(Main.java:73) at org.sonarsource.scanner.cli.Main.main(Main.java:61) Caused by: java.lang.IllegalStateException: Fail to get bootstrap index from server at org.sonarsource.scanner.api.internal.BootstrapIndexDownloader.getIndex(BootstrapIndexDownloader.java:42) at org.sonarsource.scanner.api.internal.JarDownloader.getScannerEngineFiles(JarDownloader.java:58) at org.sonarsource.scanner.api.internal.JarDownloader.download(JarDownloader.java:53) at org.sonarsource.scanner.api.internal.IsolatedLauncherFactory.lambda$createLauncher$0(IsolatedLauncherFactory.java:76) ... 7 more Caused by: javax.net.ssl.SSLHandshakeException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:131) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:369) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:312) at java.base/sun.security.ssl.TransportContext.fatal(TransportContext.java:307) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1357) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.onConsumeCertificate(CertificateMessage.java:1232) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.consume(CertificateMessage.java:1175) at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:478) at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:456) at java.base/sun.security.ssl.TransportContext.dispatch(TransportContext.java:199) at java.base/sun.security.ssl.SSLTransport.decode(SSLTransport.java:172) at java.base/sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1377) at java.base/sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1290) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:411) at java.base/sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:383) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.RealConnection.connectTls(RealConnection.java:281) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.RealConnection.establishProtocol(RealConnection.java:251) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.RealConnection.connect(RealConnection.java:151) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.StreamAllocation.findConnection(StreamAllocation.java:195) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.StreamAllocation.findHealthyConnection(StreamAllocation.java:121) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.StreamAllocation.newStream(StreamAllocation.java:100) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:42) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92) at org.sonarsource.scanner.api.internal.shaded.okhttp.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67) at org.sonarsource.scanner.api.internal.shaded.okhttp.RealCall.getResponseWithInterceptorChain(RealCall.java:185) at org.sonarsource.scanner.api.internal.shaded.okhttp.RealCall.execute(RealCall.java:69) at org.sonarsource.scanner.api.internal.ServerConnection.callUrl(ServerConnection.java:113) at org.sonarsource.scanner.api.internal.ServerConnection.downloadString(ServerConnection.java:98) at org.sonarsource.scanner.api.internal.BootstrapIndexDownloader.getIndex(BootstrapIndexDownloader.java:39) ... 10 more Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:439) at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306) at java.base/sun.security.validator.Validator.validate(Validator.java:264) at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313) at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:222) at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:129) at java.base/sun.security.ssl.CertificateMessage$T13CertificateConsumer.checkServerCerts(CertificateMessage.java:1341) ... 43 more Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141) at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126) at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297) at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434) ... 49 more npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! pam-work@0.0.0 sonar: `sonar-scanner -X` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the pam-work@0.0.0 sonar script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\TonkaIn-2022001\AppData\Roaming\npm-cache\_logs\2022-08-17T15_53_14_582Z-debug.log
sonar-project.properties配置文件内容:
sonar.host.url=https://sonar.pamwork.com sonar.login=login sonar.password=pass sonar.projectKey=key sonar.sourceEncoding=UTF-8 sonar.sources=src sonar.tests=src sonar.exclusions=**/node_modules/** sonar.test.inclusions=**/*.spec.ts sonar.typescript.lcov.reportPaths=coveragecob/chrome/lcov.info sonar.testExecutionReportPaths=reports/ut_report.xml
日志显示问题根源为SSL握手失败,出现PKIX路径构建错误,无法找到有效的证书路径。
问题本质是本地Java环境(sonar-scanner依赖Java运行)不信任SonarQube服务器的SSL证书,以下是几种解决方式:
方式一:将SonarQube证书导入Java信任库(推荐生产环境)
导出SonarQube服务器的SSL证书
- 浏览器访问
https://sonar.pamwork.com,点击地址栏锁图标,查看证书详情,导出为Base64编码的X.509格式(.crt文件)。 - 或用OpenSSL命令导出:
openssl s_client -connect sonar.pamwork.com:443 < /dev/null | sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > sonar-cert.crt
- 浏览器访问
定位sonar-scanner使用的Java环境
从日志可知使用Java 11,找到对应JRE路径,信任库默认路径为{JRE_HOME}/lib/security/cacerts。导入证书到信任库
使用keytool命令导入,默认信任库密码为changeit:keytool -importcert -file sonar-cert.crt -alias sonar.pamwork.com -keystore {JRE_HOME}/lib/security/cacerts输入密码后确认导入即可。
方式二:配置sonar-scanner忽略SSL证书验证(仅测试环境使用)
在sonar-scanner的配置文件(路径见日志:C:\Users\TonkaIn-2022001\Documents\PAMWork Project\client\PAM Work Employees\node_modules\sonar-scanner\conf\sonar-scanner.properties)中添加:
sonar.web.javaAdditionalOpts=-Dsonar.ssl.trustAll=true
或执行扫描时临时添加参数:
sonar-scanner -Dsonar.ssl.trustAll=true
注意:此方式跳过所有SSL验证,存在安全风险,仅用于测试环境。
方式三:检查证书链完整性
如果使用的是商业CA颁发的证书,需确认服务器配置了完整的证书链(包含中间证书),避免因链不完整导致信任失败。
内容的提问来源于stack exchange,提问作者Donald Hunter Kengue

