Skip to content

feat: make HashiCorp vault authentication extensible #4822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions extensions/common/vault/vault-hashicorp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,18 @@
*
* Contributors:
* Mercedes-Benz Tech Innovation GmbH - Initial API and Implementation
* Cofinity-X - implement extensible authentication
*
*/

plugins {
`java-library`
}

dependencies {
api(project(":spi:common:core-spi"))
api(project(":spi:common:http-spi"))
api(project(":spi:common:vault-hashicorp-spi"))

implementation(project(":core:common:lib:util-lib"))

Expand All @@ -28,7 +31,4 @@ dependencies {
testImplementation(libs.testcontainers.junit)
testImplementation(libs.testcontainers.vault)
implementation(libs.bouncyCastle.bcpkixJdk18on)

}


Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Contributors:
* Mercedes-Benz Tech Innovation GmbH - Initial API and Implementation
* Materna Information & Communications SE - Refactoring
* Cofinity-X - implement extensible authentication
*
*/

Expand All @@ -27,6 +28,7 @@
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.spi.security.Vault;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultSettings;
import org.eclipse.edc.vault.hashicorp.spi.auth.HashicorpVaultTokenProvider;
import org.eclipse.edc.vault.hashicorp.util.PathUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
Expand All @@ -51,12 +53,18 @@ public class HashicorpVault implements Vault {
private final HashicorpVaultSettings settings;
private final EdcHttpClient httpClient;
private final ObjectMapper objectMapper;
private final HashicorpVaultTokenProvider tokenProvider;

public HashicorpVault(@NotNull Monitor monitor, HashicorpVaultSettings settings, EdcHttpClient httpClient, ObjectMapper objectMapper) {
public HashicorpVault(@NotNull Monitor monitor,
HashicorpVaultSettings settings,
EdcHttpClient httpClient,
ObjectMapper objectMapper,
HashicorpVaultTokenProvider tokenProvider) {
this.monitor = monitor;
this.settings = settings;
this.httpClient = httpClient;
this.objectMapper = objectMapper;
this.tokenProvider = tokenProvider;
}

@Override
Expand All @@ -65,7 +73,7 @@ public HashicorpVault(@NotNull Monitor monitor, HashicorpVaultSettings settings,
var requestUri = getSecretUrl(key, VAULT_SECRET_DATA_PATH);
var request = new Request.Builder()
.url(requestUri)
.header(VAULT_TOKEN_HEADER, settings.token())
.header(VAULT_TOKEN_HEADER, tokenProvider.vaultToken())
.get()
.build();

Expand Down Expand Up @@ -102,7 +110,7 @@ public Result<Void> storeSecret(String key, String value) {
var requestPayload = Map.of("data", Map.of(VAULT_DATA_ENTRY_NAME, value));
var request = new Request.Builder()
.url(requestUri)
.header(VAULT_TOKEN_HEADER, settings.token())
.header(VAULT_TOKEN_HEADER, tokenProvider.vaultToken())
.post(jsonBody(requestPayload))
.build();

Expand All @@ -122,7 +130,7 @@ public Result<Void> deleteSecret(String key) {
var requestUri = getSecretUrl(key, VAULT_SECRET_METADATA_PATH);
var request = new Request.Builder()
.url(requestUri)
.header(VAULT_TOKEN_HEADER, settings.token())
.header(VAULT_TOKEN_HEADER, tokenProvider.vaultToken())
.delete()
.build();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
* Contributors:
* Mercedes-Benz Tech Innovation GmbH - Initial API and Implementation
* Mercedes-Benz Tech Innovation GmbH - Implement automatic Hashicorp Vault token renewal
* Cofinity-X - implement extensible authentication
*
*/

Expand All @@ -29,7 +30,9 @@
import org.eclipse.edc.spi.system.ServiceExtensionContext;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultHealthService;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultSettings;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultTokenRenewService;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultTokenRenewTask;
import org.eclipse.edc.vault.hashicorp.spi.auth.HashicorpVaultTokenProvider;
import org.jetbrains.annotations.NotNull;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;
Expand All @@ -45,6 +48,9 @@ public class HashicorpVaultExtension implements ServiceExtension {
@Inject
private ExecutorInstrumentation executorInstrumentation;

@Inject
private HashicorpVaultTokenProvider tokenProvider;

@Configuration
private HashicorpVaultSettings config;

Expand All @@ -59,29 +65,31 @@ public String name() {

@Provider
public Vault hashicorpVault() {
return new HashicorpVault(monitor, config, httpClient, MAPPER);
return new HashicorpVault(monitor, config, httpClient, MAPPER, tokenProvider);
}

@Provider
public SignatureService signatureService() {
return new HashicorpVaultSignatureService(monitor, config, httpClient, MAPPER);
return new HashicorpVaultSignatureService(monitor, config, httpClient, MAPPER, tokenProvider);
}

@Override
public void initialize(ServiceExtensionContext context) {
monitor = context.getMonitor().withPrefix(NAME);

var tokenRenewService = new HashicorpVaultTokenRenewService(httpClient, MAPPER, config, tokenProvider, monitor);
tokenRenewalTask = new HashicorpVaultTokenRenewTask(
NAME,
executorInstrumentation,
createHealthService(),
tokenRenewService,
config.renewBuffer(),
monitor);
}

@Provider
public @NotNull HashicorpVaultHealthService createHealthService() {
if (healthService == null) {
healthService = new HashicorpVaultHealthService(httpClient, MAPPER, monitor, config);
healthService = new HashicorpVaultHealthService(httpClient, config, tokenProvider);
}
return healthService;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2025 Confinity-X
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
Expand All @@ -9,6 +9,7 @@
*
* Contributors:
* Cofinity-X - initial API and implementation
* Cofinity-X - implement extensible authentication
*
*/

Expand All @@ -24,6 +25,7 @@
import org.eclipse.edc.spi.result.Result;
import org.eclipse.edc.spi.security.SignatureService;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultSettings;
import org.eclipse.edc.vault.hashicorp.spi.auth.HashicorpVaultTokenProvider;

import java.io.IOException;
import java.util.Base64;
Expand All @@ -41,13 +43,15 @@ public class HashicorpVaultSignatureService implements SignatureService {
private final HashicorpVaultSettings settings;
private final EdcHttpClient httpClient;
private final ObjectMapper objectMapper;
private final HashicorpVaultTokenProvider tokenProvider;


public HashicorpVaultSignatureService(Monitor monitor, HashicorpVaultSettings settings, EdcHttpClient httpClient, ObjectMapper objectMapper) {
public HashicorpVaultSignatureService(Monitor monitor, HashicorpVaultSettings settings, EdcHttpClient httpClient, ObjectMapper objectMapper, HashicorpVaultTokenProvider tokenProvider) {
this.monitor = monitor;
this.settings = settings;
this.httpClient = httpClient;
this.objectMapper = objectMapper;
this.tokenProvider = tokenProvider;
}

/**
Expand All @@ -73,7 +77,7 @@ public Result<byte[]> sign(String key, byte[] payload, String signatureAlgorithm

var request = new Request.Builder()
.url(url)
.header(VaultConstants.VAULT_TOKEN_HEADER, settings.token())
.header(VaultConstants.VAULT_TOKEN_HEADER, tokenProvider.vaultToken())
.post(jsonBody(body))
.build();

Expand Down Expand Up @@ -124,7 +128,7 @@ public Result<Void> verify(String key, byte[] signingInput, byte[] signature, St

var request = new Request.Builder()
.url(url)
.header(VaultConstants.VAULT_TOKEN_HEADER, settings.token())
.header(VaultConstants.VAULT_TOKEN_HEADER, tokenProvider.vaultToken())
.post(jsonBody(body))
.build();

Expand Down Expand Up @@ -165,7 +169,7 @@ public Result<Void> rotate(String key, Map<String, Object> ignored) {

var request = new Request.Builder()
.url(url)
.header(VaultConstants.VAULT_TOKEN_HEADER, settings.token())
.header(VaultConstants.VAULT_TOKEN_HEADER, tokenProvider.vaultToken())
.post(RequestBody.create(new byte[0], null))
.build();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.vault.hashicorp.auth;

import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.runtime.metamodel.annotation.Setting;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.vault.hashicorp.spi.auth.HashicorpVaultTokenProvider;

import static java.util.Objects.requireNonNull;

@Extension(value = HashicorpVaultAuthenticationExtension.NAME)
public class HashicorpVaultAuthenticationExtension implements ServiceExtension {

public static final String NAME = "Hashicorp Vault Authentication";

@Setting(description = "The token used to access the Hashicorp Vault. Only required, if default token authentication is used.", key = "edc.vault.hashicorp.token", required = false)
private String token;

@Provider(isDefault = true)
public HashicorpVaultTokenProvider tokenProvider() {
requireNonNull(token, "Using default TokenProvider: Configuration of vault token is required (setting: 'edc.vault.hashicorp.token').");
return new HashicorpVaultTokenProviderImpl(token);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright (c) 2025 Cofinity-X
*
* This program and the accompanying materials are made available under the
* terms of the Apache License, Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Cofinity-X - initial API and implementation
*
*/

package org.eclipse.edc.vault.hashicorp.auth;

import org.eclipse.edc.vault.hashicorp.spi.auth.HashicorpVaultTokenProvider;

import static java.util.Objects.requireNonNull;

/**
* Implements the token auth method of the HashiCorp vault. Returns the configured token.
*/
public class HashicorpVaultTokenProviderImpl implements HashicorpVaultTokenProvider {

private final String token;

public HashicorpVaultTokenProviderImpl(String token) {
requireNonNull(token, "Vault token must not be null");
this.token = token;
}

@Override
public String vaultToken() {
return token;
}
}
Loading