From f7573aceca9fa95f61cdef264b0c595bf7e44153 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Mon, 1 Jun 2020 16:47:33 -0500 Subject: [PATCH 01/18] Start adding couchbase db to spring cloud vault --- README.adoc | 4 +- .../databases/VaultCouchbaseProperties.java | 123 ++++++++++++++++ .../CouchbaseSecretIntegrationTests.java | 113 +++++++++++++++ .../databases/VaultConfigCouchbaseTests.java | 134 ++++++++++++++++++ 4 files changed, 372 insertions(+), 2 deletions(-) create mode 100644 spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java create mode 100644 spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java create mode 100644 spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java diff --git a/README.adoc b/README.adoc index 20f1a67a2..a8e6c850b 100644 --- a/README.adoc +++ b/README.adoc @@ -263,7 +263,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`). @@ -592,4 +592,4 @@ Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on t - `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL. - `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`. -IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. \ No newline at end of file +IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources. diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java new file mode 100644 index 000000000..9beb9ddba --- /dev/null +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java @@ -0,0 +1,123 @@ +/* + * 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 Mark Paluch + * @author Sebastien Nahelou + */ +@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. + * + * @since 2.2 + */ + private boolean staticRole = false; + + /** + * Couchbase backend path. + */ + @NotEmpty + private String backend = "couchbase"; + + /** + * 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; + } + +} diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java new file mode 100644 index 000000000..909a9ade2 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java @@ -0,0 +1,113 @@ +/* + * 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 java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Before; +import org.junit.Test; + +import org.springframework.cloud.vault.config.VaultConfigOperations; +import org.springframework.cloud.vault.config.VaultConfigTemplate; +import org.springframework.cloud.vault.config.VaultProperties; +import org.springframework.cloud.vault.util.CanConnect; +import org.springframework.cloud.vault.util.IntegrationTestSupport; +import org.springframework.cloud.vault.util.Settings; +import org.springframework.vault.core.VaultOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; +import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecretBackendMetadataFactory.forDatabase; + +/** + * Integration tests for {@link VaultConfigTemplate} using the couchbase secret backend. + * This test requires a running Couchbase instance, see {@link #COUCHBASE_HOST} and other + * {@code COUCHBASE_*} properties. + * + * @author Mark Paluch + */ +public class CouchbaseSecretIntegrationTests extends IntegrationTestSupport { + + private static final String COUCHBASE_HOST = "localhost"; + + private static final int COUCHBASE_PORT = 9042; + + private static final String COUCHBASE_USERNAME = "springvault"; + + private static final String COUCHBASE_PASSWORD = "springvault"; + + private static final String CREATE_USER_AND_GRANT_CQL = "CREATE USER '{{username}}' WITH PASSWORD '{{password}}' NOSUPERUSER;" + + "GRANT SELECT ON ALL KEYSPACES TO {{username}};"; + + private VaultProperties vaultProperties = Settings.createVaultProperties(); + + private VaultConfigOperations configOperations; + + private VaultCouchbaseProperties couchbase = new VaultCouchbaseProperties(); + + /** + * Initialize couchbase secret backend. + */ + @Before + public void setUp() { + + assumeTrue(CanConnect.to(new InetSocketAddress(COUCHBASE_HOST, COUCHBASE_PORT))); + + this.couchbase.setEnabled(true); + this.couchbase.setRole("readonly"); + + if (!prepare().hasSecretBackend(this.couchbase.getBackend())) { + prepare().mountSecret(this.couchbase.getBackend()); + } + + VaultOperations vaultOperations = this.vaultRule.prepare().getVaultOperations(); + + Map connection = new HashMap<>(); + connection.put("hosts", COUCHBASE_HOST); + connection.put("username", COUCHBASE_USERNAME); + connection.put("password", COUCHBASE_PASSWORD); + connection.put("protocol_version", 3); + + vaultOperations.write( + String.format("%s/config/connection", this.couchbase.getBackend()), + connection); + + Map role = new HashMap<>(); + + role.put("creation_cql", CREATE_USER_AND_GRANT_CQL); + role.put("consistency", "All"); + + vaultOperations.write(String.format("%s/roles/%s", this.couchbase.getBackend(), + this.couchbase.getRole()), role); + + this.configOperations = new VaultConfigTemplate(vaultOperations, + this.vaultProperties); + } + + @Test + public void shouldCreateCredentialsCorrectly() { + + Map secretProperties = this.configOperations + .read(forDatabase(this.couchbase)).getData(); + + assertThat(secretProperties).containsKeys("spring.data.couchbase.username", + "spring.data.couchbase.password"); + } + +} diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java new file mode 100644 index 000000000..601d254b9 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java @@ -0,0 +1,134 @@ +/* + * 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 java.net.InetSocketAddress; +import java.util.HashMap; +import java.util.Map; + +import com.datastax.oss.driver.api.core.CqlSession; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +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.test.context.junit4.SpringRunner; +import org.springframework.vault.core.VaultOperations; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assume.assumeTrue; + +/** + * Integration tests using the couchbase 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}. + * + * @author Mark Paluch + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = VaultConfigCouchbaseTests.TestApplication.class, + properties = { "spring.cloud.vault.couchbase.enabled=true", + "spring.cloud.vault.couchbase.role=readonly", + "spring.data.couchbase.jmx-enabled=false" }) +public class VaultConfigCouchbaseTests { + + private static final String COUCHBASE_HOST = "localhost"; + + private static final int COUCHBASE_PORT = 9042; + + private static final String COCHBASE_USERNAME = "springvault"; + + private static final String COUCHBASE_PASSWORD = "springvault"; + + private static final String CREATE_USER_AND_GRANT_CQL = "CREATE USER '{{username}}' WITH PASSWORD '{{password}}' NOSUPERUSER;" + + "GRANT SELECT ON ALL KEYSPACES TO {{username}};"; + + @Value("${spring.data.couchbase.username}") + String username; + + @Value("${spring.data.couchbase.password}") + String password; + + @Autowired + CqlSession cqlSession; + + /** + * Initialize the couchbase secret backend. + */ + @BeforeClass + public static void beforeClass() { + + assumeTrue(CanConnect.to(new InetSocketAddress(COUCHBASE_HOST, COUCHBASE_PORT))); + + VaultRule vaultRule = new VaultRule(); + vaultRule.before(); + + if (!vaultRule.prepare().hasSecretBackend("couchbase")) { + vaultRule.prepare().mountSecret("couchbase"); + } + + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + Map connection = new HashMap<>(); + connection.put("hosts", COUCHBASE_HOST); + connection.put("username", COUCHBASE_USERNAME); + connection.put("password", COUCHBASE_PASSWORD); + connection.put("protocol_version", 3); + + vaultOperations.write(String.format("%s/config/connection", "couchbase"), + connection); + + Map role = new HashMap<>(); + + role.put("creation_cql", CREATE_USER_AND_GRANT_CQL); + role.put("consistency", "All"); + + vaultOperations.write("couchbase/roles/readonly", role); + } + + @Test + public void shouldUseAuthenticatedSession() { + assertThat(this.cqlSession.getMetadata().getKeyspace("system")).isNotEmpty(); + } + + @Test + public void shouldConnectUsingCouchbaseClient() { + + try (CqlSession session = CqlSession.builder().withLocalDatacenter("dc1") + .addContactPoint(new InetSocketAddress(COUCHBASE_HOST, COUCHBASE_PORT)) + .withAuthCredentials(this.username, this.password).build()) { + assertThat(session.getMetadata().getKeyspace("system")).isNotEmpty(); + } + } + + @SpringBootApplication + public static class TestApplication { + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } + + } + +} From 17d082b803c69bb34f5753984fc9246ddb65c585 Mon Sep 17 00:00:00 2001 From: "fhitchen@gmail.com" Date: Wed, 3 Jun 2020 14:29:02 -0500 Subject: [PATCH 02/18] Worked. --- ...grationTests.java => CouchbaseSecretIntegrationTests.java | 4 ++-- pom.xml | 4 ++-- .../databases/VaultConfigDatabaseBootstrapConfiguration.java | 5 +++-- .../vault/config/databases/VaultConfigCouchbaseTests.java | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) rename spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java => CouchbaseSecretIntegrationTests.java (97%) diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java b/CouchbaseSecretIntegrationTests.java similarity index 97% rename from spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java rename to CouchbaseSecretIntegrationTests.java index 909a9ade2..566004e88 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.java +++ b/CouchbaseSecretIntegrationTests.java @@ -40,13 +40,13 @@ * This test requires a running Couchbase instance, see {@link #COUCHBASE_HOST} and other * {@code COUCHBASE_*} properties. * - * @author Mark Paluch + * @author Francis J. Hitchens */ public class CouchbaseSecretIntegrationTests extends IntegrationTestSupport { private static final String COUCHBASE_HOST = "localhost"; - private static final int COUCHBASE_PORT = 9042; + private static final int COUCHBASE_PORT = 11210; private static final String COUCHBASE_USERNAME = "springvault"; diff --git a/pom.xml b/pom.xml index 13a876a46..3557321b5 100644 --- a/pom.xml +++ b/pom.xml @@ -190,10 +190,10 @@ flatten-maven-plugin 1.1.0 - + io.spring.javaformat spring-javaformat-maven-plugin diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java index 700cf5874..b0965f3bc 100644 --- a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultConfigDatabaseBootstrapConfiguration.java @@ -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 diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java index 601d254b9..7ce17ce5a 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java @@ -57,7 +57,7 @@ public class VaultConfigCouchbaseTests { private static final int COUCHBASE_PORT = 9042; - private static final String COCHBASE_USERNAME = "springvault"; + private static final String COUCHBASE_USERNAME = "springvault"; private static final String COUCHBASE_PASSWORD = "springvault"; From 454fbc76fc719c02fcefde084268859e107f6c48 Mon Sep 17 00:00:00 2001 From: "fhitchen@gmail.com" Date: Sat, 6 Jun 2020 10:19:06 -0500 Subject: [PATCH 03/18] Initial fumblings --- pom.xml | 5 +++-- .../config/databases/CouchbaseSecretIntegrationTests.avaj | 0 2 files changed, 3 insertions(+), 2 deletions(-) rename CouchbaseSecretIntegrationTests.java => spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj (100%) diff --git a/pom.xml b/pom.xml index 3557321b5..b9a692545 100644 --- a/pom.xml +++ b/pom.xml @@ -217,7 +217,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.0.1 + 3.2.0 @@ -235,7 +235,8 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + + 2.21.0 true diff --git a/CouchbaseSecretIntegrationTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj similarity index 100% rename from CouchbaseSecretIntegrationTests.java rename to spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj From 5065b3c39bf9adcae5fe3601ad18572d43ed7e32 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Wed, 10 Jun 2020 21:23:46 -0500 Subject: [PATCH 04/18] Added correct couchbase-database-plugin test file. --- spring-cloud-vault-config-databases/pom.xml | 5 + .../VaultConfigCouchbaseDatabaseTests.java | 135 ++++++++++++++++++ .../databases/VaultConfigCouchbaseTests.java | 2 +- src/test/bash/create_certificates.sh | 2 +- 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java diff --git a/spring-cloud-vault-config-databases/pom.xml b/spring-cloud-vault-config-databases/pom.xml index 0abbfb99e..7f3f16c5d 100644 --- a/spring-cloud-vault-config-databases/pom.xml +++ b/spring-cloud-vault-config-databases/pom.xml @@ -95,6 +95,11 @@ spring-boot-starter-jdbc test + + com.couchbase.client + java-client + 3.0.5 + diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java new file mode 100644 index 000000000..32740a38b --- /dev/null +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java @@ -0,0 +1,135 @@ +/* + * 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.*; +import com.couchbase.client.java.kv.*; +import com.couchbase.client.java.json.*; +import com.couchbase.client.java.query.*; + +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.springframework.beans.factory.annotation.Autowired; +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}. + * + * @author Francis Hitchens + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = VaultConfigCouchbaseDatabaseTests.TestApplication.class, + properties = { "spring.cloud.vault.database.enabled=true", + "spring.cloud.vault.database.role=readonly", + "spring.datasource.url=jdbc:mysql://localhost:3306/mysql?useSSL=false&serverTimezone=UTC", + "spring.main.allow-bean-definition-overriding=true" }) +public class VaultConfigCouchbaseDatabaseTests { + + private static final int COUCHBASE_PORT = 8091; + + private static final String COUCHBASE_HOST = "localhost"; + + @Value("${spring.datasource.username}") + String username; + + @Value("${spring.datasource.password}") + String password; + + @Autowired + DataSource dataSource; + + /** + * 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() + .isGreaterThanOrEqualTo(Version.parse("0.7.1"))); + + if (!vaultRule.prepare().hasSecretBackend("database")) { + vaultRule.prepare().mountSecret("database"); + } + + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + Map config = new HashMap<>(); + config.put("plugin_name", "couchbase-database-plugin"); + config.put("hosts", "couchbase://localhost"); + config.put("username", "Administrator"); + config.put("password", "Admin123"); + config.put("allowed_roles", "*"); + + vaultOperations.write("database/config/spring-cloud-vault-couchbase", config); + + Map body = new HashMap<>(); + body.put("db_name", "spring-cloud-vault-couchbase"); + body.put("creation_statements", "[{\"name\":\"ro_admin\"}]"); + + vaultOperations.write("database/roles/readonly", body); + } + + @Test + public void shouldConnectUsingDataSource() throws SQLException { + + this.dataSource.getConnection().close(); + } + + @Test + public void shouldConnectUsingJdbcUrlConnection() throws SQLException { + + Cluster cluster = Cluster.connect("localhost", this.username, this.password); + } + + @SpringBootApplication + public static class TestApplication { + + public static void main(String[] args) { + SpringApplication.run(TestApplication.class, args); + } + + } + +} diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java index 7ce17ce5a..52f7c5f93 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseTests.java @@ -55,7 +55,7 @@ public class VaultConfigCouchbaseTests { private static final String COUCHBASE_HOST = "localhost"; - private static final int COUCHBASE_PORT = 9042; + private static final int COUCHBASE_PORT = 65535; private static final String COUCHBASE_USERNAME = "springvault"; diff --git a/src/test/bash/create_certificates.sh b/src/test/bash/create_certificates.sh index 628115635..e7e07546a 100755 --- a/src/test/bash/create_certificates.sh +++ b/src/test/bash/create_certificates.sh @@ -67,7 +67,7 @@ chmod 400 ${CA_DIR}/private/localhost.decrypted.key.pem echo "[INFO] Generating server certificate request" openssl req -config <(cat ${DIR}/openssl.cnf \ - <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1")) \ + <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1,DNS:chanchan2")) \ -reqexts SAN \ -key ${CA_DIR}/private/localhost.key.pem \ -passin pass:changeit \ From 4447b470bcfe94654aba468c05094b661035fdb1 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Sun, 14 Jun 2020 17:37:16 -0500 Subject: [PATCH 05/18] Working couchbase solution. --- .../databases/VaultCouchbaseProperties.java | 2 +- .../VaultConfigCouchbaseDatabaseTests.java | 33 +++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java index 9beb9ddba..17c8c099a 100644 --- a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java @@ -52,7 +52,7 @@ public class VaultCouchbaseProperties implements DatabaseSecretProperties { * Couchbase backend path. */ @NotEmpty - private String backend = "couchbase"; + private String backend = "database"; /** * Target property for the obtained username. diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java index 32740a38b..fbf771bf6 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java @@ -22,13 +22,13 @@ import com.couchbase.client.java.kv.*; import com.couchbase.client.java.json.*; import com.couchbase.client.java.query.*; +import com.couchbase.client.core.error.*; import java.sql.DriverManager; import java.sql.SQLException; import java.util.HashMap; import java.util.Map; - -import javax.sql.DataSource; +import java.time.Duration; import org.junit.BeforeClass; import org.junit.Test; @@ -57,9 +57,10 @@ */ @RunWith(SpringRunner.class) @SpringBootTest(classes = VaultConfigCouchbaseDatabaseTests.TestApplication.class, - properties = { "spring.cloud.vault.database.enabled=true", - "spring.cloud.vault.database.role=readonly", - "spring.datasource.url=jdbc:mysql://localhost:3306/mysql?useSSL=false&serverTimezone=UTC", + properties = { "spring.cloud.vault.couchbase.enabled=true", + "spring.cloud.vault.couchbase.role=readonly", + "spring.data.couchbase.username=foo", + "spring.data.couchbase.password=bar", "spring.main.allow-bean-definition-overriding=true" }) public class VaultConfigCouchbaseDatabaseTests { @@ -67,14 +68,14 @@ public class VaultConfigCouchbaseDatabaseTests { private static final String COUCHBASE_HOST = "localhost"; - @Value("${spring.datasource.username}") + @Value("${spring.data.couchbase.username}") String username; - @Value("${spring.datasource.password}") + @Value("${spring.data.couchbase.password}") String password; - @Autowired - DataSource dataSource; + // @Autowired + Cluster cluster; /** * Initialize the couchbase secret backend. @@ -112,15 +113,19 @@ public static void beforeClass() { } @Test - public void shouldConnectUsingDataSource() throws SQLException { + public void shouldConnectConnection() throws UnambiguousTimeoutException { - this.dataSource.getConnection().close(); + this.cluster = Cluster.connect("127.0.0.1", this.username, this.password); + this.cluster.waitUntilReady(Duration.ofSeconds(5)); + this.cluster.disconnect(); } - @Test - public void shouldConnectUsingJdbcUrlConnection() throws SQLException { + @Test(expected = UnambiguousTimeoutException.class) + public void shouldFailConnectConnection() throws UnambiguousTimeoutException { - Cluster cluster = Cluster.connect("localhost", this.username, this.password); + this.cluster = Cluster.connect("127.0.0.1", this.username, "fake.pwd"); + this.cluster.waitUntilReady(Duration.ofSeconds(5)); + this.cluster.disconnect(); } @SpringBootApplication From 1c94f7fe256e24be295c35cf7e64f3938234e712 Mon Sep 17 00:00:00 2001 From: Francis Hitchens Date: Sat, 20 Jun 2020 09:41:20 -0500 Subject: [PATCH 06/18] added documentation. --- .../src/main/asciidoc/spring-cloud-vault.adoc | 35 +++++++++++++++++++ .../databases/VaultCouchbaseProperties.java | 3 +- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-vault.adoc b/docs/src/main/asciidoc/spring-cloud-vault.adoc index 830ce3608..7f8eb9619 100644 --- a/docs/src/main/asciidoc/spring-cloud-vault.adoc +++ b/docs/src/main/asciidoc/spring-cloud-vault.adoc @@ -900,6 +900,7 @@ Spring Cloud Vault integrates with these backends: * <> * <> +* <> * <> * <> * <> @@ -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 upCouchbase with Vault] + [[vault.config.backends.elasticsearch]] === Elasticsearch diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java index 17c8c099a..41304d9ac 100644 --- a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java @@ -24,8 +24,7 @@ /** * Configuration properties for Vault using the Couchbase integration. * - * @author Mark Paluch - * @author Sebastien Nahelou + * @author Francis Hitchens */ @ConfigurationProperties("spring.cloud.vault.couchbase") @Validated From 511564ca7cb6e20617b61906aab3c5d3996e5c85 Mon Sep 17 00:00:00 2001 From: Francis Hitchens Date: Mon, 22 Jun 2020 13:58:00 -0500 Subject: [PATCH 07/18] Added static role test for Couchbase. --- ...ultConfigCouchbaseDatabaseStaticTests.java | 142 ++++++++++++++++++ .../VaultConfigCouchbaseDatabaseTests.java | 1 - 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java new file mode 100644 index 000000000..71b797965 --- /dev/null +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java @@ -0,0 +1,142 @@ +/* + * 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.*; +import com.couchbase.client.java.kv.*; +import com.couchbase.client.java.json.*; +import com.couchbase.client.java.query.*; +import com.couchbase.client.core.error.*; + +import java.sql.DriverManager; +import java.sql.SQLException; +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.Autowired; +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}. + * + * @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() + .isGreaterThanOrEqualTo(Version.parse("0.7.1"))); + + if (!vaultRule.prepare().hasSecretBackend("database")) { + vaultRule.prepare().mountSecret("database"); + } + + VaultOperations vaultOperations = vaultRule.prepare().getVaultOperations(); + + Map config = new HashMap<>(); + config.put("plugin_name", "couchbase-database-plugin"); + config.put("hosts", "couchbase://localhost"); + config.put("username", "Administrator"); + config.put("password", "Admin123"); + config.put("allowed_roles", "*"); + + vaultOperations.write("database/config/spring-cloud-vault-couchbase", config); + + Map body = new HashMap<>(); + body.put("db_name", "spring-cloud-vault-couchbase"); + body.put("username", "vault-static"); + 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); + } + + } + +} diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java index fbf771bf6..6158eaa05 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java @@ -74,7 +74,6 @@ public class VaultConfigCouchbaseDatabaseTests { @Value("${spring.data.couchbase.password}") String password; - // @Autowired Cluster cluster; /** From 6d587d131e48281b8060334fe7e2de0ae10ad20b Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Mon, 22 Jun 2020 17:19:12 -0500 Subject: [PATCH 08/18] Added note. --- .../databases/VaultConfigCouchbaseDatabaseStaticTests.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java index 71b797965..7d20fe645 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java @@ -53,6 +53,8 @@ * spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is * referenced with {@code ../work/keystore.jks}. * + * Needs existing Couchbase user named vault-static with at least ro_admin privs. + * * @author Francis Hitchens */ @RunWith(SpringRunner.class) From 7ed535ebaeef10e52844224d892340f9f6f8b492 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Mon, 22 Jun 2020 17:32:10 -0500 Subject: [PATCH 09/18] Added couchbase. --- docs/src/main/asciidoc/intro.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/main/asciidoc/intro.adoc b/docs/src/main/asciidoc/intro.adoc index 1ac5a77cc..9d6514e64 100644 --- a/docs/src/main/asciidoc/intro.adoc +++ b/docs/src/main/asciidoc/intro.adoc @@ -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. From c1d3edd58584375a9f562f98789c92f405a2d377 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Tue, 23 Jun 2020 11:43:52 -0500 Subject: [PATCH 10/18] Fixed issues from the PR review. --- pom.xml | 1 - spring-cloud-vault-config-databases/pom.xml | 5 +- .../databases/VaultCouchbaseProperties.java | 1 - .../CouchbaseSecretIntegrationTests.avaj | 113 ------------------ src/test/bash/create_certificates.sh | 2 +- 5 files changed, 3 insertions(+), 119 deletions(-) delete mode 100644 spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj diff --git a/pom.xml b/pom.xml index b9a692545..8ca5697ed 100644 --- a/pom.xml +++ b/pom.xml @@ -235,7 +235,6 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 true diff --git a/spring-cloud-vault-config-databases/pom.xml b/spring-cloud-vault-config-databases/pom.xml index 7f3f16c5d..1ebf79794 100644 --- a/spring-cloud-vault-config-databases/pom.xml +++ b/spring-cloud-vault-config-databases/pom.xml @@ -96,9 +96,8 @@ test - com.couchbase.client - java-client - 3.0.5 + org.springframework.data + spring-data-couchbase diff --git a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java index 41304d9ac..790136d4e 100644 --- a/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java +++ b/spring-cloud-vault-config-databases/src/main/java/org/springframework/cloud/vault/config/databases/VaultCouchbaseProperties.java @@ -43,7 +43,6 @@ public class VaultCouchbaseProperties implements DatabaseSecretProperties { /** * Enable static role usage. * - * @since 2.2 */ private boolean staticRole = false; diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj deleted file mode 100644 index 566004e88..000000000 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/CouchbaseSecretIntegrationTests.avaj +++ /dev/null @@ -1,113 +0,0 @@ -/* - * 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 java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; - -import org.junit.Before; -import org.junit.Test; - -import org.springframework.cloud.vault.config.VaultConfigOperations; -import org.springframework.cloud.vault.config.VaultConfigTemplate; -import org.springframework.cloud.vault.config.VaultProperties; -import org.springframework.cloud.vault.util.CanConnect; -import org.springframework.cloud.vault.util.IntegrationTestSupport; -import org.springframework.cloud.vault.util.Settings; -import org.springframework.vault.core.VaultOperations; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.Assume.assumeTrue; -import static org.springframework.cloud.vault.config.databases.VaultConfigDatabaseBootstrapConfiguration.DatabaseSecretBackendMetadataFactory.forDatabase; - -/** - * Integration tests for {@link VaultConfigTemplate} using the couchbase secret backend. - * This test requires a running Couchbase instance, see {@link #COUCHBASE_HOST} and other - * {@code COUCHBASE_*} properties. - * - * @author Francis J. Hitchens - */ -public class CouchbaseSecretIntegrationTests extends IntegrationTestSupport { - - private static final String COUCHBASE_HOST = "localhost"; - - private static final int COUCHBASE_PORT = 11210; - - private static final String COUCHBASE_USERNAME = "springvault"; - - private static final String COUCHBASE_PASSWORD = "springvault"; - - private static final String CREATE_USER_AND_GRANT_CQL = "CREATE USER '{{username}}' WITH PASSWORD '{{password}}' NOSUPERUSER;" - + "GRANT SELECT ON ALL KEYSPACES TO {{username}};"; - - private VaultProperties vaultProperties = Settings.createVaultProperties(); - - private VaultConfigOperations configOperations; - - private VaultCouchbaseProperties couchbase = new VaultCouchbaseProperties(); - - /** - * Initialize couchbase secret backend. - */ - @Before - public void setUp() { - - assumeTrue(CanConnect.to(new InetSocketAddress(COUCHBASE_HOST, COUCHBASE_PORT))); - - this.couchbase.setEnabled(true); - this.couchbase.setRole("readonly"); - - if (!prepare().hasSecretBackend(this.couchbase.getBackend())) { - prepare().mountSecret(this.couchbase.getBackend()); - } - - VaultOperations vaultOperations = this.vaultRule.prepare().getVaultOperations(); - - Map connection = new HashMap<>(); - connection.put("hosts", COUCHBASE_HOST); - connection.put("username", COUCHBASE_USERNAME); - connection.put("password", COUCHBASE_PASSWORD); - connection.put("protocol_version", 3); - - vaultOperations.write( - String.format("%s/config/connection", this.couchbase.getBackend()), - connection); - - Map role = new HashMap<>(); - - role.put("creation_cql", CREATE_USER_AND_GRANT_CQL); - role.put("consistency", "All"); - - vaultOperations.write(String.format("%s/roles/%s", this.couchbase.getBackend(), - this.couchbase.getRole()), role); - - this.configOperations = new VaultConfigTemplate(vaultOperations, - this.vaultProperties); - } - - @Test - public void shouldCreateCredentialsCorrectly() { - - Map secretProperties = this.configOperations - .read(forDatabase(this.couchbase)).getData(); - - assertThat(secretProperties).containsKeys("spring.data.couchbase.username", - "spring.data.couchbase.password"); - } - -} diff --git a/src/test/bash/create_certificates.sh b/src/test/bash/create_certificates.sh index e7e07546a..628115635 100755 --- a/src/test/bash/create_certificates.sh +++ b/src/test/bash/create_certificates.sh @@ -67,7 +67,7 @@ chmod 400 ${CA_DIR}/private/localhost.decrypted.key.pem echo "[INFO] Generating server certificate request" openssl req -config <(cat ${DIR}/openssl.cnf \ - <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1,DNS:chanchan2")) \ + <(printf "\n[SAN]\nsubjectAltName=DNS:localhost,IP:127.0.0.1")) \ -reqexts SAN \ -key ${CA_DIR}/private/localhost.key.pem \ -passin pass:changeit \ From 077e525803db5de5c002d3359d98ccf2a7d3a142 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Tue, 23 Jun 2020 11:49:03 -0500 Subject: [PATCH 11/18] Fixed issues from the PR review. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8ca5697ed..0c29180c3 100644 --- a/pom.xml +++ b/pom.xml @@ -190,10 +190,10 @@ flatten-maven-plugin 1.1.0 - + io.spring.javaformat spring-javaformat-maven-plugin From 2a03cbcfa303583fc4fc07850473315317cdcb64 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Tue, 23 Jun 2020 11:52:22 -0500 Subject: [PATCH 12/18] Fixed issues from the PR review. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0c29180c3..7becf4a2f 100644 --- a/pom.xml +++ b/pom.xml @@ -193,7 +193,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - + io.spring.javaformat spring-javaformat-maven-plugin From 66bdef62f2d70e063757eefb678fe2d8ca2c2865 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Tue, 23 Jun 2020 11:53:28 -0500 Subject: [PATCH 13/18] Fixed issues from the PR review. --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 7becf4a2f..92bea0296 100644 --- a/pom.xml +++ b/pom.xml @@ -193,7 +193,7 @@ org.apache.maven.plugins maven-checkstyle-plugin - + io.spring.javaformat spring-javaformat-maven-plugin From 922b379c142c49130216aeb1f842337bb56ef23f Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Tue, 23 Jun 2020 11:56:09 -0500 Subject: [PATCH 14/18] Fixed issues from the PR review. --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 92bea0296..13a876a46 100644 --- a/pom.xml +++ b/pom.xml @@ -217,7 +217,7 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.2.0 + 3.0.1 @@ -235,7 +235,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + 2.21.0 true From 1a35a2b2e2dd3935ac0fdf685d391d7ecc97bcde Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Thu, 9 Jul 2020 12:36:53 -0500 Subject: [PATCH 15/18] Updated dynamic role test to use new role+group creation statement for the couchbase plugin. --- docs/src/main/asciidoc/spring-cloud-vault.adoc | 2 +- .../config/databases/VaultConfigCouchbaseDatabaseTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/main/asciidoc/spring-cloud-vault.adoc b/docs/src/main/asciidoc/spring-cloud-vault.adoc index 7f8eb9619..3a7ebe634 100644 --- a/docs/src/main/asciidoc/spring-cloud-vault.adoc +++ b/docs/src/main/asciidoc/spring-cloud-vault.adoc @@ -1037,7 +1037,7 @@ spring.cloud.vault: * `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 upCouchbase with Vault] +See also: https://www.vaultproject.io/docs/secrets/couchbase/index.html[Vault Documentation: Setting up Couchbase with Vault] [[vault.config.backends.elasticsearch]] === Elasticsearch diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java index 6158eaa05..880b12193 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java @@ -106,7 +106,7 @@ public static void beforeClass() { Map body = new HashMap<>(); body.put("db_name", "spring-cloud-vault-couchbase"); - body.put("creation_statements", "[{\"name\":\"ro_admin\"}]"); + body.put("creation_statements", "{\"roles\":[{\"role\":\"ro_admin\"}]}"); vaultOperations.write("database/roles/readonly", body); } From 27cde252f93a98f0c887b5dda1828ecdd058808e Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Sun, 12 Jul 2020 13:09:48 -0500 Subject: [PATCH 16/18] Fixed checkstyle import issues. --- .../VaultConfigCouchbaseDatabaseStaticTests.java | 12 +++--------- .../databases/VaultConfigCouchbaseDatabaseTests.java | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java index 7d20fe645..b419608f8 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java @@ -18,14 +18,9 @@ import java.net.InetSocketAddress; -import com.couchbase.client.java.*; -import com.couchbase.client.java.kv.*; -import com.couchbase.client.java.json.*; -import com.couchbase.client.java.query.*; -import com.couchbase.client.core.error.*; - -import java.sql.DriverManager; -import java.sql.SQLException; +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; @@ -34,7 +29,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java index 880b12193..581297565 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java @@ -18,14 +18,9 @@ import java.net.InetSocketAddress; -import com.couchbase.client.java.*; -import com.couchbase.client.java.kv.*; -import com.couchbase.client.java.json.*; -import com.couchbase.client.java.query.*; -import com.couchbase.client.core.error.*; - -import java.sql.DriverManager; -import java.sql.SQLException; +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; @@ -34,7 +29,6 @@ import org.junit.Test; import org.junit.runner.RunWith; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; From 9e95a4ab5561f38700cfdc673564e0253a959263 Mon Sep 17 00:00:00 2001 From: "Francis J. Hitchens" Date: Thu, 13 Aug 2020 15:57:57 -0500 Subject: [PATCH 17/18] Switched to use Couchbase sandbox image. --- .../databases/VaultConfigCouchbaseDatabaseStaticTests.java | 2 +- .../config/databases/VaultConfigCouchbaseDatabaseTests.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java index b419608f8..c071235f0 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java @@ -96,7 +96,7 @@ public static void beforeClass() { config.put("plugin_name", "couchbase-database-plugin"); config.put("hosts", "couchbase://localhost"); config.put("username", "Administrator"); - config.put("password", "Admin123"); + config.put("password", "password"); config.put("allowed_roles", "*"); vaultOperations.write("database/config/spring-cloud-vault-couchbase", config); diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java index 581297565..97093a2ab 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseTests.java @@ -93,7 +93,7 @@ public static void beforeClass() { config.put("plugin_name", "couchbase-database-plugin"); config.put("hosts", "couchbase://localhost"); config.put("username", "Administrator"); - config.put("password", "Admin123"); + config.put("password", "password"); config.put("allowed_roles", "*"); vaultOperations.write("database/config/spring-cloud-vault-couchbase", config); From 6f2bcabd71a109757c35ab63b1bdef40510885ae Mon Sep 17 00:00:00 2001 From: Francis Hitchens Date: Sat, 15 Aug 2020 08:55:55 -0500 Subject: [PATCH 18/18] fixed pom.xml --- spring-cloud-vault-config-databases/pom.xml | 5 +++-- .../databases/VaultConfigCouchbaseDatabaseStaticTests.java | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/spring-cloud-vault-config-databases/pom.xml b/spring-cloud-vault-config-databases/pom.xml index 1ebf79794..4b700aeb9 100644 --- a/spring-cloud-vault-config-databases/pom.xml +++ b/spring-cloud-vault-config-databases/pom.xml @@ -96,8 +96,9 @@ test - org.springframework.data - spring-data-couchbase + org.springframework.data + spring-data-couchbase + test diff --git a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java index c071235f0..454477eb8 100644 --- a/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java +++ b/spring-cloud-vault-config-databases/src/test/java/org/springframework/cloud/vault/config/databases/VaultConfigCouchbaseDatabaseStaticTests.java @@ -47,7 +47,8 @@ * spring-cloud-vault-config/spring-cloud-vault-config directory as the keystore is * referenced with {@code ../work/keystore.jks}. * - * Needs existing Couchbase user named vault-static with at least ro_admin privs. + * 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 */ @@ -103,7 +104,7 @@ public static void beforeClass() { Map body = new HashMap<>(); body.put("db_name", "spring-cloud-vault-couchbase"); - body.put("username", "vault-static"); + body.put("username", "admin"); body.put("rotation_period", "5m"); body.put("creation_statements", "[{\"name\":\"ro_admin\"}]");