Skip to content

[Tier 7] Plugin SDK + signed plugin registry (the platform play) #64

@dcoln25-writer

Description

@dcoln25-writer

Problem

Aperio ships 7 connectors, 7 SIEM destinations, and (post-#50) 6+ workflow destinations. Every additional integration today requires a PR into core, code review by Aperio maintainers, a release, and a deploy. That model does not scale to the long tail:

The HashiCorp Terraform-provider model is the canonical answer: define a stable plugin interface, let the community ship plugins out-of-tree, build a registry. Aperio's bet is that an OSS-licensed plugin ecosystem outruns every closed SSPM's first-party integration roadmap by an order of magnitude.

This is the platform play. The first 19 issues build the product; this one builds the moat.

Goals

  1. Plugin interface (gRPC over stdin/stdout, à la terraform-plugin-go) for three extension points:
    • Connector plugins — new providers (auth, sync, event normalization).
    • Remediation handler plugins — new provider-side write actions.
    • SIEM / workflow destination plugins — new outbound transports.
  2. Plugin host in the Go server that discovers, fork/execs, supervises, and tears down plugin binaries.
  3. Plugin SDK packages — Go (first-class) and Python (for the data/security engineering community) helper libraries that hide the gRPC plumbing.
  4. Project templateaperio plugin init github.com/acme/aperio-plugin-foo produces a buildable skeleton.
  5. Plugin registry — published index of community plugins (mirrors registry.terraform.io).
  6. Signing + supply-chain guards — every plugin binary signed via Sigstore; tenants can opt-in to "verified publishers only".

Non-goals

  • Not running plugins inside the API process (security boundary; isolation matters).
  • Not building a UI marketplace in v1 — registry is a published index; install is operator-driven.
  • Not building wasm plugins in v1 — fork/exec gRPC is well-trodden; wasm is the v2 conversation.

Proposed design

Plugin interface (gRPC schema)

// proto/aperio/plugin/v1/connector.proto
service ConnectorPlugin {
  rpc Schema(SchemaRequest) returns (SchemaResponse);          // declares config schema, scopes, capabilities
  rpc TestConnection(TestRequest) returns (TestResponse);
  rpc Sync(SyncRequest) returns (stream SyncEvent);            // streams normalized aperio.event.v1 envelopes
  rpc OAuthCallback(OAuthCallbackRequest) returns (OAuthCallbackResponse);
}

service RemediationPlugin {
  rpc Capabilities(CapabilitiesRequest) returns (CapabilitiesResponse);
  rpc Execute(ExecuteRequest) returns (ExecuteResponse);
}

service DestinationPlugin {
  rpc Capabilities(CapabilitiesRequest) returns (CapabilitiesResponse);
  rpc Deliver(DeliverRequest) returns (DeliverResponse);
}

All payloads use Aperio's existing event/finding envelopes from proto/aperio/contracts/v1/.

Plugin host

internal/pluginhost/ Go package:

  1. Reads ~/.aperio/plugins/ (or configurable directory) for plugin binaries on startup.
  2. For each plugin, fork/execs the binary and establishes a gRPC connection over its stdout/stdin (HashiCorp go-plugin library is the reference impl — battle-tested).
  3. Maintains a registry of available connectors / remediations / destinations the host has discovered.
  4. Heartbeats; restarts crashed plugins with exponential backoff; circuit-breaks repeatedly-failing plugins.
  5. Per-plugin resource limits (CPU, memory, file-descriptor count, network egress allowlist).

Plugin lifecycle in the product

  • Operators install plugins via aperio plugin install <registry-ref> (depends on Public API surface: tokens, OpenAPI, SDKs, Terraform provider, aperio CLI #52 CLI) — pulls signed binary from the registry, verifies signature, drops into the plugin directory.
  • Plugins appear in the existing connector / SIEM / workflow / remediation catalogs alongside built-ins; UI surfaces a "Community plugin" badge.
  • All existing tenant-isolation guarantees apply: plugins receive only the org-scoped credentials needed for their work.

Project template

aperio plugin init github.com/acme/aperio-plugin-box

Generates:

aperio-plugin-box/
├── README.md
├── go.mod
├── plugin.go              # main entrypoint; wires SDK + provider logic
├── connector.go           # ConnectorPlugin impl
├── connector_test.go
├── manifest.yaml          # plugin metadata: name, version, provider id, scopes
└── .github/workflows/release.yml  # build + Sigstore sign + publish

Plugin SDK

// pkg/aperio-plugin-go/sdk.go
import "github.com/writer/aperio-plugin-go/connector"

type BoxConnector struct{ /* ... */ }

func (b *BoxConnector) Schema(...) (*connector.SchemaResponse, error) { ... }
func (b *BoxConnector) Sync(req *connector.SyncRequest, stream connector.SyncStream) error {
    for event := range b.iterEvents(req) {
        if err := stream.Send(event); err != nil { return err }
    }
    return nil
}

func main() {
    connector.Serve(&BoxConnector{})
}

The SDK handles transport, error envelope conversion, panic recovery, structured logging conversion, and Aperio envelope encoding so plugin authors write business logic only.

Registry

A published JSON manifest at https://registry.aperio.io/plugins.json (initially a flat list, can grow into a real registry later):

{
  "version": 1,
  "updated_at": "2026-06-06T00:00:00Z",
  "plugins": [
    {
      "id": "acme/box-connector",
      "kind": "connector",
      "versions": [
        {
          "version": "1.0.0",
          "download_url": "https://github.com/acme/aperio-plugin-box/releases/.../linux-amd64.tar.gz",
          "sha256": "...",
          "sigstore_bundle": "...",
          "publisher": {"name": "acme", "verified": true}
        }
      ]
    }
  ]
}

PR-reviewed contributions to the registry; CI verifies Sigstore signatures + plugin manifest schema.

Phasing

Phase Scope
P1 Plugin interface protos; plugin host using go-plugin; Go SDK; project template + aperio plugin init; one reference plugin (Box connector) to dogfood the SDK
P2 Remediation + Destination plugin interfaces; CLI commands aperio plugin install/list/remove; Sigstore signing pipeline; registry JSON publication
P3 Python SDK; "Community plugin" badge in UI; per-plugin resource limits; circuit breaker semantics
P4 Plugin marketplace UI inside Aperio; verified-publisher review process; cross-tenant plugin telemetry (anonymized, opt-in) to surface "popular plugins"

Open questions

  • Plugin compatibility across Aperio versions — semver the plugin interface; minor-version-skew safe, major-version-skew enforced at load time.
  • How do plugins persist state? Recommend: stateless plugins + writes back through the host's existing repositories. Stateful plugins (caches, watermarks) get a host-provided KV interface, never their own storage.
  • Auth model for plugin → external APIs — plugins receive scoped tokens minted by the host per-invocation, never long-lived secrets.
  • Registry governance — Aperio org-maintained for v1, evolves toward community-elected if/when scale demands.

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    developer-experiencePublic API, SDKs, Terraform, CLIplugin-sdkPlugin SDK + community plugin registrytier-7-audience-expansionTier 7: new audiences (execs, customers, ecosystem)

    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