从AWS Credentials提供商获取安全令牌 [英] Get security token from AWS Credentials Provider

查看:101
本文介绍了从AWS Credentials提供商获取安全令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有人可以向我解释一下,我该如何从此

Can somebody explain me, how do I need to implement the first step from this blog? I can't find it in AWS documentation.

换句话说,我需要翻译一个命令:

In other words, I need to translate a command:

curl --cert eeb81a0eb6-certificate.pem.crt --key eeb81a0eb6-private.pem.key -H "x-amzn-iot-thingname: myThingName" --cacert AmazonRootCA1.pem https://<prefix>.credentials.iot.us-west-2.amazonaws.com/role-aliases/MyAlias/credentials

到JAVA.我该怎么做?我需要它的AWS开发工具包(我更喜欢没有自定义客户端来发出HTTPS请求"的解决方案)

to JAVA. How can I do it? I need AWS SDK for it (I prefer a solution without "custom client to make an HTTPS request")

更新:

我试图使用自定义客户端来发出HTTPS请求,但是在将密钥导出到Java KeyStore时遇到了困难(BUT curl命令对我来说很好用):

I tried to use a custom client to make an HTTPS request, but I stuck when strated to export my keys to Java KeyStore (BUT curl command works for me fine):

$ winpty openssl pkcs12 -export -in eeb81a0eb6-certificate.pem.crt -inkey eeb81a0eb6-private.pem.key -chain -CAfile AmazonRootCA1.pem -name mycompany.com -out my.p12

Error unable to get local issuer certificate getting chain.

另一个更新(我已经尝试过的内容)

  1. 将myPrivateKey和deviceCertificate转换为JKS:

  1. Convert myPrivateKey and deviceCertificate to JKS:

winpty openssl pkcs12 -export -in eeb81a0eb6-certificate.pem.crt -inkey eeb81a0eb6-private.pem.key -name mycompany.com -out my.p12

winpty openssl pkcs12 -export -in eeb81a0eb6-certificate.pem.crt -inkey eeb81a0eb6-private.pem.key -name mycompany.com -out my.p12

keytool -importkeystore -destkeystore mycompany.jks -srckeystore my.p12 -srcstoretype PKCS12

keytool -importkeystore -destkeystore mycompany.jks -srckeystore my.p12 -srcstoretype PKCS12

从我的代码中使用此JKS:

Use this JKS from my code:

 System.setProperty("deployment.security.TLSv1.2", "true");
 System.setProperty("https.protocols", "TLSv1.2");
 System.setProperty("javax.net.debug", "ssl");

 HttpPost request = new HttpPost(clientEndpoint);
 request.setHeader("x-amzn-iot-thingname", "0ad16050-d974-4f78-88ea-c6ee2b0a551e");

 KeyStore keyStore;
 try (InputStream keyStoreStream = this.getClass().getResourceAsStream(KEYSTOREPATH)) {
     keyStore = KeyStore.getInstance("PKCS12");
     keyStore.load(keyStoreStream, KEYSTOREPASS.toCharArray());
 }

 SSLContext sslContext = SSLContexts.custom()
         .loadKeyMaterial(keyStore, KEYPASS.toCharArray()) // use null as second param if you don't have a separate key password
         .loadTrustMaterial(null, new TrustSelfSignedStrategy())
         .build();   

 SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext);
 Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                                                 .register("https", sslConnectionSocketFactory)
                                                 .register("http", new PlainConnectionSocketFactory())
                                                 .build();

 BasicHttpClientConnectionManager manager = new BasicHttpClientConnectionManager(registry);

 try (CloseableHttpClient httpClient = HttpClients
                                         .custom()
                                         .setSSLSocketFactory(sslConnectionSocketFactory)
                                         .setConnectionManager(manager)
                                         .build();
      CloseableHttpResponse response = httpClient.execute(request)) {


     System.out.println();



 } catch (IOException e) {
     System.err.println(e);
 }

  • 我遇到异常:

  • I get exception:

    javax.net.ssl.SSLHandshakeException:收到致命警报:bad_certificate

    javax.net.ssl.SSLHandshakeException: Received fatal alert: bad_certificate

    推荐答案

    AWS开发工具包提供了

    The AWS SDK provides several implementations of SdkHttpClient that you can use to interact with your Amazon Services, both synchronously or asynchronously.

    例如,您可以使用

    For instance, you can use the ApacheHttpClient class.

    所有这些HTTP客户端都是通过 Builder s,

    All this HTTP clients are created and configured with Builders, ApacheHttpClient.Builder for ApacheHttpClient.

    ApacheHttpClient.Builder 提供的方法可让您为客户端,远程对等或相互身份验证配置安全的HTTP连接.

    ApacheHttpClient.Builder provides methods that allows you to configure secure HTTP connections for client side, remote peer, or mutual authentication.

    如果必须对客户端进行身份验证,则必须提供用于该目的的证书和私钥,与-cert -key 您的 curl 调用的code>参数.

    If the client must be authenticated, it is necessary to provide the certificate and private key that must be used for that purpose, corresponding to the --cert and --key arguments of your curl invocation.

    通常,此证书和私钥存储在一个受密码保护的 KeyStore 中,通常以PKCS#12格式( .p12 .pfx 文件).

    Typically, this certificate and private key are stored in one password protected KeyStore, usually in PKCS#12 format (a .p12 or .pfx file).

    可以通过两种方式使 ApacheHttpClient.Builder 可以访问此信息.

    This information can be made accessible to ApacheHttpClient.Builder in two ways.

    首先,通过设置一系列 System 属性:

    First, by setting a series of System properties:

    import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE;
    import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_PASSWORD;
    import static software.amazon.awssdk.utils.JavaSystemSetting.SSL_KEY_STORE_TYPE;
    
    //...
    
    Path clientKeyStore = Paths.get(...);
    
    System.setProperty(SSL_KEY_STORE.property(), clientKeyStore.toAbsolutePath().toString());
    System.setProperty(SSL_KEY_STORE_TYPE.property(), "pkcs12");
    System.setProperty(SSL_KEY_STORE_PASSWORD.property(), "password");
    

    注意: static 导入只是标准

    NOTE: The static imports are only constants for the standard JSSE properties javax.net.ssl.keyStore, javax.net.ssl.keyStorePassword, and javax.net.ssl.keyStoreType.

    其次,通过提供>代码> TlsKeyManagersProvider 实现到 ApacheHttpClient.Builder tlsKeyManagersProvider 方法.例如:

    Second, by providing a TlsKeyManagersProvider implementation to the tlsKeyManagersProvider method of ApacheHttpClient.Builder. For instance:

    Path clientKeyStore = ...
    TlsKeyManagersProvider keyManagersProvider = FileStoreTlsKeyManagersProvider.create(clientKeyStore, "pkcs12", "password");
    

    实际上,如果您需要对服务器进行身份验证,则还有两个选择.

    If you need to authenticate the server, you also have two options.

    首先,再次通过设置几个 System 属性:

    First, again, by setting several System properties:

    Path serverKeyStore = Paths.get(...);
    System.setProperty("javax.net.ssl.trustStore", serverKeyStore.toAbsolutePath().toString());
    System.setProperty("javax.net.ssl.trustStorePassword", "password");
    System.setProperty("javax.net.ssl.trustStoreType", "jks");
    

    为简单起见,如您所见,这次我们使用的是另一种 KeyStore jks .您可以从AWS服务器证书PEM文件(与 curl 命令中与-cacert 关联的文件)构建这样的 KeyStore 像这样:

    As you can see, for simplicity, this time we are using a different kind of KeyStore, jks. You can build such a KeyStore from your AWS server certificate PEM file (the one associated with the --cacert in your curl command) with something like this:

    Path pemPath = ...;
    try(final InputStream is = Files.newInputStream(pemPath) {
      CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
      X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(is);
      String alias = cert.getSubjectX500Principal().getName();
      KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
      keyStore.load(null);
      keyStore.setCertificateEntry(alias, cert);
    }
    

    在相互身份验证的情况下,尽管可以重复使用相同的 KeyStore ,但最佳实践是维护两个,一个使用客户端私钥和证书,另一个使用服务器证书.信任(信任库).

    In the case of mutual authentication, although you can reuse the same KeyStore, it is a best practice maintain two, one with the client private key and certificate, and other with the server certificates you will trust (the trust store).

    或者,您也可以通过定义

    Alternatively, you can also configure server side authentication by defining the TrustManagers that need to be used.

    对于此任务, ApacheHttpClient.Builder 提供方法 tlsTrustManagersProvider .此方法要求实现 TlsTrustManagersProvider 界面.

    For this task, the ApacheHttpClient.Builder provides the method tlsTrustManagersProvider. This method requires an implementation of the TlsTrustManagersProvider interface.

    此接口定义单个方法 trustManagers ,该方法返回必须用于检查SSL通信中的远程对等方的 TrustManager 的数组.

    This interface define a single method, trustManagers, that returns the array of TrustManagers that must be used to check the remote peer in the SSL communication.

    不幸的是,AWS开发工具包未提供此接口的实现,您需要实现自己的接口(如果需要更多信息,请告诉我).

    Unfortunately, the AWS SDK does not provide an implementation of this interface, you need to implement your own (let me know if you need further info).

    初始化和配置后,您可以将此 SdkHttpClient 或其 SdkHttpClient.Builder 提供给自定义服务客户端,例如

    Once initialized and configured, you can provide this SdkHttpClient or its SdkHttpClient.Builder, to a custom service client, like IotClient, using the httpClient or the httpClientBuilder methods, respectively.

    如果您只需要像 curl 命令一样测试TLS连接,则可以尝试执行以下操作:

    If you just need to test TLS connectivity like with your curl command, you can try something like this:

    Path clientKeyStore = Paths.get(...);
    System.setProperty("javax.net.ssl.keyStore", clientKeyStore.toAbsolutePath().toString());
    System.setProperty("javax.net.ssl.keyStoreType", "pkcs12");
    System.setProperty("javax.net.ssl.keyStorePassword", "password");
    
    Path serverKeyStore = Paths.get(...);
    System.setProperty("javax.net.ssl.trustStore", serverKeyStore.toAbsolutePath().toString());
    System.setProperty("javax.net.ssl.trustStorePassword", "password");
    System.setProperty("javax.net.ssl.trustStoreType", "jks");
    
    SdkHttpClient client = ApacheHttpClient.builder().build();
    
    SdkHttpRequest httpRequest = SdkHttpFullRequest.builder()
            .method(SdkHttpMethod.GET)
            .uri(new URI("https://<prefix>.credentials.iot.us-west-2.amazonaws.com/role-aliases/MyAlias/credentials"))
            .putHeader("x-amzn-iot-thingname", "myThingName")
            .build();
    
    HttpExecuteRequest request = HttpExecuteRequest.builder()
            .request(httpRequest)
            .build();
    
    HttpExecuteResponse response = client.prepareRequest(request).call();
    

    请检查

    Please, review this test in the AWS Java SDK, it can be also helpful.

    最后,还有您可以在项目中使用的异步HTTP客户端.在这些客户端中配置安全HTTP通信的方式与上述段落中所述的方式非常相似.

    Finally, there is also async HTTP clients that you can use in your project. The way in which secure HTTP communication is configured in these clients is very similar to the one described in the above paragraphs.

    您可以在 AWS Java SDK v2 GitHub存储库中找到所有这些资源.

    您可以将整个SDK导入项目中(我假设您正在使用Maven):

    You can import in your project the whole SDK (I assume you are using Maven):

    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>aws-sdk-java</artifactId>
      <version>2.15.7</version>
    </dependency>
    

    尽管,对于测试Apache HTTP客户端,我认为以下依赖项是唯一必要的:

    Although, for testing Apache HTTP client, I think that the following dependency will be the only necessary:

    <dependency>
      <groupId>software.amazon.awssdk</groupId>
      <artifactId>apache-client</artifactId>
      <version>2.15.7</version>
    </dependency>
    

    尽管我已尝试将答案集中在AWS开发工具包提供的代码上,据我所知,这是必要的,但要获得这些临时凭证,也可以使用任何允许安全连接到AWS的机制,例如ApacheHttpClient,例如您的示例中的OkHttp等.

    Although I have tried to focus the answer on code provided by the AWS SDK, as I understood it was necessary, to obtain these temporary credentials it is also possible to use any mechanism that allows a secure connection to AWS, such as Apache HttpClient, like in your example, OkHttp, etcetera.

    这些临时凭证可用于签署任何AWS Request并根据假定的IAM角色在AWS服务上执行操作.例如,按照

    These temporary credentials can be used to sign any AWS Request and perform operations - according to the assumed IAM role - on AWS services. For instance, following the example in the blog that you indicated, you can insert an item in a DynamoDB table:

    AwsSessionCredentials credentials = AwsSessionCredentials.create(
      "the_returned_access_key_id",
      "the_returned_secret_key_id",
      "the_returned_session_token"
    );
    
    DynamoDbClient ddb = DynamoDbClient.builder()
      .region(Region.US_EAST_1)
      .credentialsProvider(StaticCredentialsProvider.create(credentials))
      .build();
    
     HashMap<String,AttributeValue> itemValues = new HashMap<String,AttributeValue>();
    
    itemValues.put("serial_number", AttributeValue.builder().s("123456789").build());
    itemValues.put("timestamp", AttributeValue.builder().s("2017-11-20T06:00:00.000Z").build());
    itemValues.put("current_temp", AttributeValue.builder().n("65").build());
    itemValues.put("target_temp", AttributeValue.builder().n("70").build());
    itemValues.put("humidity", AttributeValue.builder().n("45").build());
    
    PutItemRequest request = PutItemRequest.builder()
      .tableName("MyHomeThermostat")
      .item(itemValues)
      .build();
    
    try {
      ddb.putItem(request);
    } catch (ResourceNotFoundException e) {
      //...
    } catch (DynamoDbException e) {
      //...
    } 
    

    关于您在上面的评论中如何续签获得的令牌的问题,我必须承认我无法给您提供 answer .

    In relation to your question in the comments above how to renew the obtained token, I must recognize that I am unable to give you an answer.

    我认为,恐怕无法刷新上述调用返回的临时凭证,至少AWS开发工具包没有为此提供任何机制:该凭证提供者是为物联网设计的非常具体的用例,在您引用的博客和 AWS官方文档中指出.

    In my opinion, I am afraid that the temporary credentials returned by the above mentioned call cannot be refreshed, at least the AWS SDK does not provide any mechanism for that: this credential provider is a very specific use case designed for IoT as indicated in the blog you cited and in the official AWS documentation.

    AWS开发工具包提供了不同的 AWSCredentialsProvider ,它们支持令牌续签,例如

    The AWS SDK provides different AWSCredentialsProviders that supports token renewal, like StsAssumeRoleCredentialsProvider or StsGetSessionTokenCredentialsProvider, among others, but there is no specific provider for this use case.

    如果有帮助,可以查看基类的源代码

    If it is of any help, you can review the source code of the base class StsCredentialsProvider, specially the code in its constructor related with the setup of CachedSupplier and related stuff.

    这篇关于从AWS Credentials提供商获取安全令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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