
com.bettercloud.vault.VaultConfig Maven / Gradle / Ivy
Show all versions of vault-java-driver Show documentation
package com.bettercloud.vault;
import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A container for the configuration settings needed to initialize a Vault
driver instance.
*
* Construct instances of this class using a builder pattern, calling setter methods for each value and then
* terminating with a call to build():
*
*
* {@code
* final VaultConfig config = new VaultConfig()
* .address("http://127.0.0.1:8200")
* .token("eace6676-4d78-c687-4e54-03cad00e3abf")
* .sslConfig(new SslConfig().verify(false).build())
* .timeout(30)
* .build();
* }
*
*
* @see SslConfig
*/
public class VaultConfig implements Serializable {
protected static final String VAULT_TOKEN = "VAULT_TOKEN";
private static final String VAULT_ADDR = "VAULT_ADDR";
private static final String VAULT_OPEN_TIMEOUT = "VAULT_OPEN_TIMEOUT";
private static final String VAULT_READ_TIMEOUT = "VAULT_READ_TIMEOUT";
private Map secretsEnginePathMap = new ConcurrentHashMap<>();
private String address;
private String token;
private SslConfig sslConfig;
private Integer openTimeout;
private Integer readTimeout;
private int prefixPathDepth = 1;
private int maxRetries;
private int retryIntervalMilliseconds;
private Integer globalEngineVersion;
private String nameSpace;
private EnvironmentLoader environmentLoader;
/**
* The code used to load environment variables is encapsulated here, so that a mock version of that environment
* loader can be used by unit tests.
*
* This method is primarily intended for use by unit tests, to inject a mock environment variable when
* constructing a VaultConfig
instance using the builder pattern approach rather than the convenience
* constructor. This method's access level was therefore originally set to protected
, but was bumped
* up to public
due to community request for the ability to disable environment loading altogether
* (see https://github.com/BetterCloud/vault-java-driver/issues/77).
*
* Note that if you do override this, however, then obviously all of the environment checking discussed in the
* documentation becomes disabled.
*
* @param environmentLoader An environment variable loader implementation (presumably a mock)
* @return This object, with environmentLoader populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig environmentLoader(final EnvironmentLoader environmentLoader) {
this.environmentLoader = environmentLoader;
return this;
}
/**
* Optional. Sets a global namespace to the Vault server instance, if desired. Otherwise, namespace can be applied individually to any read / write / auth call.
*
*
Namespace support requires Vault Enterprise Pro, please see https://learn.hashicorp.com/vault/operations/namespaces
*
* @param nameSpace The namespace to use globally in this VaultConfig instance.
* @return This object, with the namespace populated, ready for additional builder-pattern method calls or else
* finalization with the build() method
*
* @throws VaultException If any error occurs
*/
public VaultConfig nameSpace(final String nameSpace) throws VaultException {
if (nameSpace != null && !nameSpace.isEmpty()) {
this.nameSpace = nameSpace;
return this;
} else throw new VaultException("A namespace cannot be empty.");
}
/**
* Sets the KV Secrets Engine version of the Vault server instance.
*
*
If no version is explicitly set, it will be defaulted to version 2, the current version.
*
* @param globalEngineVersion The Vault KV Secrets Engine version
* @return This object, with KV Secrets Engine version populated, ready for additional builder-pattern method calls or else
* finalization with the build() method
*/
public VaultConfig engineVersion(final Integer globalEngineVersion) {
this.globalEngineVersion = globalEngineVersion;
return this;
}
/**
* Sets the address (URL) of the Vault server instance to which API calls should be sent.
* E.g. http://127.0.0.1:8200
.
*
* If no address is explicitly set, the object will look to the VAULT_ADDR
environment variable.
*
* address
is required for the Vault driver to function. If you do not supply it explicitly AND no
* environment variable value is found, then initialization of the VaultConfig
object will fail.
*
* @param address The Vault server base URL
* @return This object, with address populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig address(final String address) {
this.address = address.trim();
if (this.address.endsWith("/")) {
this.address = this.address.substring(0, this.address.length() - 1);
}
return this;
}
/**
* Sets the token used to access Vault.
*
* If no token is explicitly set, then the object will look to the VAULT_TOKEN
environment
* variable.
*
* There are some cases where you might want to instantiate a VaultConfig
object without a token
* (e.g. you plan to retrieve a token programmatically, with a call to the "userpass" auth backend, and populate
* it prior to making any other API calls).
*
* @param token The token to use for accessing Vault
* @return This object, with token populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig token(final String token) {
this.token = token;
return this;
}
/**
* Sets the secrets Engine paths used by Vault.
*
* @param secretEngineVersions paths to use for accessing Vault secrets.
* Key: secret path, value: Engine version to use.
* Example map: "/secret/foo" , "1",
* "/secret/bar", "2"
* @return This object, with secrets paths populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig secretsEnginePathMap(final Map secretEngineVersions) {
this.secretsEnginePathMap = new ConcurrentHashMap<>(secretEngineVersions);
return this;
}
/**
* Sets the secrets Engine version be used by Vault for the provided path.
*
* @param path the path to use for accessing Vault secrets.
* Example "/secret/foo"
* @param version The key-value engine version used for this path.
* @return This object, with a new entry in the secrets paths map, ready for additional builder-pattern method calls or else finalization with
* the build() method
*/
public VaultConfig putSecretsEngineVersionForPath(String path, String version) {
this.secretsEnginePathMap.put(path, version);
return this;
}
/**
* A container for SSL-related configuration options (e.g. certificates).
*
* Although typically necessary in most production environments, this is not strictly required (e.g. if your
* Vault server address begins with "http://" instead of "https://", then any SSL config will be ignored).
* However, if your Vault server uses HTTPS, and you wish to skip SSL certificate verification (NOT RECOMMENDED
* FOR PRODUCTION!), then you must supply an SslConfig
object with {@link SslConfig#verify(Boolean)}
* explicitly set to false
.
*
* @param sslConfig SSL-related configuration options
* @return This object, with SSL configuration options populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig sslConfig(final SslConfig sslConfig) {
this.sslConfig = sslConfig;
return this;
}
/**
* The number of seconds to wait before giving up on establishing an HTTP(S) connection to the Vault server.
*
* If no openTimeout is explicitly set, then the object will look to the VAULT_OPEN_TIMEOUT
* environment variable.
*
* @param openTimeout Number of seconds to wait for an HTTP(S) connection to successfully establish
* @return This object, with openTimeout populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig openTimeout(final Integer openTimeout) {
this.openTimeout = openTimeout;
return this;
}
/**
* After an HTTP(S) connection has already been established, this is the number of seconds to wait for all
* data to finish downloading.
*
* If no readTimeout is explicitly set, then the object will look to the VAULT_READ_TIMEOUT
* environment variable.
*
* @param readTimeout Number of seconds to wait for all data to be retrieved from an established HTTP(S) connection
* @return This object, with readTimeout populated, ready for additional builder-pattern method calls or else finalization with the build() method
*/
public VaultConfig readTimeout(final Integer readTimeout) {
this.readTimeout = readTimeout;
return this;
}
/**
* Set the "path depth" of the prefix path. Normally this is just
* 1, to correspond to one path element in the prefix path. To use
* a longer prefix path, set this value.
*
* @param prefixPathDepth integer number of path elements in the prefix path
* @return VaultConfig
*/
public VaultConfig prefixPathDepth(int prefixPathDepth) {
if (prefixPathDepth < 1) {
throw new IllegalArgumentException("pathLength must be > 1");
}
this.prefixPathDepth = prefixPathDepth;
return this;
}
/**
* Set the "path depth" of the prefix path, by explicitly specifying
* the prefix path, e.g., "foo/bar/blah" would set the prefix path depth
* to 3.
*
* @param prefixPath string prefix path, with or without initial or final forward slashes
* @return VaultConfig
*/
public VaultConfig prefixPath(String prefixPath) {
int orig = 0;
int pos;
int countElements = 0;
int pathLen = prefixPath.length();
if (pathLen == 0) {
throw new IllegalArgumentException("can't use an empty path");
}
while ((orig < pathLen) &&
((pos = prefixPath.indexOf('/',orig)) >= 0)) {
countElements++;
orig = pos+1;
}
if (prefixPath.charAt(0) == '/') {
countElements--;
}
if (prefixPath.charAt(pathLen-1) == '/') {
countElements--;
}
return prefixPathDepth(countElements+1);
}
/**
*
Sets the maximum number of times that an API operation will retry upon failure.
*
* This method is not meant to be called from application-level code outside of this package (hence
* the protected
access level. It is meant to be invoked via Vault.withRetries()
* in a builder pattern DSL-style.
*
* @param maxRetries The number of times that API operations will be retried when a failure occurs.
*/
void setMaxRetries(final int maxRetries) {
this.maxRetries = maxRetries;
}
/**
* Sets the period of time (in milliseconds) that the driver will wait in between retry attempts for a
* failing API operation.
*
* This method is not meant to be called from application-level code outside of this package (hence
* the protected
access level. It is meant to be invoked via Vault.withRetries()
* in a builder pattern DSL-style.
*
* @param retryIntervalMilliseconds The number of milliseconds that the driver will wait in between retries.
*/
void setRetryIntervalMilliseconds(final int retryIntervalMilliseconds) {
this.retryIntervalMilliseconds = retryIntervalMilliseconds;
}
/**
* Sets the global Engine version for this Vault Config instance. If no KV Engine version map is provided, use this version
* globally.
* If the provided KV Engine version map does not contain a requested secret, or when writing new secrets, fall back to this version.
*
* @param engineVersion The version of the Vault KV Engine to use globally.
*/
void setEngineVersion(final Integer engineVersion) {
this.globalEngineVersion = engineVersion;
}
/**
* This is the terminating method in the builder pattern. The method that validates all of the fields that
* has been set already, uses environment variables when available to populate any unset fields, and returns
* a VaultConfig
object that is ready for use.
*
* @return This object, with all available config options parsed and loaded
* @throws VaultException If the address
field was left unset, and there is no VAULT_ADDR
environment variable value with which to populate it.
*/
public VaultConfig build() throws VaultException {
if (this.environmentLoader == null) {
this.environmentLoader = new EnvironmentLoader();
}
if (this.address == null) {
final String addressFromEnv = environmentLoader.loadVariable(VAULT_ADDR);
if (addressFromEnv != null) {
this.address = addressFromEnv;
} else {
throw new VaultException("No address is set");
}
}
if (this.token == null && environmentLoader.loadVariable(VAULT_TOKEN) != null) {
this.token = environmentLoader.loadVariable(VAULT_TOKEN);
}
if (this.openTimeout == null && environmentLoader.loadVariable(VAULT_OPEN_TIMEOUT) != null) {
try {
this.openTimeout = Integer.valueOf(environmentLoader.loadVariable(VAULT_OPEN_TIMEOUT));
} catch (NumberFormatException e) {
System.err.printf("The " + VAULT_OPEN_TIMEOUT + " environment variable contains value \"%s\", which cannot be parsed as an integer timeout period.%n",
environmentLoader.loadVariable(VAULT_OPEN_TIMEOUT));
}
}
if (this.readTimeout == null && environmentLoader.loadVariable(VAULT_READ_TIMEOUT) != null) {
try {
this.readTimeout = Integer.valueOf(environmentLoader.loadVariable(VAULT_READ_TIMEOUT));
} catch (NumberFormatException e) {
System.err.printf("The " + VAULT_READ_TIMEOUT + " environment variable contains value \"%s\", which cannot be parsed as an integer timeout period.%n",
environmentLoader.loadVariable(VAULT_READ_TIMEOUT));
}
}
if (this.sslConfig == null) {
this.sslConfig = new SslConfig().environmentLoader(this.environmentLoader).build();
}
return this;
}
public Map getSecretsEnginePathMap() {
return secretsEnginePathMap;
}
public String getAddress() {
return address;
}
public String getToken() {
return token;
}
public SslConfig getSslConfig() {
return sslConfig;
}
public Integer getOpenTimeout() {
return openTimeout;
}
public Integer getReadTimeout() {
return readTimeout;
}
public int getMaxRetries() {
return maxRetries;
}
public int getRetryIntervalMilliseconds() {
return retryIntervalMilliseconds;
}
public Integer getGlobalEngineVersion() {
return globalEngineVersion;
}
public String getNameSpace() {
return nameSpace;
}
public int getPrefixPathDepth() {
return prefixPathDepth;
}
}