From 798d6ed99ecc46d8edc80b4afadd3a625174f764 Mon Sep 17 00:00:00 2001 From: Mark Paluch Date: Mon, 19 Sep 2016 21:37:43 +0200 Subject: [PATCH] Enhance documentation about client support. Fixes gh-4. --- src/main/asciidoc/index.adoc | 8 +- src/main/asciidoc/new-features.adoc | 5 +- src/main/asciidoc/preface.adoc | 3 +- .../asciidoc/reference/authentication.adoc | 338 +++++++++ .../asciidoc/reference/client-support.adoc | 55 ++ src/main/asciidoc/reference/dependencies.adoc | 49 ++ .../asciidoc/reference/getting-started.adoc | 302 ++++++++ src/main/asciidoc/reference/vault.adoc | 646 +----------------- 8 files changed, 754 insertions(+), 652 deletions(-) create mode 100644 src/main/asciidoc/reference/authentication.adoc create mode 100644 src/main/asciidoc/reference/client-support.adoc create mode 100644 src/main/asciidoc/reference/dependencies.adoc create mode 100644 src/main/asciidoc/reference/getting-started.adoc diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc index 31bfdd2a..d6e264ab 100644 --- a/src/main/asciidoc/index.adoc +++ b/src/main/asciidoc/index.adoc @@ -2,7 +2,7 @@ Mark Paluch; :revnumber: {version} :revdate: {localdate} -:toc: +:toc: macro :toc-placement!: (C) 2016 The original authors. @@ -11,16 +11,12 @@ NOTE: _Copies of this document may be made for your own use and for distribution toc::[] -:leveloffset: +1 include::preface.adoc[] include::new-features.adoc[] -:leveloffset: -1 -[[reference]] -= Reference Documentation +ifndef::ebook-format[= Reference documentation [[reference-documentation]]] :leveloffset: +1 include::reference/introduction.adoc[] include::reference/vault.adoc[] :leveloffset: -1 - diff --git a/src/main/asciidoc/new-features.adoc b/src/main/asciidoc/new-features.adoc index 2735f914..f50fce1b 100644 --- a/src/main/asciidoc/new-features.adoc +++ b/src/main/asciidoc/new-features.adoc @@ -1,8 +1,7 @@ [[new-features]] -= New & Noteworthy +== New & Noteworthy [[new-features.1-0-0]] -== What's new in Spring Vault 1.0 +=== What's new in Spring Vault 1.0 * Initial Vault support. - diff --git a/src/main/asciidoc/preface.adoc b/src/main/asciidoc/preface.adoc index fb05314d..2a2179de 100644 --- a/src/main/asciidoc/preface.adoc +++ b/src/main/asciidoc/preface.adoc @@ -9,7 +9,8 @@ This section provides some basic introduction to Spring and Vault. The rest of t [[get-started:first-steps:spring]] == Knowing Spring -Spring Vault uses Spring framework's http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/spring-core.html[core] functionality, such as the http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/beans.html[IoC] container, http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/validation.html#core-convert[type conversion system], http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/expressions.html[expression language], http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/jmx.html[JMX integration], and portable http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/dao.html#dao-exceptions[DAO exception hierarchy]. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar for whatever IoC container you choose to use. + +Spring Vault uses Spring framework's http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/spring-core.html[core] functionality, such as the http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/beans.html[IoC] container. While it is not important to know the Spring APIs, understanding the concepts behind them is. At a minimum, the idea behind IoC should be familiar for whatever IoC container you choose to use. The core functionality of the Vault support can be used directly, with no need to invoke the IoC services of the Spring Container. This is much like `RestTemplate` which can be used 'standalone' without any other services of the Spring container. To leverage all the features of Spring Vault document, such as the session support, you will need to configure some parts of the library using Spring. diff --git a/src/main/asciidoc/reference/authentication.adoc b/src/main/asciidoc/reference/authentication.adoc new file mode 100644 index 00000000..9143fc7e --- /dev/null +++ b/src/main/asciidoc/reference/authentication.adoc @@ -0,0 +1,338 @@ +[[vault.core.authentication]] += Authentication Methods + +Different organizations have different requirements for security +and authentication. Vault reflects that need by shipping multiple authentication +methods. Spring Vault supports multiple authentications mechanisms. + +== Token authentication + +Tokens are the core method for authentication within Vault. +Token authentication requires a static token to be provided. + +NOTE: Token authentication is the default authentication method. +If a token is disclosed an unintended party, it gains access to Vault and +can access secrets for the intended client. + +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + return new TokenAuthentication("…"); + } + + // … +} +---- +==== + +See also: https://www.vaultproject.io/docs/concepts/tokens.html[Vault Documentation: Tokens] + +== AppId authentication + +Vault supports https://www.vaultproject.io/docs/auth/app-id.html[AppId] +authentication that consists of two hard to guess tokens. The AppId +defaults to `spring.application.name` that is statically configured. +The second token is the UserId which is a part determined by the application, +usually related to the runtime environment. IP address, Mac address or a +Docker container name are good examples. Spring Vault supports +IP address, Mac address and static UserId's (e.g. supplied via System properties). +The IP and Mac address are represented as Hex-encoded SHA256 hash. + +IP address-based UserId's use the local host's IP address. + + +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder().appId("myapp") // + .userIdMechanism(new IpAddressUserId()) // + .build(); + + return new AppIdAuthentication(options, vaultClient()); + } + + // … +} +---- +==== + +The corresponding command to generate the IP address UserId from a command line is: + +---- +$ echo -n 192.168.99.1 | sha256sum +---- + +NOTE: Including the line break of `echo` leads to a different hash value +so make sure to include the `-n` flag. + +Mac address-based UserId's obtain their network device from the +localhost-bound device. The configuration also allows specifying +a `network-interface` hint to pick the right device. The value of +`network-interface` is optional and can be either an interface +name or interface index (0-based). + +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder().appId("myapp") // + .userIdMechanism(new MacAddressUserId()) // + .build(); + + return new AppIdAuthentication(options, vaultClient()); + } + + // … +} +---- +==== + +The corresponding command to generate the IP address UserId from a command line is: + +---- +$ echo -n 0AFEDE1234AC | sha256sum +---- + +NOTE: The Mac address is specified uppercase and without colons. +Including the line break of `echo` leads to a different hash value +so make sure to include the `-n` flag. + +=== Custom UserId + +A more advanced approach lets you implementing your own `AppIdUserIdMechanism`. +This class must be on your classpath and must implement +the `org.springframework.vault.authentication.AppIdUserIdMechanism` interface +and the `createUserId` method. Spring Vault will obtain the UserId +by calling `createUserId` each time it authenticates using AppId to +obtain a token. + +==== +[source,java] +.MyUserIdMechanism.java +---- +public class MyUserIdMechanism implements AppIdUserIdMechanism { + + @Override + public String createUserId() { + String userId = ... + return userId; + } +} +---- +==== + +See also: https://www.vaultproject.io/docs/auth/app-id.html[Vault Documentation: Using the App ID auth backend] + +== AWS-EC2 authentication + +The https://www.vaultproject.io/docs/auth/aws-ec2.html[aws-ec2] +auth backend provides a secure introduction mechanism +for AWS EC2 instances, allowing automated retrieval of a Vault +token. Unlike most Vault authentication backends, this backend +does not require first-deploying, or provisioning security-sensitive +credentials (tokens, username/password, client certificates, etc.). +Instead, it treats AWS as a Trusted Third Party and uses the +cryptographically signed dynamic metadata information that uniquely +represents each EC2 instance. + +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + return new AwsEc2Authentication(vaultClient()); + } + + // … +} +---- +==== + +AWS-EC2 authentication enables nonce by default to follow +the Trust On First Use (TOFU) principle. Any unintended party that +gains access to the PKCS#7 identity metadata can authenticate +against Vault. + +During the first login, Spring Vault generates a nonce +that is stored in the auth backend aside the instance Id. +Re-authentication requires the same nonce to be sent. Any other +party does not have the nonce and can raise an alert in Vault for +further investigation. + +The nonce is kept in memory and is lost during application restart. + +AWS-EC2 authentication roles are optional and default to the AMI. +You can configure the authentication role by setting +it in `AwsEc2AuthenticationOptions`. + +See also: https://www.vaultproject.io/docs/auth/aws-ec2.html[Vault Documentation: Using the aws-ec2 auth backend] + +== TLS certificate authentication + +The `cert` auth backend allows authentication using SSL/TLS client +certificates that are either signed by a CA or self-signed. + +To enable `cert` authentication you need to: + +1. Use SSL, see <> +2. Configure a Java `Keystore` that contains the client +certificate and the private key + +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + return new ClientCertificateAuthentication(options, vaultClient()); + } + + // … +} +---- +==== + +See also: https://www.vaultproject.io/docs/auth/cert.html[Vault Documentation: Using the cert auth backend] + +== Cubbyhole authentication + +Cubbyhole authentication uses Vault primitives to provide a secured authentication +workflow. Cubbyhole authentication uses tokens as primary login method. +An ephemeral token is used to obtain a second, login VaultToken from Vault's +Cubbyhole secret backend. The login token is usually longer-lived and used to +interact with Vault. The login token can be retrieved either from a wrapped +response or from the `data` section. + +*Creating a wrapped token* + +NOTE: Response Wrapping for token creation requires Vault 0.6.0 or higher. + +.Crating and storing tokens +==== +[source,shell] +---- +$ vault token-create -wrap-ttl="10m" +Key Value +--- ----- +wrapping_token: 397ccb93-ff6c-b17b-9389-380b01ca2645 +wrapping_token_ttl: 0h10m0s +wrapping_token_creation_time: 2016-09-18 20:29:48.652957077 +0200 CEST +wrapped_accessor: 46b6aebb-187f-932a-26d7-4f3d86a68319 +---- +==== + +.Wrapped token response usage +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + + CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions + .builder() + .initialToken(VaultToken.of("…")) + .wrapped() + .build(); + + return new CubbyholeAuthentication(options, vaultClient()); + } + + // … +} +---- +==== + +*Using stored tokens* + +.Crating and storing tokens +==== +[source,shell] +---- +$ vault token-create +Key Value +--- ----- +token f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819 +token_accessor 4eee9bd9-81bb-06d6-af01-723c54a72148 +token_duration 0s +token_renewable false +token_policies [root] + +$ token-create -use-limit=2 -orphan -no-default-policy -policy=none +Key Value +--- ----- +token 895cb88b-aef4-0e33-ba65-d50007290780 +token_accessor e84b661c-8aa8-2286-b788-f258f30c8325 +token_duration 0s +token_renewable false +token_policies [none] + +$ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780 +$ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819 +---- +==== + +.Stored token response usage +==== +[source,java] +---- +@Configuration +class AppConfig extends AbstractVaultConfiguration { + + // … + + @Override + public ClientAuthentication clientAuthentication() { + + CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions + .builder() + .initialToken(VaultToken.of("…")) + .path("cubbyhole/token") + .build(); + + return new CubbyholeAuthentication(options, vaultClient()); + } + + // … +} +---- +==== + +See also: + +* https://www.vaultproject.io/docs/concepts/tokens.html[Vault Documentation: Tokens] +* https://www.vaultproject.io/docs/secrets/cubbyhole/index.html[Vault Documentation:Cubbyhole Secret Backend] +* https://www.vaultproject.io/docs/concepts/response-wrapping.html[Vault Documentation: Response Wrapping] \ No newline at end of file diff --git a/src/main/asciidoc/reference/client-support.adoc b/src/main/asciidoc/reference/client-support.adoc new file mode 100644 index 00000000..1cfece30 --- /dev/null +++ b/src/main/asciidoc/reference/client-support.adoc @@ -0,0 +1,55 @@ +[[vault.core.client.support]] += Client support + +Spring Vault supports a various HTTP clients to access Vault's HTTP API. Spring Vault uses http://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference/html/remoting.html#rest-resttemplate[`RestTemplate`] as primary interface accessing Vault. Dedicated client support originates from <> that is scoped only to Spring Vault's client components. + +Spring Vault supports following HTTP clients: + +* Java's builtin `HttpURLConnection` (default client) +* Apache Http Components +* Netty +* OkHttp 2 + +Using a specific client requires the according dependency to be available on the classpath so Spring Vault can use the available client for communicating with Vault. + +== Java's builtin `HttpURLConnection` + +Java's builtin `HttpURLConnection` is available out-of-the-box without additional configuration. Using `HttpURLConnection` comes with a limitation regarding SSL configuration. Spring Vault won't apply <> as it would require a deep reconfiguration of the JVM. This configuration would affect all components relying on the default SSL context. Configuring SSL settings using `HttpURLConnection` requires you providing these settings as System Properties. See +https://docs.oracle.com/javase/8/docs/technotes/guides/security/jsse/JSSERefGuide.html#InstallationAndCustomization[Customizing JSSE] for further details. + +== External Clients +You can use external clients to access Vault's API. Simply add one of the following dependencies to your project. You can omit the version number if using <> + + +.Apache Http Components Dependency +==== +[source, xml] +---- + + org.apache.httpcomponents + httpclient + +---- +==== + +.Netty Dependency +==== +[source, xml] +---- + + io.netty + netty-all + +---- +==== + +.Square OkHttp 2 +==== +[source, xml] +---- + + com.squareup.okhttp + okhttp + +---- +==== diff --git a/src/main/asciidoc/reference/dependencies.adoc b/src/main/asciidoc/reference/dependencies.adoc new file mode 100644 index 00000000..9d90ac32 --- /dev/null +++ b/src/main/asciidoc/reference/dependencies.adoc @@ -0,0 +1,49 @@ +[[dependencies]] +== Dependencies + +The easiest way to find compatible versions of Spring Vault dependencies is by relying on the Spring Vault BOM we ship with the compatible versions defined. In a Maven project you would declare this dependency in the `` section of your `pom.xml`: + +.Using the Spring Vault BOM +==== +[source, xml] +---- + + + + org.springframework.vault + spring-vault-dependencies + ${version} + import + pom + + + +---- +==== + +[[dependencies.names]] +The current version is `{version}`. The version name follows the following pattern: `$\{version\}-$\{release\}` where release can be one of the following: + +* `BUILD-SNAPSHOT` - current snapshots +* `M1`, `M2` etc. - milestones +* `RC1`, `RC2` etc. - release candidates +* `RELEASE` - GA release +* `SR1`, `SR2` etc. - service releases + +.Declaring a dependency to Spring Vault +==== +[source, xml] +---- + + + org.springframework.vault + spring-vault-core + + +---- +==== + +[[dependencies.spring-framework]] +=== Spring Framework + +The current version of Spring Vault requires Spring Framework in version {springVersion} or better. The modules might also work with an older bugfix version of that minor version. However, using the most recent version within that generation is highly recommended. \ No newline at end of file diff --git a/src/main/asciidoc/reference/getting-started.adoc b/src/main/asciidoc/reference/getting-started.adoc new file mode 100644 index 00000000..8b50f4fb --- /dev/null +++ b/src/main/asciidoc/reference/getting-started.adoc @@ -0,0 +1,302 @@ +[[vault.core.getting-started]] +=== Getting Started + +Spring Vault support requires Vault 0.5 or higher and Java SE 6 or higher. +An easy way to bootstrap setting up a working environment is to create a Spring based project in http://spring.io/tools/sts[STS]. + +First you need to set up a running Vault server. Refer to the https://www.vaultproject.io/intro/[Vault] for an explanation on how to startup a Vault instance. + +To create a Spring project in STS go to File -> New -> Spring Template Project -> Simple Spring Utility Project -> press Yes when prompted. Then enter a project and a package name such as org.spring.vault.example. + +Then add the following to `pom.xml` dependencies section. + +.Using the Spring Vault BOM +==== +[source,xml] +---- + + + + + + org.springframework.vault + spring-vault-core + {version} + + + +---- +==== + +You will also need to add the location of the Spring Milestone repository for maven to your `pom.xml` which is at the same level of your `` element. + +==== +[source,xml] +---- + + + spring-milestone + Spring Maven MILESTONE Repository + http://repo.spring.io/libs-milestone + + +---- +==== + +The repository is also http://repo.spring.io/milestone/org/springframework/vault/[browseable here]. + +You may also want to set the logging level to `DEBUG` to see some additional information, edit the log4j.properties file to have + +[source] +---- +log4j.category.org.springframework.vault=DEBUG +log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n +---- +Create a simple `Secrets` class to persist: + +.Mapped data object +==== +[source,java] +---- +package org.spring.vault.example; + +public class Secrets { + + String username; + String password; + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } +} +---- +==== + +And a main application to run + +.Example application using Spring Vault +==== +[source,java] +---- +package org.springframework.vault.example; + +import org.springframework.vault.authentication.TokenAuthentication; +import org.springframework.vault.client.VaultClient; +import org.springframework.vault.core.VaultTemplate; +import org.springframework.vault.support.VaultResponseSupport; + +public class VaultApp { + + public static void main(String[] args) { + + VaultTemplate vaultTemplate = new VaultTemplate(new VaultClient(), + new TokenAuthentication("00000000-0000-0000-0000-000000000000")); + + Secrets secrets = new Secrets(); + secrets.username = "hello"; + secrets.password = "world"; + + vaultTemplate.write("secret/myapp", secrets); + + VaultResponseSupport response = vaultTemplate.read("secret/myapp", Secrets.class); + System.out.println(response.getData().getUsername()); + + vaultTemplate.delete("secret/myapp"); + } +} +---- +==== + +Even in this simple example, there are few things to take notice of + +* You can instantiate the central helper class of Spring Vault, +<>, using the `org.springframework.vault.client.VaultClient` + object and the `ClientAuthentication`. +* The mapper works against standard POJO objects without the need for any +additional metadata (though you can optionally provide that information). +* Mapping conventions can use field access. Notice the `Secrets` class has only getters. +* If the constructor argument names match the field names of the stored document, +they will be used to instantiate the object + +[[vault.core.connection]] +== Connecting to Vault with Spring + +One of the first tasks when using Vault and Spring is to create a `org.springframework.vault.client.VaultClient` object using the IoC container. + +[[vault.core.vault-java-config]] +=== Registering a Vault instance using Java based metadata + +An example of using Java based bean metadata to register common Vault support classes. + +.Registering a Spring Vault objects using Java based bean metadata +==== +[source,java] +---- +@Configuration +public class AppConfig extends AbstractVaultConfiguration { + + /** + * Specify an endpoint for connecting to Vault. + */ + @Override + public VaultEndpoint vaultEndpoint() { + return new VaultEndpoint(); + } + + /** + * Configure a client authentication. + * Please consider a more secure authentication method + * for production use. + */ + @Override + public ClientAuthentication clientAuthentication() { + return new TokenAuthentication("…"); + } +} +---- +==== + +[[vault.core.template]] +== Introduction to VaultTemplate + +The class `VaultTemplate`, located in the package `org.springframework.vault.core`, +is the central class of the Spring's Vault support providing a rich feature set to +interact with Vault. The template offers convenience operations to read, write and +delete data in Vault and provides a mapping between your domain objects and Vault data. + +NOTE: Once configured, `VaultTemplate` is thread-safe and can be reused across multiple instances. + +The mapping between Vault documents and domain classes is done by delegating to +`RestTemplate`. Spring Web support provides the mapping infrastructure. + +The `VaultTemplate` class implements the interface `VaultOperations`. +In as much as possible, the methods on `VaultOperations` are named after methods +available on the Vault API to make the API familiar to existing Vault developers +who are used to the API and CLI. For example, you will find methods such as +"write", "delete", "read", and "revoke". +The design goal was to make it as easy as possible to transition between +the use of the Vault API and `VaultOperations`. A major difference in between +the two APIs is that `VaultOperations` can be passed domain objects instead of JSON Key-Value pairs. + +NOTE: The preferred way to reference the operations on `VaultTemplate` instance is via its interface `VaultOperations`. + +While there are many convenience methods on `VaultTemplate` to help you easily +perform common tasks if you should need to access the Vault API directly to access +functionality not explicitly exposed by the `VaultTemplate` you can use one of +several execute callback methods to access underlying APIs. The execute callbacks +will give you a reference to either a `RestTemplate` or a `VaultClient` object. Please see the section <> for more information. + +Now let's look at a examples of how to work with the `VaultTemplate` in the context of the Spring container. + +[[vault.core.template.instantiating]] +=== Instantiating VaultTemplate + +You can use Java to create and register an instance of `VaultTemplate` as shown below. + +.Registering a `VaultTemplate` object +==== +[source,java] +---- +@Configuration +class AppConfig { + + @Bean + public VaultTemplate vaultTemplate() { + + VaultTemplate vaultTemplate = new VaultTemplate(); + vaultTemplate.setSessionManager(sessionManager()); + vaultTemplate.setVaultClientFactory(clientFactory()); + + return vaultTemplate; + } + + @Bean + public DefaultVaultClientFactory clientFactory() { + return new DefaultVaultClientFactory(); + } + + @Bean + public DefaultSessionManager sessionManager() { + return new DefaultSessionManager(new TokenAuthentication("…")); + } +} +---- +==== + +There are several overloaded constructors of `VaultTemplate`. These are + +* `VaultTemplate(VaultClient, ClientAuthentication)` - takes the `VaultClient` object and client authentication +* `VaultTemplate(VaultClientFactory, SessionManager)` - takes a client factory for resource management and a `SessionManager`. + +[[vault.client-ssl]] +== Vault Client SSL configuration + +SSL can be configured using `SslConfiguration` by setting various properties. +You can set either `javax.net.ssl.trustStore` to configure +JVM-wide SSL settings or configure `SslConfiguration` +to set SSL settings only for Spring Vault. + +==== +[source,java] +---- + +SslConfiguration sslConfiguration = new SslConfiguration( <1> + new FileSystemResource("client-cert.jks"), "changeit", + new FileSystemResource("truststore.jks"), "changeit"); + +SslConfiguration.forTrustStore(new FileSystemResource("keystore.jks"), <2> + "changeit") + +SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"), <3> + "changeit") + +---- +<1> Full configuration. +<2> Configuring only trust store settings. +<3> Configuring only key store settings. +==== + +Please note that providing `SslConfiguration` can be only +applied when either Apache Http Components or the OkHttp client +is on your class-path. + +[[vault.core.executioncallback]] +== Execution callbacks + +One common design feature of all Spring template classes is that all functionality is routed into one of the templates execute callback methods. This helps ensure that exceptions and any resource management that maybe required are performed consistency. While this was of much greater need in the case of JDBC and JMS than with Vault, it still offers a single spot for access and logging to occur. As such, using the execute callback is the preferred way to access the Vault API to perform uncommon operations that we've not exposed as methods on `VaultTemplate`. + +Here is a list of execute callback methods. + +* ` T` *doWithVault* `(ClientCallback clientCallback)` Executes the given `ClientCallback`, allows to interact with Vault using `VaultClient` without requiring a session. + +* ` T` *doWithVault* `(SessionCallback sessionCallback)` Executes the given `SessionCallback`, allows to interact with Vault in an authenticated session.. + +* ` T` *doWithRestTemplate* `(String pathTemplate, Map variables, RestTemplateCallback callback)` Expands the `pathTemplate` to an `java.net.URI` and allows low-level interaction with the underlying `org.springframework.web.client.RestTemplate`. + + +Here is an example that uses the `ClientCallback` to initialize Vault: + +==== +[source,java] +---- +return vaultTemplate.doWithVault(new ClientCallback() { + + @Override + public VaultInitializationResponse doWithVault(VaultClient client) { + + VaultResponseEntity response = client.putForEntity("sys/init", + vaultInitializationRequest, VaultInitializationResponse.class); + + if (response.isSuccessful() && response.hasBody()) { + return response.getBody(); + } + + return null. + } + }); +---- +==== \ No newline at end of file diff --git a/src/main/asciidoc/reference/vault.adoc b/src/main/asciidoc/reference/vault.adoc index b99dd84f..5e307642 100644 --- a/src/main/asciidoc/reference/vault.adoc +++ b/src/main/asciidoc/reference/vault.adoc @@ -13,650 +13,12 @@ accessing functionality such as reading data from Vault or issuing administrativ get a hold of the low-level API artifacts such as `RestTemplate` to communicate directly with Vault. -[[vault.core.getting-started]] -== Getting Started -Spring Vault support requires Vault 0.5 or higher and Java SE 6 or higher. -An easy way to bootstrap setting up a working environment is to create a Spring based project in http://spring.io/tools/sts[STS]. +include::dependencies.adoc[] -First you need to set up a running Vault server. Refer to the https://www.vaultproject.io/intro/[Vault] for an explanation on how to startup a Vault instance. +include::getting-started.adoc[] -To create a Spring project in STS go to File -> New -> Spring Template Project -> Simple Spring Utility Project -> press Yes when prompted. Then enter a project and a package name such as org.spring.vault.example. +include::client-support.adoc[] -Then add the following to pom.xml dependencies section. +include::authentication.adoc[] -[source,xml] ----- - - - - - - org.springframework.vault - spring-vault-core - {version} - - - ----- - -Also change the version of Spring in the pom.xml to be - -[source,xml] ----- -{springVersion} ----- - -You will also need to add the location of the Spring Milestone repository for maven to your pom.xml which is at the same level of your element - -[source,xml] ----- - - - spring-milestone - Spring Maven MILESTONE Repository - http://repo.spring.io/libs-milestone - - ----- - -The repository is also http://repo.spring.io/milestone/org/springframework/data/[browseable here]. - -You may also want to set the logging level to `DEBUG` to see some additional information, edit the log4j.properties file to have - -[source] ----- -log4j.category.org.springframework.vault=DEBUG -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %40.40c:%4L - %m%n ----- -Create a simple `Secrets` class to persist: - -.Mapped data object -==== -[source,java] ----- -package org.spring.vault.example; - -public class Secrets { - - String username; - String password; - - public String getUsername() { - return username; - } - - public String getPassword() { - return password; - } -} ----- -==== - -And a main application to run - -.Example application using Spring Vault -==== -[source,java] ----- -package org.springframework.vault.example; - -import org.springframework.vault.authentication.TokenAuthentication; -import org.springframework.vault.client.VaultClient; -import org.springframework.vault.core.VaultTemplate; -import org.springframework.vault.support.VaultResponseSupport; - -public class VaultApp { - - public static void main(String[] args) { - - VaultTemplate vaultTemplate = new VaultTemplate(new VaultClient(), - new TokenAuthentication("00000000-0000-0000-0000-000000000000")); - - Secrets secrets = new Secrets(); - secrets.username = "hello"; - secrets.password = "world"; - - vaultTemplate.write("secret/myapp", secrets); - - VaultResponseSupport response = vaultTemplate.read("secret/myapp", Secrets.class); - System.out.println(response.getData().getUsername()); - - vaultTemplate.delete("secret/myapp"); - } -} ----- -==== - -Even in this simple example, there are few things to take notice of - -* You can instantiate the central helper class of Spring Vault, -<>, using the `org.springframework.vault.client.VaultClient` - object and the `ClientAuthentication`. -* The mapper works against standard POJO objects without the need for any -additional metadata (though you can optionally provide that information). -* Mapping conventions can use field access. Notice the `Secrets` class has only getters. -* If the constructor argument names match the field names of the stored document, -they will be used to instantiate the object - -[[vault.core.connection]] -== Connecting to Vault with Spring - -One of the first tasks when using Vault and Spring is to create a `org.springframework.vault.client.VaultClient` object using the IoC container. - -[[vault.core.vault-java-config]] -=== Registering a Vault instance using Java based metadata - -An example of using Java based bean metadata to register common Vault support classes. - -.Registering a Spring Vault objects using Java based bean metadata -==== -[source,java] ----- -@Configuration -public class AppConfig extends AbstractVaultConfiguration { - - /** - * Specify an endpoint for connecting to Vault. - */ - @Override - public VaultEndpoint vaultEndpoint() { - return new VaultEndpoint(); - } - - /** - * Configure a client authentication. - * Please consider a more secure authentication method - * for production use. - */ - @Override - public ClientAuthentication clientAuthentication() { - return new TokenAuthentication("…"); - } -} ----- -==== - -[[vault.core.template]] -== Introduction to VaultTemplate - -The class `VaultTemplate`, located in the package `org.springframework.vault.core`, -is the central class of the Spring's Vault support providing a rich feature set to -interact with Vault. The template offers convenience operations to read, write and -delete data in Vault and provides a mapping between your domain objects and Vault data. - -NOTE: Once configured, `VaultTemplate` is thread-safe and can be reused across multiple instances. - -The mapping between Vault documents and domain classes is done by delegating to -`RestTemplate`. Spring Web support provides the mapping infrastructure. - -The `VaultTemplate` class implements the interface `VaultOperations`. -In as much as possible, the methods on `VaultOperations` are named after methods -available on the Vault API to make the API familiar to existing Vault developers -who are used to the API and CLI. For example, you will find methods such as -"write", "delete", "read", and "revoke". -The design goal was to make it as easy as possible to transition between -the use of the Vault API and `VaultOperations`. A major difference in between -the two APIs is that `VaultOperations` can be passed domain objects instead of JSON Key-Value pairs. - -NOTE: The preferred way to reference the operations on `VaultTemplate` instance is via its interface `VaultOperations`. - -While there are many convenience methods on `VaultTemplate` to help you easily -perform common tasks if you should need to access the Vault API directly to access -functionality not explicitly exposed by the `VaultTemplate` you can use one of -several execute callback methods to access underlying APIs. The execute callbacks -will give you a reference to either a `RestTemplate` or a `VaultClient` object. Please see the section <> for more information. - -Now let's look at a examples of how to work with the `VaultTemplate` in the context of the Spring container. - -[[vault.core.template.instantiating]] -=== Instantiating VaultTemplate - -You can use Java to create and register an instance of `VaultTemplate` as shown below. - -.Registering a `VaultTemplate` object -==== -[source,java] ----- -@Configuration -class AppConfig { - - @Bean - public VaultTemplate vaultTemplate() { - - VaultTemplate vaultTemplate = new VaultTemplate(); - vaultTemplate.setSessionManager(sessionManager()); - vaultTemplate.setVaultClientFactory(clientFactory()); - - return vaultTemplate; - } - - @Bean - public DefaultVaultClientFactory clientFactory() { - return new DefaultVaultClientFactory(); - } - - @Bean - public DefaultSessionManager sessionManager() { - return new DefaultSessionManager(new TokenAuthentication("…")); - } -} ----- -==== - -There are several overloaded constructors of `VaultTemplate`. These are - -* `VaultTemplate(VaultClient, ClientAuthentication)` - takes the `VaultClient` object and client authentication -* `VaultTemplate(VaultClientFactory, SessionManager)` - takes a client factory for resource management and a `SessionManager`. - -[[vault.core.clients]] -=== Client support - - -[[vault.core.authentication]] -== Vault authentication - -Different organizations have different requirements for security -and authentication. Vault reflects that need by shipping multiple authentication -methods. Spring Vault supports multiple authentications mechanisms. - -=== Token authentication - -Tokens are the core method for authentication within Vault. -Token authentication requires a static token to be provided. - -NOTE: Token authentication is the default authentication method. -If a token is disclosed an unintended party, it gains access to Vault and -can access secrets for the intended client. - -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - return new TokenAuthentication("…"); - } - - // … -} ----- -==== - -See also: https://www.vaultproject.io/docs/concepts/tokens.html[Vault Documentation: Tokens] - -=== AppId authentication - -Vault supports https://www.vaultproject.io/docs/auth/app-id.html[AppId] -authentication that consists of two hard to guess tokens. The AppId -defaults to `spring.application.name` that is statically configured. -The second token is the UserId which is a part determined by the application, -usually related to the runtime environment. IP address, Mac address or a -Docker container name are good examples. Spring Vault supports -IP address, Mac address and static UserId's (e.g. supplied via System properties). -The IP and Mac address are represented as Hex-encoded SHA256 hash. - -IP address-based UserId's use the local host's IP address. - - -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder().appId("myapp") // - .userIdMechanism(new IpAddressUserId()) // - .build(); - - return new AppIdAuthentication(options, vaultClient()); - } - - // … -} ----- -==== - -The corresponding command to generate the IP address UserId from a command line is: - ----- -$ echo -n 192.168.99.1 | sha256sum ----- - -NOTE: Including the line break of `echo` leads to a different hash value -so make sure to include the `-n` flag. - -Mac address-based UserId's obtain their network device from the -localhost-bound device. The configuration also allows specifying -a `network-interface` hint to pick the right device. The value of -`network-interface` is optional and can be either an interface -name or interface index (0-based). - -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - AppIdAuthenticationOptions options = AppIdAuthenticationOptions.builder().appId("myapp") // - .userIdMechanism(new MacAddressUserId()) // - .build(); - - return new AppIdAuthentication(options, vaultClient()); - } - - // … -} ----- -==== - -The corresponding command to generate the IP address UserId from a command line is: - ----- -$ echo -n 0AFEDE1234AC | sha256sum ----- - -NOTE: The Mac address is specified uppercase and without colons. -Including the line break of `echo` leads to a different hash value -so make sure to include the `-n` flag. - -==== Custom UserId - -A more advanced approach lets you implementing your own `AppIdUserIdMechanism`. -This class must be on your classpath and must implement -the `org.springframework.vault.authentication.AppIdUserIdMechanism` interface -and the `createUserId` method. Spring Vault will obtain the UserId -by calling `createUserId` each time it authenticates using AppId to -obtain a token. - -==== -[source,java] -.MyUserIdMechanism.java ----- -public class MyUserIdMechanism implements AppIdUserIdMechanism { - - @Override - public String createUserId() { - String userId = ... - return userId; - } -} ----- -==== - -See also: https://www.vaultproject.io/docs/auth/app-id.html[Vault Documentation: Using the App ID auth backend] - -=== AWS-EC2 authentication - -The https://www.vaultproject.io/docs/auth/aws-ec2.html[aws-ec2] -auth backend provides a secure introduction mechanism -for AWS EC2 instances, allowing automated retrieval of a Vault -token. Unlike most Vault authentication backends, this backend -does not require first-deploying, or provisioning security-sensitive -credentials (tokens, username/password, client certificates, etc.). -Instead, it treats AWS as a Trusted Third Party and uses the -cryptographically signed dynamic metadata information that uniquely -represents each EC2 instance. - -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - return new AwsEc2Authentication(vaultClient()); - } - - // … -} ----- -==== - -AWS-EC2 authentication enables nonce by default to follow -the Trust On First Use (TOFU) principle. Any unintended party that -gains access to the PKCS#7 identity metadata can authenticate -against Vault. - -During the first login, Spring Vault generates a nonce -that is stored in the auth backend aside the instance Id. -Re-authentication requires the same nonce to be sent. Any other -party does not have the nonce and can raise an alert in Vault for -further investigation. - -The nonce is kept in memory and is lost during application restart. - -AWS-EC2 authentication roles are optional and default to the AMI. -You can configure the authentication role by setting -it in `AwsEc2AuthenticationOptions`. - -See also: https://www.vaultproject.io/docs/auth/aws-ec2.html[Vault Documentation: Using the aws-ec2 auth backend] - -=== TLS certificate authentication - -The `cert` auth backend allows authentication using SSL/TLS client -certificates that are either signed by a CA or self-signed. - -To enable `cert` authentication you need to: - -1. Use SSL, see <> -2. Configure a Java `Keystore` that contains the client -certificate and the private key - -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - return new ClientCertificateAuthentication(options, vaultClient()); - } - - // … -} ----- -==== - -See also: https://www.vaultproject.io/docs/auth/cert.html[Vault Documentation: Using the cert auth backend] - -=== Cubbyhole authentication - -Cubbyhole authentication uses Vault primitives to provide a secured authentication -workflow. Cubbyhole authentication uses tokens as primary login method. -An ephemeral token is used to obtain a second, login VaultToken from Vault's -Cubbyhole secret backend. The login token is usually longer-lived and used to -interact with Vault. The login token can be retrieved either from a wrapped -response or from the `data` section. - -*Creating a wrapped token* - -NOTE: Response Wrapping for token creation requires Vault 0.6.0 or higher. - -.Crating and storing tokens -==== -[source,shell] ----- -$ vault token-create -wrap-ttl="10m" -Key Value ---- ----- -wrapping_token: 397ccb93-ff6c-b17b-9389-380b01ca2645 -wrapping_token_ttl: 0h10m0s -wrapping_token_creation_time: 2016-09-18 20:29:48.652957077 +0200 CEST -wrapped_accessor: 46b6aebb-187f-932a-26d7-4f3d86a68319 ----- -==== - -.Wrapped token response usage -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - - CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions - .builder() - .initialToken(VaultToken.of("…")) - .wrapped() - .build(); - - return new CubbyholeAuthentication(options, vaultClient()); - } - - // … -} ----- -==== - -*Using stored tokens* - -.Crating and storing tokens -==== -[source,shell] ----- -$ vault token-create -Key Value ---- ----- -token f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819 -token_accessor 4eee9bd9-81bb-06d6-af01-723c54a72148 -token_duration 0s -token_renewable false -token_policies [root] - -$ token-create -use-limit=2 -orphan -no-default-policy -policy=none -Key Value ---- ----- -token 895cb88b-aef4-0e33-ba65-d50007290780 -token_accessor e84b661c-8aa8-2286-b788-f258f30c8325 -token_duration 0s -token_renewable false -token_policies [none] - -$ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780 -$ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819 ----- -==== - -.Stored token response usage -==== -[source,java] ----- -@Configuration -class AppConfig extends AbstractVaultConfiguration { - - // … - - @Override - public ClientAuthentication clientAuthentication() { - - CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions - .builder() - .initialToken(VaultToken.of("…")) - .path("cubbyhole/token") - .build(); - - return new CubbyholeAuthentication(options, vaultClient()); - } - - // … -} ----- -==== - -See also: - -* https://www.vaultproject.io/docs/concepts/tokens.html[Vault Documentation: Tokens] -* https://www.vaultproject.io/docs/secrets/cubbyhole/index.html[Vault Documentation:Cubbyhole Secret Backend] -* https://www.vaultproject.io/docs/concepts/response-wrapping.html[Vault Documentation: Response Wrapping] - -[[vault.client-ssl]] -== Vault Client SSL configuration - -SSL can be configured using `SslConfiguration` by setting various properties. -You can set either `javax.net.ssl.trustStore` to configure -JVM-wide SSL settings or configure `SslConfiguration` -to set SSL settings only for Spring Vault. - -==== -[source,java] ----- - -SslConfiguration sslConfiguration = new SslConfiguration( <1> - new FileSystemResource("client-cert.jks"), "changeit", - new FileSystemResource("truststore.jks"), "changeit"); - -SslConfiguration.forTrustStore(new FileSystemResource("keystore.jks"), <2> - "changeit") - -SslConfiguration.forKeyStore(new FileSystemResource("keystore.jks"), <3> - "changeit") - ----- -<1> Full configuration. -<2> Configuring only trust store settings. -<3> Configuring only key store settings. -==== - -Please note that providing `SslConfiguration` can be only -applied when either Apache Http Components or the OkHttp client -is on your class-path. - -[[vault.core.executioncallback]] -== Execution callbacks - -One common design feature of all Spring template classes is that all functionality is routed into one of the templates execute callback methods. This helps ensure that exceptions and any resource management that maybe required are performed consistency. While this was of much greater need in the case of JDBC and JMS than with Vault, it still offers a single spot for access and logging to occur. As such, using the execute callback is the preferred way to access the Vault API to perform uncommon operations that we've not exposed as methods on `VaultTemplate`. - -Here is a list of execute callback methods. - -* ` T` *doWithVault* `(ClientCallback clientCallback)` Executes the given `ClientCallback`, allows to interact with Vault using `VaultClient` without requiring a session. - -* ` T` *doWithVault* `(SessionCallback sessionCallback)` Executes the given `SessionCallback`, allows to interact with Vault in an authenticated session.. - -* ` T` *doWithRestTemplate* `(String pathTemplate, Map variables, RestTemplateCallback callback)` Expands the `pathTemplate` to an `java.net.URI` and allows low-level interaction with the underlying `org.springframework.web.client.RestTemplate`. - - -Here is an example that uses the `ClientCallback` to initialize Vault: - -==== -[source,java] ----- -return vaultTemplate.doWithVault(new ClientCallback() { - - @Override - public VaultInitializationResponse doWithVault(VaultClient client) { - - VaultResponseEntity response = client.putForEntity("sys/init", - vaultInitializationRequest, VaultInitializationResponse.class); - - if (response.isSuccessful() && response.hasBody()) { - return response.getBody(); - } - - return null. - } - }); ----- -==== \ No newline at end of file