Nhận mã thông báo xác thực từ AWS EKS bằng AWS Java SDK v2


11

Làm cách nào tôi có thể nhận được mã thông báo xác thực Kubernetes từ AWS EKS bằng AWS Java SDK v2? Mã thông báo xác thực sau đó có thể được sử dụng để xác thực với Kubernetes bằng SDK Kubernetes. Nói cách khác, tôi muốn nhận mã thông báo xác thực từ EKS để sử dụng để xác thực với Kubernetes để tôi không phải tạo "cấu hình kube".

Tôi thực sự có một giải pháp làm việc với AWS Java SDK v1 (không phải v2) xem xét các ví dụ mã trong vấn đề mở sau . Ngoài ra còn có một ví dụ mã Python ở đây NHƯNG tôi không có bất kỳ thành công nào với AWS Java SDK v2. Nỗ lực của tôi trong việc thực hiện với 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);
    }
}

Nó tạo ra một mã thông báo, nhưng khi tôi sử dụng mã thông báo trong ứng dụng khách Kubernetes của mình (SDK Kubernetes Java chính thức), tôi nhận được phản hồi "Không được phép" - vì vậy tôi thiếu một thứ gì đó mà tôi không thể đặt ngón tay vào ...

Phiên bản AWS Java SDK v1 trông giống như thế này: (Từ vấn đề mở được đề cập trước đó)

Tôi đã làm cho nó hoạt động, nhưng tôi đang vật lộn để có được thứ gì đó tương tự như hoạt động trong 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;
        }
    }

Như đã chỉ ra trong vấn đề AWS Java SDK v1, việc triển khai rất nhạy cảm trong việc chỉ định ngày hết hạn quá dài. Tôi đã chơi xung quanh với ngày hết hạn một chút, nhưng nó không giải quyết được vấn đề.
NS du Toit

bạn đã thử sử dụng tiện ích aws-iam-Authenticator để nhận mã thông báo
Umesh Kumhar

Tôi đã sử dụng aws-iam-Authenticator trước đây, nhưng tôi cần có khả năng tạo mã thông báo từ mã nguồn Java - mà không cần cài đặt bất cứ thứ gì. Và tôi đã có được thứ này để hoạt động với AWS Java SDK v1, chỉ gặp vấn đề với v2 của SDK.
NS du Toit

Tôi hiện đang sử dụng AWS Java SDK v1 để tạo mã thông báo - nhưng bây giờ tôi phải có nó trên đường dẫn lớp của mình :( Ngay khi tôi có thể tìm ra điều này, tôi có thể cấu trúc lại và xóa v1 SDK khỏi các phụ thuộc của mình :)
NS du Toit

Phiên bản Kubernetes nào bạn đang chạy? Ứng dụng này chạy ở đâu (bên ngoài cụm, bên trong nó)?
mewa

Câu trả lời:


2

Được rồi, cuối cùng tôi đã làm cho nó hoạt động.

Phiên bản 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);
    }
}

Vấn đề là ở điểm cuối STS Uri của tôi:

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

Lưu ý /trong pathđối số (thứ ba) cho URIđối tượng. Phiên bản AWS Java SDK v1 không tạo ra URI như thế, nhưng chỉ định /ở nơi khác. Nếu bây giờ tôi in ra URIdưới dạng Chuỗi tôi nhận được https://sts.eu-west-1.amazonaws.com/, trong khi phiên bản gốc trong câu hỏi vừa trả vềhttps://sts.eu-west-1.amazonaws.com

Đủ thú vị - phiên bản gốc cũng đã tạo ra một mã thông báo, nhưng mã thông báo đã bị Kubernetes từ chối. Mọi người nên mong đợi hành vi tương tự nếu ngày hết hạn quá xa trong tương lai - bạn sẽ nhận được mã thông báo, nhưng nó sẽ dẫn đến mộtUnauthorized phản hồi từ dịch vụ Kubernetes.

Sau khi thay đổi điểm cuối STS, mọi thứ đều hoạt động, nhưng tôi đã thực hiện thêm một thay đổi:

Tôi đã thêm dòng sau vào Aws4PresignerParams:

.signingClockOverride(Clock.systemUTC())

Không bắt buộc, nhưng AWS Java SDK v1 ban đầu đã làm gì đó với đồng hồ khi được chỉ định SdkClock.STANDARDZonedDateTimetôi sử dụng trong phiên bản AWS Java SDK v2 sử dụng múi giờ UTC.


Vì vậy, có, tôi đã làm cho nó hoạt động, nhưng tôi không có quá nhiều cái nhìn sâu sắc về lý do đằng sau nó. Ngay cả khi không có /tôi vẫn nhận được mã thông báo, nhưng như đã chỉ ra, nó chỉ không hoạt động khi tôi bắt đầu tích hợp với Kubernetes.
NS du Toit

Chỉ là một điều thú vị khác - vấn đề AWS Java SDK v1 ban đầu đã chỉ ra rằng mã thông báo rất ngắn. Ngay khi tôi cố gắng đặt ngày hết hạn thành hơn 60 giây, điều tương tự cũng xảy ra - tôi nhận được mã thông báo, nhưng nó dẫn đến Unauthorizedphản hồi.
NS du Toit
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.