Search code examples
spring-bootauthenticationkubernetesvaultspring-vault

Kubernetes Authentication no re-create token


I can't configure spring.cloud.vault to re-authenticate the application when the token expire. I use Kubernetes Authentication with service token, bun in the SessionManager class I find the batch token (it`s TTL ending and spring vault just throw errors) and it cant be re-new

What I have to check or search in first time? Or how I can fix the error?

I can`t use Vault Agent in my company

Stack trace:

Caused by: org.springframework.vault.VaultException: Status 403 Forbidden: permission denied; nested exception is org.springframework.web.client.HttpClientErrorException$Forbidden: 403 Forbidden: "{"errors":["permission denied"]}<EOL>"
at org.springframework.vault.client.VaultResponses.buildException(VaultResponses.java:85)
at org.springframework.vault.core.VaultKeyValueAccessor.lambda$doRead$2(VaultKeyValueAccessor.java:174)
at org.springframework.vault.core.VaultTemplate.doWithSession(VaultTemplate.java:448)
at org.springframework.vault.core.VaultKeyValueAccessor.doRead(VaultKeyValueAccessor.java:163)
at org.springframework.vault.core.VaultKeyValueAccessor.doRead(VaultKeyValueAccessor.java:132)
at org.springframework.vault.core.VaultKeyValueAccessor.doRead(VaultKeyValueAccessor.java:107)
at org.springframework.vault.core.VaultKeyValue1Template.get(VaultKeyValue1Template.java:69)
at sbp.bpm.designer.utils.credential.VaultAwareCredentialSetup.lambda$createSecretRetriever$2(VaultAwareCredentialSetup.java:127)
at com.google.common.cache.LocalCache$LocalManualCache$1.load(LocalCache.java:4868)
at com.google.common.cache.LocalCache$LoadingValueReference.loadFuture(LocalCache.java:3533)
at com.google.common.cache.LocalCache$Segment.loadSync(LocalCache.java:2282)
at com.google.common.cache.LocalCache$Segment.lockedGetOrLoad(LocalCache.java:2159)
at com.google.common.cache.LocalCache$Segment.get(LocalCache.java:2049)
... 16 common frames omitted

Here is the application.yaml config

spring:
  servlet:
    multipart:
      enabled: true
      max-file-size: 10MB
      max-request-size: 10MB
  cloud:
    vault:
      enabled: true
      uri: http://vault.url:8080
      authentication: KUBERNETES
      kubernetes:
        role: role
        kubernetes-path: k8s/dap.url.com
        service-account-token-file: /var/run/secrets/kubernetes.io/serviceaccount/token

Dependency version:

<spring-cloud-vault.version>3.1.3</spring-cloud-vault.version> <spring-cloud-starter-config.version>3.1.7</spring-cloud-starter-config.version>


Solution

  • Spring vault don`t use own revoke/renew logic if your token has type = renew false, this code helps me:

    @Component                              
    @ConditionalOnProperty(name = "spring.cloud.vault.enabled", havingValue = "true") 
    public class CustomVaultSessionManager implements SessionManager {
    
        private final ClientAuthentication authentication;
    
        private Optional<VaultToken> actualToken = Optional.empty();
        private Optional<Long> expirationTime = Optional.empty();
    
        public CustomVaultSessionManager(ClientAuthentication authentication) {
            this.authentication = authentication;
        }
    
        @NotNull
        @Synchronized
        @Override
        public VaultToken getSessionToken() {
            if (isTokenExpired() || actualToken.isEmpty()) {
                actualToken = Optional.of(generateNewToken());
                log.info("Get session token : {}", actualToken.get());
            }
             return actualToken.get();
        }
    
        private boolean isTokenExpired() {
            Boolean isTokenExpired = expirationTime
                    .map(expiration -> expiration < System.currentTimeMillis())
                    .orElse(false);
            return isTokenExpired;
        }
    
        private VaultToken generateNewToken() {
            VaultToken newToken = authentication.login();
            if (newToken instanceof LoginToken) {
                LoginToken loginToken = (LoginToken) newToken;
                expirationTime = updateExpirationTime(loginToken);
            } else {
                expirationTime = Optional.empty();
            }
            return newToken;
        }
    
        private Optional<Long> updateExpirationTime(LoginToken loginToken) {
            return Optional.of(System.currentTimeMillis() + loginToken.getLeaseDuration().toMillis() - 500);
        } }