Polishing.

Rename vault-role configuration property to role for a consistent naming. Introduce path and server-name config properties. Eagerly fetch AWS credentials to fail early if credentials cannot be obtained. Fix properties in reference docs. Javadoc, reference docs wording. Add author tags. Re-generate readme.

Original pull request: gh-175.
See gh-134.
This commit is contained in:
Mark Paluch
2017-10-27 10:44:21 +02:00
parent c936227912
commit f7a7ffa6dc
5 changed files with 128 additions and 37 deletions

View File

@@ -11,8 +11,8 @@ Spring Cloud Vault Config provides client-side support for externalized configur
Specifically for Spring applications:
* Retrieve secrets from Vault and initialize Spring Environment with remote property sources
* Obtain {docs}#vault.config.backends.generic[secrets] secured with SSL
* Retrieve secrets from Vault and initialize Spring Environment with remote property sources.
* Obtain {docs}#vault.config.backends.generic[secrets] secured with SSL.
* Generate credentials for
{docs}#vault.config.backends.mysql[MySQL],
{docs}#vault.config.backends.postgresql[PostgreSQL],
@@ -24,9 +24,11 @@ Specifically for Spring applications:
{docs}#vault.config.authentication.appid[AppId],
{docs}#vault.config.authentication.approle[AppRole],
{docs}#vault.config.authentication.clientcert[Client Certificate],
{docs}#vault.config.authentication.cubbyhole[Cubbyhole], and
{docs}#vault.config.authentication.awsec2[AWS-EC2] authentication
* Bootstrap application context: a parent context for the main application that can be trained to do anything
{docs}#vault.config.authentication.cubbyhole[Cubbyhole],
{docs}#vault.config.authentication.awsec2[AWS-EC2] authentication, and
{docs}#vault.config.authentication.awsiam[AWS-IAM] authentication.
* Bootstrap application context: a parent context for the main application that can be trained to do anything.
== Quick Start

View File

@@ -8,8 +8,8 @@ include::intro.adoc[]
Specifically for Spring applications:
* Retrieve secrets from Vault and initialize Spring Environment with remote property sources
* Obtain {docs}#vault.config.backends.generic[secrets] secured with SSL
* Retrieve secrets from Vault and initialize Spring Environment with remote property sources.
* Obtain {docs}#vault.config.backends.generic[secrets] secured with SSL.
* Generate credentials for
{docs}#vault.config.backends.mysql[MySQL],
{docs}#vault.config.backends.postgresql[PostgreSQL],
@@ -23,9 +23,9 @@ Specifically for Spring applications:
{docs}#vault.config.authentication.clientcert[Client Certificate],
{docs}#vault.config.authentication.cubbyhole[Cubbyhole],
{docs}#vault.config.authentication.awsec2[AWS-EC2] authentication, and
{docs}#vault.config.authentication.awsiam[AWS-IAM] authentication
{docs}#vault.config.authentication.awsiam[AWS-IAM] authentication.
* Bootstrap application context: a parent context for the main application that can be trained to do anything
* Bootstrap application context: a parent context for the main application that can be trained to do anything.
== Quick Start

View File

