无法使用AWS安全令牌找到到所请求目标的有效认证路径 [英] Unable to find valid certification path to requested target with AWS security token

查看:160
本文介绍了无法使用AWS安全令牌找到到所请求目标的有效认证路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试实施此文章: https://aws.amazon.com/blogs/security/how-to-eliminate-the-need-for-hardcoded通过使用aws-iot-credentials-provider/

所以我做了下一步:

  1. 创建本地密钥库:

  1. 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;
    }
}

  1. 因此,我成功获得了临时凭证,但是当我使用它们时:

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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