Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# con-x-controlplane-postgresql-hashicorp-vault Module

## Building

From the project root directory, run

```shell
./gradlew :edc-controlplane:edc-controlplane-construct-x:con-x-controlplane-postgres-hashicorp-vault:dockerize
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/********************************************************************************
* Copyright (c) 2022 Mercedes-Benz Tech Innovation GmbH
* Copyright (c) 2026 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
* Copyright (c) 2021,2022 Contributors to the Eclipse Foundation
*
* See the NOTICE file(s) distributed with this work for additional
* information regarding copyright ownership.
*
* 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.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/

plugins {
`java-library`
id("application")
alias(libs.plugins.shadow)
}

dependencies {
val edcVersion = "0.14.1"
val txVersion = "0.11.2"
implementation("org.eclipse.edc:controlplane-dcp-bom:$edcVersion")
implementation("org.eclipse.edc:controlplane-feature-sql-bom:$edcVersion")

implementation("org.eclipse.edc:vault-hashicorp:$edcVersion")
implementation("org.eclipse.tractusx.edc:agreements:$txVersion")
implementation("org.eclipse.tractusx.edc:retirement-evaluation-store-sql:$txVersion")
implementation("org.eclipse.tractusx.edc:control-plane-migration:$txVersion")
implementation("org.eclipse.tractusx.edc:tx-dcp:${txVersion}")
}

tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
mergeServiceFiles()
duplicatesStrategy = DuplicatesStrategy.INCLUDE
archiveFileName.set("con-x-controlplane-postgresql-hashicorp-vault.jar")
transform(com.github.jengelman.gradle.plugins.shadow.transformers.Log4j2PluginsCacheFileTransformer())
}

tasks.named("build") {
dependsOn(tasks.named("shadowJar"))
}

application {
mainClass.set("org.eclipse.edc.boot.system.runtime.BaseRuntime")
}
118 changes: 118 additions & 0 deletions edc-controlplane/edc-controlplane-construct-x/local/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Construct-X Local Docker Testbed


This `docker-compose.yaml` provides you a minimal environment for testing a pair of construct-x-edc's against each other.

It will start the following containers on your local machine:

- one instance of an issuer-service
- two instances of identity-hubs (for consumer and provider each)
- two instances of our current Construct-X controlplanes (as above)
- two instances of our current Construct-X dataplanes (as above)
- one Postgres DB (which is, for the sake of saving you resources on your local machine, shared by all aforementioned containers)
- one HashiCorp Vault (also shared)
- one (very short-lived) init-container, whose only job is to create edr-signing keys for the dataplanes, store them on the vault and then to terminate



Before anything else, please make sure you have the docker images for con-x-controlplane-postgresql-hashicorp-vault in your local docker repository, see [here](../con-x-controlplane-postgresql-hashicorp-vault/README.md) and [here](../../../edc-dataplane/edc-dataplane-construct-x/con-x-dataplane-postgresql-hashicorp-vault/README.md).

Beyond that, you need to obtain the docker images needed to run the identity hub and the issuer services. In order to do so, please checckout this [repository](https://github.com/FraunhoferISST/dev-identity-services) and clone it onto your local machine. The upper section of this [README](https://github.com/FraunhoferISST/dev-identity-services/blob/main/runtimes/dev/README.md) informs
you about the steps necessary to create the docker images.


### Start the environment
Now we are ready to start the environment. For that, please run (from the `local` folder of this README file!)

Optionally (from the project root)
```
cd edc-controlplane/edc-controlplane-construct-x/local
```
Then:

```
docker compose up
```

Then please use the attached Bruno collection. ([Bruno](https://www.usebruno.com/) is a convenient http client, which
you should install, if you haven't already). In order to this, choose the "open" (not "import") option item in the Bruno UI and select the respective [folder](bruno/con-x-local-test). If prompted by a popup if you want to choose "Safe Mode" or "Developer Mode", then just select "Safe Mode".

After that, please use the icon in the upper right corner
of the Bruno GUI to select the `local-con-x-env` environment (which stores the variables that the requests will need).

In that collection you should first run the requests of the `identities` folder. These request can also be safely executed from top to bottom in batch mode, especially if you are more interested in doing the "normal" `transactions` between the two edc's. Though can find more details one the `identities` folder below, if you're interested.
After you have completed all required steps, the provider and the consumer identity are onboarded in your own dataspace
and ready to interact with each other.

Now you are ready to perform a simple contract negotiation and data transfer between these two actors.

Be sure to also read the documentation that is attached to the folders in the Bruno collection. You may also want to
check the pre- and postrequest scripts of many requests, because they may give you further insights. You can find the docs content
in the Bruno GUI on the far right side of the menu bar, where the "Headers", "Auth", "Vars", etc. items are located. You may have to unwrap the
menu using the ">>" icon.

In a nutshell, we are presenting the following workflows here:

### Create an issuer-participant (`Prepare Issuer` folder)

The issuer-participant will act as the dataspaces' trusted issuer. This issuer is mandated to sign and hand
out verifiable credentials, which the members of the dataspace can use to prove their membership (or potentially other
relevant properties of themselves) to other partners in the same dataspace. After the registration of the issuer we are
also providing the basic definition of the credential that shall be issued. And we also need register the expected (
user-) members of the dataspace at the issuer service as holders at the trusted issuer's participant context.

Assuming that the majority of users does not (at least in the beginning) want to get into the details of designing credentials, you can most probably skip the `Optionalconfig` folder (though it does no harm, if you run these requests, as long as you don't edit these requests in any way). If you're interested in the (rather advanced) topic of using customized credential subject contents in your credentials, you can take a further look at this [README](https://github.com/FraunhoferISST/dev-identity-services/blob/main/runtimes/dev/README.md).

Pretty much the same goes for the `createAttestation` and the `createCredentialDef` requests. If you're an average user, you just need to know that
they are a technical necessity at this point and you just to need to run them to ensure that rest of the requests in this collection can be executed properly.

### Create a consumer and a provider identity

Somewhat similar to the creation of the issuer, we will now create a consumer and a provider identity on their
respective wallets (i.e. identity hubs). After the creation, we receive an api token and a sts secret from the identity
hub. The sts secret is essential for operating the edc. So we need to store that in the hashicorp vault under a given
secret alias, so that the edc can use it later. Also, we can take a look at the DID document, that was generated on the
identity hubs. And we need to tell our identity hub, that we want to request a membership token from the trusted issuer.

When this is done, we can have a look at the credentials, that the issuer hopefully delivered to consumer and provider
respectively. And we can also do some kind of a simulated DCP flow with the just created credentials. Please see the
documentation in the Bruno collection if you are interested in learning some more details (though that is directed at
the more advanced members of the audience here, beginners can definitely skip that part).

#### Known issue / validating the identity setup
In rare cases (chances seem to be below 0.5 %) there is currently a possibility, that one of the `CreateParticipant` calls may (silently) fail. We assume that this is something that needs to be fixed on the upstream EDC identity hub project. See this [issue](https://github.com/eclipse-edc/IdentityHub/issues/913) for details. If you are unfortunate enough encounter this bug, you should notice that one of the calls in the `InspectOutcome` folder shows an empty response and that (at least) the last call of `Simulated DCP Flow` shows a negative test result.

If one encounter one these symptoms, we would suggest that you cleanly restart the entire docker compose (see below). Chances
are near 99 % that on your next attempt, you won't encounter this problem again.

Also, if you're interested in some more details


### Do a transaction between provider and consumer

Finally, we are ready now to do a more or less 'normal' DSP/DCP protocol backed transaction between the consumer and the
provider. I.e. firstly we need the provider to prepare a data asset, which the consumer can negotiate with him for. Then
the consumer
can discover this asset via a catalog request towards the provider edc, initiate a negotiation and a transfer. If you
are interested
in a more detailed explanation of these interactions, please see
the [EDC Samples](https://github.com/eclipse-edc/Samples/tree/main/transfer).

NOTE: The requests in the `transactions/consumer` folder are definitely not suited for being run in batch mode. Instead,
especially before you run the `InitiateNegotiation` or the `Get EDR` requests, it is strongly recommended that you make sure
that a healthy timespan (like 2 seconds) lies between them and the respective previous request. This is because the
EDC controlplane needs some time to complete the negotiation process respectively retrieve the EDR token from the provider side.


### Clean restart
When you're done testing and want to end your session (using 'CTRL-C' on the terminal, where you started docker
compose),
you may want to run

```
docker compose down -v
```

This will delete the data from your previous session and ensure, that the next time, you are starting this, you will
have no data remnants in your containers, which may cause confusion or conflicts, when you start the docker-compose.yaml
and the requests of the Bruno collection later again.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
handlers = java.util.logging.ConsoleHandler

# Console Handler Config

java.util.logging.ConsoleHandler.formatter = org.eclipse.tractusx.identityhub.monitor.ColorfulFormatter
java.util.logging.ConsoleHandler.level = FINE

# Root level und Package-level

.level = INFO
jakarta.json.level = OFF
jdk.event.level = OFF
okhttp3.internal.level = OFF
org.eclipse.edc.level = FINE
org.flywaydb.level = OFF
org.glassfish.level = OFF
org.jvnet.level = OFF
org.postgresql.level = OFF
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"MC-Cred-Def": {
"blackList": [],
"default": {
"credentialSubject": {
"isMember": true
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE DATABASE iss_db;
CREATE DATABASE cons_ih_db;
CREATE DATABASE prov_ih_db;
CREATE DATABASE cons_cpl;
CREATE DATABASE cons_dpl;
CREATE DATABASE prov_cpl;
CREATE DATABASE prov_dpl;

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash

#
# Copyright (c) 2026 Fraunhofer-Gesellschaft zur Foerderung der angewandten Forschung e.V. (represented by Fraunhofer ISST)
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# 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.
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

VAULT="${VAULT_ADDR:-http://shared-vault:8200}"
TOKEN="${VAULT_TOKEN:?missing VAULT_TOKEN}"

# function that creates and deploys a rsa keypair:

create_and_store_keypair() {
local prefix=$1

# create rsa keypair
openssl genrsa -out /tmp/${prefix}_priv_pkcs1.pem 2048
openssl pkcs8 -topk8 -nocrypt -in /tmp/${prefix}_priv_pkcs1.pem -out /tmp/${prefix}_priv.pem
openssl rsa -in /tmp/${prefix}_priv_pkcs1.pem -pubout -out /tmp/${prefix}_pub.pem

# deploy secrets to vault
jq -n --rawfile content /tmp/${prefix}_priv.pem '{data:{content:$content}}' | \
curl -fsS -H "X-Vault-Token: $TOKEN" -H "Content-Type: application/json" \
-X POST --data-binary @- "$VAULT/v1/secret/data/${prefix}_priv"

jq -n --rawfile content /tmp/${prefix}_pub.pem '{data:{content:$content}}' | \
curl -fsS -H "X-Vault-Token: $TOKEN" -H "Content-Type: application/json" \
-X POST --data-binary @- "$VAULT/v1/secret/data/${prefix}_pub"

# cleanup temp files
rm -f /tmp/${prefix}_priv_pkcs1.pem /tmp/${prefix}_priv.pem /tmp/${prefix}_pub.pem
}

# create keypair for consumer and provider dataplane:

create_and_store_keypair "cons"
create_and_store_keypair "prov"
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": "1",
"name": "con-x-local-test",
"type": "collection",
"ignore": [
"node_modules",
".git"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
vars {
ISSUER_DID_API: http://localhost:10000
ISSUER_ID_API: http://localhost:10100/api/identity
ISSUER_ISS_API: http://localhost:10200/api/issuer
CONSUMER_IDHUB_DID_API: http://localhost:20000
CONSUMER_IDHUB_ID_API: http://localhost:20100/api/identity
CONSUMER_IDHUB_STS_API: http://localhost:20500/api/sts
CONSUMER_IDHUB_CREDS_API: http://localhost:20600/api/credentials
ISSUER_APIKEY: ZGlkOndlYjpsb2NhbC1pc3N1ZXItc2VydmljZTpmeC1pc3N1ZXI=.CmYgVcuzneJXqzcbj7vmld5feejy6OguIylflSrz6WTjG1HNQRvO62EafFrQjS/lVlZAwiwz2rwwZgXrbpyhcg==
CONSUMER_IH_APIKEY: ZGlkOndlYjpsb2NhbC11c2VyLWlkaHViOnVzZXI6Y29uc3VtZXI=.ObFly02OtymUNRE43uH9SblWVtsZH0NMddgm1dFYQXRekO3qXX+rHFV7NvM+DUW3lcA2PbILt5rwWYEqm7WNgw==
PROVIDER_IH_APIKEY: ZGlkOndlYjpsb2NhbC11c2VyLWlkaHViOnVzZXI6cHJvdmlkZXI=.Knip+hedL63qedBQfOvZhhrF2ooSCfP2YgjONvtmehofor2ejdw/en0MAXDBZEcXrCwYNppDMNFDsRlG5rB/Mw==
VAULTURL: http://localhost:8200
CONSUMER_STS_SECRET: VD0q6jOEyslSeFV2
PROVIDER_STS_SECRET: XjDk9ncaJSrSfkQW
PROVIDER_MANAGEMENT: http://localhost:39010/management
CONSUMER_MANAGEMENT: http://localhost:29010/management
PROVIDER_DATAPLANE_PUBLIC: http://localhost:9500/public
PROVIDER_IDHUB_DID_API: http://localhost:21000
PROVIDER_IDHUB_ID_API: http://localhost:21100/api/identity
PROVIDER_IDHUB_STS_API: http://localhost:21500/api/sts
PROVIDER_IDHUB_CREDS_API: http://localhost:21600/api/credentials
ISS_ID: did:web:local-issuer-service:con-x-issuer
CONS_ID: did:web:consumer-idhub:user:consumer
PROV_ID: did:web:provider-idhub:user:provider
B64_ISS_ID:
B64_CONS_ID:
B64_PROV_ID:
cons_access_token: eyJraWQiOiJkaWQ6d2ViOmNvbnN1bWVyLWlkaHViOnVzZXI6Y29uc3VtZXIja2V5LTEiLCJhbGciOiJFZDI1NTE5In0.eyJhdWQiOiJkaWQ6d2ViOmNvbnN1bWVyLWlkaHViOnVzZXI6Y29uc3VtZXIiLCJzdWIiOiJkaWQ6d2ViOnByb3ZpZGVyLWlkaHViOnVzZXI6cHJvdmlkZXIiLCJuYmYiOjE3NzAyNzg5NTQsInNjb3BlIjoib3JnLmVjbGlwc2UudHJhY3R1c3gudmMudHlwZTpNZW1iZXJzaGlwQ3JlZGVudGlhbDpyZWFkIiwiaXNzIjoiZGlkOndlYjpjb25zdW1lci1pZGh1Yjp1c2VyOmNvbnN1bWVyIiwiZXhwIjoxNzcwMjc5MjU0LCJpYXQiOjE3NzAyNzg5NTQsImp0aSI6ImFjY2Vzc3Rva2VuLTcxYThmNTA5LTgwYTktNDMwZC1iMjU0LTMxNGFiYTBkNjY5OSJ9.ipRpdi_Ekh7y4IIqhqLgHU35Fn7NNkv6e6hILXy8pZObdy33y3MKppI61424eyHwqzmh7X2kwV2S5gDy3aOKCQ
prov_access_token: eyJraWQiOiJkaWQ6d2ViOnByb3ZpZGVyLWlkaHViOnVzZXI6cHJvdmlkZXIja2V5LTEiLCJhbGciOiJFZDI1NTE5In0.eyJzdWIiOiJkaWQ6d2ViOnByb3ZpZGVyLWlkaHViOnVzZXI6cHJvdmlkZXIiLCJhdWQiOiJkaWQ6d2ViOmNvbnN1bWVyLWlkaHViOnVzZXI6Y29uc3VtZXIiLCJuYmYiOjE3NzAyNzg5NTUsImlzcyI6ImRpZDp3ZWI6cHJvdmlkZXItaWRodWI6dXNlcjpwcm92aWRlciIsImV4cCI6MTc3MDI3OTI1NSwiaWF0IjoxNzcwMjc4OTU1LCJqdGkiOiJkNjA0MTVjOS1kMGM0LTRiNWQtYjI4My01ZmNmYjhlMDY2OGQiLCJ0b2tlbiI6ImV5SnJhV1FpT2lKa2FXUTZkMlZpT21OdmJuTjFiV1Z5TFdsa2FIVmlPblZ6WlhJNlkyOXVjM1Z0WlhJamEyVjVMVEVpTENKaGJHY2lPaUpGWkRJMU5URTVJbjAuZXlKaGRXUWlPaUprYVdRNmQyVmlPbU52Ym5OMWJXVnlMV2xrYUhWaU9uVnpaWEk2WTI5dWMzVnRaWElpTENKemRXSWlPaUprYVdRNmQyVmlPbkJ5YjNacFpHVnlMV2xrYUhWaU9uVnpaWEk2Y0hKdmRtbGtaWElpTENKdVltWWlPakUzTnpBeU56ZzVOVFFzSW5OamIzQmxJam9pYjNKbkxtVmpiR2x3YzJVdWRISmhZM1IxYzNndWRtTXVkSGx3WlRwTlpXMWlaWEp6YUdsd1EzSmxaR1Z1ZEdsaGJEcHlaV0ZrSWl3aWFYTnpJam9pWkdsa09uZGxZanBqYjI1emRXMWxjaTFwWkdoMVlqcDFjMlZ5T21OdmJuTjFiV1Z5SWl3aVpYaHdJam94Tnpjd01qYzVNalUwTENKcFlYUWlPakUzTnpBeU56ZzVOVFFzSW1wMGFTSTZJbUZqWTJWemMzUnZhMlZ1TFRjeFlUaG1OVEE1TFRnd1lUa3RORE13WkMxaU1qVTBMVE14TkdGaVlUQmtOalk1T1NKOS5pcFJwZGlfRWtoN3k0SUlxaHFMZ0hVMzVGbjdOTmt2NmU2aElMWHk4cFpPYmR5MzN5M01LcHBJNjE0MjRleUh3cXptaDdYMmt3VjJTNWdEeTNhT0tDUSJ9.42YDTnuzZ0RprqLjFw6hUoAXrgpPxyzKNFrqLdbWz6HXAiujkq32QAFU-M9gtQ0hMNcjshRZUX6DryBWxhGNDw
offerId: MQ==:YXNzZXRJZA==:MDFhN2ZjYWYtODgzOS00N2JmLTllZDAtM2Y0YjliMTFiOWM5
negotiation-id: 3745ad50-6b99-4142-bf1a-509b3d0e313d
contractId: 3345f7f1-f735-4c92-8aa2-6e137203b2f9
transferId: 3ebe55c6-900a-4c03-b213-20c5c3f0274d
pullSecret: eyJraWQiOiJwcm92X3B1YiIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJhbm9ueW1vdXMiLCJhdWQiOiJkaWQ6d2ViOmNvbnN1bWVyLWlkaHViOnVzZXI6Y29uc3VtZXIiLCJzdWIiOiJhbm9ueW1vdXMiLCJpYXQiOjE3NzAyNzg5ODgsImp0aSI6IjUwYWQxMjk3LWZhN2QtNDI0ZC1hNjBhLTg5M2MwMGE4OTZhYyJ9.GkSz0qXhFmqPaLQpfPLkAvODX-iekoAQvLh3Kglhm7DApNF3PsGnv-Qzm7m8eNAqTUTWB9XXkRng_XqWmuAd-FWvzwG8d7ZaAahuykkOgX1W7vHWBMdJa-zvNm0cnzm-TQLWYCU-tDSKk_g_UrDUaFf9Jdq-avCoer3wcZrEmrf0K4o_WWs-l5hZEfDIOYHRsgoCY3P8pMcZYRjV57zdLUDl9SvLuCRR0ex0fKxJ2pb7mlaCL5ooD6fRaqWyrLvrIKZaDYfwKrX7IRJT9ePKyls9VKA9JBakh676L0jBr5-2TYG3uE9Xhyv4CZlqyck-_NyiL4Jao8-lL5FVCbPDVQ
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
meta {
name: ShowConsumerCredentials
type: http
seq: 1
}

get {
url: {{CONSUMER_IDHUB_ID_API}}/v1alpha/credentials
body: none
auth: none
}

headers {
x-api-key: YWRtaW4.adminKey
}

settings {
encodeUrl: true
timeout: 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
meta {
name: ShowProviderCredentials
type: http
seq: 2
}

get {
url: {{PROVIDER_IDHUB_ID_API}}/v1alpha/credentials
body: none
auth: none
}

headers {
x-api-key: YWRtaW4.adminKey
}

settings {
encodeUrl: true
timeout: 0
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
meta {
name: Inspect Outcome
seq: 4
}

auth {
mode: inherit
}

docs {
Here we are taking a look at the credentials, that the trusted issuer created for the participants.
}
Loading