Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ Depending on how you have set up Vault you might need additional configuration l
{docs}#vault.config.ssl[SSL] and
{docs}#vault.config.authentication[authentication].

If the application imports the `spring-boot-starter-actuator` project, the status of the vault server will be available via the `/health` endpoint.
If the application imports the `spring-boot-starter-actuator` project, the status of the vault server will be available via the `/actuator/health` endpoint.

The vault health indicator can be enabled or disabled through the property `management.health.vault.enabled` (default to `true`).

Expand Down
2 changes: 1 addition & 1 deletion docs/src/main/asciidoc/intro.adoc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
Spring Cloud Vault Config provides client-side support for externalized configuration in a distributed system.
With https://www.vaultproject.io[HashiCorp's Vault] you have a central place to manage external secret properties for applications across all environments.
Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, MongoDB, Consul, AWS and more.
Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, Couchbase, MongoDB, Consul, AWS and more.
35 changes: 35 additions & 0 deletions docs/src/main/asciidoc/spring-cloud-vault.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,7 @@ Spring Cloud Vault integrates with these backends:

* <<vault.config.backends.database>>
* <<vault.config.backends.cassandra>>
* <<vault.config.backends.couchbase>>
* <<vault.config.backends.elasticsearch>>
* <<vault.config.backends.mongodb>>
* <<vault.config.backends.mysql>>
Expand Down Expand Up @@ -1004,6 +1005,40 @@ spring.cloud.vault:

See also: https://www.vaultproject.io/docs/secrets/cassandra/index.html[Vault Documentation: Setting up Apache Cassandra with Vault]

[[vault.config.backends.couchbase]]
=== Couchbase Database

Spring Cloud Vault can obtain credentials for Couchbase.
The integration can be enabled by setting
`spring.cloud.vault.couchbase.enabled=true` (default `false`) and providing the role name with `spring.cloud.vault.couchbase.role=…`.

Username and password are available from `spring.data.couchbase.username`
and `spring.data.couchbase.password` properties so using Spring Boot will pick up the generated credentials without further configuration.
You can configure the property names by setting
`spring.cloud.vault.couchbase.username-property` and
`spring.cloud.vault.couchbase.password-property`.

====
[source,yaml]
----
spring.cloud.vault:
couchbase:
enabled: true
role: readonly
backend: database
username-property: spring.data.couchbase.username
password-property: spring.data.couchbase.password
----
====

* `enabled` setting this value to `true` enables the Couchbase backend config usage
* `role` sets the role name of the Couchbase role definition
* `backend` sets the path of the Couchbase mount to use
* `username-property` sets the property name in which the Couchbase username is stored
* `password-property` sets the property name in which the Couchbase password is stored

See also: https://www.vaultproject.io/docs/secrets/couchbase/index.html[Vault Documentation: Setting up Couchbase with Vault]

[[vault.config.backends.elasticsearch]]
=== Elasticsearch

Expand Down
5 changes: 5 additions & 0 deletions spring-cloud-vault-config-databases/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@
<artifactId>spring-boot-starter-jdbc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-couchbase</artifactId>
<scope>test</scope>
</dependency>
Comment thread
fhitchen marked this conversation as resolved.
</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,18 @@

