From 67f7119d228fde33d33d4b833bd909be995481d9 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Thu, 27 Oct 2016 15:53:59 +0200 Subject: [PATCH] Document how to externalize login credentials. Fixes gh-26. --- .../vault/demo/SecurePropertyUsage.java | 109 ++++++++++++++++++ .../vault/demo/other.properties | 1 + .../vault/demo/secure-introduction.properties | 1 + .../asciidoc/reference/authentication.adoc | 43 +++++++ .../asciidoc/reference/getting-started.adoc | 5 + 5 files changed, 159 insertions(+) create mode 100644 spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java create mode 100644 spring-vault-core/src/test/resources/org/springframework/vault/demo/other.properties create mode 100644 spring-vault-core/src/test/resources/org/springframework/vault/demo/secure-introduction.properties diff --git a/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java b/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java new file mode 100644 index 00000000..ad3443d0 --- /dev/null +++ b/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java @@ -0,0 +1,109 @@ +/* + * Copyright 2016 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 + * + * http://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.vault.demo; + +import java.util.HashMap; +import java.util.Map; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.context.annotation.PropertySources; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; +import org.springframework.vault.annotation.VaultPropertySource; +import org.springframework.vault.authentication.ClientAuthentication; +import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.core.VaultIntegrationTestConfiguration; +import org.springframework.vault.core.VaultOperations; +import org.springframework.vault.util.PrepareVault; +import org.springframework.vault.util.VaultRule; + +/** + * This application uses {@link PropertySources} to define static config files and + * {@link VaultPropertySource} to retrieve properties from Vault. + *

+ * {@code secure-introduction.properties} externalizes Vault login credentials to keep + * authentication details outside the code. + *

+ * {@code other.properties} references a Vault property to illustrate possible integration + * with Spring Vault's property source support. + * + * @author Mark Paluch + */ +public class SecurePropertyUsage { + + public static void main(String[] args) { + + VaultRule vaultRule = new VaultRule(); + vaultRule.before(); + + PrepareVault prepareVault = vaultRule.prepare(); + VaultOperations vaultOperations = prepareVault.getVaultOperations(); + + Map data = new HashMap(); + data.put("encrypted", "Much secret. Very confidential. Wow."); + + vaultOperations.write("secret/secure-introduction", data); + + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + Config.class); + + System.out.println(context.getEnvironment().getProperty( + "my-property-that-references-vault")); + System.out.println(context.getEnvironment().getProperty("encrypted")); + + System.out.println(context.getBean(Client.class).myValue); + + context.stop(); + } + + @PropertySources({ + @PropertySource("classpath:/org/springframework/vault/demo/secure-introduction.properties"), + @PropertySource("classpath:/org/springframework/vault/demo/other.properties") }) + @VaultPropertySource({ "secret/secure-introduction" }) + @Configuration + @ComponentScan + static class Config extends VaultIntegrationTestConfiguration implements + ApplicationContextAware { + + private Environment environment; + + @Override + public ClientAuthentication clientAuthentication() { + return new TokenAuthentication(environment.getProperty("vault.token")); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + environment = applicationContext.getEnvironment(); + } + } + + @Component + static class Client { + + @Value("${encrypted}") + String myValue; + + } +} diff --git a/spring-vault-core/src/test/resources/org/springframework/vault/demo/other.properties b/spring-vault-core/src/test/resources/org/springframework/vault/demo/other.properties new file mode 100644 index 00000000..747c2416 --- /dev/null +++ b/spring-vault-core/src/test/resources/org/springframework/vault/demo/other.properties @@ -0,0 +1 @@ +my-property-that-references-vault=Value: ${encrypted} diff --git a/spring-vault-core/src/test/resources/org/springframework/vault/demo/secure-introduction.properties b/spring-vault-core/src/test/resources/org/springframework/vault/demo/secure-introduction.properties new file mode 100644 index 00000000..cf466ce3 --- /dev/null +++ b/spring-vault-core/src/test/resources/org/springframework/vault/demo/secure-introduction.properties @@ -0,0 +1 @@ +vault.token=00000000-0000-0000-0000-000000000000 diff --git a/src/main/asciidoc/reference/authentication.adoc b/src/main/asciidoc/reference/authentication.adoc index c2be34a6..f4cc587e 100644 --- a/src/main/asciidoc/reference/authentication.adoc +++ b/src/main/asciidoc/reference/authentication.adoc @@ -5,6 +5,49 @@ Different organizations have different requirements for security and authentication. Vault reflects that need by shipping multiple authentication methods. Spring Vault supports multiple authentications mechanisms. +== Externalizing login credentials + +Obtaining first-time access to a secured system is known as secure introduction. +Any client requires ephemeral or permanent credentials to access Vault. Externalizing credentials +is a good pattern to keep code maintainability high but comes at a risk of increased disclosure. + +Disclosure of login credentials to any party allows login to Vault and access secrets that +are permitted by the underlying role. Picking the appropriate client authentication and +injecting credentials into the application is subject to risk evaluation. + +Spring's http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-property-source-abstraction[PropertySource abstraction] is a natural fit +to keep configuration outside the application code. You can use system properties, environment +variables or property files to store login credentials. Each approach comes with its own properties. +Keep in mind that the command line and environment properties can be introspected with appropriate +OS access levels. + +.Externalizing `vault.token` to a properties file +==== +---- +@PropertySource("configuration.properties"), +@Configuration +static class Config extends VaultIntegrationTestConfiguration implements + ApplicationContextAware { + + private Environment environment; + + @Override + public ClientAuthentication clientAuthentication() { + return new TokenAuthentication(environment.getProperty("vault.token")); + } + + @Override + public void setApplicationContext(ApplicationContext applicationContext) + throws BeansException { + environment = applicationContext.getEnvironment(); + } +} +---- +==== + +See https://github.com/spring-projects/spring-vault/blob/master/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java[`SecurePropertyUsage.java`] +for a sample on referencing properties in components and other property sources. + == Token authentication Tokens are the core method for authentication within Vault. diff --git a/src/main/asciidoc/reference/getting-started.adoc b/src/main/asciidoc/reference/getting-started.adoc index 2d3360ac..6ba397dc 100644 --- a/src/main/asciidoc/reference/getting-started.adoc +++ b/src/main/asciidoc/reference/getting-started.adoc @@ -299,6 +299,11 @@ Vault can be used in many different ways. One specific use-case is using Vault to store encrypted properties. Spring Vault supports Vault as property source to obtain configuration properties using Spring's http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-property-source-abstraction[PropertySource abstraction]. +NOTE: You can reference properties stored inside Vault in other property sources or use value injection with `@Value(…)`. Special attention is required when bootstrapping beans that require data stored inside of Vault. A `VaultPropertySource` must be initialized at that time to retrieve properties from Vault. + +NOTE: Spring Boot/Spring Cloud users can benefit from https://github.com/spring-cloud-incubator/spring-cloud-vault-config[Spring Cloud Vault]'s +configuration integration that initializes various property sources during application startup. + === Registering `VaultPropertySource` Spring Vault provides a `VaultPropertySource` to be used with Vault to obtain