Support AWS credential generation
Tests require external provided access and secret keys to run. fixes gh-4
This commit is contained in:
1
pom.xml
1
pom.xml
@@ -26,6 +26,7 @@
|
||||
<module>spring-cloud-vault-config-databases</module>
|
||||
<module>spring-cloud-vault-config-consul</module>
|
||||
<module>spring-cloud-vault-config-rabbitmq</module>
|
||||
<module>spring-cloud-vault-config-aws</module>
|
||||
<module>spring-cloud-vault-starter-config</module>
|
||||
<module>docs</module>
|
||||
</modules>
|
||||
|
||||
56
spring-cloud-vault-config-aws/pom.xml
Normal file
56
spring-cloud-vault-config-aws/pom.xml
Normal file
@@ -0,0 +1,56 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-vault-parent</artifactId>
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-vault-config-aws</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>Spring Cloud Vault Config AWS support</name>
|
||||
<description>Spring Cloud Vault Config AWS support</description>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-aws</artifactId>
|
||||
<version>1.1.0.RELEASE</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-vault-core</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-vault-core</artifactId>
|
||||
<type>test-jar</type>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-vault-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.squareup.okhttp</groupId>
|
||||
<artifactId>okhttp</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2016 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
|
||||
*
|
||||
* http://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.aws;
|
||||
|
||||
import org.hibernate.validator.constraints.NotEmpty;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.cloud.vault.VaultSecretBackend;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Configuration properties for Vault using the AWS integration.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.vault.aws")
|
||||
@Data
|
||||
public class VaultAwsProperties implements VaultSecretBackend {
|
||||
|
||||
/**
|
||||
* Enable aws backend usage.
|
||||
*/
|
||||
private boolean enabled = false;
|
||||
|
||||
/**
|
||||
* Role name for credentials.
|
||||
*/
|
||||
private String role;
|
||||
|
||||
/**
|
||||
* aws backend path.
|
||||
*/
|
||||
@NotEmpty
|
||||
private String backend = "aws";
|
||||
|
||||
/**
|
||||
* Target property for the obtained access key.
|
||||
*/
|
||||
@NotEmpty
|
||||
private String accessKeyProperty = "cloud.aws.credentials.accessKey";
|
||||
|
||||
/**
|
||||
* Target property for the obtained secret key.
|
||||
*/
|
||||
@NotEmpty
|
||||
private String secretKeyProperty = "cloud.aws.credentials.secretKey";
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright 2016 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
|
||||
*
|
||||
* http://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.aws;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.vault.SecureBackendAccessor;
|
||||
import org.springframework.cloud.vault.VaultSecretBackend;
|
||||
import org.springframework.cloud.vault.config.SecureBackendAccessorFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties
|
||||
public class VaultConfigAwsBootstrapConfiguration {
|
||||
|
||||
@Bean
|
||||
public SecureBackendAccessorFactory<VaultAwsProperties> secureBackendAccessorFactory() {
|
||||
return new AwsSecureBackendAccessorFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public VaultAwsProperties awsProperties() {
|
||||
return new VaultAwsProperties();
|
||||
}
|
||||
|
||||
static class AwsSecureBackendAccessorFactory
|
||||
implements SecureBackendAccessorFactory<VaultAwsProperties> {
|
||||
|
||||
@Override
|
||||
public SecureBackendAccessor createSecureBackendAccessor(
|
||||
VaultAwsProperties properties) {
|
||||
return forAws(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(VaultSecretBackend secretBackend) {
|
||||
return secretBackend instanceof VaultAwsProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link SecureBackendAccessor} for a secure backend using
|
||||
* {@link VaultAwsProperties}. This accessor transforms Vault's
|
||||
* username/password property names to names provided with
|
||||
* {@link VaultAwsProperties#getAccessKeyProperty()} and
|
||||
* {@link VaultAwsProperties#getSecretKeyProperty()}.
|
||||
*
|
||||
* @param properties must not be {@literal null}.
|
||||
* @return the {@link SecureBackendAccessor}
|
||||
*/
|
||||
public static SecureBackendAccessor forAws(
|
||||
final VaultAwsProperties properties) {
|
||||
Assert.notNull(properties, "VaultAwsProperties must not be null");
|
||||
|
||||
return new SecureBackendAccessor() {
|
||||
|
||||
@Override
|
||||
public Map<String, String> variables() {
|
||||
|
||||
Map<String, String> variables = new HashMap<>();
|
||||
variables.put("backend", properties.getBackend());
|
||||
variables.put("key", String.format("creds/%s", properties.getRole()));
|
||||
return variables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("%s with Role %s", properties.getBackend(),
|
||||
properties.getRole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> transformProperties(
|
||||
Map<String, String> input) {
|
||||
|
||||
Map<String, String> result = new HashMap();
|
||||
result.put(properties.getAccessKeyProperty(), input.get("access_key"));
|
||||
result.put(properties.getSecretKeyProperty(), input.get("secret_key"));
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**
|
||||
* AWS integration with Vault.
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
package org.springframework.cloud.vault.config.aws;
|
||||
@@ -0,0 +1,3 @@
|
||||
# Bootstrap Configuration
|
||||
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
|
||||
org.springframework.cloud.vault.config.aws.VaultConfigAwsBootstrapConfiguration
|
||||
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2016 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
|
||||
*
|
||||
* http://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.aws;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assume.*;
|
||||
import static org.springframework.cloud.vault.config.aws.VaultConfigAwsBootstrapConfiguration.AwsSecureBackendAccessorFactory.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cloud.vault.AbstractIntegrationTests;
|
||||
import org.springframework.cloud.vault.TestRestTemplateFactory;
|
||||
import org.springframework.cloud.vault.VaultClient;
|
||||
import org.springframework.cloud.vault.VaultProperties;
|
||||
import org.springframework.cloud.vault.util.Settings;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultClient} using the aws secret backend. This test
|
||||
* requires AWS credentials and a region, see {@link #AWS_ACCESS_KEY} and
|
||||
* {@link #AWS_SECRET_KEY} to be provided externally.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class AwsSecretIntegrationTests extends AbstractIntegrationTests {
|
||||
|
||||
private final static String AWS_REGION = "eu-west-1";
|
||||
private final static String AWS_ACCESS_KEY = System.getProperty("aws.access.key");
|
||||
private final static String AWS_SECRET_KEY = System.getProperty("aws.secret.key");
|
||||
|
||||
private final static String ARN = "arn:aws:iam::aws:policy/ReadOnlyAccess";
|
||||
|
||||
private VaultProperties vaultProperties = Settings.createVaultProperties();
|
||||
private VaultClient vaultClient = new VaultClient(vaultProperties);
|
||||
private VaultAwsProperties aws = new VaultAwsProperties();
|
||||
|
||||
/**
|
||||
* Initialize the aws secret backend.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
assumeTrue(StringUtils.hasText(AWS_ACCESS_KEY)
|
||||
&& StringUtils.hasText(AWS_SECRET_KEY));
|
||||
|
||||
aws.setEnabled(true);
|
||||
aws.setRole("readonly");
|
||||
|
||||
if (!prepare().hasSecret(aws.getBackend())) {
|
||||
prepare().mountSecret(aws.getBackend());
|
||||
}
|
||||
|
||||
Map<String, String> connection = new HashMap<>();
|
||||
connection.put("region", AWS_REGION);
|
||||
connection.put("access_key", AWS_ACCESS_KEY);
|
||||
connection.put("secret_key", AWS_SECRET_KEY);
|
||||
|
||||
prepare().write(String.format("%s/config/root", aws.getBackend()), connection);
|
||||
|
||||
prepare().write(String.format("%s/roles/%s", aws.getBackend(), aws.getRole()),
|
||||
Collections.singletonMap("arn", ARN));
|
||||
|
||||
vaultClient.setRest(TestRestTemplateFactory.create(vaultProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldCreateCredentialsCorrectly() throws Exception {
|
||||
|
||||
Map<String, String> secretProperties = vaultClient.read(forAws(aws),
|
||||
Settings.token());
|
||||
|
||||
assertThat(secretProperties).containsKeys("cloud.aws.credentials.accessKey",
|
||||
"cloud.aws.credentials.secretKey");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2016 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
|
||||
*
|
||||
* http://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.aws;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.junit.Assume.*;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.IntegrationTest;
|
||||
import org.springframework.boot.test.SpringApplicationConfiguration;
|
||||
import org.springframework.cloud.vault.util.VaultRule;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Integration tests using the aws 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}.
|
||||
* <p>
|
||||
* This test requires AWS credentials and a region, see {@link #AWS_ACCESS_KEY},
|
||||
* {@link #AWS_SECRET_KEY} and the {@link IntegrationTest} properties to be provided
|
||||
* externally.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringApplicationConfiguration(classes = VaultConfigAwsTests.TestApplication.class)
|
||||
@IntegrationTest({ "spring.cloud.vault.aws.enabled=true",
|
||||
"spring.cloud.vault.aws.role=readonly", "cloud.aws.region.auto=false",
|
||||
"cloud.aws.region.static=eu-west-1" })
|
||||
public class VaultConfigAwsTests {
|
||||
|
||||
private final static String AWS_REGION = "eu-west-1";
|
||||
private final static String AWS_ACCESS_KEY = System.getProperty("aws.access.key");
|
||||
private final static String AWS_SECRET_KEY = System.getProperty("aws.secret.key");
|
||||
|
||||
private final static String ARN = "arn:aws:iam::aws:policy/ReadOnlyAccess";
|
||||
|
||||
/**
|
||||
* Initialize the aws secret backend.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
|
||||
assumeTrue(StringUtils.hasText(AWS_ACCESS_KEY)
|
||||
&& StringUtils.hasText(AWS_SECRET_KEY));
|
||||
|
||||
VaultRule vaultRule = new VaultRule();
|
||||
vaultRule.before();
|
||||
|
||||
if (!vaultRule.prepare().hasSecret("aws")) {
|
||||
vaultRule.prepare().mountSecret("aws");
|
||||
}
|
||||
|
||||
Map<String, String> connection = new HashMap<>();
|
||||
connection.put("region", AWS_REGION);
|
||||
connection.put("access_key", AWS_ACCESS_KEY);
|
||||
connection.put("secret_key", AWS_SECRET_KEY);
|
||||
|
||||
vaultRule.prepare().write("aws/config/root", connection);
|
||||
|
||||
vaultRule.prepare().write("aws/roles/readonly",
|
||||
Collections.singletonMap("arn", ARN));
|
||||
}
|
||||
|
||||
@Value("${cloud.aws.credentials.accessKey}")
|
||||
String accessKey;
|
||||
|
||||
@Value("${cloud.aws.credentials.secretKey}")
|
||||
String secretKey;
|
||||
|
||||
@Test
|
||||
public void shouldInitializeAwsProperties() throws Exception {
|
||||
|
||||
assertThat(accessKey).isNotEmpty();
|
||||
assertThat(secretKey).isNotEmpty();
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
public static class TestApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(TestApplication.class, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
spring:
|
||||
application.name: testVaultApp
|
||||
cloud.vault.token: 00000000-0000-0000-0000-000000000000
|
||||
cloud.vault.ssl.trust-store: file:../work/keystore.jks
|
||||
cloud.vault.ssl.trust-store-password: changeit
|
||||
Reference in New Issue
Block a user