2

I am trying to make versioned KV store of vault work with VaultPropertySource so that property can be accessed using @Value. However it is not working as expected. I am using 2.1.2.RELEASE version of spring-vault-core. The intention is to make it work with spring vault and Spring MVC.

I have already tried with @import(EnvironmentVaultConfiguration.class) to no avail.

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.vault.authentication.ClientAuthentication;
import org.springframework.vault.authentication.TokenAuthentication;
import org.springframework.vault.client.VaultEndpoint;
import org.springframework.vault.config.AbstractVaultConfiguration;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.core.env.VaultPropertySource;

import javax.annotation.PostConstruct;
import java.net.URI;
import java.util.List;

@Configuration
@PropertySource("vault.properties")
public class AppConfig extends AbstractVaultConfiguration {

    @Value("${vault.uri}")
    private URI vaultUri;

    @Value("${vault.token}")
    private String token;

    @Value("#{'${vault.sources:}'.split(',')}")
    private List<String> vaultSources;

    @Autowired
    private ConfigurableEnvironment environment;

    @Autowired
    private VaultTemplate vaultTemplate;

    /**
     * Specify an endpoint for connecting to Vault.
     */
    @Override
    public VaultEndpoint vaultEndpoint() {
        return VaultEndpoint.from(vaultUri);
    }

    /**
     * Configure a client authentication.
     * Please consider a more secure authentication method
     * for production use.
     */
    @Override
    public ClientAuthentication clientAuthentication() {
        return new TokenAuthentication(token);
    }

    @PostConstruct
    public void setPropertySource() {
        MutablePropertySources sources = environment.getPropertySources();
        vaultSources.stream().forEach(vs -> {
            sources.addFirst(new VaultPropertySource(vaultTemplate, vs));
        });
    }
}

In the given code, if I provide vault.sources=secret/data/abcd,secret/data/pqrs then it works and returns secrets with data. and metadata. prefix. Which means that it is using generic approach to fetch secrets and not kv one.

If I remove data from path i.e. vault.sources=secret/abcd,secret/pqrs, it simply does not connect and throws exception with 403. This means that it must not be using kv v2.

Can someone please help me with how to use Versioned API of spring-vault in this code?

2 Answers2

0

Key-Value 2 support using VaultPropertySource is not yet released. It will be shipped with Spring Vault 2.2 (see this GitHub issue).

Until then, you can use snapshot builds to verify the code is helpful for your use case.

mp911de
  • 17,546
  • 2
  • 55
  • 95
0

Based on Mark's reponse above, I decided to use VaultPropertySource with PropertyTransformer until we get KV version2 support out of the box.

public class DataMetadataPrefixRemoverPropertyTransformer implements PropertyTransformer {

    private final String dataPrefix = "data.";
    private final String metadataPrefix = "metadata.";

    public Map<String, Object> transformProperties(Map<String, ? extends Object> inputProperties) {
        Map<String, Object> target = new LinkedHashMap(inputProperties.size(), 1.0F);
        Iterator propertiesIterator = inputProperties.entrySet().iterator();

        while(propertiesIterator.hasNext()) {

            Map.Entry<String, ? extends Object> entry = (Map.Entry)propertiesIterator.next();
            String key = entry.getKey();

            // do not add metadata properties to environment for now - do not see a use case for it as of now.
            if (StringUtils.startsWithIgnoreCase(key, metadataPrefix)) {
                continue;
            }

            if (StringUtils.startsWithIgnoreCase(key, dataPrefix)) {
                key = StringUtils.replace(key, dataPrefix, "");
            }

            target.put(key, entry.getValue());
        }
        return target;
    }
}

Hope it can help someone looking for similar solution.