Dapatkan token otentikasi dari AWS EKS menggunakan AWS Java SDK v2

11

Bagaimana saya bisa mendapatkan token otentikasi Kubernetes dari AWS EKS menggunakan AWS Java SDK v2? Token otentikasi yang kemudian dapat digunakan untuk mengautentikasi dengan Kubernetes menggunakan Kubernetes SDK. Dengan kata lain saya ingin mendapatkan token otentikasi dari EKS untuk digunakan untuk otentikasi dengan Kubernetes sehingga saya tidak perlu membuat "kube config".

Saya benar-benar mendapat solusi bekerja dengan AWS Java SDK v1 (bukan v2) melihat contoh kode dalam masalah terbuka berikut . Ada juga contoh kode Python di sini TETAPI saya tidak berhasil dengan AWS Java SDK v2. Upaya saya melakukannya dengan 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);
    }
}

Ini menghasilkan token, tetapi ketika saya menggunakan token di klien Kubernetes saya (Java Kubernetes SDK resmi), saya mendapatkan respons "Tidak Diotorisasi" - jadi saya kehilangan sesuatu yang tidak bisa saya letakkan di ...

Versi AWS Java SDK v1 terlihat seperti ini: (Dari masalah terbuka yang disebutkan sebelumnya)

Saya membuatnya bekerja, tetapi saya berjuang untuk mendapatkan sesuatu yang mirip dengan bekerja di 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;
        }
    }
NS du Toit
sumber
Seperti yang ditunjukkan dalam masalah AWS Java SDK v1, implementasinya sensitif untuk menetapkan tanggal kedaluwarsa yang terlalu lama. Saya memang bermain-main dengan tanggal kedaluwarsa sedikit, tetapi itu tidak menyelesaikan masalah.
NS du Toit
apakah Anda mencoba menggunakan utilitas aws-iam-authenticator untuk mendapatkan token
Umesh Kumhar
Saya telah menggunakan aws-iam-authenticator sebelumnya, tetapi saya harus dapat menghasilkan token dari kode sumber Java - tanpa menginstal apa pun. Dan saya mendapatkan hal ini untuk bekerja dengan AWS Java SDK v1, hanya mengalami masalah dengan v2 dari SDK.
NS du Toit
Saat ini saya menggunakan AWS Java SDK v1 untuk menghasilkan token - tetapi sekarang saya harus memilikinya di classpath saya :( Segera setelah saya mengetahui hal ini saya dapat refactor dan menghapus v1 SDK dari dependensi saya :)
NS du Toit
Apa versi Kubernet yang Anda jalankan? Di mana aplikasi ini dimaksudkan untuk dijalankan (di luar cluster, di dalamnya)?
mewa

Jawaban:

2

Oke, saya akhirnya berhasil.

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

Masalahnya adalah pada titik akhir STS saya 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);
    }
}

Perhatikan /dalam pathargumen (ketiga) untuk URIobjek. Versi AWS Java SDK v1 tidak membuat URI seperti itu, tetapi menentukan tempat /lain. Jika sekarang saya mencetak URIsebagai String saya dapatkan https://sts.eu-west-1.amazonaws.com/, sedangkan versi asli dalam pertanyaan baru saja kembalihttps://sts.eu-west-1.amazonaws.com

Cukup menarik - versi aslinya juga menghasilkan token, tetapi token ditolak oleh Kubernetes. Orang harus mengharapkan perilaku yang sama jika tanggal kedaluwarsa terlalu jauh ke masa depan - Anda akan mendapatkan token, tetapi itu akan mengarah pada Unauthorizedrespons dari layanan Kubernetes.

Setelah mengubah titik akhir STS semuanya bekerja, tapi saya membuat satu perubahan lagi:

Saya menambahkan baris berikut ke Aws4PresignerParams:

.signingClockOverride(Clock.systemUTC())

Itu tidak diperlukan, tetapi AWS Java SDK v1 asli melakukan sesuatu dengan jam ketika ditentukan SdkClock.STANDARD, dan ZonedDateTimeyang saya gunakan dalam versi AWS Java SDK v2 menggunakan zona waktu UTC.

NS du Toit
sumber
Jadi ya, saya membuatnya bekerja, tetapi saya tidak memiliki terlalu banyak wawasan tentang alasan di baliknya. Bahkan tanpa itu /saya masih mendapat token, tetapi seperti yang ditunjukkan itu tidak berfungsi ketika saya mulai berintegrasi dengan Kubernetes.
NS du Toit
Selain hal lain yang menarik - masalah AWS Java SDK v1 yang asli memang menunjukkan bahwa token tersebut berumur pendek. Segera setelah saya mencoba mengatur tanggal kedaluwarsa menjadi lebih dari 60 detik, hal yang sama terjadi - saya mendapat token, tetapi hal itu mengarah pada Unauthorizedrespons.
NS du Toit