@@ -273,12 +273,12 @@ spring.cloud.vault:
* `authentication` setting this value to `AWS_EC2` selects the AWS EC2
authentication method
* `role` sets the role name of the AWS EC2 role definition
* `role` sets the name of the role against which the login is being attempted.
* `aws-ec2-path` sets the path of the AWS EC2 mount to use
* `identity-document` sets URL of the PKCS#7 AWS EC2 identity document
* `nonce` used for AWS-EC2 authentication. An empty nonce defaults to nonce generation
See also: https://www.vaultproject.io/docs/auth/aws-ec2.html[Vault Documentation: Using the aws-ec2 auth backend]
See also: https://www.vaultproject.io/docs/auth/aws.html[Vault Documentation: Using the aws auth backend]
[[vault.config.authentication.awsiam]]
=== AWS-IAM authentication
@@ -293,14 +293,15 @@ Instead, it treats AWS as a Trusted Third Party and uses the
4 pieces of information signed by the caller with their IAM credentials
to verify that the caller is indeed using that IAM role.
The current IAM role the application is running in is automatically calculated. If you are
running your application on AWS ECS then the application will use the IAM role assigned
to the ECS task of the running container. If you are running your application naked on top of
an EC2 instance then the IAM role used will be the one assigned to the EC2 instance.
The current IAM role the application is running in is automatically calculated.
If you are running your application on AWS ECS then the application
will use the IAM role assigned to the ECS task of the running container.
If you are running your application naked on top of an EC2 instance then
the IAM role used will be the one assigned to the EC2 instance.
When using the AWS-IAM authentication you must create a role in vault and assign it to your IAM
role. If no vault-role value is supplied in the configuration (as below) then the friendly name
of the current IAM role will be used as the vault role.
When using the AWS-IAM authentication you must create a role in Vault
and assign it to your IAM role. An empty `role` defaults to
the friendly name the current IAM role.
.bootstrap.yml with required AWS-IAM Authentication properties
====
@@ -311,21 +312,27 @@ spring.cloud.vault:
----
====
.bootstrap.yml with all AWS-IAM Authentication properties
====
[source,yaml]
----
spring.cloud.vault:
authentication: AWS_IAM
vault-role: my-dev-role
aws-iam:
role: my-dev-role
aws-path: aws
server-id: some.server.name
----
====
* `vault-role` sets the vault-role that is to be logged in to, this should be bound to your IAM role. If one is not
supplied then the friendly name of the current IAM user will be used as the vault role.
* `role` sets the name of the role against which the login is being attempted. This should be bound to your IAM role. If one is not supplied then the friendly name of the current IAM user will be used as the vault role.
* `aws-path` sets the path of the AWS mount to use
* `server-id` sets the value to use for the `X-Vault-AWS-IAM-Server-ID` header preventing certain types of replay attacks.
See also: https://www.vaultproject.io/docs/auth/aws.html[Vault documentation on configuring iam auth]
AWS-IAM requires the AWS Java SDK dependency (`com.amazonaws:aws-java-sdk-core`)
as the authentication implementation uses AWS SDK types for credentials and request signing.
See also: https://www.vaultproject.io/docs/auth/aws.html[Vault Documentation: Using the aws auth backend]
[[vault.config.authentication.clientcert]]
=== TLS certificate authentication

View File

