Vert.x Config provides a way to configure your Vert.x application. It:
offers multiple configuration syntaxes (JSON, properties, Yaml (extension), Hocon (extension)…
offers multiple configuration stores such as files, directories, HTTP, git (extension), Redis (extension), system properties and environment properties.
lets you define the processing order and overloading
supports runtime reconfiguration
The library is structured around:
a*Config Retriever instantiated and used by the Vert.x application. It configures a set of configuration store Configuration store** defines a location from where the configuration data is read and also a format (JSON by default)
The configuration is retrieved as a JSON Object.
To use the Config Retriever, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
----
Once done, you first need to instantiate the ConfigRetriever
:
var retriever = ConfigRetriever.create(vertx)
By default, the Config Retriever is configured with the following stores (in this order):
The Vert.x verticle config()
The system properties
The environment variables
A conf/config.json
file. This path can be overridden using the vertx-config-path
system property or
VERTX_CONFIG_PATH
environment variable.
You can configure your own stores:
var httpStore = ConfigStoreOptions()
.setType("http")
.setConfig(new io.vertx.core.json.JsonObject().put("host", "localhost").put("port", 8080).put("path", "/conf"))
var fileStore = ConfigStoreOptions()
.setType("file")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "my-config.json"))
var sysPropsStore = ConfigStoreOptions()
.setType("sys")
var options = ConfigRetrieverOptions()
.setStores(Set(httpStore, fileStore, sysPropsStore))
var retriever = ConfigRetriever.create(vertx, options)
More details about the overloading rules and available stores are available below. Each store can be marked as
optional
. If a failure is caught while retrieving (or processing) the configuration from an optional store, the failure
is logged, but the processing does not fail. Instead, an empty JSON object is returned ({}
). To mark a store as
optional, use the optional
attribute:
var fileStore = ConfigStoreOptions()
.setType("file")
.setOptional(true)
.setConfig(new io.vertx.core.json.JsonObject().put("path", "my-config.json"))
var sysPropsStore = ConfigStoreOptions()
.setType("sys")
var options = ConfigRetrieverOptions()
.setStores(Set(fileStore, sysPropsStore))
var retriever = ConfigRetriever.create(vertx, options)
Once you have the instance of the Config Retriever, retrieve the configuration as follows:
retriever.getConfigFuture().onComplete{
case Success(result) => {
// Failed to retrieve the configuration
}
case Failure(cause) => {
println(s"$cause")
}
}
The declaration order of the configuration store is important as it defines the overloading. For conflicting key, configuration stores arriving last overloads the value provided by the previous configuration stores. Let’s take an example. We have 2 configuration stores:
A
provides {a:value, b:1}
B
provides {a:value2, c:2}
Declared in this order (A, B), the resulting configuration would be:
{a:value2, b:1, c:2}
.
If you declare them in the reverse order (B, A), you will get: {a:value, b:1, c:2}
.
The retrieve configuration allows:
configuring verticles,
configure ports, clients, locations and so on,
configuring Vert.x itself
This section gives a few examples of usage.
The following example can be placed in the start
method of a verticle. It retrieves the configuration (using the
default stores), and configure an HTTP server with the content of the configuration.
var retriever = ConfigRetriever.create(vertx)
retriever.getConfigFuture().onComplete{
case Success(result) => println("Success")
case Failure(cause) => println("Failure")
}
The following example configures 2 verticles using the configurations contained in the verticles.json
file:
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(ConfigStoreOptions()
.setType("file")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "verticles.json"))
))
)
retriever.getConfigFuture().onComplete{
case Success(result) => println("Success")
case Failure(cause) => println("Failure")
}
You can also configure Vert.x directly. For this, you need a temporary Vert.x instance used to retrieve the configuration. Then the actual instance is created:
// Create a first instance of Vert.x
var vertx = Vertx.vertx()
// Create the config retriever
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(ConfigStoreOptions()
.setType("file")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "vertx.json"))
))
)
// Retrieve the configuration
retriever.getConfigFuture().onComplete{
case Success(result) => println("Success")
case Failure(cause) => println("Failure")
}
Vert.x Config notifies you when the configuration changes. If you want to react to this event, you need to implement the reaction yourself. For instance, you can un-deploy and redeploy verticle or send the new configuration on the event bus. The following example shows this latter case. It sends the new configuration on the event bus. Interested verticles can listen for this address and update themselves:
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(ConfigStoreOptions()
.setType("file")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "verticles.json"))
))
)
retriever.getConfigFuture().onComplete{
case Success(result) => println("Success")
case Failure(cause) => println("Failure")
}
retriever.listen((change: io.vertx.scala.config.ConfigChange) => {
var json = todo-renderDataObjectMemberSelect
vertx.eventBus().publish("new-configuration", json)
})
The Config Retriever provides a set of configuration stores and formats. More are available as extensions, and you can also implement your own.
Each declared data store must specify the type
. It can also define the format
. If
not set JSON is used.
Some configurations tore requires additional configuration (such a path…). This
configuration is passed as a Json Object using config
This configuration store just read the configuration from a file. It supports all supported formats.
var file = ConfigStoreOptions()
.setType("file")
.setFormat("properties")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "path-to-file.properties"))
The path
configuration is required.
The JSON configuration store serves the given JSON config as it is.
var json = ConfigStoreOptions()
.setType("json")
.setConfig(new io.vertx.core.json.JsonObject().put("key", "value"))
The only supported format for this configuration store is JSON.
This configuration store transforms environment variables to a JSON Object contributed to the global configuration.
var json = ConfigStoreOptions()
.setType("env")
This configuration store does not support the format
configuration. By default, the retrieved value is
transformed into JSON compatible structures (number, string, boolean, JSON object and JSON array). To avoid this
conversion, configure the raw-data
attribute:
var json = ConfigStoreOptions()
.setType("env")
.setConfig(new io.vertx.core.json.JsonObject().put("raw-data", true))
You can configure the raw-data
attribute (false
by default). If raw-data
is true
no attempts to convert
values is made, and you’ll be able to get raw values using config.getString(key)
. It is useful when manipulating
large integers.
If you want to select the set of keys to import, use the keys
attributes. It filters out all non selected keys. Keys
must be listed individually:
var json = ConfigStoreOptions()
.setType("env")
.setConfig(new io.vertx.core.json.JsonObject().put("keys", new io.vertx.core.json.JsonArray().add("SERVICE1_HOST").add("SERVICE2_HOST")))
This configuration store transforms system properties to a JSON Object contributed to the global configuration.
var json = ConfigStoreOptions()
.setType("sys")
.setConfig(new io.vertx.core.json.JsonObject().put("cache", "false"))
This configuration store does not support the format
configuration.
You can configure the cache
attribute (true
by default) let you decide whether or
not it caches the system properties on the first access and does not reload them.
You can also configure the raw-data
attribute (false
by default). If raw-data
is true
no attempts to convert
values is made, and you’ll be able to get raw values using config.getString(key)
. It is useful when manipulating
large integers.
This configuration store retrieves the configuration from an HTTP location. It can use any supported format.
var http = ConfigStoreOptions()
.setType("http")
.setConfig(new io.vertx.core.json.JsonObject().put("host", "localhost").put("port", 8080).put("path", "/A"))
It creates a Vert.x HTTP Client with the store configuration (see next snippet). To
ease the configuration; you can also configure the host
, port
and path
with the
host
, port
and path
properties.
var http = ConfigStoreOptions()
.setType("http")
.setConfig(new io.vertx.core.json.JsonObject().put("defaultHost", "localhost").put("defaultPort", 8080).put("ssl", true).put("path", "/A"))
This event bus configuration store receives the configuration from the event bus. This stores let you distribute your configuration among your local and distributed components.
var eb = ConfigStoreOptions()
.setType("event-bus")
.setConfig(new io.vertx.core.json.JsonObject().put("address", "address-getting-the-conf"))
This configuration store supports any format.
This configuration store is similar to the file
configuration store, but instead of
reading a single file, read several files from a directory.
This configuration store configuration requires:
a path
- the root directory in which files are located
at least one fileset
- an object to select the files
for properties file, you can indicate if you want to disable the type conversion using the raw-data
attribute
Each fileset
contains:
* a pattern
: a Ant-style pattern to select files. The pattern is applied on the
relative path of the files from the current working directory.
* an optional format
indicating the format of the files (each fileset can use a
different format, BUT files in a fileset must share the same format).
var dir = ConfigStoreOptions()
.setType("directory")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "config").put("filesets", new io.vertx.core.json.JsonArray().add(new io.vertx.core.json.JsonObject().put("pattern", "dir/*json")).add(new io.vertx.core.json.JsonObject().put("pattern", "dir/*.properties").put("format", "properties"))))
var dirWithRawData = ConfigStoreOptions()
.setType("directory")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "config").put("filesets", new io.vertx.core.json.JsonArray().add(new io.vertx.core.json.JsonObject().put("pattern", "dir/*json")).add(new io.vertx.core.json.JsonObject().put("pattern", "dir/*.properties").put("format", "properties").put("raw-data", true))))
Vert.x Config can read properties file. When reading such a file, you can pass the raw-data
attribute to
indicate to Vert.x to not attempt to convert values. It is useful when manipulating large integers. Values can be
retrieved using config.getString(key)
.
var propertyWithRawData = ConfigStoreOptions()
.setFormat("properties")
.setType("file")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "raw.properties").put("raw-data", true))
Some properties configuration maybe is hierarchical in nature.
When reading such a file, you can pass the hierarchical
attribute to
indicate to Vert.x to convert the configuration to a json object while maintaining this hierarchy,
in contrast to the previous method with a flat structure.
Example:
server.host=localhost server.port=8080 multiple.values=1,2,3
Get values:
var propertyWitHierarchical = ConfigStoreOptions()
.setFormat("properties")
.setType("file")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "hierarchical.properties").put("hierarchical", true))
var options = ConfigRetrieverOptions()
.setStores(Set(propertyWitHierarchical))
var configRetriever = ConfigRetriever.create(Vertx.vertx(), options)
configRetriever.configStream().handler((config: io.vertx.scala.core.json.JsonObject) => {
var host = config.getValue("server").getValue("host")
var port = config.getValue("server").getValue("port")
var multiple = config.getValue("multiple").getValue("values")
for ( i <- 0 until todo-renderJsonArraySize) {
var value = multiple.getValue(i)
}
})
The Configuration Retriever periodically retrieve the configuration, and if the outcome is different from the current one, your application can be reconfigured. By default, the configuration is reloaded every 5 seconds.
var options = ConfigRetrieverOptions()
.setScanPeriod(2000)
.setStores(Set(store1, store2))
var retriever = ConfigRetriever.create(Vertx.vertx(), options)
retriever.getConfigFuture().onComplete{
case Success(result) => println("Success")
case Failure(cause) => println("Failure")
}
retriever.listen((change: io.vertx.scala.config.ConfigChange) => {
// Previous configuration
var previous = todo-renderDataObjectMemberSelect
// New configuration
var conf = todo-renderDataObjectMemberSelect
})
You can retrieve the last retrieved configuration without "waiting" to be retrieved using:
var last = retriever.getCachedConfig()
The ConfigRetriever
provide a way to access the stream of configuration.
It’s a ReadStream
of JsonObject
. By registering the right
set of handlers you are notified:
when a new configuration is retrieved
when an error occur while retrieving a configuration
when the configuration retriever is closed (the
endHandler
is called).
var options = ConfigRetrieverOptions()
.setScanPeriod(2000)
.setStores(Set(store1, store2))
var retriever = ConfigRetriever.create(Vertx.vertx(), options)
retriever.configStream().endHandler((v: java.lang.Void) => {
// retriever closed
}).exceptionHandler((t: java.lang.Throwable) => {
// an error has been caught while retrieving the configuration
}).handler((conf: io.vertx.scala.core.json.JsonObject) => {
// the configuration
})
You can configure a processor that can validate and update the configuration. This is done using the
setConfigurationProcessor
method.
The prcessing must not return null
. It takes the retrieved configuration and returns the processed one. If the processor
does not update the configuration, it must return the input configuration. If the processor can throw an exception (for
example for validation purpose).
The ConfigRetriever
provide a way to retrieve the configuration as a
Future
:
var future = ConfigRetriever.getConfigAsFuture(retriever)
future.setHandlerFuture().onComplete{
case Success(result) => {
// Failed to retrieve the configuration
}
case Failure(cause) => {
println(s"$cause")
}
}
You can extend the configuration by implementing:
the ConfigProcessor
SPI to add support for a
format
the ConfigStoreFactory
SPI to add support for
configuration store (place from where the configuration data is retrieved)
Besides of the out of the box format supported by this library, Vert.x Config provides additional formats you can use in your application.
The Hocon Configuration Format extends the Vert.x Configuration Retriever and provides the support for the HOCON(https://github.com/typesafehub/config/blob/master/HOCON.md) format.
It supports includes, json, properties, macros…
To use the Hocon Configuration Format, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-hocon</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-hocon:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this format:
var store = ConfigStoreOptions()
.setType("file")
.setFormat("hocon")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "my-config.conf"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
You just need to set format
to hocon
.
The Yaml Configuration Format extends the Vert.x Configuration Retriever and provides the support for the Yaml Configuration Format format.
To use the Yaml Configuration Format, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-yaml</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-yaml:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this format:
var store = ConfigStoreOptions()
.setType("file")
.setFormat("yaml")
.setConfig(new io.vertx.core.json.JsonObject().put("path", "my-config.yaml"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
You just need to set format
to yaml
.
Besides of the out of the box stores supported by this library, Vert.x Config provides additional stores you can use in your application.
The Git Configuration Store is an extension to the Vert.x Configuration Retriever to retrieve configuration from a Git repository.
To use the Git Configuration, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-git</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-git:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var git = ConfigStoreOptions()
.setType("git")
.setConfig(new io.vertx.core.json.JsonObject().put("url", "https://github.com/cescoffier/vertx-config-test.git").put("path", "local").put("filesets", new io.vertx.core.json.JsonArray().add(new io.vertx.core.json.JsonObject().put("pattern", "*.json"))))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(git))
)
The configuration requires:
the url
of the repository
the path
where the repository is cloned (local directory)
the user
for private repository (no authentication by default)
the password
of the user
the idRsaKeyPath
for private repository and requires ssh uri
at least fileset
indicating the set of files to read (same behavior as the
directory configuration store).
You can also configure the branch
(master
by default) to use and the name of the
remote
repository (origin
by default).
If the local path
does not exist, the configuration store clones the repository into
this directory. Then it reads the file matching the different file sets.
It the local path
exist, it tried to update it (it switches branch if needed)). If the
update failed the configuration retrieval fails.
Periodically, the repositories is updated to check if the configuration has been updated.
The Kubernetes ConfigMap Store extends the Vert.x Configuration Retriever and provides support Kubernetes Config Map and Secrets. So, configuration is retrieved by reading the config map or the secrets.
To use the Kubernetes ConfigMap Store, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-kubernetes-configmap</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-kubernetes-configmap:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var store = ConfigStoreOptions()
.setType("configmap")
.setConfig(new io.vertx.core.json.JsonObject().put("namespace", "my-project-namespace").put("name", "configmap-name"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
You need to configure the store to find the right configmap. this is done with:
namespace
- the project namespace, default
by default. If the KUBERNETES_NAMESPACE
ENV variable is set, it
uses this value.
name
- the name of the config map
optional
- whether or not the config map is optional (true
by default)
If the config map is composed by several element, you can use the key
parameter to tell
which key
is read
The application must have the permissions to read the config map.
To read data from a secret, just configure the secret
property to true
:
var store = ConfigStoreOptions()
.setType("configmap")
.setConfig(new io.vertx.core.json.JsonObject().put("namespace", "my-project-namespace").put("name", "my-secret").put("secret", true))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
If the config map is not available, an empty JSON object is passed as configuration chunk. To disable this
behavior and explicitly fail, you can set the optional
configuration to false
.
The Redis Configuration Store extends the Vert.x Configuration Retriever and provides the way to retrieve configuration from a Redis server.
To use the Redis Configuration Store, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-redis</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-redis:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var store = ConfigStoreOptions()
.setType("redis")
.setConfig(new io.vertx.core.json.JsonObject().put("host", "localhost").put("port", 6379).put("key", "my-configuration"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
The store configuration is used to create an instance of
RedisClient
. check the documentation of the Vert.x Redis Client
for further details.
In addition, you can set the key
instructing the store in which field the configuration
is stored. configuration
is used by default.
The created Redis client retrieves the configuration using the HGETALL
configuration.
The Zookeeper Configuration Store extends the Vert.x Configuration Retriever and provides the way to retrieve configuration from a Zookeeper server. It uses Apache Curator as client.
To use the Redis Configuration Store, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-zookeeper</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-zookeeper:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var store = ConfigStoreOptions()
.setType("zookeeper")
.setConfig(new io.vertx.core.json.JsonObject().put("connection", "localhost:2181").put("path", "/path/to/my/conf"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
The store configuration is used to configure the Apache Curator client and the path of the Zookeeper node containing the configuration. Notice that the format of the configuration can be JSON, or any supported format.
The configuration requires the configuration
attribute indicating the connection string of the Zookeeper
server, and the path
attribute indicating the path of the node containing the configuration.
In addition you can configure:
maxRetries
: the number of connection attempt, 3 by default
baseSleepTimeBetweenRetries
: the amount of milliseconds to wait between retries (exponential backoff strategy).
1000 ms by default.
The Consul Configuration Store extends the Vert.x Configuration Retriever and provides the way to retrieve configuration from a Consul.
To use the Consul Configuration Store, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-consul</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-consul:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var store = ConfigStoreOptions()
.setType("consul")
.setConfig(new io.vertx.core.json.JsonObject().put("host", "localhost").put("port", 8500).put("prefix", "foo"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
The store configuration is used to create an instance of
ConsulClient
. Check the documentation of the Vert.x Consul Client
for further details. And this is the parameters specific to the Consul Configuration Store:
prefix
A prefix that will not be taken into account when building the configuration tree. Defaults to empty.
delimiter
Symbol that used to split keys in the Consul storage to obtain levels in the configuration tree. Defaults to "/".
The Spring Config Server Store extends the Vert.x Configuration Retriever and provides the a way to retrieve configuration from a Spring Server.
To use the Spring Config Server Store, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-spring-config-server</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-spring-config-server:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var store = ConfigStoreOptions()
.setType("spring-config-server")
.setConfig(new io.vertx.core.json.JsonObject().put("url", "http://localhost:8888/foo/development"))
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
Configurable attributes are:
url
- the url
to retrieve the configuration (mandatory), supports two type of formats:
/{application}/{environment}
which produces response with separated propertySources
/{application}-{environment}.json
which produces response as JSON with unique fields and resolved Spring placeholders
timeout
- the timeout (in milliseconds) to retrieve the configuration, 3000 by default
user
- the user
(no authentication by default)
password
- the password
httpClientConfiguration
- the configuration of the underlying HTTP client
The Vault Store extends the Vert.x Configuration Retriever and provides support for Vault (https://www.vaultproject.io/). So, configuration (secrets) is retrieved from Vault.
To use the Vault Config Store, add the following dependency to the dependencies section of your build descriptor:
Maven (in your pom.xml
):
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config-vault</artifactId>
<version>3.6.2</version>
</dependency>
<dependency>
<groupId>io.vertx</groupId>
<artifactId>vertx-config</artifactId>
<version>3.6.2</version>
</dependency>
Gradle (in your build.gradle
file):
compile 'io.vertx:vertx-config:3.6.2'
compile 'io.vertx:vertx-config-vault:3.6.2'
Once added to your classpath or dependencies, you need to configure the
ConfigRetriever
to use this store:
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
To use the Vault config store, set the type
to vault
. The configuration is provided as Json. It configures the
access to Vault, authentication and the path of the secret to retrieve:
var vault_config = new io.vertx.core.json.JsonObject().put("host", "127.0.0.1").put("port", 8200).put("ssl", true)
// Certificates
var certs = PemKeyCertOptions()
.setCertPaths(Set("target/vault/config/ssl/client-cert.pem"))
.setKeyPaths(Set("target/vault/config/ssl/client-privatekey.pem"))
vault_config.put("pemKeyCertOptions", certs.toJson())
// Truststore
var jks = JksOptions()
.setPath("target/vault/config/ssl/truststore.jks")
vault_config.put("trustStoreOptions", jks.toJson())
// Path to the secret to read.
vault_config.put("path", "secret/my-secret")
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(vault_config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
}
The vault_config
object can contain the HTTP client / Web client configuration such as trust stores, timeout,
certificates, port and host. The path
and host
entries are mandatory. The path
indicates the secret to
retrieve. The host
is the hostname of the Vault server. By default the port 8200 is used. SSL is disabled by
default, but you should enable it for production settings.
Then, you need to use one of the following method to configure the token to use or the authentication mechanism.
If you know the token to use, set the token
entry in the configuration:
var vault_config = new io.vertx.core.json.JsonObject()
// ...
// Path to the secret to read.
vault_config.put("path", "secret/my-secret")
// The token
vault_config.put("token", token)
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(vault_config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
You can use the root token, but it’s not recommended. When the token is revoked, the access to the secret is blocked. If the token is renewable, the token is renewed when it expires.
If you have a token allowing you to generate new token, you can request the token generation:
var vault_config = new io.vertx.core.json.JsonObject()
// ...
// Path to the secret to read.
vault_config.put("path", "secret/my-secret")
// Configure the token generation
// Configure the token request (https://www.vaultproject.io/docs/auth/token.html)
var tokenRequest = new io.vertx.core.json.JsonObject().put("ttl", "1h").put("noDefault", true).put("token", token)
vault_config.put("auth-backend", "token").put("renew-window", 5000).put("token-request", tokenRequest)
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(vault_config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
When using this approach, no token must be provided in the root configuration, the the token use to request the
generation is passed in the nested JSON structure. If the generated token is renewable, it will be
renewed automatically upon expiration. The renew-window
is the time window to add to the token validity to renew
it. If the generated token is revoked, the access to the secret is blocked.
You can use TLS certificates as authentication mechanism. So, you don’t need to know a token, the token is generated automatically.
var vault_config = new io.vertx.core.json.JsonObject()
// ...
var certs = PemKeyCertOptions()
.setCertPaths(Set("target/vault/config/ssl/client-cert.pem"))
.setKeyPaths(Set("target/vault/config/ssl/client-privatekey.pem"))
vault_config.put("pemKeyCertOptions", certs.toJson())
var trust = PemTrustOptions()
.setCertPaths(Set("target/vault/config/ssl/cert.pem"))
vault_config.put("pemTrustStoreOptions", trust.toJson())
var jks = JksOptions()
.setPath("target/vault/config/ssl/truststore.jks")
vault_config.put("trustStoreOptions", jks.toJson())
vault_config.put("auth-backend", "cert")
// Path to the secret to read.
vault_config.put("path", "secret/my-secret")
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(vault_config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
Check out the HTTP client and Web client configuration to pass the certificates. If the generated token is renewable, it will be renewed. If not, the store attempts to authenticate again.
AppRole
is used when your application is known by Vault and you have the appRoleId
and secretId
. You don’t
need a token, the token being generated automatically:
var vault_config = new io.vertx.core.json.JsonObject()
// ...
vault_config.put("auth-backend", "approle").put("approle", new io.vertx.core.json.JsonObject().put("role-id", appRoleId).put("secret-id", secretId))
// Path to the secret to read.
vault_config.put("path", "secret/my-secret")
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(vault_config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
If the generated token is renewable, it will be renewed. If not, the store attempts to authenticate again.
The userpass
auth backend is used when the user / app is authenticated using a username/password. You don’t need a
token as the token is generated during the authentication process:
var vault_config = new io.vertx.core.json.JsonObject()
// ...
vault_config.put("auth-backend", "userpass").put("user-credentials", new io.vertx.core.json.JsonObject().put("username", username).put("password", password))
// Path to the secret to read.
vault_config.put("path", "secret/my-secret")
var store = ConfigStoreOptions()
.setType("vault")
.setConfig(vault_config)
var retriever = ConfigRetriever.create(vertx, ConfigRetrieverOptions()
.setStores(Set(store))
)
If the generated token is renewable, it will be renewed. If not, the store attempts to authenticate again.