AWS Java SDK v2를 사용하여 AWS EKS에서 인증 토큰 받기


11

AWS Java SDK v2를 사용하여 AWS EKS에서 Kubernetes 인증 토큰을 얻으려면 어떻게해야합니까? Kubernetes SDK를 사용하여 Kubernetes로 인증하는 데 사용할 수있는 인증 토큰입니다. 다시 말해 Kubernetes 인증에 사용할 EKS의 인증 토큰을 가져 와서 "kube 구성"을 만들 필요가 없습니다.

실제로 다음 공개 문제 의 코드 예제를보고 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 유틸리티를 사용하여 토큰을 얻으려고
하십니까

이전에 aws-iam-authenticator를 사용했지만 아무것도 설치하지 않고 Java 소스 코드에서 토큰을 생성 할 수 있어야합니다. 그리고 SDK v2에 문제가있는 AWS Java SDK v1에서 작동하도록이 내용을 얻었습니다.
NS du Toit

저는 현재 토큰을 생성하기 위해 AWS 자바 SDK v1을 사용하고 있습니다 -하지만 지금 나는이 그림 내가 리팩토링 할 수 밖으로 :) 내 종속에서 SDK의 v1을 제거 할 수있는 한 빨리 내 클래스 경로 :(으로에 있어야
NS를 du Toit

어떤 Kubernetes 버전을 실행하고 있습니까? 이 앱은 어디에서 실행되어야합니까 (클러스터 외부, 내부)?
mewa

답변:


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);
    }
}

객체 의 /in path(third) 인수에 유의하십시오 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 자바 SDK v1을은 지정된 때 시계와 일을했다 SdkClock.STANDARD, 그리고 ZonedDateTime나는 AWS 자바 SDK V2 버전에서 사용하는은 UTC 시간대를 사용 않습니다.


그렇습니다, 나는 그것이 효과가 있었지만 그 배후의 추론에 대해 너무 많은 통찰력을 가지고 있지 않습니다. /I 없이도 여전히 토큰을 얻었지만 Kubernetes와 통합하기 시작했을 때 작동하지 않았습니다.
NS du Toit

또 다른 흥미로운 점은 원래 AWS Java SDK v1 문제에서 토큰의 수명이 매우 짧다는 것입니다. 만료 날짜를 60 초 이상으로 설정하려고하면 동일한 일이 발생합니다. 토큰을 얻지 만 Unauthorized응답으로 이어집니다 .
NS du Toit
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.