使用AWS Java SDK v2从AWS EKS获取身份验证令牌


11

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

实际上,我有一个使用AWS Java SDK v1(而非v2)的解决方案,它在以下未解决的问题中查看了代码示例。这里还有一个Python代码示例但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);
    }
}

它生成一个令牌,但是当我在Kubernetes客户端(官方Java Kubernetes SDK)中使用该令牌时,我得到一个“未经授权”的响应-因此,我缺少了一些我无法动弹的东西...

AWS Java SDK v1版本看起来像这样:(来自前面提到的未解决问题

我可以使用它,但是我正在努力获得与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 v1问题中所述,该实现很容易指定过期时间过长。我确实有一些有效期,但是它不能解决问题。
NS du Toit

您是否尝试使用aws-iam-authenticator实用程序获取令牌
Umesh Kumhar

我以前使用过aws-iam-authenticator,但是我需要能够从Java源代码生成令牌-无需安装任何工具。而且我已经将这些东西与AWS Java SDK v1一起使用,只是SDK的v2出现了问题。
NS du Toit

我目前正在使用AWS Java SDK v1生成令牌-但现在我必须将其放在类路径中:(一旦我弄清楚了,就可以从依赖项中重构和删除SDK v1 :)
NS du Toit

您正在运行哪个Kubernetes版本?该应用程序应在何处运行(群集外部,内部)?
mewa

Answers:


2

好吧,我终于开始工作了。

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

足够有趣-原始版本也生成了令牌,但是令牌被Kubernetes拒绝。如果到期日期离将来太远,您应该会期待类似的行为-您将获得令牌,但是它将导致UnauthorizedKubernetes服务的响应。

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

我将以下行添加到我的Aws4PresignerParams

.signingClockOverride(Clock.systemUTC())

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


是的,我知道了,但是我对它背后的原因没有太多的了解。即使没有/I,我仍然获得了令牌,但是如所示,当我开始与Kubernetes集成时,它只是不起作用。
NS du Toit

除了另一个有趣的问题-原始的AWS Java SDK v1问题确实表明该令牌的寿命很短。一旦我尝试将过期日期设置为60秒以上,就会发生同样的事情-我得到了令牌,但它会导致Unauthorized响应。
NS du Toit
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.