gpt4 book ai didi

java - 从 AWS Credentials Provider 获取安全 token

转载 作者:行者123 更新时间:2023-12-04 08:47:09 25 4
gpt4 key购买 nike

有人可以解释我,我需要如何从这个 blog 实现第一步?
我在 AWS 文档中找不到它。
换句话说,我需要翻译一个命令:

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 SDK(我更喜欢没有“自定义客户端发出 HTTPS 请求”的解决方案)
更新:
我尝试使用自定义客户端发出 HTTPS 请求,但是在将我的 key 导出到 Java KeyStore 时我卡住了(但是 curl 命令对我来说很好用):
$ 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.
另一个更新(我已经尝试过)
  • 将 myPrivateKey 和 deviceCertificate 转换为 JKS:
    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
  • 从我的代码中使用这个 JKS:
     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);
    }
  • 我得到异常(exception):
    javax.net.ssl.SSLHandshakeException:收到致命警报:bad_certificate
  • 最佳答案

    AWS 开发工具包提供了多种 SdkHttpClient 实现,您可以使用它们与您的 Amazon 服务进行同步或异步交互。
    例如,您可以使用 ApacheHttpClient 类。
    所有这些 HTTP 客户端都是使用 Builder s, ApacheHttpClient.Builder ApacheHttpClient 创建和配置的。ApacheHttpClient.Builder 提供的方法允许您为客户端、远程对等方或相互身份验证配置安全的 HTTP 连接。
    如果必须对客户端进行身份验证,则必须提供必须用于该目的的证书和私钥,对应于 --cert 调用的 --keycurl 参数。
    通常,此证书和私钥存储在一个受密码保护的 KeyStore 中,通常采用 PKCS#12 格式(.p12.pfx 文件)。ApacheHttpClient.Builder 可以通过两种方式访问​​此信息。
    首先,通过设置一系列 System 属性:

    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 导入只是标准 JSSE 属性 javax.net.ssl.keyStorejavax.net.ssl.keyStorePasswordjavax.net.ssl.keyStoreType 的常量。
    其次,通过为 TlsKeyManagersProvidertlsKeyManagersProvider 方法提供 ApacheHttpClient.Builder 实现。例如:
    Path clientKeyStore = ...
    TlsKeyManagersProvider keyManagersProvider = FileStoreTlsKeyManagersProvider.create(clientKeyStore, "pkcs12", "password");
    事实上,在幕后,上面提到的基于 System 属性的配置被 SystemPropertyTlsKeyManagersProvider 使用,另一个 TlsKeyManagersProvider 实现。
    如果您需要对服务器进行身份验证,您还有两个选择。
    首先,再次通过设置几个 System 属性:
    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 文件(与 KeyStore 命令中的 --cacert 关联的文件)构建这样的 curl,如下所示:
    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 ,但最好的做法是维护两个,一个使用客户端私钥和证书,另一个使用您将信任的服务器证书(信任库)。
    或者,您也可以通过定义需要使用的 TrustManager 来配置服务器端身份验证。
    对于此任务, ApacheHttpClient.Builder 提供了 tlsTrustManagersProvider 方法。此方法需要 TlsTrustManagersProvider 接口(interface)的实现。
    此接口(interface)定义了一个方法 trustManagers ,该方法返回 TrustManager 数组,必须用于检查 SSL 通信中的远程对等方。
    不幸的是,AWS SDK 不提供此接口(interface)的实现,您需要实现自己的(如果您需要更多信息,请告诉我)。
    初始化和配置后,您可以分别使用 SdkHttpClientSdkHttpClient.Builder 方法将此 IotClient 或其 httpClient 提供给自定义服务客户端,例如 httpClientBuilder
    如果您只需要像使用 curl 命令一样测试 TLS 连接,您可以尝试以下操作:
    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();
    请查看 AWS Java SDK 中的 this test,它也很有帮助。
    最后,您还可以在项目中使用 async HTTP clients。在这些客户端中配置安全 HTTP 通信的方式与上述段落中描述的方式非常相似。
    您可以在 AWS Java SDK v2 GitHub repository 中找到所有这些资源。
    您可以在您的项目中导入整个 SDK(我假设您使用的是 Maven):
    <dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>aws-sdk-java</artifactId>
    <version>2.15.7</version>
    </dependency>
    虽然,为了测试 Apache HTTP 客户端,我认为以下依赖项将是唯一必要的:
    <dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>apache-client</artifactId>
    <version>2.15.7</version>
    </dependency>
    虽然我试图将答案集中在 AWS SDK 提供的代码上,但据我所知,为了获得这些临时凭证,也可以使用任何允许安全连接到 AWS 的机制,例如 Apache HttpClient,如在您的示例中,OkHttp 等。
    这些临时凭证可用于签署任何 AWS 请求并根据所承担的 IAM 角色对 AWS 服务执行操作。例如,按照您指示的 blog 中的示例,您可以在 DynamoDB 表中插入一个项目:
    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) {
    //...
    }
    关于您在上述评论中如何更新获得的 token 的问题,我必须承认我无法给您答案。
    在我看来,恐怕无法刷新上述调用返回的临时凭证,至少 AWS SDK 没有为此提供任何机制:此凭证提供程序是专为 IoT 设计的非常具体的用例,如您引用的博客和 official AWS documentation
    AWS 开发工具包提供了不同的 AWSCredentialsProvider 支持 token 续订,例如 StsAssumeRoleCredentialsProvider StsGetSessionTokenCredentialsProvider 等,但没有针对此用例的特定提供商。
    如果有帮助,您可以查看基类 StsCredentialsProvider 的源代码,特别是其构造函数中与 CachedSupplier 和相关内容设置相关的代码。

    关于java - 从 AWS Credentials Provider 获取安全 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64257498/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com