Session: the OpenBao plugin speaks OpenBao's plugin protocol, in Rust (ruling D1) #48

Closed
opened 2026-09-05 20:21:49 +00:00 by larandar · 0 comments
Owner

Proposal

Turn openbao-plugin from a library OpenBao cannot load into a secrets-engine plugin binary OpenBao spawns, so OpenBao actually owns the lease the contract says it owns.

Why

openbao-plugin/ (PR #27, Session #20) holds the ordered issue flow, the lease machine, the one-shot wrapper, and the signed command dispatch — as a Rust library behind trait ports (IntentStore, PrivateMint, LeaseStore, WrapStore, LeaseBackend). Nothing speaks OpenBao's plugin protocol: no go-plugin handshake, no GRPCBackend service, no broker dial-back for storage. OpenBao's SDK is Go only; no Rust plugin SDK exists. The 2026-09-05 delivery run for Ting/Ting#60 found this as the largest delta on the canonical path, and the freeholder ruled (Larandar, 2026-09-05, in-session, ruling D1): "it's better to have the plugin be same language as Vedanta so Rust it is."

Session review boundary

One PR, one verdict: OpenBao loads the binary from its plugin catalog, mounts it, and issue/read/renew/revoke on the mount drive the existing Rust flows unchanged; storage goes through OpenBao's broker; the credential value crosses only inside the wrapped response.

Design

  • A [[bin]] in openbao-plugin (or a sibling crate) implementing the go-plugin protocol with tonic/prost: the handshake line on stdout (CORE-PROTOCOL-VERSION|APP-PROTOCOL-VERSION|unix|<socket>|grpc|<base64 cert>), the magic-cookie env check, auto-mTLS with the client certificate OpenBao passes in PLUGIN_CLIENT_CERT, and the GRPCController, GRPCBroker, GRPCStdio services go-plugin expects.
  • plugin.GRPCBackend from OpenBao's sdk/plugin/pb/backend.proto (vendored at a pinned OpenBao revision with its licence): Setup, Initialize, SpecialPaths, HandleRequest, HandleExistenceCheck, Type, Cleanup, InvalidateKey. Storage and system views are reached by dialling the broker ID Setup supplies (Storage, SystemView services), which is how IntentStore, LeaseStore, WrapStore and LeaseBackend get a durable implementation without the plugin owning a file.
  • Paths: issue, lease/<id> (read), lease/<id>/renew, lease/<id>/revoke, unwrap/<token>; responses carry OpenBao Secret lease metadata so OpenBao's own lease manager calls renew/revoke.
  • PrivateMint over the private transport Vedanta #47 serves (unix socket, signed envelope); the plugin holds the Ed25519 signing key from a path OpenBao's plugin environment supplies, never in storage.
  • The go-plugin handshake and every proto message get capture-double tests; an integration check that runs a real bao binary in dev mode with plugin_directory set and registers the built binary is the acceptance test.

Tasks

  • Vendor the pinned OpenBao/go-plugin proto files and generate with tonic-build.
  • Implement the handshake, auto-mTLS, and the three go-plugin control services.
  • Implement GRPCBackend and route the five paths to IssueService / LeaseService.
  • Implement the broker-backed Storage client and the four stores over it.
  • Return Secret lease metadata so OpenBao's lease manager owns renew/revoke.
  • Integration check against bao server -dev with the plugin registered; record measured results.

Specification Delta

Requirement: OpenBao owns the lease it issued

Scenario: the mount is used end to end in dev mode

  • GIVEN the built plugin registered in OpenBao's catalog and mounted
  • WHEN a claimant writes issue and then reads, renews, and revokes the lease
  • THEN OpenBao's lease manager drives the plugin's renew and revoke paths
  • AND the credential value is observable only through one unwrap

OpenSpec

Projects from contracts.identity.openbao-lease-backend (openbao-owns-the-public-lease-contract, credential-material-is-one-shot, operation-ids-are-idempotent-and-replay-safe, pilot-timing-follows-grant-version-0-1-4).

Structural parent

Ting/Ting#60; continues #20 / #12 / #24. Sibling of #47 (the Vedanta side of the same transport).

Provenance

Filed by the queen session of the 2026-09-05 delivery run (Claude Code, harness ba993052); ruling D1 attributed to Larandar in-session.

## Proposal Turn `openbao-plugin` from a library OpenBao cannot load into a secrets-engine plugin binary OpenBao spawns, so OpenBao actually owns the lease the contract says it owns. ### Why `openbao-plugin/` (PR #27, Session #20) holds the ordered issue flow, the lease machine, the one-shot wrapper, and the signed command dispatch — as a Rust library behind trait ports (`IntentStore`, `PrivateMint`, `LeaseStore`, `WrapStore`, `LeaseBackend`). Nothing speaks OpenBao's plugin protocol: no go-plugin handshake, no `GRPCBackend` service, no broker dial-back for storage. OpenBao's SDK is Go only; no Rust plugin SDK exists. The 2026-09-05 delivery run for [Ting/Ting#60](https://jo.et0.pw/Ting/Ting/issues/60) found this as the largest delta on the canonical path, and the freeholder ruled (Larandar, 2026-09-05, in-session, ruling D1): *"it's better to have the plugin be same language as Vedanta so Rust it is."* ## Session review boundary One PR, one verdict: OpenBao loads the binary from its plugin catalog, mounts it, and issue/read/renew/revoke on the mount drive the existing Rust flows unchanged; storage goes through OpenBao's broker; the credential value crosses only inside the wrapped response. ## Design - A `[[bin]]` in `openbao-plugin` (or a sibling crate) implementing the go-plugin protocol with `tonic`/`prost`: the handshake line on stdout (`CORE-PROTOCOL-VERSION|APP-PROTOCOL-VERSION|unix|<socket>|grpc|<base64 cert>`), the magic-cookie env check, auto-mTLS with the client certificate OpenBao passes in `PLUGIN_CLIENT_CERT`, and the `GRPCController`, `GRPCBroker`, `GRPCStdio` services go-plugin expects. - `plugin.GRPCBackend` from OpenBao's `sdk/plugin/pb/backend.proto` (vendored at a pinned OpenBao revision with its licence): `Setup`, `Initialize`, `SpecialPaths`, `HandleRequest`, `HandleExistenceCheck`, `Type`, `Cleanup`, `InvalidateKey`. Storage and system views are reached by dialling the broker ID `Setup` supplies (`Storage`, `SystemView` services), which is how `IntentStore`, `LeaseStore`, `WrapStore` and `LeaseBackend` get a durable implementation without the plugin owning a file. - Paths: `issue`, `lease/<id>` (read), `lease/<id>/renew`, `lease/<id>/revoke`, `unwrap/<token>`; responses carry OpenBao `Secret` lease metadata so OpenBao's own lease manager calls renew/revoke. - `PrivateMint` over the private transport Vedanta #47 serves (unix socket, signed envelope); the plugin holds the Ed25519 signing key from a path OpenBao's plugin environment supplies, never in storage. - The go-plugin handshake and every proto message get capture-double tests; an integration check that runs a real `bao` binary in dev mode with `plugin_directory` set and registers the built binary is the acceptance test. ## Tasks - [ ] Vendor the pinned OpenBao/go-plugin proto files and generate with `tonic-build`. - [ ] Implement the handshake, auto-mTLS, and the three go-plugin control services. - [ ] Implement `GRPCBackend` and route the five paths to `IssueService` / `LeaseService`. - [ ] Implement the broker-backed `Storage` client and the four stores over it. - [ ] Return `Secret` lease metadata so OpenBao's lease manager owns renew/revoke. - [ ] Integration check against `bao server -dev` with the plugin registered; record measured results. ## Specification Delta ### Requirement: OpenBao owns the lease it issued #### Scenario: the mount is used end to end in dev mode - **GIVEN** the built plugin registered in OpenBao's catalog and mounted - **WHEN** a claimant writes `issue` and then reads, renews, and revokes the lease - **THEN** OpenBao's lease manager drives the plugin's renew and revoke paths - **AND** the credential value is observable only through one `unwrap` ## OpenSpec Projects from `contracts.identity.openbao-lease-backend` (`openbao-owns-the-public-lease-contract`, `credential-material-is-one-shot`, `operation-ids-are-idempotent-and-replay-safe`, `pilot-timing-follows-grant-version-0-1-4`). ## Structural parent [Ting/Ting#60](https://jo.et0.pw/Ting/Ting/issues/60); continues [#20](https://jo.et0.pw/Ting/Vedanta/issues/20) / [#12](https://jo.et0.pw/Ting/Vedanta/issues/12) / [#24](https://jo.et0.pw/Ting/Vedanta/issues/24). Sibling of #47 (the Vedanta side of the same transport). ## Provenance Filed by the queen session of the 2026-09-05 delivery run (Claude Code, harness ba993052); ruling D1 attributed to Larandar in-session.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Ting/Vedanta#48
No description provided.