Skip to content

Use Vault Transit engine for key management #982

@paullatzelsperger

Description

@paullatzelsperger

Feature Request

Instead of having IdentityHub manage participant keys, we want to offer an alternative approach where key pairs remain in Hashicorp Vault's Transit engine, and instead of loading keys into memory to sign data (e.g. VCs, VPs), the payload is sent to Transit for signing.

Which Areas Would Be Affected?

  • a new KeyPairService impl to delegate creating/rotating/revoking/... keys to the Transit engine

  • a new SigningService interface + TransitEngineSigningService impl that takes a payload and sends it to Transit for signing

  • new JwsSignerProvider and JWSSigner impls that handle signing

  • either a new PublicKeyResolver, that can load public key information from the Transit engine

  • or a new TokenValidationService, that delegates the verification to Transit. This would be the more flexible approach.

Why Is the Feature Desired?

in multi-participant environments it may be desirable to isolate all security-related operations as much as possible. Since we already practically depend on Vault for secret storage, it seems like a foregone conclusion to also use the Transit engine.

Who will sponsor this feature?

Please @-mention the committer that will sponsor your feature.

Solution Proposal

Implement a new module :core:identity-hub-keypairs-transit, that contains all of the aforementioned new classes. Bunching all impls in one module might not seem ultra-clean, but it has a few advantages: it keeps the module count down (which is an ongoing problem for EDC), and it keeps classes together that depend on one another.

In terms of security I propose to use participant isolation through policies. That means, that a naming scheme is required for keys, for example part_<PARTICIPANT_CONTEXT_ID>_<KEYNAME> and a vault policy is created restricting access thus:

{
    "policy": "path \"transit/keys/part_<PARTICIPANT_CONTEXT_ID>*\" { capabilities = [\"create\",\"read\",\"update\"] }\npath \"transit/sign/part_<PARTICIPANT_CONTEXT_ID>*\" { capabilities = [\"update\"] }\npath \"transit/verify/part_<PARTICIPANT_CONTEXT_ID>-*\" { capabilities = [\"update\"] }"
  }

and to make this more dynamic (one policy for all participants) we could use an entity alias accessor in Vault.

Isolating keys at mount-level is surely easier, but that would spin up a Transit engine per participant, which will scale poorly.

Metadata

Metadata

Labels

enhancementNew feature or requeststorytriageall new issues awaiting classification

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions