Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Vault docs, uplifted Vault image version #3685

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 25 additions & 25 deletions docs/modules/vault.md
Expand Up @@ -4,31 +4,31 @@ Testcontainers module for [Vault](https://github.com/hashicorp/vault). Vault is

## Usage example

Running Vault in your Junit tests is easily done with an @Rule or @ClassRule such as the following:

```java
public class SomeTest {

@ClassRule
public static VaultContainer vaultContainer = new VaultContainer<>()
.withVaultToken("my-root-token")
.withVaultPort(8200)
.withSecretInVault("secret/testing", "top_secret=password1","db_password=dbpassword1");
@Test
public void someTestMethod() {
//interact with Vault via the container's host, port and Vault token.
//There are many integration clients for Vault so let's just define a general one here:
VaultClient client = new VaultClient(
vaultContainer.getHost(),
vaultContainer.getMappedPort(8200),
"my-root-token");
List<String> secrets = client.readSecret("secret/testing");
}
```
Start Vault container as a `@ClassRule`:

<!--codeinclude-->
[Starting a Vault container](../../modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java) inside_block:vaultContainer
<!--/codeinclude-->

Use CLI to read data from Vault container:

<!--codeinclude-->
[Use CLI to read data](../../modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java) inside_block:readFirstSecretPathWithCli
<!--/codeinclude-->

Use Http API to read data from Vault container:

<!--codeinclude-->
[Use Http API to read data](../../modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java) inside_block:readFirstSecretPathOverHttpApi
<!--/codeinclude-->

Use client library to read data from Vault container:

<!--codeinclude-->
[Use library to read data](../../modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java) inside_block:readWithLibrary
<!--/codeinclude-->

[See full example.](https://github.com/testcontainers/testcontainers-java/blob/master/modules/vault/src/test/java/org/testcontainers/vault/VaultContainerTest.java)

## Why Vault in Junit tests?

Expand Down
Expand Up @@ -60,6 +60,10 @@ public VaultContainer(final DockerImageName dockerImageName) {
withExposedPorts(port);
}

public String getHttpHostAddress() {
return String.format("http://%s:%s", getHost(), getMappedPort(port));
}

@Override
protected void containerIsStarted(InspectContainerResponse containerInfo) {
addSecrets();
Expand Down Expand Up @@ -182,8 +186,8 @@ public SELF withSecretInVault(String path, String firstSecret, String... remaini

/**
* Run initialization commands using the vault cli.
*
* Useful for enableing more secret engines like:
* <p>
* Useful for enabling more secret engines like:
* <pre>
* .withInitCommand("secrets enable pki")
* .withInitCommand("secrets enable transit")
Expand Down
Expand Up @@ -17,10 +17,7 @@ public class VaultClientTest {

@Test
public void writeAndReadMultipleValues() throws VaultException {
try (
VaultContainer<?> vaultContainer = new VaultContainer<>(VaultTestImages.VAULT_IMAGE)
.withVaultToken(VAULT_TOKEN)
) {
try (VaultContainer<?> vaultContainer = new VaultContainer<>("vault:1.1.3").withVaultToken(VAULT_TOKEN)) {
vaultContainer.start();

final VaultConfig config = new VaultConfig()
Expand Down
@@ -1,25 +1,30 @@
package org.testcontainers.vault;

import com.bettercloud.vault.Vault;
import com.bettercloud.vault.VaultConfig;
import com.bettercloud.vault.response.LogicalResponse;
import io.restassured.response.Response;
import org.junit.ClassRule;
import org.junit.Test;
import org.testcontainers.containers.GenericContainer;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import static io.restassured.RestAssured.given;
import static org.assertj.core.api.Assertions.assertThat;

/**
* This test shows the pattern to use the VaultContainer @ClassRule for a junit test. It also has tests that ensure
* the secrets were added correctly by reading from Vault with the CLI and over HTTP.
* the secrets were added correctly by reading from Vault with the CLI, over HTTP and over Client Library.
*/
public class VaultContainerTest {

private static final String VAULT_TOKEN = "my-root-token";

@ClassRule
public static VaultContainer<?> vaultContainer = new VaultContainer<>(VaultTestImages.VAULT_IMAGE)
// vaultContainer {
public static VaultContainer<?> vaultContainer = new VaultContainer<>("vault:1.6.1")
.withVaultToken(VAULT_TOKEN)
.withSecretInVault("secret/testing1", "top_secret=password123")
.withSecretInVault(
Expand All @@ -32,28 +37,30 @@ public class VaultContainerTest {
)
.withInitCommand("secrets enable transit", "write -f transit/keys/my-key");

// }

@Test
public void readFirstSecretPathWithCli() throws IOException, InterruptedException {
public void readFirstSecretPathWithCli() throws Exception {
GenericContainer.ExecResult result = vaultContainer.execInContainer(
"vault",
"kv",
"get",
"-format=json",
"secret/testing1"
);
final String output = result.getStdout().replaceAll("\\r?\\n", "");
assertThat(output).contains("password123");
assertThat(result.getStdout()).contains("password123");
}

@Test
public void readSecondSecretPathWithCli() throws IOException, InterruptedException {
public void readSecondSecretPathWithCli() throws Exception {
GenericContainer.ExecResult result = vaultContainer.execInContainer(
"vault",
"kv",
"get",
"-format=json",
"secret/testing2"
);

final String output = result.getStdout().replaceAll("\\r?\\n", "");
System.out.println("output = " + output);
assertThat(output).contains("password1");
Expand All @@ -63,11 +70,11 @@ public void readSecondSecretPathWithCli() throws IOException, InterruptedExcepti
}

@Test
public void readFirstSecretPathOverHttpApi() throws InterruptedException {
public void readFirstSecretPathOverHttpApi() {
Response response = given()
.header("X-Vault-Token", VAULT_TOKEN)
.when()
.get("http://" + getHostAndPort() + "/v1/secret/data/testing1")
.get(vaultContainer.getHttpHostAddress() + "/v1/secret/data/testing1")
.thenReturn();
assertThat(response.body().jsonPath().getString("data.data.top_secret")).isEqualTo("password123");
}
Expand All @@ -77,7 +84,7 @@ public void readSecondSecretPathOverHttpApi() throws InterruptedException {
Response response = given()
.header("X-Vault-Token", VAULT_TOKEN)
.when()
.get("http://" + getHostAndPort() + "/v1/secret/data/testing2")
.get(vaultContainer.getHttpHostAddress() + "/v1/secret/data/testing2")
.andReturn();

assertThat(response.body().jsonPath().getString("data.data.secret_one")).contains("password1");
Expand All @@ -91,13 +98,67 @@ public void readTransitKeyOverHttpApi() throws InterruptedException {
Response response = given()
.header("X-Vault-Token", VAULT_TOKEN)
.when()
.get("http://" + getHostAndPort() + "/v1/transit/keys/my-key")
.get(vaultContainer.getHttpHostAddress() + "/v1/transit/keys/my-key")
.thenReturn();

assertThat(response.body().jsonPath().getString("data.name")).isEqualTo("my-key");
}

private String getHostAndPort() {
return vaultContainer.getHost() + ":" + vaultContainer.getMappedPort(8200);
@Test
// readWithLibrary {
public void readFirstSecretPathOverClientLibrary() throws Exception {
final VaultConfig config = new VaultConfig()
.address(vaultContainer.getHttpHostAddress())
.token(VAULT_TOKEN)
.build();

final Vault vault = new Vault(config);

final Map<String, String> value = vault.logical().read("secret/testing1").getData();

assertThat(value).containsEntry("top_secret", "password123");
}

// }

@Test
public void readSecondSecretPathOverClientLibrary() throws Exception {
final VaultConfig config = new VaultConfig()
.address(vaultContainer.getHttpHostAddress())
.token(VAULT_TOKEN)
.build();

final Vault vault = new Vault(config);
final Map<String, String> value = vault.logical().read("secret/testing2").getData();

assertThat(value)
.containsEntry("secret_one", "password1")
.containsEntry("secret_two", "password2")
.containsEntry("secret_three", "[\"password3\",\"password3\"]")
.containsEntry("secret_four", "password4");
}

@Test
public void writeSecretOverClientLibrary() throws Exception {
final VaultConfig config = new VaultConfig()
.address(vaultContainer.getHttpHostAddress())
.token(VAULT_TOKEN)
.build();

final Vault vault = new Vault(config);

final Map<String, Object> secrets = new HashMap<>();
secrets.put("value", "world");
secrets.put("other_value", "another world");

// Write operation
final LogicalResponse writeResponse = vault.logical().write("secret/hello", secrets);

assertThat(writeResponse.getRestResponse().getStatus()).isEqualTo(200);

// Read operation
final Map<String, String> value = vault.logical().read("secret/hello").getData();

assertThat(value).containsEntry("value", "world").containsEntry("other_value", "another world");
}
}

This file was deleted.