Add integration tests for Vault's namespace support.
Closes gh-465.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,6 +1,9 @@
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
*.crt
|
||||
*.hcl
|
||||
*.key
|
||||
.classpath
|
||||
.idea
|
||||
.project
|
||||
|
||||
@@ -20,6 +20,7 @@ env:
|
||||
- VAULT_VER=1.0.3
|
||||
- VAULT_VER=1.1.5
|
||||
- VAULT_VER=1.2.2
|
||||
- EDITION=enterprise VAULT_VER=0.11.0
|
||||
- PROFILE=springNext
|
||||
|
||||
before_install:
|
||||
|
||||
@@ -194,8 +194,11 @@ public class WebClientBuilder {
|
||||
builder.filter((request, next) -> {
|
||||
|
||||
return next.exchange(ClientRequest.from(request)
|
||||
.headers(headers -> defaultHeaders.forEach(headers::addIfAbsent))
|
||||
.build());
|
||||
.headers(headers -> defaultHeaders.forEach((key, value) -> {
|
||||
if (!headers.containsKey(key)) {
|
||||
headers.add(key, value);
|
||||
}
|
||||
})).build());
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2019 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.vault.authentication;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.util.Files;
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.vault.client.ClientHttpConnectorFactory;
|
||||
import org.springframework.vault.client.ClientHttpRequestFactoryFactory;
|
||||
import org.springframework.vault.client.RestTemplateBuilder;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.WebClientBuilder;
|
||||
import org.springframework.vault.core.ReactiveVaultTemplate;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.core.VaultSysOperations;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.ClientOptions;
|
||||
import org.springframework.vault.support.Policy;
|
||||
import org.springframework.vault.support.VaultMount;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestRestTemplateFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.vault.util.Settings.findWorkDir;
|
||||
|
||||
/**
|
||||
* Integration tests for Vault using namespaces (Enterprise feature) with Client
|
||||
* Certificate authentication.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ClientCertificateNamespaceIntegrationTests extends IntegrationTestSupport {
|
||||
|
||||
static final Policy POLICY = Policy.of(Policy.Rule.builder().path("/*")
|
||||
.capabilities(Policy.BuiltinCapabilities.READ,
|
||||
Policy.BuiltinCapabilities.CREATE, Policy.BuiltinCapabilities.UPDATE)
|
||||
.build());
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
|
||||
Assumptions.assumeTrue(prepare().getVersion().isEnterprise(),
|
||||
"Namespaces require enterprise version");
|
||||
|
||||
List<String> namespaces = new ArrayList<>(Arrays.asList("dev/", "marketing/"));
|
||||
List<String> list = prepare().getVaultOperations().list("sys/namespaces");
|
||||
namespaces.removeAll(list);
|
||||
|
||||
for (String namespace : namespaces) {
|
||||
prepare().getVaultOperations()
|
||||
.write("sys/namespaces/" + namespace.replaceAll("/", ""));
|
||||
}
|
||||
|
||||
RestTemplateBuilder devRestTemplate = RestTemplateBuilder.builder()
|
||||
.requestFactory(ClientHttpRequestFactoryFactory
|
||||
.create(new ClientOptions(), Settings.createSslConfiguration()))
|
||||
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
|
||||
.customizer(restTemplate -> restTemplate.getInterceptors()
|
||||
.add(VaultClients.createNamespaceInterceptor("dev")));
|
||||
|
||||
VaultTemplate dev = new VaultTemplate(devRestTemplate,
|
||||
new SimpleSessionManager(new TokenAuthentication(Settings.token())));
|
||||
|
||||
mountKv(dev, "dev-secrets");
|
||||
dev.opsForSys().createOrUpdatePolicy("relaxed", POLICY);
|
||||
|
||||
if (!dev.opsForSys().getAuthMounts().containsKey("cert/")) {
|
||||
dev.opsForSys().authMount("cert", VaultMount.create("cert"));
|
||||
}
|
||||
|
||||
dev.doWithSession((RestOperationsCallback<Object>) restOperations -> {
|
||||
|
||||
File workDir = findWorkDir();
|
||||
|
||||
String certificate = Files.contentOf(
|
||||
new File(workDir, "ca/certs/client.cert.pem"),
|
||||
StandardCharsets.US_ASCII);
|
||||
|
||||
Map<String, String> role = new LinkedHashMap<>();
|
||||
role.put("token_policies", "relaxed");
|
||||
role.put("policies", "relaxed");
|
||||
role.put("certificate", certificate);
|
||||
|
||||
return restOperations.postForEntity("auth/cert/certs/relaxed", role,
|
||||
Map.class);
|
||||
});
|
||||
}
|
||||
|
||||
private void mountKv(VaultTemplate template, String path) {
|
||||
|
||||
VaultSysOperations vaultSysOperations = template.opsForSys();
|
||||
|
||||
Map<String, VaultMount> mounts = vaultSysOperations.getMounts();
|
||||
|
||||
if (!mounts.containsKey(path + "/")) {
|
||||
vaultSysOperations.mount(path, VaultMount.builder().type("kv")
|
||||
.options(Collections.singletonMap("version", "1")).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAuthenticateWithNamespace() {
|
||||
|
||||
ClientHttpRequestFactory clientHttpRequestFactory = ClientHttpRequestFactoryFactory
|
||||
.create(new ClientOptions(),
|
||||
ClientCertificateAuthenticationIntegrationTestBase
|
||||
.prepareCertAuthenticationMethod());
|
||||
|
||||
RestTemplateBuilder builder = RestTemplateBuilder.builder()
|
||||
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
|
||||
.requestFactory(clientHttpRequestFactory)
|
||||
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "dev");
|
||||
|
||||
RestTemplate forAuthentication = builder.build();
|
||||
|
||||
ClientCertificateAuthentication authentication = new ClientCertificateAuthentication(
|
||||
forAuthentication);
|
||||
|
||||
VaultTemplate dev = new VaultTemplate(builder,
|
||||
new SimpleSessionManager(authentication));
|
||||
|
||||
dev.write("dev-secrets/my-secret", Collections.singletonMap("key", "dev"));
|
||||
|
||||
assertThat(dev.read("dev-secrets/my-secret").getRequiredData())
|
||||
.containsEntry("key", "dev");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAuthenticateReactiveWithNamespace() {
|
||||
|
||||
ClientHttpConnector connector = ClientHttpConnectorFactory.create(
|
||||
new ClientOptions(), ClientCertificateAuthenticationIntegrationTestBase
|
||||
.prepareCertAuthenticationMethod());
|
||||
|
||||
WebClientBuilder builder = WebClientBuilder.builder()
|
||||
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
|
||||
.httpConnector(connector)
|
||||
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "dev");
|
||||
|
||||
WebClient forAuthentication = builder.build();
|
||||
|
||||
AuthenticationSteps steps = ClientCertificateAuthentication
|
||||
.createAuthenticationSteps();
|
||||
|
||||
AuthenticationStepsOperator operator = new AuthenticationStepsOperator(steps,
|
||||
forAuthentication);
|
||||
|
||||
ReactiveVaultTemplate dev = new ReactiveVaultTemplate(builder, operator);
|
||||
|
||||
dev.write("dev-secrets/my-secret", Collections.singletonMap("key", "dev"))
|
||||
.as(StepVerifier::create).verifyComplete();
|
||||
|
||||
dev.read("dev-secrets/my-secret").as(StepVerifier::create)
|
||||
.consumeNextWith(actual -> {
|
||||
|
||||
assertThat(actual.getRequiredData()).containsEntry("key", "dev");
|
||||
}).verifyComplete();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright 2019 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.vault.core;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Assumptions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.test.StepVerifier;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.vault.authentication.ClientAuthentication;
|
||||
import org.springframework.vault.authentication.SimpleSessionManager;
|
||||
import org.springframework.vault.authentication.TokenAuthentication;
|
||||
import org.springframework.vault.client.ClientHttpConnectorFactory;
|
||||
import org.springframework.vault.client.ClientHttpRequestFactoryFactory;
|
||||
import org.springframework.vault.client.RestTemplateBuilder;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultEndpointProvider;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.WebClientBuilder;
|
||||
import org.springframework.vault.config.AbstractVaultConfiguration;
|
||||
import org.springframework.vault.support.ClientOptions;
|
||||
import org.springframework.vault.support.Policy;
|
||||
import org.springframework.vault.support.SslConfiguration;
|
||||
import org.springframework.vault.support.VaultMount;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestRestTemplateFactory;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for Vault namespaces (Vault Enterprise feature).
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class VaultNamespaceSecretIntegrationTests extends IntegrationTestSupport {
|
||||
|
||||
static final Policy POLICY = Policy.of(Policy.Rule.builder().path("/*")
|
||||
.capabilities(Policy.BuiltinCapabilities.READ,
|
||||
Policy.BuiltinCapabilities.CREATE, Policy.BuiltinCapabilities.UPDATE)
|
||||
.build());
|
||||
|
||||
RestTemplateBuilder devRestTemplate;
|
||||
RestTemplateBuilder maketingRestTemplate;
|
||||
|
||||
String devToken;
|
||||
String marketingToken;
|
||||
|
||||
@BeforeEach
|
||||
void before() {
|
||||
|
||||
Assumptions.assumeTrue(prepare().getVersion().isEnterprise(),
|
||||
"Namespaces require enterprise version");
|
||||
|
||||
List<String> namespaces = new ArrayList<>(Arrays.asList("dev/", "marketing/"));
|
||||
List<String> list = prepare().getVaultOperations().list("sys/namespaces");
|
||||
namespaces.removeAll(list);
|
||||
|
||||
for (String namespace : namespaces) {
|
||||
prepare().getVaultOperations()
|
||||
.write("sys/namespaces/" + namespace.replaceAll("/", ""));
|
||||
}
|
||||
|
||||
devRestTemplate = RestTemplateBuilder.builder()
|
||||
.requestFactory(ClientHttpRequestFactoryFactory
|
||||
.create(new ClientOptions(), Settings.createSslConfiguration()))
|
||||
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
|
||||
.customizer(restTemplate -> restTemplate.getInterceptors()
|
||||
.add(VaultClients.createNamespaceInterceptor("dev")));
|
||||
|
||||
maketingRestTemplate = RestTemplateBuilder.builder()
|
||||
.requestFactory(ClientHttpRequestFactoryFactory
|
||||
.create(new ClientOptions(), Settings.createSslConfiguration()))
|
||||
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
|
||||
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "marketing");
|
||||
|
||||
VaultTemplate dev = new VaultTemplate(devRestTemplate,
|
||||
new SimpleSessionManager(new TokenAuthentication(Settings.token())));
|
||||
|
||||
mountKv(dev, "dev-secrets");
|
||||
dev.opsForSys().createOrUpdatePolicy("relaxed", POLICY);
|
||||
this.devToken = dev.opsForToken()
|
||||
.create(VaultTokenRequest.builder().withPolicy("relaxed").build())
|
||||
.getToken().getToken();
|
||||
|
||||
VaultTemplate marketing = new VaultTemplate(maketingRestTemplate,
|
||||
new SimpleSessionManager(new TokenAuthentication(Settings.token())));
|
||||
|
||||
mountKv(marketing, "marketing-secrets");
|
||||
marketing.opsForSys().createOrUpdatePolicy("relaxed", POLICY);
|
||||
this.marketingToken = marketing.opsForToken()
|
||||
.create(VaultTokenRequest.builder().withPolicy("relaxed").build())
|
||||
.getToken().getToken();
|
||||
}
|
||||
|
||||
private void mountKv(VaultTemplate template, String path) {
|
||||
|
||||
VaultSysOperations vaultSysOperations = template.opsForSys();
|
||||
|
||||
Map<String, VaultMount> mounts = vaultSysOperations.getMounts();
|
||||
|
||||
if (!mounts.containsKey(path + "/")) {
|
||||
vaultSysOperations.mount(path, VaultMount.builder().type("kv")
|
||||
.options(Collections.singletonMap("version", "1")).build());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void namespaceSecretsAreIsolated() {
|
||||
|
||||
VaultTemplate dev = new VaultTemplate(devRestTemplate,
|
||||
new SimpleSessionManager(new TokenAuthentication(devToken)));
|
||||
VaultTemplate marketing = new VaultTemplate(maketingRestTemplate,
|
||||
new SimpleSessionManager(new TokenAuthentication(marketingToken)));
|
||||
|
||||
dev.write("dev-secrets/my-secret", Collections.singletonMap("key", "dev"));
|
||||
marketing.write("marketing-secrets/my-secret",
|
||||
Collections.singletonMap("key", "marketing"));
|
||||
|
||||
assertThat(dev.read("marketing-secrets/my-secret")).isNull();
|
||||
assertThat(marketing.read("marketing-secrets/my-secret")).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
void namespacesSupportedThroughConfiguration() {
|
||||
|
||||
namespaceSecretsAreIsolated();
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
NamespaceConfiguration.class);
|
||||
VaultOperations operations = context.getBean(VaultOperations.class);
|
||||
assertThat(operations.read("marketing-secrets/my-secret")).isNotNull();
|
||||
|
||||
context.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
void reactiveNamespaceSecretsAreIsolated() {
|
||||
|
||||
VaultTemplate marketing = new VaultTemplate(maketingRestTemplate,
|
||||
new SimpleSessionManager(new TokenAuthentication(marketingToken)));
|
||||
|
||||
WebClientBuilder webClientBuilder = WebClientBuilder.builder()
|
||||
.httpConnector(ClientHttpConnectorFactory.create(new ClientOptions(),
|
||||
Settings.createSslConfiguration()))
|
||||
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
|
||||
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "marketing");
|
||||
|
||||
ReactiveVaultTemplate reactiveMarketing = new ReactiveVaultTemplate(
|
||||
webClientBuilder, () -> Mono.just(VaultToken.of(marketingToken)));
|
||||
|
||||
marketing.write("marketing-secrets/my-secret",
|
||||
Collections.singletonMap("key", "marketing"));
|
||||
|
||||
assertThat(marketing.read("marketing-secrets/my-secret")).isNotNull();
|
||||
|
||||
reactiveMarketing.read("marketing-secrets/my-secret").as(StepVerifier::create)
|
||||
.consumeNextWith(actual -> {
|
||||
assertThat(actual.getRequiredData()).containsEntry("key",
|
||||
"marketing");
|
||||
}).verifyComplete();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class NamespaceConfiguration extends AbstractVaultConfiguration {
|
||||
|
||||
@Override
|
||||
public VaultEndpoint vaultEndpoint() {
|
||||
return TestRestTemplateFactory.TEST_VAULT_ENDPOINT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientAuthentication clientAuthentication() {
|
||||
return new TokenAuthentication(Settings.token());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SslConfiguration sslConfiguration() {
|
||||
return Settings.createSslConfiguration();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RestTemplateBuilder restTemplateBuilder(
|
||||
VaultEndpointProvider endpointProvider,
|
||||
ClientHttpRequestFactory requestFactory) {
|
||||
return super.restTemplateBuilder(endpointProvider, requestFactory)
|
||||
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "marketing");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,13 +39,15 @@ public class Version implements Comparable<Version> {
|
||||
|
||||
final int build;
|
||||
|
||||
final boolean enterprise;
|
||||
|
||||
/**
|
||||
* Creates a new {@link Version} from the given integer values. At least one value has
|
||||
* to be given but a maximum of 4.
|
||||
*
|
||||
* @param parts must not be {@literal null} or empty.
|
||||
*/
|
||||
private Version(int... parts) {
|
||||
private Version(boolean enterprise, int... parts) {
|
||||
|
||||
Assert.notNull(parts, "Parts must not be null");
|
||||
Assert.isTrue(parts.length > 0 && parts.length < 5,
|
||||
@@ -55,6 +57,7 @@ public class Version implements Comparable<Version> {
|
||||
this.minor = parts.length > 1 ? parts[1] : 0;
|
||||
this.bugfix = parts.length > 2 ? parts[2] : 0;
|
||||
this.build = parts.length > 3 ? parts[3] : 0;
|
||||
this.enterprise = enterprise;
|
||||
|
||||
Assert.isTrue(major >= 0, "Major version must be greater or equal zero!");
|
||||
Assert.isTrue(minor >= 0, "Minor version must be greater or equal zero!");
|
||||
@@ -70,10 +73,11 @@ public class Version implements Comparable<Version> {
|
||||
*/
|
||||
public static Version parse(String version) {
|
||||
|
||||
Assert.hasText(version);
|
||||
Assert.hasText(version, "Version must not be empty!");
|
||||
|
||||
String[] parts = version.trim().split("\\.");
|
||||
int[] intParts = new int[parts.length];
|
||||
boolean enterprise = version.endsWith("+ent");
|
||||
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
|
||||
@@ -91,7 +95,7 @@ public class Version implements Comparable<Version> {
|
||||
}
|
||||
}
|
||||
|
||||
return new Version(intParts);
|
||||
return new Version(enterprise, intParts);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,6 +180,10 @@ public class Version implements Comparable<Version> {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isEnterprise() {
|
||||
return enterprise;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -196,7 +204,8 @@ public class Version implements Comparable<Version> {
|
||||
digits.add(build);
|
||||
}
|
||||
|
||||
return StringUtils.collectionToDelimitedString(digits, ".");
|
||||
return StringUtils.collectionToDelimitedString(digits, ".")
|
||||
+ (isEnterprise() ? "+ent" : "");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -207,11 +216,12 @@ public class Version implements Comparable<Version> {
|
||||
return false;
|
||||
Version version = (Version) o;
|
||||
return major == version.major && minor == version.minor
|
||||
&& bugfix == version.bugfix && build == version.build;
|
||||
&& bugfix == version.bugfix && build == version.build
|
||||
&& enterprise == version.enterprise;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(major, minor, bugfix, build);
|
||||
return Objects.hash(major, minor, bugfix, build, enterprise);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,46 +1,160 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
|
||||
###########################################################################
|
||||
# Download and Install Vault #
|
||||
# This script is prepared for caching of the download directory #
|
||||
###########################################################################
|
||||
|
||||
set -o errexit
|
||||
|
||||
VAULT_VER="${VAULT_VER:-1.2.2}"
|
||||
UNAME=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
VAULT_ZIP="vault_${VAULT_VER}_${UNAME}_amd64.zip"
|
||||
IGNORE_CERTS="${IGNORE_CERTS:-no}"
|
||||
EDITION="${EDITION:-oss}"
|
||||
VAULT_OSS="${VAULT_OSS:-1.2.2}"
|
||||
VAULT_ENT="${VAULT_ENT:-0.11.0}"
|
||||
UNAME=$(uname -s | tr '[:upper:]' '[:lower:]')
|
||||
VERBOSE=false
|
||||
VAULT_DIRECTORY=vault
|
||||
DOWNLOAD_DIRECTORY=download
|
||||
readonly script_name="$(basename "${BASH_SOURCE[0]}")"
|
||||
|
||||
# cleanup
|
||||
mkdir -p vault
|
||||
mkdir -p download
|
||||
function say() {
|
||||
echo "$@"
|
||||
}
|
||||
|
||||
if [[ ! -f "download/${VAULT_ZIP}" ]] ; then
|
||||
cd download
|
||||
function verbose() {
|
||||
if [[ ${VERBOSE} == true ]]; then
|
||||
echo "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
function initialize() {
|
||||
# cleanup
|
||||
mkdir -p ${VAULT_DIRECTORY}
|
||||
mkdir -p ${DOWNLOAD_DIRECTORY}
|
||||
}
|
||||
|
||||
function usage() {
|
||||
cat <<EOF
|
||||
Usage: ${script_name} [OPTION]...
|
||||
Download and extract HashiCorp Vault
|
||||
Options:
|
||||
-h|--help Displays this help
|
||||
-v|--version Vault version number
|
||||
-e|--edition oss|enterprise Vault Edition
|
||||
EOF
|
||||
}
|
||||
|
||||
function parse_options() {
|
||||
local option
|
||||
while [[ $# -gt 0 ]]; do
|
||||
option="$1"
|
||||
shift
|
||||
case ${option} in
|
||||
-h | -H | --help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--verbose)
|
||||
VERBOSE=true
|
||||
;;
|
||||
-v | --version)
|
||||
VAULT_VER="$1"
|
||||
verbose "VAULT_VER=${VAULT_VER}"
|
||||
shift
|
||||
;;
|
||||
-e | --edition)
|
||||
EDITION="$1"
|
||||
verbose "EDITION=${EDITION}"
|
||||
shift
|
||||
;;
|
||||
|
||||
*)
|
||||
script_exit "Invalid argument was provided: ${option}" 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
function unpack() {
|
||||
|
||||
cd ${VAULT_DIRECTORY}
|
||||
|
||||
if [[ -f vault ]]; then
|
||||
rm vault
|
||||
fi
|
||||
|
||||
say "Unzipping ${VAULT_FILE}..."
|
||||
verbose " unzip ../${DOWNLOAD_DIRECTORY}/${VAULT_FILE}"
|
||||
if [[ ${VERBOSE} == true ]]; then
|
||||
unzip "../${DOWNLOAD_DIRECTORY}/${VAULT_FILE}"
|
||||
else
|
||||
unzip -q "../${DOWNLOAD_DIRECTORY}/${VAULT_FILE}"
|
||||
fi
|
||||
|
||||
chmod a+x vault
|
||||
|
||||
# check
|
||||
./vault --version
|
||||
cd ..
|
||||
}
|
||||
|
||||
function download() {
|
||||
|
||||
if [[ ! -f "${DOWNLOAD_DIRECTORY}/${VAULT_FILE}" ]]; then
|
||||
cd ${DOWNLOAD_DIRECTORY}
|
||||
# install Vault
|
||||
if [[ "${IGNORE_CERTS}" == "no" ]] ; then
|
||||
echo "Downloading Vault with certs verification"
|
||||
wget "https://releases.hashicorp.com/vault/${VAULT_VER}/${VAULT_ZIP}"
|
||||
say "Downloading Vault from ${VAULT_URL}"
|
||||
|
||||
verbose "wget ${VAULT_URL} -O ${VAULT_FILE}"
|
||||
|
||||
if [[ ${VERBOSE} == true ]]; then
|
||||
wget "${VAULT_URL}" -O "${VAULT_FILE}"
|
||||
else
|
||||
echo "WARNING... Downloading Vault WITHOUT certs verification"
|
||||
wget "https://releases.hashicorp.com/vault/${VAULT_VER}/${VAULT_ZIP}" --no-check-certificate
|
||||
wget "${VAULT_URL}" -q -O "${VAULT_FILE}"
|
||||
fi
|
||||
|
||||
if [[ $? != 0 ]] ; then
|
||||
if [[ $? != 0 ]]; then
|
||||
echo "Cannot download Vault"
|
||||
exit 1
|
||||
fi
|
||||
cd ..
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
cd vault
|
||||
function download_oss() {
|
||||
|
||||
if [[ -f vault ]] ; then
|
||||
rm vault
|
||||
fi
|
||||
VAULT_VER="${VAULT_VER:-${VAULT_OSS}}"
|
||||
VAULT_ZIP="vault_${VAULT_VER}_${UNAME}_amd64.zip"
|
||||
VAULT_FILE=${VAULT_ZIP}
|
||||
VAULT_URL="https://releases.hashicorp.com/vault/${VAULT_VER}/${VAULT_ZIP}"
|
||||
|
||||
unzip ../download/${VAULT_ZIP}
|
||||
chmod a+x vault
|
||||
download
|
||||
unpack
|
||||
}
|
||||
|
||||
# check
|
||||
./vault --version
|
||||
function download_enterprise() {
|
||||
|
||||
VAULT_VER="${VAULT_VER:-${VAULT_ENT}}"
|
||||
VAULT_ZIP="vault-enterprise_${VAULT_VER}%2Bent_${UNAME}_amd64.zip"
|
||||
VAULT_FILE="vault-enterprise_${VAULT_VER}+ent_${UNAME}_amd64.zip"
|
||||
VAULT_URL="http://hc-enterprise-binaries.s3.amazonaws.com/vault/ent/${VAULT_VER}/${VAULT_ZIP}"
|
||||
|
||||
download
|
||||
unpack
|
||||
}
|
||||
|
||||
function main() {
|
||||
|
||||
initialize
|
||||
parse_options "$@"
|
||||
|
||||
if [[ ${EDITION} == 'oss' ]]; then
|
||||
download_oss
|
||||
elif [[ ${EDITION} == 'enterprise' ]]; then
|
||||
download_enterprise
|
||||
else
|
||||
say "Ignoring edition option: ${EDITION} - oss and enterprise supported only"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
||||
Reference in New Issue
Block a user