amazon-web-services - 使用 AWS Java SDK v2 从 AWS EKS 获取身份验证 token

标签 amazon-web-services kubernetes aws-sdk amazon-eks aws-java-sdk-2.x

如何使用 AWS Java SDK v2 从 AWS EKS 获取 Kubernetes 身份验证 token ?然后可用于使用 Kubernetes SDK 向 Kubernetes 进行身份验证的身份验证 token 。换句话说,我想从 EKS 获取身份验证 token 以用于与 Kubernetes 的身份验证,这样我就不必创建“kube 配置”。

我实际上得到了一个使用 AWS Java SDK v1(不是 v2)的解决方案,查看以下 open issue 中的代码示例.还有一个Python代码示例here但是我在使用 AWS Java SDK v2 时没有取得任何成功。我尝试使用 AWS Java SDK v2 执行此操作:

public static String getAuthenticationToken(AwsCredentialsProvider awsAuth, Region awsRegion, String clusterName) {
    try {
        SdkHttpFullRequest requestToSign = SdkHttpFullRequest
                .builder()
                .method(SdkHttpMethod.GET)
                .uri(new URI("https", String.format("sts.%s.amazonaws.com", awsRegion.id()), null, null))
                .appendHeader("x-k8s-aws-id", clusterName)
                .appendRawQueryParameter("Action", "GetCallerIdentity")
                .appendRawQueryParameter("Version", "2011-06-15")
                .build();

        ZonedDateTime expirationDate = DateUtil.addSeconds(DateUtil.now(), 60);
        Aws4PresignerParams presignerParams = Aws4PresignerParams.builder()
                .awsCredentials(awsAuth.resolveCredentials())
                .expirationTime(expirationDate.toInstant())
                .signingName("sts")
                .signingRegion(awsRegion)
                .build();

        SdkHttpFullRequest signedRequest = Aws4Signer.create().presign(requestToSign, presignerParams);

        String encodedUrl = Base64.getUrlEncoder().withoutPadding().encodeToString(signedRequest.getUri().toString().getBytes(CharSet.UTF_8.getCharset()));
        return ("k8s-aws-v1." + encodedUrl);
    } catch (Exception e) {
        String errorMessage = "A problem occurred generating an Eks token";
        logger.error(errorMessage, e);
        throw new RuntimeException(errorMessage, e);
    }
}

它生成一个 token ,但是当我在我的 Kubernetes 客户端(官方 Java Kubernetes SDK)中使用该 token 时,我得到了一个“未经授权”的响应——所以我错过了一些我无法理解的东西......

AWS Java SDK v1 版本如下所示:
(来自前面提到的open issue)

我让它工作了,但我正在努力获得类似于在 AWS Java SDK v2 中工作的东西。

private String generateToken(String clusterName,
                                 Date expirationDate,
                                 String serviceName,
                                 String region,
                                 AWSSecurityTokenServiceClient awsSecurityTokenServiceClient,
                                 AWSCredentialsProvider credentialsProvider,
                                 String scheme,
                                 String host) throws URISyntaxException {
        try {
            DefaultRequest<GetCallerIdentityRequest> callerIdentityRequestDefaultRequest = new DefaultRequest<>(new GetCallerIdentityRequest(), serviceName);
            URI uri = new URI(scheme, host, null, null);
            callerIdentityRequestDefaultRequest.setResourcePath("/");
            callerIdentityRequestDefaultRequest.setEndpoint(uri);
            callerIdentityRequestDefaultRequest.setHttpMethod(HttpMethodName.GET);
            callerIdentityRequestDefaultRequest.addParameter("Action", "GetCallerIdentity");
            callerIdentityRequestDefaultRequest.addParameter("Version", "2011-06-15");
            callerIdentityRequestDefaultRequest.addHeader("x-k8s-aws-id", clusterName);

            Signer signer = SignerFactory.createSigner(SignerFactory.VERSION_FOUR_SIGNER, new SignerParams(serviceName, region));
            SignerProvider signerProvider = new DefaultSignerProvider(awsSecurityTokenServiceClient, signer);
            PresignerParams presignerParams = new PresignerParams(uri,
                    credentialsProvider,
                    signerProvider,
                    SdkClock.STANDARD);

            PresignerFacade presignerFacade = new PresignerFacade(presignerParams);
            URL url = presignerFacade.presign(callerIdentityRequestDefaultRequest, expirationDate);
            String encodedUrl = Base64.getUrlEncoder().withoutPadding().encodeToString(url.toString().getBytes());
            log.info("Token [{}]", encodedUrl);
            return "k8s-aws-v1." + encodedUrl;
        } catch (URISyntaxException e) {
            log.error("could not generate token", e);
            throw e;
        }
    }

