Plugin host architecture

How the plugin host isolates first-party plugins from the Platform Orchestrator, and what the v1alpha contract covers.

This chapter describes the plugin foundation released with chart 0.8.0. The changelog lists the compatible component versions and the upgrade behavior changes.

The Platform Orchestrator contains a neutral plugin host. It lets an operator add a separately packaged Stellwerk plugin without changing, rebuilding, or forking the Control Plane, Data Plane, IAM, or Console images. A plugin runs as its own Kubernetes workload, owns its own database, and reaches the Orchestrator only through documented, delegated APIs.

Terms

TermMeaning
CoreThe Control Plane, Data Plane, IAM, Console, the octl CLI, the Terraform/OpenTofu provider, and the Helm chart
Plugin packageAn immutable, signed OCI artifact with a plugin manifest, one static Linux executable per platform, and optional UI assets
Plugin runtimeThe generic runtime image and Helm chart that verify and run a package. Every plugin uses the same runtime image
Plugin IDThe immutable reverse-DNS identity of a plugin, for example dev.stellwerk.progressive-rollouts
InstallationThe deployment-wide Core record of one installed package version, kept by the Plugin Manager, identified by an immutable installation UUID
EnablementThe availability state of an installation for one organization. One installation can hold an enablement for every organization
Platform principalAn IAM service user that belongs to no organization and holds no role. An installation acts as its platform principal
EntitlementA signed, offline-verifiable license grant for plugin features, for one organization of an installation or for the whole installation

Components

 Browser ── Console ──(sandboxed iframe)──> plugin UI (separate hostname)
               │
               ▼
 API gateway (IAM authentication) <─────────────────────────────┐
   │                                                            │
   ▼                                                            │ plugin calls Core with
 Control Plane (plugin host)                                    │ a short-lived workload
   │ checks enablement, license, and the registered operation  │ token
   │ signs a request context for the delegated user            │
   ▼                                                            │
 plugin workload (generic runtime image) ───────────────────────┘
   ├─ plugin executable ──> plugin database (owned by the plugin)
   ├─ token sidecar
   └─ UI server

 Data Plane ──> normal Runner path. Deployments that a plugin requests are
                ordinary Deployments.
  • The Control Plane hosts the plugin gateway. It reads the Plugin Manager state, answers discovery, enforces enablement and entitlement, and forwards registered operations to the plugin.
  • The plugin runtime verifies the signed package, its SBOM, and its provenance attestation before anything runs, executes a sealed in-memory copy of the verified executable, and serves only digest-verified UI assets. It tells the plugin its installation UUID and the verified package digest, and the plugin reports both to Core, which activates the installation only if they match.
  • IAM exchanges the plugin Pod’s projected Kubernetes ServiceAccount token for a short-lived token of the installation’s platform principal. See Plugin workload identity. IAM also decides which users operate the Plugin Manager.
  • The Console shows a plugin’s pages in a sandboxed iframe from the plugin’s own origin.
  • The Data Plane runs every Deployment through the normal Runner path. There is no second execution engine for plugins.

How a request reaches a plugin

  1. A client discovers plugins. GET /orgs/{orgId}/plugins lists the plugins available to an organization with their state, mode, advertised operations, and UI contribution. GET /orgs/{orgId}/plugins/{pluginId} returns the state of one plugin, a remediation hint in admin_action, and the license projection. An unknown plugin is reported as not_installed.
  2. The client invokes a registered operation with POST /orgs/{orgId}/plugins/{pluginId}/invoke. The body names an operation_id and can carry path_parameters, query, body, and an idempotency_key. Mutating operations require an idempotency key of at most 128 characters.
  3. The Control Plane rejects operations that the Plugin Manager does not register, checks the plugin’s state and the license feature that the operation requires, and signs a short-lived request context. The context binds plugin, organization, acting user, operation, method, path, body digest, and request ID. The Control Plane never forwards the caller’s cookies, bearer token, or From header.
  4. The plugin verifies the context and applies its own resource-level checks. When it calls Core, it authenticates as its platform principal, and Core checks the delegated user again where the contract requires end-user authority.

Plugin APIs are reached through these operation IDs. Arbitrary REST paths under a plugin namespace are not part of v1alpha.

Boundaries

  • Out of process. No plugin code runs in a Core Pod. The runtime never executes a file path; it executes the verified bytes from a sealed in-memory copy.
  • No Core database access. A plugin owns its database and migrations. The migration runs in a separate Job with its own database principal. The runtime principal cannot migrate, and the package fetch step never receives database credentials.
  • Namespaced identifiers. Plugin IAM capabilities have the form plugin.<plugin-id>.<name>. Plugin events have the type plugin.<plugin-id>.<event>. A plugin cannot register capabilities or events in another namespace.
  • One plugin, several organizations. One installation serves every organization that is enabled for it, with one runtime, one plugin database, and one platform principal. Core confines each effect of the plugin to one organization and checks that organization’s enablement inside the effect’s own transaction. The platform principal holds no IAM role in any organization. A compromised plugin reaches every enabled organization within the plugin boundary, and all organizations share the plugin’s database, so a plugin bug can mix their data there. See Limits.
  • No implied Core rights. A plugin capability never grants a Core permission. For example, a plugin capability that overrides a Pin for one operation never grants module.version.unpin.
  • Events without broker credentials. Plugins read Core resource events from an HTTP journal and publish their own events through the Core transactional outbox. They receive no NATS credentials.
  • Isolated UI. Plugin pages run in a sandboxed cross-origin iframe on a separate hostname. They receive no Console cookies and no Core tokens. The Console renders a plugin only after Core confirms its enablement and entitlement. Hiding navigation is not authorization.
  • Contained failures. If a plugin fails, its operations fail with plugin_unavailable. Core APIs, ordinary Deployments, and Module Version Management keep working.

