Add support for AWS STS credential types.
We now support assumed role and federation tokens. Closes gh-572 Original pull request gh-575.
This commit is contained in:
@@ -196,10 +196,21 @@ dependency.
|
||||
The integration can be enabled by setting
|
||||
`spring.cloud.vault.aws=true` (default `false`) and providing the role name with `spring.cloud.vault.aws.role=…`.
|
||||
|
||||
Supported AWS credential Types:
|
||||
|
||||
* iam_user (Defaults)
|
||||
* assumed_role (STS)
|
||||
* federation_token (STS)
|
||||
|
||||
The access key and secret key are stored in `cloud.aws.credentials.accessKey`
|
||||
and `cloud.aws.credentials.secretKey` so using Spring Cloud AWS will pick up the generated credentials without further configuration.
|
||||
and `cloud.aws.credentials.secretKey`. So using Spring Cloud AWS will pick up the generated credentials without further configuration.
|
||||
|
||||
You can configure the property names by setting `spring.cloud.vault.aws.access-key-property` and
|
||||
`spring.cloud.vault.aws.secret-key-property`.
|
||||
`spring.cloud.vault.aws.secret-key-property`.
|
||||
|
||||
For STS security token, you can configure the property name by setting `spring.cloud.vault.aws.session-token-key-property`. The security token is stored under `cloud.aws.credentials.sessionToken` (defaults).
|
||||
|
||||
Example: iam_user
|
||||
|
||||
====
|
||||
[source,yaml]
|
||||
@@ -214,11 +225,33 @@ spring.cloud.vault:
|
||||
----
|
||||
====
|
||||
|
||||
Example: assumed_role (STS)
|
||||
====
|
||||
[source,yaml]
|
||||
----
|
||||
spring.cloud.vault:
|
||||
aws:
|
||||
enabled: true
|
||||
role: sts-vault-role
|
||||
backend: aws
|
||||
credential-type: assumed_role
|
||||
access-key-property: cloud.aws.credentials.accessKey
|
||||
secret-key-property: cloud.aws.credentials.secretKey
|
||||
session-token-key-property: cloud.aws.credentials.sessionToken
|
||||
ttl: 3600s
|
||||
role-arn: arn:aws:iam::${AWS_ACCOUNT}:role/sts-app-role
|
||||
----
|
||||
====
|
||||
|
||||
* `enabled` setting this value to `true` enables the AWS backend config usage
|
||||
* `role` sets the role name of the AWS role definition
|
||||
* `backend` sets the path of the AWS mount to use
|
||||
* `access-key-property` sets the property name in which the AWS access key is stored
|
||||
* `secret-key-property` sets the property name in which the AWS secret key is stored
|
||||
* `session-token-key-property` sets the property name in which the AWS STS security token is stored.
|
||||
* `credential-type` sets the aws credential type to use for this backend. Defaults to `iam_user`
|
||||
* `ttl` sets the ttl for the STS token when using `assumed_role` or `federation_token`. Defaults to the ttl specified by the vault role. Min/Max values are also limited to what AWS would support for STS.
|
||||
* `role-arn` sets the IAM role to assume if more than one are configured for the vault role when using `assumed_role`.
|
||||
|
||||
See also: https://www.vaultproject.io/docs/secrets/aws/index.html[Vault Documentation: Setting up AWS with Vault]
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2013-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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Kris Iyer
|
||||
*
|
||||
* Supported Aws credential types.
|
||||
*/
|
||||
package org.springframework.cloud.vault.config.aws;
|
||||
|
||||
public enum AwsCredentialType {
|
||||
|
||||
IAM_USER, ASSUMED_ROLE, FEDERATION_TOKEN
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.springframework.lang.Nullable;
|
||||
* Configuration properties for Vault using the AWS integration.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Kris Iyer
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.vault.aws")
|
||||
public class VaultAwsProperties implements VaultSecretBackendDescriptor {
|
||||
@@ -44,6 +45,11 @@ public class VaultAwsProperties implements VaultSecretBackendDescriptor {
|
||||
*/
|
||||
private String backend = "aws";
|
||||
|
||||
/**
|
||||
* aws credential type
|
||||
*/
|
||||
private AwsCredentialType credentialType = AwsCredentialType.IAM_USER;
|
||||
|
||||
/**
|
||||
* Target property for the obtained access key.
|
||||
*/
|
||||
@@ -54,6 +60,24 @@ public class VaultAwsProperties implements VaultSecretBackendDescriptor {
|
||||
*/
|
||||
private String secretKeyProperty = "cloud.aws.credentials.secretKey";
|
||||
|
||||
/**
|
||||
* Target property for the obtained secret key.
|
||||
*/
|
||||
private String sessionTokenKeyProperty = "cloud.aws.credentials.sessionToken";
|
||||
|
||||
/**
|
||||
*
|
||||
* Role arn for assumed_role in case we have multiple roles associated with the vault
|
||||
* role
|
||||
*/
|
||||
private String roleArn;
|
||||
|
||||
/**
|
||||
* TTL for sts tokens. Defaults to whatever the vault Role may have for Max. Also
|
||||
* limited to what AWS supports to be the max for STS.
|
||||
*/
|
||||
private String ttl;
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
@@ -97,4 +121,36 @@ public class VaultAwsProperties implements VaultSecretBackendDescriptor {
|
||||
this.secretKeyProperty = secretKeyProperty;
|
||||
}
|
||||
|
||||
public AwsCredentialType getCredentialType() {
|
||||
return credentialType;
|
||||
}
|
||||
|
||||
public void setCredentialType(AwsCredentialType credentialType) {
|
||||
this.credentialType = credentialType;
|
||||
}
|
||||
|
||||
public String getSessionTokenKeyProperty() {
|
||||
return sessionTokenKeyProperty;
|
||||
}
|
||||
|
||||
public void setSessionTokenKeyProperty(String sessionTokenKeyProperty) {
|
||||
this.sessionTokenKeyProperty = sessionTokenKeyProperty;
|
||||
}
|
||||
|
||||
public String getRoleArn() {
|
||||
return roleArn;
|
||||
}
|
||||
|
||||
public void setRoleArn(String roleArn) {
|
||||
this.roleArn = roleArn;
|
||||
}
|
||||
|
||||
public String getTtl() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
public void setTtl(String ttl) {
|
||||
this.ttl = ttl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.vault.config.LeasingSecretBackendMetadata;
|
||||
import org.springframework.cloud.vault.config.PropertyNameTransformer;
|
||||
import org.springframework.cloud.vault.config.SecretBackendMetadata;
|
||||
import org.springframework.cloud.vault.config.SecretBackendMetadataFactory;
|
||||
@@ -28,12 +29,17 @@ import org.springframework.cloud.vault.config.VaultSecretBackendDescriptor;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.core.lease.domain.RequestedSecret;
|
||||
import org.springframework.vault.core.lease.domain.RequestedSecret.Mode;
|
||||
import org.springframework.vault.core.util.PropertyTransformer;
|
||||
|
||||
/**
|
||||
* Bootstrap configuration providing support for the AWS secret backend.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @author Kris Iyer
|
||||
*
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(VaultAwsProperties.class)
|
||||
@@ -57,6 +63,7 @@ public class VaultConfigAwsBootstrapConfiguration {
|
||||
* property names to names provided with
|
||||
* {@link VaultAwsProperties#getAccessKeyProperty()} and
|
||||
* {@link VaultAwsProperties#getSecretKeyProperty()}.
|
||||
* {@link VaultAwsProperties#getSessionTokenKeyProperty()}.
|
||||
* @param properties must not be {@literal null}.
|
||||
* @return the {@link SecretBackendMetadata}
|
||||
*/
|
||||
@@ -68,34 +75,100 @@ public class VaultConfigAwsBootstrapConfiguration {
|
||||
transformer.addKeyTransformation("access_key", properties.getAccessKeyProperty());
|
||||
transformer.addKeyTransformation("secret_key", properties.getSecretKeyProperty());
|
||||
|
||||
return new SecretBackendMetadata() {
|
||||
if (properties.getCredentialType() == AwsCredentialType.ASSUMED_ROLE
|
||||
|| properties.getCredentialType() == AwsCredentialType.FEDERATION_TOKEN) {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("%s with Role %s", properties.getBackend(), properties.getRole());
|
||||
}
|
||||
// security token transformer for STS
|
||||
transformer.addKeyTransformation("security_token", properties.getSessionTokenKeyProperty());
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return String.format("%s/creds/%s", properties.getBackend(), properties.getRole());
|
||||
}
|
||||
return new LeasingSecretBackendMetadata() {
|
||||
|
||||
@Override
|
||||
public PropertyTransformer getPropertyTransformer() {
|
||||
return transformer;
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("%s with Role %s", properties.getBackend(), properties.getRole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
@Override
|
||||
public String getPath() {
|
||||
String defaultPath = "%s/sts/%s";
|
||||
|
||||
Map<String, String> variables = new HashMap<>();
|
||||
// do we have any ttl or role parameters configured?
|
||||
if (StringUtils.hasText(properties.getTtl())
|
||||
|| (properties.getCredentialType() == AwsCredentialType.ASSUMED_ROLE
|
||||
&& StringUtils.hasText(properties.getRoleArn()))) {
|
||||
defaultPath += "?";
|
||||
}
|
||||
// ttl for assumed_role or federation_token
|
||||
// pass through to let aws take care of min and max validations
|
||||
// per
|
||||
// the vault role
|
||||
if (StringUtils.hasText(properties.getTtl())) {
|
||||
defaultPath += "ttl=" + properties.getTtl() + "&";
|
||||
}
|
||||
|
||||
variables.put("backend", properties.getBackend());
|
||||
variables.put("key", String.format("creds/%s", properties.getRole()));
|
||||
// role_arn for assumed_role for vault role that has multiple role
|
||||
// associations.
|
||||
if (properties.getCredentialType() == AwsCredentialType.ASSUMED_ROLE
|
||||
&& StringUtils.hasText(properties.getRoleArn())) {
|
||||
defaultPath += "role_arn=" + properties.getRoleArn();
|
||||
}
|
||||
return String.format(defaultPath, properties.getBackend(), properties.getRole());
|
||||
}
|
||||
|
||||
return variables;
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public PropertyTransformer getPropertyTransformer() {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
|
||||
Map<String, String> variables = new HashMap<>();
|
||||
|
||||
variables.put("backend", properties.getBackend());
|
||||
variables.put("key", String.format("sts/%s", properties.getRole()));
|
||||
|
||||
return variables;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Mode getLeaseMode() {
|
||||
return RequestedSecret.Mode.ROTATE;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
return new SecretBackendMetadata() {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return String.format("%s with Role %s", properties.getBackend(), properties.getRole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return String.format("%s/creds/%s", properties.getBackend(), properties.getRole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertyTransformer getPropertyTransformer() {
|
||||
return transformer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getVariables() {
|
||||
|
||||
Map<String, String> variables = new HashMap<>();
|
||||
|
||||
variables.put("backend", properties.getBackend());
|
||||
variables.put("key", String.format("creds/%s", properties.getRole()));
|
||||
|
||||
return variables;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user