最佳答案

好的,我终于让它工作了。

AWS Java SDK v2 版本:

public static String getAuthenticationToken(AwsCredentialsProvider awsAuth, Region awsRegion, String clusterName) {
    try {    
        SdkHttpFullRequest requestToSign = SdkHttpFullRequest
                .builder()
                .method(SdkHttpMethod.GET)
                .uri(StsUtil.getStsRegionalEndpointUri(awsRegion))
                .appendHeader("x-k8s-aws-id", clusterName)
                .appendRawQueryParameter("Action", "GetCallerIdentity")
                .appendRawQueryParameter("Version", "2011-06-15")
                .build();

        ZonedDateTime expirationDate = DateUtil.addSeconds(DateUtil.now(), 60);
        Aws4PresignerParams presignerParams = Aws4PresignerParams.builder()
                .awsCredentials(awsAuth.resolveCredentials())
                .signingRegion(awsRegion)
                .signingName("sts")
                .signingClockOverride(Clock.systemUTC())
                .expirationTime(expirationDate.toInstant())
                .build();

        SdkHttpFullRequest signedRequest = Aws4Signer.create().presign(requestToSign, presignerParams);

        String encodedUrl = Base64.getUrlEncoder().withoutPadding().encodeToString(signedRequest.getUri().toString().getBytes(CharSet.UTF_8.getCharset()));
        return ("k8s-aws-v1." + encodedUrl);
    } catch (Exception e) {
        String errorMessage = "A problem occurred generating an Eks authentication token for cluster: " + clusterName;
        logger.error(errorMessage, e);
        throw new RuntimeException(errorMessage, e);
    }
}

问题出在我的 STS 端点 Uri 中:

public static URI getStsRegionalEndpointUri(Region awsRegion) {
    try {
        return new URI("https", String.format("sts.%s.amazonaws.com", awsRegion.id()), "/", null);
    } catch (URISyntaxException shouldNotHappen) {
        String errorMessage = "An error occurred creating the STS regional endpoint Uri";
        logger.error(errorMessage, shouldNotHappen);
        throw new RuntimeException(errorMessage, shouldNotHappen);
    }
}

请注意 /path (第三) URI 的论据目的。 AWS Java SDK v1 版本没有创建这样的 URI,而是指定了 /别处。如果我现在打印出 URI作为字符串,我得到 https://sts.eu-west-1.amazonaws.com/ ,而问题中的原始版本刚刚返回 https://sts.eu-west-1.amazonaws.com
很有趣 - 原始版本确实也生成了一个 token ,但该 token 被 Kubernetes 拒绝了。如果到期日期太远,人们应该期待类似的行为——你会得到一个 token ,但它会导致 Unauthorized来自 Kubernetes 服务的响应。

更改 STS 端点后一切正常,但我又做了一个更改:

我将以下行添加到我的 Aws4PresignerParams :

.signingClockOverride(Clock.systemUTC())

这不是必需的,但原始 AWS Java SDK v1 在指定 SdkClock.STANDARD 时确实对时钟做了一些事情。 ,以及 ZonedDateTime我在 AWS Java SDK v2 版本中使用的确实使用了 UTC 时区。

关于amazon-web-services - 使用 AWS Java SDK v2 从 AWS EKS 获取身份验证 token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59853623/

相关文章:

php - Windows 10 无法将 AWS SDK for PHP v3 与 Composer 一起使用

kubernetes - 如何在 Prometheus 中推送 Kubernetes 指标而不是拉取?

Kubernetes 无法从私有(private) docker 镜像仓库拉取镜像

java - 为什么 mock 对象的 getter() 返回 null?

node.js - Node js 中的 AWS SDK - 从子目录获取对象

amazon-web-services - 如何通过从 CloudFormation 中删除全局二级索引来将其从 DynamoDb 中删除?

amazon-web-services - Amazon API ItemSearch 返回 (400) 错误请求

amazon-s3 - 是否可以将 s3 存储桶移动/复制到其他帐户?

kubernetes - 如何在 v3.2.1 中列出有关 helm 搜索 url 的完整 url

使用 PayPal 移动 SDK 的 iOS 构建错误