无法使用AWS安全令牌找到到所请求目标的有效认证路径 [英] Unable to find valid certification path to requested target with AWS security token
问题描述
所以我做了下一步:
-
创建本地密钥库:
Create local keystore:
keystore winpty openssl pkcs12 -export -in eeb81a0eb6-certificate.pem.crt -inkey eeb81a0eb6-private.pem.key -name myname -out my.p12 -password pass:mypass
keytool -importkeystore -destkeystore mykeystore.jks -srckeystore my.p12 -srcstoretype PKCS12 -deststorepass mypass -srcstorepass mypass
创建本地信任库:
keytool -keystore my_ca.jks -alias myalias -import -file AmazonRootCA1.pem
我的代码:
public class AWSSessionCredentialsProviderImpl implements AWSSessionCredentialsProvider {
private static final Logger LOGGER = LogManager.getLogger(AWSSessionCredentialsProviderImpl.class.getName());
private final Gson gson = new Gson();
private SdkHttpClient client;
private HttpExecuteRequest request;
private String awsAccessKeyId;
private String awsSecretAccessKeyId;
private String awsSessionToken;
public void init(String clientId) throws IOException, URISyntaxException {
System.setProperty("javax.net.ssl.trustStore", Configuration.KEYSTOREPATH_CA.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.trustStoreType", "jks");
try {
System.setProperty("javax.net.ssl.trustStorePassword", new String(Files.readAllBytes(Configuration.KEYSTOREPATH_CA_PASS)));
} catch (IOException e) {
throw new IOException("Read password of trust store is failed", e);
}
System.setProperty("javax.net.ssl.keyStore", Configuration.KEYSTOREPATH.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.keyStoreType", "jks");
try {
System.setProperty("javax.net.ssl.keyStorePassword", new String(Files.readAllBytes(Configuration.KEYSTOREPATH_PASS)));
} catch (IOException e) {
throw new IOException("Read password of key store is failed", e);
}
client = ApacheHttpClient.builder().build();
SdkHttpRequest httpRequest;
try {
httpRequest = SdkHttpFullRequest.builder()
.method(SdkHttpMethod.GET)
.uri(new URI(Configuration.CLIENT_ENDPOINT))
.putHeader("x-amzn-iot-thingname", clientId)
.build();
} catch (URISyntaxException e) {
throw new URISyntaxException(Configuration.CLIENT_ENDPOINT, "Building URI from client endpoint is failed");
}
request = HttpExecuteRequest.builder()
.request(httpRequest)
.build();
try {
setCredentials();
} catch (IOException e) {
throw new IOException("Set temporary credentials is failed", e);
}
}
@Override
public void refresh() {
try {
setCredentials();
} catch (IOException e) {
LOGGER.error("Refresh session credentials is failed", e);
}
}
@Override
public AWSSessionCredentials getCredentials() {
return new BasicSessionCredentials(awsAccessKeyId, awsSecretAccessKeyId, awsSessionToken);
}
private void setCredentials() throws IOException {
HttpExecuteResponse response = client.prepareRequest(request).call();
String credStr = IoUtils.toUtf8String(response.responseBody().get());
CredentialsJson credJson = gson.fromJson(credStr, CredentialsJson.class);
awsAccessKeyId = credJson.credentials.accessKeyId;
awsSecretAccessKeyId = credJson.credentials.secretAccessKey;
awsSessionToken = credJson.credentials.sessionToken;
}
}
- 因此,我成功获得了临时凭证,但是当我使用它们时:
AWSSessionCredentialsProviderImpl credentialsProvider = new AWSSessionCredentialsProviderImpl();
credentialsProvider.init("someid");
s3Client = AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(credentialsProvider)
.build();
s3Client.putObject(request);
我得到异常:
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
如果我可以成功获得临时凭据,我不明白为什么会出现此异常.
I don't understand why I get this exception if I can get temporary credentials successfully.
推荐答案
问题可能与很多事情有关.
The problem could be related with many things.
您的Java程序很可能无法与远程对等方建立信任关系,这可能是因为AWS CA不是预先配置的JVM信任的CA之一.
Most likely, your Java program will not be able to establish a trust relationship with the remote peer, probably because the AWS CA is not one of the preconfigured JVM trusted CAs.
我认为您可以采用的最好方法是将已经拥有的SdkHttpClient
也传递给S3客户端.
I think the best approach you can take to solve the problem is to pass the SdkHttpClient
that you already have to the S3 client as well.
请注意,在示例代码中,您正在使用AmazonS3ClientBuilder
(AWS Java SDK版本1类),而其余代码在使用AWS SDK v2.
Please, be aware that in your sample code you are using AmazonS3ClientBuilder
, a AWS Java SDK version 1 class, meanwhile the rest of the code is using AWS SDK v2.
Maybe you can update your code to the latest version of the S3Client and try something like this:
System.setProperty("javax.net.ssl.trustStore", Configuration.KEYSTOREPATH_CA.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.trustStoreType", "jks");
try {
System.setProperty("javax.net.ssl.trustStorePassword", new String(Files.readAllBytes(Configuration.KEYSTOREPATH_CA_PASS)));
} catch (IOException e) {
throw new IOException("Read password of trust store is failed", e);
}
System.setProperty("javax.net.ssl.keyStore", Configuration.KEYSTOREPATH.toAbsolutePath().toString());
System.setProperty("javax.net.ssl.keyStoreType", "jks");
try {
System.setProperty("javax.net.ssl.keyStorePassword", new String(Files.readAllBytes(Configuration.KEYSTOREPATH_PASS)));
} catch (IOException e) {
throw new IOException("Read password of key store is failed", e);
}
SdkHttpClient client = ApacheHttpClient.builder().build();
// The idea is reuse the configured HTTP client, modify it as per your needs
AWSSessionCredentialsProviderImpl credentialsProvider = new AWSSessionCredentialsProviderImpl(client);
credentialsProvider.init("someid");
S3Client s3 = S3Client.builder()
.httpClient(client)
.region(region)
.credentialsProvider(credentialsProvider)
.build();
请确保您的信任库包含实际的SSL证书.您具有AWS的根CA证书,但可能没有与实际服务相对应的证书.
Please, be sure that your trust store contains the actual SSL certificate. You have the root CA certificate of AWS, but maybe not the corresponding to the actual service.
如有必要,您可以通过以下方式获取服务SSL证书:
If necessary, you can obtain the service SSL certificate with something like this:
openssl s_client -connect s3.us-west-1.amazonaws.com:443
请根据您所在的地区更改命令.您需要从响应中提取PEM内容.
Please, change the command according to your region. You need to extract the PEM content from the response.
如答案注释中所示,另一种方法可能是取消设置在调用S3Client
之前获得凭据时建立的System
属性:
As indicated in the comments to the answer, another alternative could be unset the System
properties established when you obtain your credentials before the invocation of the S3Client
:
System.clearProperty("javax.net.ssl.trustStore");
System.clearProperty("javax.net.ssl.trustStorePassword");
System.clearProperty("javax.net.ssl.trustStoreType");
它将为AWS开发工具包提供一个全新的调用S3的环境.
It will provide the AWS SDK with a fresh environment for invoking S3.
这篇关于无法使用AWS安全令牌找到到所请求目标的有效认证路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!