/**
* Bootstrap configuration providing support for the Database secret backends such as
* Database, Apache Cassandra and MongoDB.
* Database, Apache Cassandra, Couchbase and MongoDB.
*
* @author Mark Paluch
* @author Per Abich
* @author Sebastien Nahelou
* @author Francis Hitchens
*/
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties({ VaultMySqlProperties.class,
VaultPostgreSqlProperties.class, VaultCassandraProperties.class,
VaultMongoProperties.class, VaultElasticsearchProperties.class,
VaultDatabaseProperties.class })
VaultDatabaseProperties.class, VaultCouchbaseProperties.class })
public class VaultConfigDatabaseBootstrapConfiguration {

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright 2016-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.vault.config.databases;

import javax.validation.constraints.NotEmpty;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

/**
* Configuration properties for Vault using the Couchbase integration.
*
* @author Francis Hitchens
*/
@ConfigurationProperties("spring.cloud.vault.couchbase")
@Validated
public class VaultCouchbaseProperties implements DatabaseSecretProperties {

/**
* Enable couchbase backend usage.
*/
private boolean enabled = false;

/**
* Role name for credentials.
*/
private String role;

/**
* Enable static role usage.
*
*/
private boolean staticRole = false;

/**
* Couchbase backend path.
*/
@NotEmpty
private String backend = "database";

/**
* Target property for the obtained username.
*/
@NotEmpty
private String usernameProperty = "spring.data.couchbase.username";

/**
* Target property for the obtained password.
*/
@NotEmpty
private String passwordProperty = "spring.data.couchbase.password";

@Override
public boolean isEnabled() {
return this.enabled;
}

public void setEnabled(boolean enabled) {
this.enabled = enabled;
}

@Override
public String getRole() {
return this.role;
}

public void setRole(String role) {
this.role = role;
}

@Override
public boolean isStaticRole() {
return this.staticRole;
}

public void setStaticRole(boolean staticRole) {
this.staticRole = staticRole;
}

@Override
public String getBackend() {
return this.backend;
}

public void setBackend(String backend) {
this.backend = backend;
}

@Override
public String getUsernameProperty() {
return this.usernameProperty;
}

public void setUsernameProperty(String usernameProperty) {
this.usernameProperty = usernameProperty;
}

@Override
public String getPasswordProperty() {
return this.passwordProperty;
}

public void setPasswordProperty(String passwordProperty) {
this.passwordProperty = passwordProperty;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
* Copyright 2017-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.cloud.vault.config.databases;

import java.net.InetSocketAddress;

import com.couchbase.client.java.Cluster;
import com.couchbase.client.core.error.UnambiguousTimeoutException;

import java.util.HashMap;
import java.util.Map;
import java.time.Duration;

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.vault.util.CanConnect;
import org.springframework.cloud.vault.util.VaultRule;
import org.springframework.cloud.vault.util.Version;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.vault.core.VaultOperations;

import static org.junit.Assume.assumeTrue;

/**
* Integration tests using the database secret backend. In case this test should fail
* because of SSL make sure you run the test within the
* spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is
* referenced with {@code ../work/keystore.jks}.
*
* Uses the existing admin user that comes with the couchbase/sandbox-server docker image
* provided by Couchbase. The test will fail if this user does not exits.
*
* @author Francis Hitchens
*/
@RunWith(SpringRunner.class)
@SpringBootTest(classes = VaultConfigCouchbaseDatabaseStaticTests.TestApplication.class,
properties = { "spring.cloud.vault.couchbase.enabled=true",
"spring.cloud.vault.couchbase.role=staticreadonly",
"spring.cloud.vault.couchbase.staticRole=true",
"spring.data.couchbase.username=foo",
"spring.data.couchbase.password=bar",
"spring.main.allow-bean-definition-overriding=true" })
public class VaultConfigCouchbaseDatabaseStaticTests {

private static final int COUCHBASE_PORT = 8091;

private static final String COUCHBASE_HOST = "localhost";

@Value("${spring.data.couchbase.username}")
String username;

@Value("${spring.data.couchbase.password}")
String password;

Cluster cluster;

/**
* Initialize the couchbase secret backend.
*/
@BeforeClass
public static void beforeClass() {

VaultRule vaultRule = new VaultRule();
vaultRule.before();

assumeTrue(CanConnect.to(new InetSocketAddress(COUCHBASE_HOST, COUCHBASE_PORT)));
assumeTrue(vaultRule.prepare().getVersion()
Comment thread
fhitchen marked this conversation as resolved.
.isGreaterThanOrEqualTo(Version.parse("0.7.1")));

if (!vaultRule.prepare().hasSecretBackend("database")) {
vaultRule.prepare().mountSecret("database");
}

VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations();

Map<String, String> config = new HashMap<>();
config.put("plugin_name", "couchbase-database-plugin");
config.put("hosts", "couchbase://localhost");
config.put("username", "Administrator");
config.put("password", "password");
config.put("allowed_roles", "*");

vaultOperations.write("database/config/spring-cloud-vault-couchbase", config);

Map<String, String> body = new HashMap<>();
body.put("db_name", "spring-cloud-vault-couchbase");
body.put("username", "admin");
body.put("rotation_period", "5m");
body.put("creation_statements", "[{\"name\":\"ro_admin\"}]");

vaultOperations.write("database/static-roles/staticreadonly", body);
}

@Test
public void shouldConnectConnection() throws UnambiguousTimeoutException {

this.cluster = Cluster.connect("127.0.0.1", this.username, this.password);
this.cluster.waitUntilReady(Duration.ofSeconds(5));
this.cluster.disconnect();
}

@Test(expected = UnambiguousTimeoutException.class)
public void shouldFailConnectConnection() throws UnambiguousTimeoutException {

this.cluster = Cluster.connect("127.0.0.1", this.username, "fake.pwd");
this.cluster.waitUntilReady(Duration.ofSeconds(5));
this.cluster.disconnect();
}

@SpringBootApplication
public static class TestApplication {

public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}

}

}
Loading