Add support for GCP IAM Credentials authentication.
Closes gh-576
This commit is contained in:
22
pom.xml
22
pom.xml
@@ -49,6 +49,7 @@
|
||||
<bcpkix-jdk15on.version>1.67</bcpkix-jdk15on.version>
|
||||
|
||||
<google-api-services-iam.version>v1-rev20201112-1.31.0</google-api-services-iam.version>
|
||||
<google-cloud-iamcredentials.version>1.2.2</google-cloud-iamcredentials.version>
|
||||
<google-auth-library-oauth2-http.version>0.22.2</google-auth-library-oauth2-http.version>
|
||||
</properties>
|
||||
|
||||
@@ -120,6 +121,27 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.cloud</groupId>
|
||||
<artifactId>google-cloud-iamcredentials</artifactId>
|
||||
<version>${google-cloud-iamcredentials.version}</version>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.auth</groupId>
|
||||
<artifactId>google-auth-library-oauth2-http</artifactId>
|
||||
|
||||
@@ -130,6 +130,32 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.cloud</groupId>
|
||||
<artifactId>google-cloud-iamcredentials</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.cloud</groupId>
|
||||
<artifactId>google-cloud-iamcredentials</artifactId>
|
||||
<optional>true</optional>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.auth</groupId>
|
||||
<artifactId>google-auth-library-oauth2-http</artifactId>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@
|
||||
<description>Spring Cloud Vault Dependencies</description>
|
||||
|
||||
<properties>
|
||||
<spring-vault.version>2.3.0</spring-vault.version>
|
||||
<spring-vault.version>2.3.2</spring-vault.version>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
||||
Reference in New Issue
Block a user