From 08577ad56a8a07c30406c76884f8fe57971dc7ed Mon Sep 17 00:00:00 2001 From: Brant Date: Mon, 27 Sep 2021 09:05:59 -0400 Subject: [PATCH] Allow fallback to ~/.vault-token file using Token authentication. This assists in usability of spring cloud vault locally after authenticating to vault via the vault CLI. Closes gh-609 Original pull request: gh-614 --- docs/src/main/asciidoc/authentication.adoc | 9 +++-- .../config/ClientAuthenticationFactory.java | 33 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/docs/src/main/asciidoc/authentication.adoc b/docs/src/main/asciidoc/authentication.adoc index f27d173b..46947ee7 100644 --- a/docs/src/main/asciidoc/authentication.adoc +++ b/docs/src/main/asciidoc/authentication.adoc @@ -11,6 +11,7 @@ Spring Cloud Vault supports token and AppId authentication. Tokens are the core method for authentication within Vault. Token authentication requires a static token to be provided using the https://github.com/spring-cloud/spring-cloud-commons/blob/master/docs/src/main/asciidoc/spring-cloud-commons.adoc#the-bootstrap-application-context[Bootstrap Application Context]. +As a fallback the token may also be retrieved from ~/.vault-token which is the default location used by the Vault CLI to cache a token. NOTE: Token authentication is the default authentication method. If a token is disclosed an unintended party gains access to Vault and can access secrets for the intended client. @@ -26,9 +27,13 @@ spring.cloud.vault: ==== * `authentication` setting this value to `TOKEN` selects the Token authentication method -* `token` sets the static token to use +* `token` sets the static token to use. If missing or empty, then an attempt will be made to retrieve a token from ~/.vault-token. -See also: https://www.vaultproject.io/docs/concepts/tokens.html[Vault Documentation: Tokens] +See also: + +* https://www.vaultproject.io/docs/concepts/tokens.html[Vault Documentation: Tokens] +* https://www.vaultproject.io/docs/commands/login[Vault Documentation: CLI login] +* https://www.vaultproject.io/docs/commands/token-helper[Vault Documentation: CLI default to ~/.vault-token] [[vault.config.authentication.vault-agent]] === Vault Agent authentication 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 a6a3317a..2b95a6e1 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,6 +16,11 @@ package org.springframework.cloud.vault.config; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.concurrent.atomic.AtomicReference; import com.amazonaws.auth.AWSCredentials; @@ -28,6 +33,7 @@ import org.springframework.cloud.vault.config.VaultProperties.AwsIamProperties; import org.springframework.cloud.vault.config.VaultProperties.AzureMsiProperties; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.StreamUtils; import org.springframework.util.StringUtils; import org.springframework.vault.authentication.AppIdAuthentication; import org.springframework.vault.authentication.AppIdAuthenticationOptions; @@ -66,6 +72,8 @@ import org.springframework.vault.authentication.TokenAuthentication; import org.springframework.vault.support.VaultToken; import org.springframework.web.client.RestOperations; +import static java.nio.charset.StandardCharsets.UTF_8; + /** * Factory for {@link ClientAuthentication}. * @@ -138,8 +146,7 @@ class ClientAuthenticationFactory { return pcfAuthentication(this.vaultProperties); case TOKEN: - Assert.hasText(this.vaultProperties.getToken(), "Token (spring.cloud.vault.token) must not be empty"); - return new TokenAuthentication(this.vaultProperties.getToken()); + return tokenAuthentication(this.vaultProperties); } throw new UnsupportedOperationException( @@ -398,6 +405,28 @@ class ClientAuthenticationFactory { return new ClientCertificateAuthentication(options, this.restOperations); } + private ClientAuthentication tokenAuthentication(VaultProperties vaultProperties) { + if (StringUtils.hasText(vaultProperties.getToken())) { + return new TokenAuthentication(vaultProperties.getToken()); + } + else { + Path vaultTokenPath = Paths.get(System.getProperty("user.home"), ".vault-token"); + if (Files.exists(vaultTokenPath)) { + try (InputStream inputStream = Files.newInputStream(vaultTokenPath)) { + String token = StreamUtils.copyToString(inputStream, UTF_8); + return new TokenAuthentication(token); + } + catch (IOException ex) { + throw new IllegalStateException("Could not retrieve vault token from ~/.vault-token", ex); + } + } + else { + throw new IllegalStateException( + "Cannot create authentication mechanism for TOKEN. This method requires either a Token (spring.cloud.vault.token) or File ~/.vault-token."); + } + } + } + private static class AwsCredentialProvider { private static AWSCredentialsProvider getAwsCredentialsProvider() {