Holen Sie sich mit dem AWS Java SDK v2 ein Authentifizierungstoken von AWS EKS

11

Wie kann ich mit dem AWS Java SDK v2 ein Kubernetes-Authentifizierungstoken von AWS EKS erhalten? Ein Authentifizierungstoken, mit dem Sie sich mithilfe eines Kubernetes SDK bei Kubernetes authentifizieren können. Mit anderen Worten, ich möchte ein Authentifizierungstoken von EKS erhalten, das für die Authentifizierung mit Kubernetes verwendet werden soll, damit ich keine "Kube-Konfiguration" erstellen muss.

Ich habe tatsächlich eine Lösung mit AWS Java SDK v1 (nicht v2) erhalten, die sich die Codebeispiele in der folgenden offenen Ausgabe ansieht . Es gibt hier auch ein Python-Codebeispiel , ABER ich habe keinen Erfolg mit AWS Java SDK v2. Mein Versuch, dies mit AWS Java SDK v2 zu tun:

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

Es wird ein Token generiert, aber wenn ich das Token in meinem Kubernetes-Client (dem offiziellen Java Kubernetes SDK) verwende, erhalte ich eine "nicht autorisierte" Antwort zurück - daher fehlt mir etwas, auf das ich keinen Finger legen kann ...

Die AWS Java SDK v1-Version sieht ungefähr so ​​aus: (Aus dem zuvor erwähnten offenen Problem )

Ich habe es zum Laufen gebracht, aber ich habe Probleme, etwas Ähnliches in AWS Java SDK v2 zum Laufen zu bringen.

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
quelle
Wie im AWS Java SDK v1-Problem angegeben, reagiert die Implementierung empfindlich auf die Angabe eines zu langen Ablaufdatums. Ich habe ein bisschen mit dem Ablaufdatum herumgespielt, aber das Problem wurde dadurch nicht behoben.
NS du Toit
haben Sie versucht , die aws-iam-Authenticator - Dienstprogramm Token zu bekommen
Umesh Kumhar
Ich habe den aws-iam-Authentifikator bereits verwendet, muss aber in der Lage sein, Token aus Java-Quellcode zu generieren - ohne etwas zu installieren. Und ich habe dieses Zeug dazu gebracht, mit AWS Java SDK v1 zu arbeiten, nur Probleme mit v2 des SDK.
NS du Toit
Ich verwende derzeit das AWS Java SDK v1, um das Token zu generieren - aber jetzt muss ich es in meinem Klassenpfad haben :( Sobald ich das herausfinden kann, kann ich v1 des SDK umgestalten und aus meinen Abhängigkeiten entfernen :)
NS du Toit
Welche Kubernetes-Version verwenden Sie? Wo soll diese App ausgeführt werden (außerhalb des Clusters, innerhalb des Clusters)?
Mewa

Antworten:

2

Okay, ich habe es endlich geschafft.

Die AWS Java SDK v2-Version:

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

Das Problem war in meinem STS-Endpunkt 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);
    }
}

Beachten Sie das Argument /im path(dritten) für das URIObjekt. Die AWS Java SDK v1-Version hat den URI nicht so erstellt, sondern an /anderer Stelle angegeben. Wenn ich jetzt die Zeichenfolge ausdrucke, URIerhalte ich sie https://sts.eu-west-1.amazonaws.com/, während die Originalversion in der Frage gerade zurückgegeben wurdehttps://sts.eu-west-1.amazonaws.com

Interessant genug - die ursprüngliche Version hat auch ein Token generiert, aber das Token wurde von Kubernetes abgelehnt. Man sollte ein ähnliches Verhalten erwarten, wenn das Ablaufdatum zu weit in der Zukunft liegt - Sie erhalten ein Token, das jedoch zu einer UnauthorizedAntwort des Kubernetes-Dienstes führt.

Nach dem Ändern des STS-Endpunkts hat alles funktioniert, aber ich habe noch eine Änderung vorgenommen:

Ich habe die folgende Zeile zu meiner hinzugefügt Aws4PresignerParams:

.signingClockOverride(Clock.systemUTC())

Es war nicht erforderlich, aber das ursprüngliche AWS Java SDK v1 hat etwas mit einer Uhr gemacht, als es angegeben wurde SdkClock.STANDARD, und das ZonedDateTime, das ich in der AWS Java SDK v2-Version verwende, verwendet die UTC-Zeitzone.

NS du Toit
quelle
Also ja, ich habe es zum Laufen gebracht, aber ich habe nicht zu viel Einblick in die Gründe dafür. Auch ohne das habe /ich noch ein Token bekommen, aber wie angegeben hat es einfach nicht funktioniert, als ich anfing, mich in Kubernetes zu integrieren.
NS du Toit
Nur ein weiterer interessanter Aspekt: ​​Das ursprüngliche Problem mit AWS Java SDK v1 hat gezeigt, dass das Token nur von kurzer Dauer ist. Sobald ich versuche, das Ablaufdatum auf mehr als 60 Sekunden einzustellen, passiert dasselbe - ich erhalte ein Token, das jedoch zu einer UnauthorizedAntwort führt.
NS du Toit