spring-cloud / spring-cloud-vault

Configuration Integration with HashiCorp Vault
http://cloud.spring.io/spring-cloud-vault/
Apache License 2.0
274 stars 152 forks source link

Vault AppRole authentication with role-id provided, secret-id wrapped does not work #651

Closed MrWong99 closed 2 years ago

MrWong99 commented 2 years ago

Describe the bug I want to authenticate my app against Vault using the AppRole login mechanism. I successfully did that when providing both the role-id and secret-id to my app. However since it is more secure/auditable I wanted to wrap my secret-id as described in the Vault tutorials.

This works fine if I unwrap it previously via curl and give the unwrapped secret-id to my app, however if I let the spring-cloud-vault-config-starter sort it out itself it fails with the error message displayed below.

I think its because this condition always wants to pull the secret-id instead of unwrapping it. In the Spring-cloud-vault docs this is described as a valid use-case though and should be done by providing the role-id and the token contains the wrapping token to retrieve the secret-id.

Sample

application.yml:

spring.config.import: vault://my/secret/path
spring.cloud.vault:
  enabled: true
  uri: https://my-vault.server
  token: my_wrapping_token_for_secret-id # e.g. s.aB2124324c14
  authentication: APPROLE
  app-role:
    role-id: my-app_role-id # e.g. f05133d5-231f-4673-ad74-1a8c476afc67
    role: my-app
  kv.enabled: true

Exception during startup:

org.springframework.vault.authentication.VaultLoginException: Cannot get Secret id using AppRole: permission denied; nested exception is org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden: "{"errors":["permission denied"]}<EOL>"
at org.springframework.vault.authentication.AppRoleAuthentication.getSecretId(AppRoleAuthentication.java:259) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.authentication.AppRoleAuthentication.getAppRoleLoginBody(AppRoleAuthentication.java:306) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.authentication.AppRoleAuthentication.createTokenUsingAppRole(AppRoleAuthentication.java:182) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.authentication.AppRoleAuthentication.login(AppRoleAuthentication.java:172) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.authentication.LifecycleAwareSessionManager.doGetSessionToken(LifecycleAwareSessionManager.java:280) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.authentication.LifecycleAwareSessionManager.getSessionToken(LifecycleAwareSessionManager.java:266) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.VaultTemplate.lambda$getSessionInterceptor$1(VaultTemplate.java:253) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.vault.client.RestTemplateBuilder.lambda$createTemplate$4(RestTemplateBuilder.java:239) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.vault.client.VaultClients.lambda$createRestTemplate$0(VaultClients.java:122) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:77) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:776) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:334) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.vault.core.VaultTemplate.lambda$doRead$5(VaultTemplate.java:461) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.VaultTemplate.doWithSession(VaultTemplate.java:448) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.VaultTemplate.doRead(VaultTemplate.java:458) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.VaultTemplate.read(VaultTemplate.java:353) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.lease.SecretLeaseContainer.doGetSecrets(SecretLeaseContainer.java:645) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.lease.SecretLeaseContainer.doStart(SecretLeaseContainer.java:390) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.lease.SecretLeaseContainer.start(SecretLeaseContainer.java:380) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.lease.SecretLeaseContainer.addRequestedSecret(SecretLeaseContainer.java:343) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.env.LeaseAwareVaultPropertySource.loadProperties(LeaseAwareVaultPropertySource.java:176) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.env.LeaseAwareVaultPropertySource.<init>(LeaseAwareVaultPropertySource.java:161) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.vault.core.env.LeaseAwareVaultPropertySource.<init>(LeaseAwareVaultPropertySource.java:119) ~[spring-vault-core-2.3.2.jar:2.3.2]
at org.springframework.cloud.vault.config.VaultConfigDataLoader.createLeasingPropertySource(VaultConfigDataLoader.java:287) ~[spring-cloud-vault-config-3.1.1.jar:3.1.1]
at org.springframework.cloud.vault.config.VaultConfigDataLoader.lambda$loadConfigData$1(VaultConfigDataLoader.java:163) ~[spring-cloud-vault-config-3.1.1.jar:3.1.1]
at org.springframework.cloud.vault.config.VaultConfigDataLoader.createConfigData(VaultConfigDataLoader.java:232) ~[spring-cloud-vault-config-3.1.1.jar:3.1.1]
at org.springframework.cloud.vault.config.VaultConfigDataLoader.loadConfigData(VaultConfigDataLoader.java:163) ~[spring-cloud-vault-config-3.1.1.jar:3.1.1]
at org.springframework.cloud.vault.config.VaultConfigDataLoader.load(VaultConfigDataLoader.java:140) ~[spring-cloud-vault-config-3.1.1.jar:3.1.1]
at org.springframework.cloud.vault.config.VaultConfigDataLoader.load(VaultConfigDataLoader.java:93) ~[spring-cloud-vault-config-3.1.1.jar:3.1.1]
at org.springframework.boot.context.config.ConfigDataLoaders.load(ConfigDataLoaders.java:107) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataImporter.load(ConfigDataImporter.java:128) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataImporter.resolveAndLoad(ConfigDataImporter.java:86) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataEnvironmentContributors.withProcessedImports(ConfigDataEnvironmentContributors.java:116) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataEnvironment.processWithProfiles(ConfigDataEnvironment.java:311) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataEnvironment.processAndApply(ConfigDataEnvironment.java:232) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:102) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.context.config.ConfigDataEnvironmentPostProcessor.postProcessEnvironment(ConfigDataEnvironmentPostProcessor.java:94) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEnvironmentPreparedEvent(EnvironmentPostProcessorApplicationListener.java:102) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.env.EnvironmentPostProcessorApplicationListener.onApplicationEvent(EnvironmentPostProcessorApplicationListener.java:87) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[spring-context-5.3.20.jar:5.3.20]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[spring-context-5.3.20.jar:5.3.20]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[spring-context-5.3.20.jar:5.3.20]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:131) ~[spring-context-5.3.20.jar:5.3.20]
at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:85) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplicationRunListeners.lambda$environmentPrepared$2(SpringApplicationRunListeners.java:66) ~[spring-boot-2.7.0.jar:2.7.0]
at java.util.ArrayList.forEach(ArrayList.java:1541) ~[?:?]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:120) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplicationRunListeners.doWithListeners(SpringApplicationRunListeners.java:114) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:65) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:344) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:302) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar:2.7.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar:2.7.0]
at de.kisters.energy.infra.logging.LoggingApplication.main(LoggingApplication.java:69) ~[classes/:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]
at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[application/:?]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[application/:?]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[application/:?]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) ~[application/:?]
 Caused by: org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden: "{"errors":["permission denied"]}<EOL>"
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:109) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:168) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:122) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:819) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:777) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:437) ~[spring-web-5.3.20.jar:5.3.20]
at org.springframework.vault.authentication.AppRoleAuthentication.getSecretId(AppRoleAuthentication.java:254) ~[spring-vault-core-2.3.2.jar:2.3.2]
... 67 more
mp911de commented 2 years ago

The configured token: my_wrapping_token_for_secret-id has not the permission to obtain the Secret Id for pulling the Secret Id. As you've provided the role name (app-role.role: my-app), the Secret Id is assumed to be pulled. If you remove the role name, then the Secret Id is assumed to be a wrapped Id.

Looking at the documentation matrix, we need to revisit the docs as the matrix seems misleading.

MrWong99 commented 2 years ago

That was the issue, thank you :)