Skip to main content
Version: v0.25.0 (Latest)

Container Deployment

The EDK is consumable in two ways. Library customers depend on EDK modules from their own Kotlin application and assemble whatever process shape suits them. Container customers run the pre-built service images Sphereon publishes and configure them through REST and YAML. This section is for the second group.

Sphereon publishes five enterprise service images to commercial customers:

  • sphereon/enterprise-kms: the cryptographic authority for the deployment. Every other service delegates key generation, signing, encryption, and public-key lookup to it. Internal-only by default.
  • sphereon/enterprise-did: a public DID resolver plus an internal admin and registrar surface for did:web, did:webvh, did:jwk, and did:key.
  • sphereon/enterprise-as: an OAuth 2.0 / OpenID authorization server scoped to the flows that EDK needs first-hand: the OID4VCI pre-authorized code grant, the OID4VCI authorization code grant via wallet federation, and client-credentials issuance for tenant service clients.
  • sphereon/enterprise-issuer: the OpenID4VCI credential issuer: protocol endpoints (/credential, /credential_deferred, /nonce, /notification), the attribute pipeline, the credential-design store, deferred and approved issuance, and the async-callback ingress.
  • sphereon/enterprise-verifier: the OpenID4VP verifier: request_uri, direct_post, DCQL query store with versioning, per-tenant trust frames, and presentation callbacks.

These are exactly the container roles. There is no combined "everything" image, and there is no per-tenant fan-out at the EDK level. Each image is one process. Each image is one logical entity (one issuer, one verifier, one AS, and so on) that becomes multi-tenant by resolving the active tenant from each request. Per-tenant fan-out of N issuers, N verifiers, or N AS instances on top of these is a VDX-only capability built on the party model and is not in scope here.

EDK container topology

How the Roles Were Drawn

The split into KMS, DID, AS, Issuer, Verifier follows where attack surfaces and access patterns actually diverge, not microservice fashion.

The KMS sees raw key material and signing requests, so it has no business being on the public internet. It exposes a peer REST surface that the issuer, verifier, AS, and DID services call from the internal cluster network and an admin REST surface for provider registration and per-tenant key alias management. The deployment template binds it to an internal LB or a service-mesh-only endpoint.

The DID service is the inverse: its primary value is public resolution. Wallets, other issuers, other verifiers, and arbitrary internet clients need to be able to fetch did:web documents and Universal Resolver responses. Splitting DID out of the issuer and verifier images keeps the public surface they expose down to just their protocol endpoints, and lets DID scale horizontally for resolution traffic independently of the issuer's pipeline workload.

The AS, Issuer, and Verifier each own one OAuth or OpenID protocol family. They have both a public protocol surface (the wallet-facing endpoints) and an internal admin surface (the tenant administrator's CRUD over designs, queries, integrations, federation providers, public-endpoint bindings). The deployment template puts the protocol path behind the public ingress and the /api/v1/... admin path behind an internal ingress with bearer-JWT authentication.

Tenant Resolution Across All Five Images

Every image embeds the same EDK tenant resolution stack and the same TenantAdminHttpAdapter mounted at /api/v1/tenants. The resolved tenant is the unit of routing and the unit of authorization. Tenants are recognised from the incoming request through a layered resolver chain:

  • JWT is the primary source for any authenticated call. The tenant_id claim in the bearer token is authoritative. The X-Tenant-Id header is informational only and is never trusted on its own.
  • Subdomain of the configured platform base host. acme.issuer.example.com resolves to the acme tenant.
  • Custom domain mapped to a tenant via the TenantDomain registry once the domain has been verified.
  • Path slug prefix. /{tenant-slug}/oid4vci/credential and the various .well-known URL forms route into the same tenant.

For the protocol metadata endpoints, the EDK supports both the spec-canonical form and the legacy slug-before-.well-known form, because clients in the field use both:

  • OID4VCI: /.well-known/openid-credential-issuer/{tenant-slug} (spec) and /{tenant-slug}/.well-known/openid-credential-issuer (legacy).
  • OAuth AS metadata: /.well-known/oauth-authorization-server/{tenant-slug} (spec) and the legacy variant.
  • OpenID Connect: /{tenant-slug}/.well-known/openid-configuration (the spec form expects slug-before).

The tenant administrator declares slugs and verified custom domains through the tenant admin REST. The data planes consume from the registry; they never invent slugs or guess.

How the Five Images Compose

A typical deployment looks like this:

  • One KMS instance, sized for the deployment's signing rate. Backed by Postgres for key-reference bookkeeping; actual key material lives in the configured provider backend (software keystore, AWS KMS, Azure Key Vault, Digidentity CSC, an HSM).
  • One DID resolver instance behind the public ingress, scaled horizontally if resolution traffic warrants it. A separate manager admin endpoint behind the internal ingress for did:web document publishing and did:webvh log management.
  • One AS instance handling the wallet-facing OAuth surface and the per-tenant federation/discovery/JWKS endpoints.
  • One Issuer instance handling the wallet-facing OID4VCI protocol surface plus the credential design, attribute supplier, integration, and webhook admin surfaces.
  • One Verifier instance handling the wallet-facing OID4VP surface plus the DCQL versioned store, trust-frame admin, and webhook admin surfaces.
  • A shared PostgreSQL instance (or per-tenant database routing if the deployment requires isolation at the DB level rather than the row level). Replicas of any data-plane image share Postgres.

For a high-traffic deployment, each role scales horizontally. Cross-replica cache invalidation is handled through Postgres LISTEN/NOTIFY plus a TTL fallback, so tenant routing, public-endpoint binding, and per-tenant config mutations made on one replica become visible on the others without a restart and without rebooting the cluster.

The optional enterprise-email-service container, sourced from VDX, is required only when admin-invite or self-service tenant onboarding journeys are enabled. The data-plane containers do not require it.

What This Section Covers

  • Topology: the public/internal ingress split, network policies, service-to-service auth, the integration with shared Postgres, and how a customer typically lays out namespaces and ingress classes.
  • KMS Container: provider registration, per-tenant key aliases, the REST surface that the other images call.
  • DID Container: the public resolver, the manager admin, per-tenant method allowlists, the did:web and did:webvh publishing model.
  • AS Container: the OAuth/OIDC surface that EDK currently supports, tenant federation, signing-key binding to KMS, the discovery URL forms.
  • Issuer Container: protocol endpoints, the attribute pipeline, the credential-design store, integration kinds for AS binding and attribute suppliers, webhooks.
  • Verifier Container: protocol endpoints, the DCQL versioned store, per-tenant trust-frame binding, presentation callbacks.
  • Configuration & Secrets: the application.yaml profile, environment variable mapping, per-tenant config storage, secret backends.
  • Operations: health, readiness, OpenTelemetry, audit, backup and restore.

What This Section Does Not Cover

Because of where the line between the EDK and the VDX commercial platform falls, several capabilities that are sometimes associated with "running these services in production" are deliberately out of scope here:

  • Multi-instance per tenant (N issuers, N verifiers, N AS instances per tenant for different credential programs or business units).
  • Operator dashboards and UIs.
  • Tenant self-service onboarding flows beyond the REST endpoints.
  • License validation, billing, and metering.
  • Durable workflow execution (sagas, long-running schedulable commands).
  • Cross-tenant catalog projection.
  • MFA, account self-service, and a full IAM admin UI on the AS.

Those capabilities are provided by the VDX commercial platform that layers on top of these containers.