Access to a package, package trust, installation, organization enablement, license entitlement, plugin service grants, and user permissions are separate decisions. A valid signature or a license never makes a user an administrator, and a license never grants an IAM permission.

Availability states

Every plugin has one state per organization. Clients map each state to a stable error code.

StateStable codeMeaningMode
availablenoneInstalled, enabled, and licensed where requiredfull
not_installedplugin_not_installedNo installation for this organization, or the server predates discoverynone
not_enabledplugin_not_enabledInstalled, but not enabled for this organizationsafety_only
not_entitledplugin_not_entitledNo current license for a required featuresafety_only, or hidden without reads
incompatibleplugin_incompatibleThe installed version is not compatible with this Core or clienthidden
unavailableplugin_unavailableOut of service, or Core cannot reach the plugin or evaluate its licensehidden

In full mode, every advertised operation is available. In safety_only mode, Core keeps advertising reads and safety operations, such as cancel and rollback, and rejects new forward work. In hidden mode, no operation is available. See Plugin availability diagnostics for the client behavior.

Scope of v1alpha

Supported

The following table describes the implemented mechanisms. The released set has passed native installation checks on Linux AMD64 and ARM64. Offline bundle verification and mirror support do not, by themselves, qualify every air-gapped topology. Validate your registry, network boundaries, and chosen infrastructure before using a disconnected installation in production.

Areav1alpha
PublishersStellwerk only. Trust configuration and data are scoped per publisher
DeliveryNative executable package, installed by the operator through Helm and the Core Plugin Manager API (octl plugin-manager)
Platformslinux/amd64 and linux/arm64
Workload identityProjected Kubernetes ServiceAccount token exchanged for a short-lived token of the installation’s role-less platform principal, bound to installation, ServiceAccount, and namespace
OrganizationsEvery organization (organizations: all, including organizations created later, with opt-out by disabling the enablement) or a chosen set. One platform principal, one runtime, and one plugin database serve all of them
Plugin writer availabilitySeveral replicas with exactly one active writer through a lease with a monotonic fencing token. A standby takes over after the lease expires. Read APIs and UI may run on every replica
EventsHTTP resource journal and the Core transactional outbox
Package trustThe managed-key-no-tlog policy for publishers pinned in an operator-supplied trust bootstrap, covering the package signature, SBOM, and provenance. An installed digest stays loadable after a key rotation; only an explicitly revoked key blocks it
EntitlementsCanonical CBOR in COSE_Sign1, bound to the installation UUID and either one organization UUID or the whole installation. A valid organization grant takes precedence; an expired or revoked one falls back to a valid installation grant. An optional soft limit counts all enabled organizations. Development trust is rejected in production mode
Air-gapped operationOffline bundle and mirror-first installation into your own registry
UISandboxed cross-origin iframe pages, navigation, and contextual actions
Operator viewA read-only Plugin Manager view in the Console for platform operators with plugin_manager_read. You change the state with octl or the API
Upgrade and removalThe Plugin Manager upgrades to a later package, and uninstalls, reinstalls, and purges an installation. It refuses a downgrade. Recovery is roll-forward, or plugin-off with schema-compatible Core images

Later. These areas are not part of v1alpha. Stellwerk has not committed to a design or a date for them.

  • Partner publishers, partner license issuers, and a partner conformance target
  • Generic NATS subscription provisioning for plugins
  • A generic renderer for schema-defined tables and forms. Navigation, contextual actions, and isolated plugin pages are supported without it
  • Keyless Sigstore publishers with transparency-log verification. Publishers without a supported policy fail closed
  • Organization self-service, delegated plugin administration, a configuration and secret broker, and quotas. In v1alpha, the operator binds Kubernetes Secret references

Not supported

  • Synchronous policy hooks
  • Same-origin UI microfrontends
  • A marketplace or catalogue, usage metering, and dependencies between plugins
  • Migrating data from earlier integrated (in-process) builds. Install plugins fresh

Plugin data export is also deferred. The Plugin Manager supports uninstall with retained data and an explicit purge; it does not provide an export step.

Provenance profiles

Provenance records which source and build inputs produced an artifact. It is separate from the SBOM, which describes its contents, and the signature, which binds those bytes to a publisher.

The release uses distinct profiles:

  • Explicit release attestations for the generic plugin runtime use the SLSA Provenance v1 predicate, https://slsa.dev/provenance/v1.
  • Image builds retain the original attestations emitted by the pinned BuildKit producer. Their format and subjects are not rewritten after the build.
  • Native plugin packages carry the source provenance predicate https://stellwerk.dev/attestation/source-provenance/v1. The runtime verifies this statement, the package signature, and the SBOM against the same trusted publisher and package digest. It is not a SLSA Provenance v1 predicate.

Artifact verification checks the source, actual builder or workflow, build inputs, subject digest, and signatures for the relevant profile. An attestation file alone is not proof that these checks passed. Neither a predicate format nor BuildKit’s mode=max establishes a certified SLSA level; this release makes no such assurance claim.

Next steps

Top