diff --git a/pom.xml b/pom.xml index 9b774067..621565b2 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,7 @@ 1.67 v1-rev20201112-1.31.0 + 1.2.2 0.22.2 @@ -120,6 +121,27 @@ true + + com.google.cloud + google-cloud-iamcredentials + ${google-cloud-iamcredentials.version} + true + + + com.fasterxml.jackson.core + jackson-core + + + org.apache.httpcomponents + httpclient + + + commons-logging + commons-logging + + + + com.google.auth google-auth-library-oauth2-http diff --git a/spring-cloud-vault-config/pom.xml b/spring-cloud-vault-config/pom.xml index 06e9709e..53f5e876 100644 --- a/spring-cloud-vault-config/pom.xml +++ b/spring-cloud-vault-config/pom.xml @@ -130,6 +130,32 @@ true + + com.google.cloud + google-cloud-iamcredentials + true + + + + com.google.cloud + google-cloud-iamcredentials + true + + + com.fasterxml.jackson.core + jackson-core + + + org.apache.httpcomponents + httpclient + + + commons-logging + commons-logging + + + + com.google.auth google-auth-library-oauth2-http diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/ClientAuthenticationFactory.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/ClientAuthenticationFactory.java index f6ad6123..521710fd 100644 --- a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/ClientAuthenticationFactory.java +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/ClientAuthenticationFactory.java @@ -16,22 +16,16 @@ package org.springframework.cloud.vault.config; -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.util.Base64; import java.util.concurrent.atomic.AtomicReference; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; -import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; import org.springframework.beans.BeanUtils; import org.springframework.cloud.vault.config.VaultProperties.AppRoleProperties; import org.springframework.cloud.vault.config.VaultProperties.AwsIamProperties; import org.springframework.cloud.vault.config.VaultProperties.AzureMsiProperties; -import org.springframework.cloud.vault.config.VaultProperties.GcpCredentials; -import org.springframework.cloud.vault.config.VaultProperties.GcpIamProperties; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; @@ -58,10 +52,6 @@ import org.springframework.vault.authentication.CubbyholeAuthenticationOptions; import org.springframework.vault.authentication.GcpComputeAuthentication; import org.springframework.vault.authentication.GcpComputeAuthenticationOptions; import org.springframework.vault.authentication.GcpComputeAuthenticationOptions.GcpComputeAuthenticationOptionsBuilder; -import org.springframework.vault.authentication.GcpCredentialSupplier; -import org.springframework.vault.authentication.GcpIamAuthentication; -import org.springframework.vault.authentication.GcpIamAuthenticationOptions; -import org.springframework.vault.authentication.GcpIamAuthenticationOptions.GcpIamAuthenticationOptionsBuilder; import org.springframework.vault.authentication.IpAddressUserId; import org.springframework.vault.authentication.KubernetesAuthentication; import org.springframework.vault.authentication.KubernetesAuthenticationOptions; @@ -85,6 +75,13 @@ import org.springframework.web.client.RestOperations; */ class ClientAuthenticationFactory { + private static final boolean GOOGLE_CREDENTIAL_AVAILABLE = ClassUtils.isPresent( + "com.google.api.client.googleapis.auth.oauth2.GoogleCredential", + ClientAuthenticationFactory.class.getClassLoader()); + + private static final boolean GOOGLE_CREDENTIALS_AVAILABLE = ClassUtils + .isPresent("com.google.auth.oauth2.GoogleCredentials", ClientAuthenticationFactory.class.getClassLoader()); + private final VaultProperties vaultProperties; private final RestOperations restOperations; @@ -342,42 +339,16 @@ class ClientAuthenticationFactory { private ClientAuthentication gcpIamAuthentication(VaultProperties vaultProperties) { - VaultProperties.GcpIamProperties gcp = vaultProperties.getGcpIam(); - - Assert.hasText(gcp.getRole(), "Role (spring.cloud.vault.gcp-iam.role) must not be empty"); - - GcpIamAuthenticationOptionsBuilder builder = GcpIamAuthenticationOptions.builder().path(gcp.getGcpPath()) - .role(gcp.getRole()).jwtValidity(gcp.getJwtValidity()); - - if (StringUtils.hasText(gcp.getProjectId())) { - builder.projectId(gcp.getProjectId()); + if (GOOGLE_CREDENTIAL_AVAILABLE) { + return GcpIamAuthenticationFactory.create(vaultProperties, this.restOperations); } - if (StringUtils.hasText(gcp.getServiceAccountId())) { - builder.serviceAccountId(gcp.getServiceAccountId()); + if (GOOGLE_CREDENTIALS_AVAILABLE) { + return GcpIamCredentialsAuthenticationFactory.create(vaultProperties, this.restOperations); } - GcpCredentialSupplier supplier = () -> getGoogleCredential(gcp); - builder.credential(supplier.get()); - - GcpIamAuthenticationOptions options = builder.build(); - - return new GcpIamAuthentication(options, this.restOperations); - } - - private GoogleCredential getGoogleCredential(GcpIamProperties gcp) throws IOException { - - GcpCredentials credentialProperties = gcp.getCredentials(); - if (credentialProperties.getLocation() != null) { - return GoogleCredential.fromStream(credentialProperties.getLocation().getInputStream()); - } - - if (StringUtils.hasText(credentialProperties.getEncodedKey())) { - return GoogleCredential.fromStream( - new ByteArrayInputStream(Base64.getDecoder().decode(credentialProperties.getEncodedKey()))); - } - - return GoogleCredential.getApplicationDefault(); + throw new IllegalStateException( + "Cannot create authentication mechanism for GCP IAM. This method requires one of the following dependencies: google-auth-library-oauth2-http or google-api-client (deprecated)."); } private ClientAuthentication kubernetesAuthentication(VaultProperties vaultProperties) { diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/GcpIamAuthenticationFactory.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/GcpIamAuthenticationFactory.java new file mode 100644 index 00000000..609c8b43 --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/GcpIamAuthenticationFactory.java @@ -0,0 +1,86 @@ +/* + * Copyright 2020-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.vault.config; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Base64; + +import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; + +import org.springframework.cloud.vault.config.VaultProperties.GcpIamProperties; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.GcpCredentialSupplier; +import org.springframework.vault.authentication.GcpIamAuthentication; +import org.springframework.vault.authentication.GcpIamAuthenticationOptions; +import org.springframework.vault.authentication.GcpIamAuthenticationOptions.GcpIamAuthenticationOptionsBuilder; +import org.springframework.web.client.RestOperations; + +/** + * Utility to create {@link GcpIamAuthentication} for the IAM authentication method. + * + * @author Mark Paluch + * @since 3.0.2 + */ +final class GcpIamAuthenticationFactory { + + private GcpIamAuthenticationFactory() { + } + + static ClientAuthentication create(VaultProperties vaultProperties, RestOperations restOperations) { + + VaultProperties.GcpIamProperties gcp = vaultProperties.getGcpIam(); + + Assert.hasText(gcp.getRole(), "Role (spring.cloud.vault.gcp-iam.role) must not be empty"); + + GcpIamAuthenticationOptionsBuilder builder = GcpIamAuthenticationOptions.builder().path(gcp.getGcpPath()) + .role(gcp.getRole()).jwtValidity(gcp.getJwtValidity()); + + if (StringUtils.hasText(gcp.getProjectId())) { + builder.projectId(gcp.getProjectId()); + } + + if (StringUtils.hasText(gcp.getServiceAccountId())) { + builder.serviceAccountId(gcp.getServiceAccountId()); + } + + GcpCredentialSupplier supplier = () -> getGoogleCredential(gcp); + builder.credential(supplier.get()); + + GcpIamAuthenticationOptions options = builder.build(); + + return new GcpIamAuthentication(options, restOperations); + } + + private static GoogleCredential getGoogleCredential(GcpIamProperties gcp) throws IOException { + + VaultProperties.GcpCredentials credentialProperties = gcp.getCredentials(); + if (credentialProperties.getLocation() != null) { + return GoogleCredential.fromStream(credentialProperties.getLocation().getInputStream()); + } + + if (StringUtils.hasText(credentialProperties.getEncodedKey())) { + return GoogleCredential.fromStream( + new ByteArrayInputStream(Base64.getDecoder().decode(credentialProperties.getEncodedKey()))); + } + + return GoogleCredential.getApplicationDefault(); + } + +} diff --git a/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/GcpIamCredentialsAuthenticationFactory.java b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/GcpIamCredentialsAuthenticationFactory.java new file mode 100644 index 00000000..98b4cd96 --- /dev/null +++ b/spring-cloud-vault-config/src/main/java/org/springframework/cloud/vault/config/GcpIamCredentialsAuthenticationFactory.java @@ -0,0 +1,83 @@ +/* + * Copyright 2020-2021 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.cloud.vault.config; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.util.Base64; + +import com.google.auth.oauth2.GoogleCredentials; + +import org.springframework.cloud.vault.config.VaultProperties.GcpIamProperties; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.GcpIamCredentialsAuthentication; +import org.springframework.vault.authentication.GcpIamCredentialsAuthenticationOptions; +import org.springframework.vault.authentication.GcpIamCredentialsAuthenticationOptions.GcpIamCredentialsAuthenticationOptionsBuilder; +import org.springframework.vault.authentication.GoogleCredentialsSupplier; +import org.springframework.web.client.RestOperations; + +/** + * Utility to create {@link GcpIamCredentialsAuthentication} for the IAM Credentials + * authentication method. + * + * @author Mark Paluch + * @since 3.0.2 + */ +final class GcpIamCredentialsAuthenticationFactory { + + private GcpIamCredentialsAuthenticationFactory() { + } + + static ClientAuthentication create(VaultProperties vaultProperties, RestOperations restOperations) { + + GcpIamProperties gcp = vaultProperties.getGcpIam(); + + Assert.hasText(gcp.getRole(), "Role (spring.cloud.vault.gcp-iam.role) must not be empty"); + + GcpIamCredentialsAuthenticationOptionsBuilder builder = GcpIamCredentialsAuthenticationOptions.builder() + .path(gcp.getGcpPath()).role(gcp.getRole()).jwtValidity(gcp.getJwtValidity()); + + if (StringUtils.hasText(gcp.getServiceAccountId())) { + builder.serviceAccountId(gcp.getServiceAccountId()); + } + + GoogleCredentialsSupplier supplier = () -> getGoogleCredential(gcp); + builder.credentials(supplier.get()); + + GcpIamCredentialsAuthenticationOptions options = builder.build(); + + return new GcpIamCredentialsAuthentication(options, restOperations); + } + + private static GoogleCredentials getGoogleCredential(GcpIamProperties gcp) throws IOException { + + VaultProperties.GcpCredentials credentialProperties = gcp.getCredentials(); + if (credentialProperties.getLocation() != null) { + return GoogleCredentials.fromStream(credentialProperties.getLocation().getInputStream()); + } + + if (StringUtils.hasText(credentialProperties.getEncodedKey())) { + return GoogleCredentials.fromStream( + new ByteArrayInputStream(Base64.getDecoder().decode(credentialProperties.getEncodedKey()))); + } + + return GoogleCredentials.getApplicationDefault(); + } + +} diff --git a/spring-cloud-vault-dependencies/pom.xml b/spring-cloud-vault-dependencies/pom.xml index 61159627..77515ecd 100644 --- a/spring-cloud-vault-dependencies/pom.xml +++ b/spring-cloud-vault-dependencies/pom.xml @@ -20,7 +20,7 @@ Spring Cloud Vault Dependencies - 2.3.0 + 2.3.2