diff --git a/examples/examples-release-latest/pom.xml b/examples/examples-release-latest/pom.xml index 806668b834..4544e89b01 100644 --- a/examples/examples-release-latest/pom.xml +++ b/examples/examples-release-latest/pom.xml @@ -90,8 +90,8 @@ ${spring.boot.version} - com.amazonaws - aws-java-sdk-sts + software.amazon.awssdk + sts @@ -116,4 +116,4 @@ - \ No newline at end of file + diff --git a/examples/examples-release-latest/src/main/java/io/kubernetes/client/examples/EKSAuthenticationExample.java b/examples/examples-release-latest/src/main/java/io/kubernetes/client/examples/EKSAuthenticationExample.java index e1e6610a2a..7ca298239a 100644 --- a/examples/examples-release-latest/src/main/java/io/kubernetes/client/examples/EKSAuthenticationExample.java +++ b/examples/examples-release-latest/src/main/java/io/kubernetes/client/examples/EKSAuthenticationExample.java @@ -12,8 +12,6 @@ */ package io.kubernetes.client.examples; -import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; -import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider; import io.kubernetes.client.openapi.ApiClient; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.VersionInfo; @@ -22,6 +20,9 @@ import io.kubernetes.client.util.version.Version; import java.io.IOException; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.services.sts.StsClient; +import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider; public class EKSAuthenticationExample { public static void main(String[] args) throws IOException, ApiException { @@ -37,10 +38,14 @@ public static void main(String[] args) throws IOException, ApiException { // EKS cluster name. String clusterName = "test-2"; - STSAssumeRoleSessionCredentialsProvider credProvider = new STSAssumeRoleSessionCredentialsProvider( - new DefaultAWSCredentialsProviderChain().getCredentials(), - roleArn, - roleSessionName); + StsClient stsClient = StsClient.builder() + .credentialsProvider(DefaultCredentialsProvider.builder().build()) + .build(); + + StsAssumeRoleCredentialsProvider credProvider = StsAssumeRoleCredentialsProvider.builder() + .stsClient(stsClient) + .refreshRequest(r -> r.roleArn(roleArn).roleSessionName(roleSessionName)) + .build(); ApiClient apiClient = ClientBuilder.standard() .setAuthentication(new EKSAuthentication(credProvider, region, clusterName)) diff --git a/pom.xml b/pom.xml index 50922fe768..52bd79fcc6 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ https://issues.apache.org/jira/browse/MNG-5632. Therefore, we specify optional dependencies here to manage them in a single location. --> true - true + true true true @@ -150,9 +150,9 @@ ${bouncycastle.version} - com.amazonaws - aws-java-sdk-sts - 1.12.787 + software.amazon.awssdk + sts + 2.31.70 com.google.protobuf diff --git a/util/pom.xml b/util/pom.xml index 233f41980f..029e81811e 100644 --- a/util/pom.xml +++ b/util/pom.xml @@ -60,9 +60,9 @@ bcpkix-jdk18on - com.amazonaws - aws-java-sdk-sts - ${com.amazonaws.aws-java-sdk-sts.optional} + software.amazon.awssdk + sts + ${software.amazon.awssdk.sts.optional} ch.qos.logback diff --git a/util/src/main/java/io/kubernetes/client/util/credentials/EKSAuthentication.java b/util/src/main/java/io/kubernetes/client/util/credentials/EKSAuthentication.java index 3c7cbddc05..afa180b918 100644 --- a/util/src/main/java/io/kubernetes/client/util/credentials/EKSAuthentication.java +++ b/util/src/main/java/io/kubernetes/client/util/credentials/EKSAuthentication.java @@ -12,23 +12,23 @@ */ package io.kubernetes.client.util.credentials; -import com.amazonaws.DefaultRequest; -import com.amazonaws.auth.AWS4Signer; -import com.amazonaws.auth.AWSSessionCredentialsProvider; -import com.amazonaws.http.HttpMethodName; -import com.amazonaws.services.securitytoken.model.GetCallerIdentityRequest; -import com.amazonaws.util.RuntimeHttpUtils; import io.kubernetes.client.openapi.ApiClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.http.SdkHttpMethod; +import software.amazon.awssdk.http.SdkHttpRequest; +import software.amazon.awssdk.http.auth.aws.signer.AwsV4FamilyHttpSigner; +import software.amazon.awssdk.http.auth.aws.signer.AwsV4HttpSigner; +import software.amazon.awssdk.http.auth.spi.signer.SignedRequest; +import software.amazon.awssdk.utils.http.SdkHttpUtils; import java.net.URI; import java.nio.charset.StandardCharsets; -import java.time.Clock; +import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.Base64; -import java.util.Date; /** * EKS cluster authentication which generates a bearer token from AWS AK/SK. It doesn't require an "aws" @@ -45,11 +45,11 @@ public class EKSAuthentication implements Authentication { * @param region the region where EKS cluster at * @param clusterName the EKS cluster name */ - public EKSAuthentication(AWSSessionCredentialsProvider provider, String region, String clusterName) { + public EKSAuthentication(AwsCredentialsProvider provider, String region, String clusterName) { this(provider, region, clusterName, MAX_EXPIRY_SECONDS); } - public EKSAuthentication(AWSSessionCredentialsProvider provider, String region, String clusterName, int expirySeconds) { + public EKSAuthentication(AwsCredentialsProvider provider, String region, String clusterName, int expirySeconds) { this.provider = provider; this.region = region; this.clusterName = clusterName; @@ -61,7 +61,7 @@ public EKSAuthentication(AWSSessionCredentialsProvider provider, String region, } private static final int MAX_EXPIRY_SECONDS = 60 * 15; - private final AWSSessionCredentialsProvider provider; + private final AwsCredentialsProvider provider; private final String region; private final String clusterName; private final URI stsEndpoint; @@ -70,30 +70,41 @@ public EKSAuthentication(AWSSessionCredentialsProvider provider, String region, @Override public void provide(ApiClient client) { - DefaultRequest defaultRequest = - new DefaultRequest<>(new GetCallerIdentityRequest(), "sts"); - defaultRequest.setResourcePath("/"); - defaultRequest.setEndpoint(stsEndpoint); - defaultRequest.setHttpMethod(HttpMethodName.GET); - defaultRequest.addParameter("Action", "GetCallerIdentity"); - defaultRequest.addParameter("Version", "2011-06-15"); - defaultRequest.addHeader("x-k8s-aws-id", clusterName); - AWS4Signer signer = new AWS4Signer(); - Date expirationTime = new Date(Clock.systemDefaultZone().millis() + 60 * 1000); - signer.setServiceName("sts"); - signer.presignRequest( - defaultRequest, - this.provider.getCredentials(), - expirationTime); - String encodedUrl = - Base64.getUrlEncoder() - .withoutPadding() - .encodeToString( RuntimeHttpUtils.convertRequestToUrl( - defaultRequest, true, false).toString() - .getBytes(StandardCharsets.UTF_8)); + SdkHttpRequest httpRequest = generateStsRequest(); + String presignedUrl = requestToPresignedUrl(httpRequest); + String encodedUrl = presignedUrlToEncodedUrl(presignedUrl); String token = "k8s-aws-v1." + encodedUrl; client.setApiKeyPrefix("Bearer"); client.setApiKey(token); log.info("Generated BEARER token for ApiClient, expiring at {}", Instant.now().plus(expirySeconds, ChronoUnit.SECONDS)); } + + private static String presignedUrlToEncodedUrl(String presignedUrl) { + return Base64.getUrlEncoder() + .withoutPadding() + .encodeToString(SdkHttpUtils.urlEncodeIgnoreSlashes(presignedUrl).getBytes(StandardCharsets.UTF_8)); + } + + private SdkHttpRequest generateStsRequest() { + return SdkHttpRequest.builder() + .uri(stsEndpoint) + .putRawQueryParameter("Version", "2011-06-15") + .putRawQueryParameter("Action", "GetCallerIdentity") + .method(SdkHttpMethod.GET) + .putHeader("x-k8s-aws-id", clusterName) + .build(); + } + + private String requestToPresignedUrl(SdkHttpRequest httpRequest) { + AwsV4HttpSigner signer = AwsV4HttpSigner.create(); + SignedRequest signedRequest = + signer.sign(r -> r.identity(this.provider.resolveCredentials()) + .request(httpRequest) + .putProperty(AwsV4HttpSigner.SERVICE_SIGNING_NAME, "sts") + .putProperty(AwsV4HttpSigner.REGION_NAME, region) + .putProperty(AwsV4HttpSigner.AUTH_LOCATION, AwsV4HttpSigner.AuthLocation.QUERY_STRING) + .putProperty(AwsV4HttpSigner.EXPIRATION_DURATION, Duration.of(60, ChronoUnit.SECONDS))); + SdkHttpRequest request = signedRequest.request(); + return request.getUri().toString(); + } } diff --git a/util/src/test/java/io/kubernetes/client/util/credentials/EKSAuthenticationTest.java b/util/src/test/java/io/kubernetes/client/util/credentials/EKSAuthenticationTest.java index b5f994c7f6..0284ca73de 100644 --- a/util/src/test/java/io/kubernetes/client/util/credentials/EKSAuthenticationTest.java +++ b/util/src/test/java/io/kubernetes/client/util/credentials/EKSAuthenticationTest.java @@ -12,13 +12,13 @@ */ package io.kubernetes.client.util.credentials; -import com.amazonaws.auth.AWSSessionCredentialsProvider; -import com.amazonaws.auth.BasicSessionCredentials; import io.kubernetes.client.openapi.ApiClient; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.verify; @@ -28,7 +28,7 @@ class EKSAuthenticationTest { @Mock - private AWSSessionCredentialsProvider provider; + private AwsCredentialsProvider provider; @Mock private ApiClient apiClient; @@ -39,7 +39,7 @@ class EKSAuthenticationTest { @Test void provideApiClient() { - when(provider.getCredentials()).thenReturn(new BasicSessionCredentials("ak", "sk", "session")); + when(provider.resolveCredentials()).thenReturn(AwsSessionCredentials.create("ak", "sk", "session")); EKSAuthentication authentication = new EKSAuthentication(provider, region, clusterName); authentication.provide(apiClient); verify(apiClient).setApiKey(anyString());