0

I am trying to connect to spring vault using role based authentication (spring boot project).

As per documentation, I should be able to connect to spring vault only using approle (pull mode). However, I am getting secrect-id missing exception on application start up.

http://cloud.spring.io/spring-cloud-vault/single/spring-cloud-vault.html#_approle_authentication

When I pass, secret-id also, I am able to connect and properties/values are getting correctly autowired.

Is there any way I can connect with vault using "token + role/role-id" and spring generate secret-id for me automatically at run time using mentioned info.

spring.cloud.vault:
    scheme: http
    host: <host url>
    port: 80
    token : <token>
    generic.application-name: vault/abc/pqr/test
    generic.backend: <some value>
    generic.default-context: vault/abc/pqr/test
    token: <security token>
    authentication: approle
    app-role:
      role-id: <role-id>

POM:

<dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-vault-starter-config</artifactId>
        <version>1.0.0.BUILD-SNAPSHOT</version>
    </dependency>

Please let me know in case any other info is required.

Update

@mp911de, I tried as per your suggestion, however spring-cloud-vault is picking properties set in bootstrap.yml and not one set inside "onApplicationEvent" and thus solution is not working. I tried setting property by "System.setProperty" method but that event didn't worked.

However, if I am setting properties in main before run method, it is working as expected. But I need to load application.properties first (need to pick some configuration from there) and thus don't want to write logic there.

Is there anything wrong in my approach ??

@Component public class LoadVaultProperties implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
private RestTemplate restTemplate = new RestTemplate();

@Override
public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
    try {
        String roleId = getRoleIdForRole(event); //helper method
        String secretId = getSecretIdForRoleId(event); //helper method

        Properties properties = new Properties();

        properties.put("spring.cloud.vault.app-role.secret-id", secretId);
        properties.put("spring.cloud.vault.app-role.role-id", roleId); 

        event.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource(
                PropertySourceBootstrapConfiguration.BOOTSTRAP_PROPERTY_SOURCE_NAME, properties));          
    } catch (Exception ex) {
        throw new IllegalStateException(ex);
    }
}

1 Answers1

2

Spring Vault's AppRole authentication supports two modes but not the pull mode:

  1. Push mode in which you need to supply the secret_id
  2. Authenticating without a secret_id by just passing role_id. This mode requires the role to be created without requiring the secret_id by setting bind_secret_id=false on role creation

Pull mode as mention in the Vault documentation requires the client to know about the secret_id, obtained from a wrapped response. Spring Vault does not fetch a wrapped secret_id but I think that would be a decent enhancement.

Update: Setting system properties before application start:

@SpringBootApplication
public class MyApplication {

    public static void main(String[] args) {

        System.setProperty("spring.cloud.vault.app-role.role-id", "…");
        System.setProperty("spring.cloud.vault.app-role.secret-id", "…");

        SpringApplication.run(MyApplication.class, args);
}

References:

mp911de
  • 17,546
  • 2
  • 55
  • 95
  • Thanks @mp911de for reply. In this case, at what point of time, I need to fetch secret_id in my code and set it to application properties so that it get picked by Spring boot automatically without secrect-id missing exception – Neeraj Kukreti Sep 04 '17 at 02:40
  • 1
    Before you launch `SpringApplication`. You could store it as system property or create a property source and register it with `SpringApplication` before you call `run(…)`. – mp911de Sep 04 '17 at 06:13
  • I tried solution suggested by you, however facing issue with that approach also. I have updated my question with further details. Thanks – Neeraj Kukreti Sep 04 '17 at 10:50
  • `onApplicationEvent(…)` is too late because all properties are already bound at that time. – mp911de Sep 04 '17 at 11:44
  • In our case token and role will reside in spring cloud config server (right now it is in local, but this is the plan), and thus secret-id cannot be fetched until mentioned config is loaded. – Neeraj Kukreti Sep 04 '17 at 14:45
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153623/discussion-between-neeraj-kukreti-and-mp911de). – Neeraj Kukreti Sep 04 '17 at 15:06
  • Fixed in spring-config-vault 2.1. See https://github.com/spring-cloud/spring-cloud-vault/issues/222 – willome Oct 03 '18 at 20:24
  • I need to load secret-id from one out of two environment variables depending on what profile is currently being used for running spring boot. E.g. if profile is dev I need to get SPRING_CLOUD_VAULT_APP_ROLE_SECRET_ID_DEV linux env variable, otherwise if the profile is prod, I need to get SPRING_CLOUD_VAULT_APP_ROLE_SECRET_ID_PROD. Given the fact that I cannot access ``@Autowired private Environment environment;`` to check what is current profile in the main function, what are the ways to implement such kind of logic? – Ievgen Aug 06 '20 at 17:47