AWS Java SDK v2を使用してAWS EKSから認証トークンを取得する


11

AWS Java SDK v2を使用してAWS EKSからKubernetes認証トークンを取得するにはどうすればよいですか?次に、Kubernetes SDKを使用してKubernetesで認証するために使用できる認証トークン。つまり、Kubernetesでの認証に使用するEKSから認証トークンを取得して、「kube config」を作成する必要がないようにしたいと考えています。

実際には、次の未解決の問題のコード例を見て、(v2ではなく)AWS Java SDK v1で動作するソリューションを得ました。そこ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デュトワ

実行している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);
    }
}

/pathするための(第3)の引数URIオブジェクト。AWS Java SDK v1バージョンはそのようなURIを作成しませんでしたが、/他の場所を指定しました。をURI文字列として出力するhttps://sts.eu-west-1.amazonaws.com/と、問題の元のバージョンが返されます。https://sts.eu-west-1.amazonaws.com

興味深いことに、元のバージョンでもトークンが生成されましたが、トークンはKubernetesによって拒否されました。有効期限が遠すぎる場合も同様の動作が予想されます。トークンを取得しますがUnauthorized、Kubernetesサービスからの応答が返されます。

STSエンドポイントを変更した後、すべてが機能しましたが、もう1つ変更を加えました。

私は次の行をmyに追加しましたAws4PresignerParams

.signingClockOverride(Clock.systemUTC())

必須ではありませんでしたが、元のAWS Java SDK v1はSdkClock.STANDARD、指定されたときにクロックZonedDateTimeを使用して何かを行いました。また、AWS Java SDK v2バージョンで使用するものはUTCタイムゾーンを使用します。


ええ、私はそれを機能させましたが、その背後にある推論についての洞察はあまりありません。/トークンがなくてもトークンを取得しましたが、示されているように、Kubernetesとの統合を開始したときに機能しませんでした。
NS du Toit

余談ですが、元のAWS Java SDK v1の問題は、トークンの寿命が非常に短いことを示していました。有効期限を60秒以上に設定しようとすると、同じことが起こります。トークンを取得しましたが、Unauthorized応答が返されます。
NS du Toit
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.