使用GCP私有CA创建证书时遇ALPN协商失败问题求助
解决Google Cloud私有CA创建时的ALPN协议协商失败问题
问题现象
运行创建Google Cloud私有证书颁发机构(CA)的Java代码时,抛出以下错误:
Caused by: io.grpc.StatusRuntimeException: UNAVAILABLE: Failed ALPN negotiation: Unable to find compatible protocol 通道管道:[SslHandler#0, ProtocolNegotiators$ClientTlsHandler#0, WriteBufferingAndExceptionHandler#0, DefaultChannelPipeline$TailContext#0]
相关代码与配置
Java代码
/* * Copyright 2021 Google LLC * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.demo.certificate; import java.io.IOException; import java.util.concurrent.ExecutionException; // [START privateca_create_ca] import com.google.api.core.ApiFuture; import com.google.cloud.security.privateca.v1.CaPoolName; import com.google.cloud.security.privateca.v1.CertificateAuthority; import com.google.cloud.security.privateca.v1.CertificateAuthority.KeyVersionSpec; import com.google.cloud.security.privateca.v1.CertificateAuthority.SignHashAlgorithm; import com.google.cloud.security.privateca.v1.CertificateAuthorityServiceClient; import com.google.cloud.security.privateca.v1.CertificateConfig; import com.google.cloud.security.privateca.v1.CertificateConfig.SubjectConfig; import com.google.cloud.security.privateca.v1.CreateCertificateAuthorityRequest; import com.google.cloud.security.privateca.v1.KeyUsage; import com.google.cloud.security.privateca.v1.KeyUsage.KeyUsageOptions; import com.google.cloud.security.privateca.v1.Subject; import com.google.cloud.security.privateca.v1.X509Parameters; import com.google.cloud.security.privateca.v1.X509Parameters.CaOptions; import com.google.longrunning.Operation; import com.google.protobuf.Duration; public class CreateCertificateAuthority { public static void main(String[] args) throws InterruptedException, ExecutionException, IOException { // TODO(developer): Replace these variables before running the sample. // location: For a list of locations, see: // https://cloud.google.com/certificate-authority-service/docs/locations // poolId: Set it to the CA Pool under which the CA should be created. // certificateAuthorityName: Unique name for the CA. String project = "corp-esgda-dev"; String location = "us-east1"; String poolId = "test-pool"; String certificateAuthorityName = "myCA"; createCertificateAuthority(project, location, poolId, certificateAuthorityName); } // Create Certificate Authority which is the root CA in the given CA Pool. public static void createCertificateAuthority( String project, String location, String poolId, String certificateAuthorityName) throws InterruptedException, ExecutionException, IOException { // Initialize client that will be used to send requests. This client only needs to be created // once, and can be reused for multiple requests. After completing all of your requests, call // the `certificateAuthorityServiceClient.close()` method on the client to safely // clean up any remaining background resources. try (CertificateAuthorityServiceClient certificateAuthorityServiceClient = CertificateAuthorityServiceClient.create()) { System.setProperty("https.protocols", "TLSv1.2"); System.out.println(System.getProperties()); String commonName = "dev"; String orgName = "qc"; int caDuration = 100000; // Validity of this CA in seconds. // Set the type of Algorithm. KeyVersionSpec keyVersionSpec = KeyVersionSpec.newBuilder().setAlgorithm(SignHashAlgorithm.RSA_PKCS1_4096_SHA256).build(); // Set CA subject config. SubjectConfig subjectConfig = SubjectConfig.newBuilder() .setSubject( Subject.newBuilder().setCommonName(commonName).setOrganization(orgName).build()) .build(); // Set the key usage options for X.509 fields. X509Parameters x509Parameters = X509Parameters.newBuilder() .setKeyUsage( KeyUsage.newBuilder() .setBaseKeyUsage( KeyUsageOptions.newBuilder().setCrlSign(true).setCertSign(true).build()) .build()) .setCaOptions(CaOptions.newBuilder().setIsCa(true).build()) .build(); // Set certificate authority settings. CertificateAuthority certificateAuthority = CertificateAuthority.newBuilder() // CertificateAuthority.Type.SELF_SIGNED denotes that this CA is a root CA. .setType(CertificateAuthority.Type.SELF_SIGNED) .setKeySpec(keyVersionSpec) .setConfig( CertificateConfig.newBuilder() .setSubjectConfig(subjectConfig) .setX509Config(x509Parameters) .build()) // Set the CA validity duration. .setLifetime(Duration.newBuilder().setSeconds(caDuration).build()) .build(); // Create the CertificateAuthorityRequest. CreateCertificateAuthorityRequest certificateAuthorityRequest = CreateCertificateAuthorityRequest.newBuilder() .setParent(CaPoolName.of(project, location, poolId).toString()) .setCertificateAuthorityId(certificateAuthorityName) .setCertificateAuthority(certificateAuthority) .build(); // Create Certificate Authority. ApiFuture<Operation> futureCall = certificateAuthorityServiceClient .createCertificateAuthorityCallable() .futureCall(certificateAuthorityRequest); System.out.println("futureCall:"+futureCall); Operation response = futureCall.get(); if (response.hasError()) { System.out.println("Error while creating CA !" + response.getError()); return; } System.out.println( "Certificate Authority created successfully : " + certificateAuthorityName); } } } // [END privateca_create_ca]
Maven Pom.xml配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>certificate</groupId> <artifactId>demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>certificate-demo</name> <properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>com.google.cloud</groupId> <artifactId>libraries-bom</artifactId> <version>26.29.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-security-private-ca</artifactId> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-monitoring</artifactId> </dependency> <dependency> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-alpn-openjdk8-client</artifactId> <version>9.4.44.v20210927</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.6</version> <!-- Use the latest version available --> </dependency> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.truth</groupId> <artifactId>truth</artifactId> <version>1.2.0</version> <scope>test</scope> </dependency> </dependencies> </project>
解决方案
1. 调整系统属性设置时机
将TLS协议配置移到main方法最开头,确保在客户端初始化前生效,同时添加gRPC SSL提供者配置:
public static void main(String[] args) throws InterruptedException, ExecutionException, IOException { // 提前设置TLS协议与gRPC SSL提供者,确保在客户端初始化前生效 System.setProperty("https.protocols", "TLSv1.2"); System.setProperty("grpc.ssl.provider", "openjdk"); String project = "corp-esgda-dev"; String location = "us-east1"; String poolId = "test-pool"; String certificateAuthorityName = "myCA"; createCertificateAuthority(project, location, poolId, certificateAuthorityName); }
2. 清理冲突依赖
移除jetty-alpn-openjdk8-client依赖,因为Google Cloud的gRPC客户端依赖已经包含适配Java 8的ALPN支持,手动添加该依赖会导致版本冲突。修改后的dependencies部分如下:
<dependencies> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-security-private-ca</artifactId> </dependency> <dependency> <groupId>com.google.cloud</groupId> <artifactId>google-cloud-monitoring</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>1.2.6</version> </dependency> <!-- 测试依赖保留 --> <dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcpkix-jdk15on</artifactId> <version>1.70</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.13.2</version> <scope>test</scope> </dependency> <dependency> <groupId>com.google.truth</groupId> <artifactId>truth</artifactId> <version>1.2.0</version> <scope>test</scope> </dependency> </dependencies>
3. 验证JDK版本
确保运行环境使用Oracle JDK 8u251+或OpenJDK 8u252+,这些版本开始内置ALPN支持,无需额外配置。若使用旧版JDK 8,需手动添加ALPN的bootclasspath参数,但推荐直接升级JDK版本简化配置。
问题根源
Java 8默认缺少ALPN(应用层协议协商)支持,而gRPC与Google Cloud服务通信依赖HTTP/2协议,ALPN是HTTP/2握手的必要环节。当客户端无法协商出兼容协议时,就会触发Failed ALPN negotiation错误。通过调整依赖和系统属性,确保客户端正确支持TLS 1.2与ALPN,即可解决该问题。
内容的提问来源于stack exchange,提问作者Kiran
相关产品推荐
相关产品推荐