@@ -15,24 +15,46 @@
*/
package org.springframework.cloud.vault.config;
import java.net.URI;
import java.util.concurrent.atomic.AtomicReference;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.vault.config.VaultProperties.AwsIamProperties;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.vault.authentication.*;
import org.springframework.vault.authentication.AppIdAuthentication;
import org.springframework.vault.authentication.AppIdAuthenticationOptions;
import org.springframework.vault.authentication.AppIdUserIdMechanism;
import org.springframework.vault.authentication.AppRoleAuthentication;
import org.springframework.vault.authentication.AppRoleAuthenticationOptions;
import org.springframework.vault.authentication.AwsEc2Authentication;
import org.springframework.vault.authentication.AwsEc2AuthenticationOptions;
import org.springframework.vault.authentication.AwsIamAuthentication;
import org.springframework.vault.authentication.AwsIamAuthenticationOptions;
import org.springframework.vault.authentication.ClientAuthentication;
import org.springframework.vault.authentication.ClientCertificateAuthentication;
import org.springframework.vault.authentication.CubbyholeAuthentication;
import org.springframework.vault.authentication.CubbyholeAuthenticationOptions;
import org.springframework.vault.authentication.IpAddressUserId;
import org.springframework.vault.authentication.MacAddressUserId;
import org.springframework.vault.authentication.StaticUserId;
import org.springframework.vault.authentication.TokenAuthentication;
import org.springframework.vault.authentication.AwsEc2AuthenticationOptions.Nonce;
import org.springframework.vault.authentication.AwsIamAuthenticationOptions.AwsIamAuthenticationOptionsBuilder;
import org.springframework.vault.support.VaultToken;
import org.springframework.web.client.RestOperations;
import java.net.URI;
/**
* Factory for {@link ClientAuthentication}.
*
* @author Mark Paluch
* @author Kevin Holditch
* @since 1.1
*/
@RequiredArgsConstructor
@@ -45,7 +67,7 @@ class ClientAuthenticationFactory {
/**
* @return a new {@link ClientAuthentication}.
*/
public ClientAuthentication createClientAuthentication() {
ClientAuthentication createClientAuthentication() {
switch (vaultProperties.getAuthentication()) {
@@ -161,18 +183,30 @@ class ClientAuthenticationFactory {
private ClientAuthentication awsIamAuthentication(VaultProperties vaultProperties) {
AwsIamAuthenticationOptions.AwsIamAuthenticationOptionsBuilder awsIamAuthenticationOptionsBuilder = AwsIamAuthenticationOptions.builder();
AwsIamProperties awsIam = vaultProperties.getAwsIam();
if (vaultProperties.getAwsIam() != null && vaultProperties.getAwsIam().getVaultRole() != null)
awsIamAuthenticationOptionsBuilder.role(vaultProperties.getAwsIam().getVaultRole());
AWSCredentialsProvider credentialsProvider = AwsCredentialProvider
.getAwsCredentialsProvider();
AwsIamAuthenticationOptions options = awsIamAuthenticationOptionsBuilder
.credentialsProvider(new DefaultAWSCredentialsProviderChain())
.build();
AwsIamAuthenticationOptionsBuilder builder = AwsIamAuthenticationOptions
.builder();
return new AwsIamAuthentication(options, restOperations);
if (StringUtils.hasText(awsIam.getRole())) {
builder.role(awsIam.getRole());
}
}
if (StringUtils.hasText(awsIam.getServerName())) {
builder.serverName(awsIam.getServerName());
}
builder.path(awsIam.getAwsPath()) //
.credentialsProvider(credentialsProvider);
AwsIamAuthenticationOptions options = builder.credentialsProvider(
credentialsProvider).build();
return new AwsIamAuthentication(options, restOperations);
}
private ClientAuthentication cubbyholeAuthentication() {
@@ -186,4 +220,38 @@ class ClientAuthenticationFactory {
return new CubbyholeAuthentication(options, restOperations);
}
private static class AwsCredentialProvider {
private static AWSCredentialsProvider getAwsCredentialsProvider() {
final DefaultAWSCredentialsProviderChain backingCredentialsProvider = DefaultAWSCredentialsProviderChain
.getInstance();
// Eagerly fetch credentials preventing lag during the first, actual login.
final AWSCredentials firstAccess = backingCredentialsProvider
.getCredentials();
final AtomicReference<AWSCredentials> once = new AtomicReference<>(
firstAccess);
return new AWSCredentialsProvider() {
@Override
public AWSCredentials getCredentials() {
if (once.compareAndSet(firstAccess, null)) {
return firstAccess;
}
return backingCredentialsProvider.getCredentials();
}
@Override
public void refresh() {
backingCredentialsProvider.refresh();
}
};
}
}
}

View File

@@ -32,6 +32,7 @@ import org.springframework.validation.annotation.Validated;
/**
* @author Spencer Gibb
* @author Mark Paluch
* @author Kevin Holditch
*/
@ConfigurationProperties("spring.cloud.vault")
@Data
@@ -230,10 +231,23 @@ public class VaultProperties implements EnvironmentAware {
@Data
public static class AwsIamProperties {
/**
* Name of the vault role, optional if not specified then the friendly IAM name will be used.
* Mount path of the AWS authentication backend.
*/
private String vaultRole;
@NotEmpty
private String awsPath = "aws";
/**
* Name of the role, optional. Defaults to the friendly IAM name if not set.
*/
private String role = "";
/**
* Name of the server used to set {@code X-Vault-AWS-IAM-Server-ID} header in the
* headers of login requests.
*/
private String serverName;
}
@Data