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 10 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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
*
*/

plugins {
`java-library`
}

dependencies {
api(project(":spi:common:core-spi"))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* 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.spi.auth;

import org.eclipse.edc.runtime.metamodel.annotation.ExtensionPoint;

/**
* Provides a token for authentication against the HashiCorp vault.
*/
@FunctionalInterface
@ExtensionPoint
public interface HashicorpVaultTokenProvider {

/**
* Obtains and returns the authentication token for the HashiCorp vault.
*
* @return the authentication token
*/
String vaultToken();

}
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(":extensions:common:vault:hashicorp: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,36 @@
/*
* 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.Configuration;
import org.eclipse.edc.runtime.metamodel.annotation.Extension;
import org.eclipse.edc.runtime.metamodel.annotation.Provider;
import org.eclipse.edc.spi.system.ServiceExtension;
import org.eclipse.edc.vault.hashicorp.client.HashicorpVaultSettings;
import org.eclipse.edc.vault.hashicorp.spi.auth.HashicorpVaultTokenProvider;

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

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

@Configuration
private HashicorpVaultSettings config;

@Provider(isDefault = true)
public HashicorpVaultTokenProvider tokenProvider() {
return new HashicorpVaultTokenProviderImpl(config.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
Loading