---
apiVersion: fundament.io/v1
kind: PluginDefinition
spec:
metadata:
name: cert-manager
displayName: Cert Manager
version: v1.17.2
description: Automated TLS certificate management for Kubernetes using cert-manager.
author: Fundament
license: Apache-2.0
icon: shield-check
urls:
homepage: https://cert-manager.io
repository: https://github.com/cert-manager/cert-manager
documentation: https://cert-manager.io/docs
tags:
- certificates
- tls
- security
FUN-11 Plugins and the Marketplace
1. Introduction
Fundament takes a minimalistic approach when it comes to Clusters, which are lightweight by default and have only the bare minimum installed. To add functionality, users may either decide to roll their own platform services and applications, or rely on the experience of others to provide packaged solutions. Plugins are a way to install and share solutions ranging from basic platform needs (object storage, gateway, dns) to complete application suites (zaaksysteem).
2. Functional requirements
-
Fundament must provide users with a generic system for installing/uninstalling of service/platform functionality into their Clusters. For now, we call this 'Plugins'.
-
Fundament must provide users with a single-pane-of-glass of all services and tools provided by Plugins.
-
Organization admins need to be able to configure and observe Plugins installed in Clusters.
-
Project members need to be able to see resources that are deployed (managed by the Plugin) in their Projects.
-
For example:
cert-managerplugin needs to show users the CertificateRequests that are being tracked in their projects.
-
-
-
Plugins must be installable in Clusters that are airgapped/offline. It is up to the implementation of the Plugin whether it is itself compatible in an airgapped/offline environment.
-
Fundament must own the complete failure domain of the Plugin installation lifecycle.
-
The plugin system by Fundament must be initially simple; Plugins themselves can become more complex when required.
-
Plugin implementations must have the flexibility to decide themselves whether they are configurable through their own CRD or by exposing the CRDs of a tool/application they may be wrapping.
-
Plugins may declare (optional) dependencies, but this is not enforced by Fundament. The plugin must be built to be eventually-consistent.
-
Plugins must declare their requirements upfront (e.g.: when a plugin needs internet access, it must declare this so the user can approve the requirements before a plugin is installed)
3. Plugin Definition
A Plugin Definition is a YAML manifest that declares the outline of a plugin. It uses a Kubernetes-style structure with apiVersion and kind:
permissions:
capabilities:
- internet_access
rbac:
- apiGroups:
- cert-manager.io
resources:
- certificates
- issuers
- clusterissuers
- certificaterequests
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
menu:
organization:
- crd: clusterissuers.cert-manager.io
list: true
detail: true
create: true
icon: globe
project:
- crd: certificates.cert-manager.io
list: true
detail: true
create: true
icon: file-lock
- crd: certificaterequests.cert-manager.io
list: true
detail: true
create: false
icon: file-search
uiHints:
certificates.cert-manager.io:
statusMapping:
jsonPath: ".status.conditions[?(@.type==\"Ready\")].status"
values:
"True":
badge: success
label: Ready
"False":
badge: danger
label: Not Ready
---
The definition is validated by plugin-sdk/pluginruntime/LoadDefinition() which checks apiVersion: fundament.io/v1 and kind: PluginDefinition.
3.1. Definition structure
-
metadata: Identifying information (name, displayName, version, description, author, license, icon, urls, tags).
-
permissions: What the plugin needs from the platform.
-
capabilities: Simple string list (e.g.internet_access). -
rbac: Kubernetes PolicyRule structures declaring the API groups, resources, and verbs the plugin requires.
-
-
menu: How the plugin appears in the Fundament console.
-
organization: Menu entries visible to organization admins (cluster-scoped CRDs). -
project: Menu entries visible to project members (namespace-scoped CRDs). -
Each entry has:
crd(fully-qualified CRD name),list,detail,create(booleans), andicon.
-
-
customComponents: Optional mapping of CRDs to custom UI component names (list/detail).
-
uiHints: Per-CRD form layout and status display hints.
-
formGroups: Groups of related fields for create/edit forms. -
statusMapping: Maps ajsonPathto badge/label values for status display.
-
-
crds: List of CRDs the plugin provides.
4. Plugin SDK
The Plugin SDK (plugin-sdk/pluginruntime/) provides the framework for building plugins. Plugin developers implement one or more interfaces and call pluginruntime.Run() to start the runtime.
4.1. Core interfaces
-
Plugin(required): The main interface withDefinition(),Start(ctx, host), andShutdown(ctx). -
Reconciler(optional): Adds periodic reconciliation viaReconcile(ctx, host)at a configurable interval (FUNP_RECONCILE_INTERVALenv var, default 5m). -
ConsoleProvider(optional): Serves console UI assets viaConsoleAssets(), mounted at/console/. -
Installer(optional): Adds structured lifecycle methods:Install(ctx, host),Uninstall(ctx, host),Upgrade(ctx, host).
4.2. Run harness
pluginruntime.Run() handles all boilerplate for the plugin binary:
-
Environment configuration via env vars (
FUNDAMENT_CLUSTER_ID,FUNDAMENT_INSTALL_ID,FUNDAMENT_ORGANIZATION_ID,FUNP_LOG_LEVEL,FUNP_RECONCILE_INTERVAL). -
Structured JSON logging (slog).
-
HTTP server on port 8080 (configurable via
WithMetadataPort()) with:-
GET /healthz- Liveness probe (always 200 OK). -
GET /readyz- Readiness probe (200 OK when plugin reports ready, 503 otherwise). -
PluginMetadataService- Connect RPC endpoint serving plugin status and definition. -
/console/- Static file server for console assets (ifConsoleProvideris implemented).
-
-
Signal handling (SIGTERM, SIGINT) with graceful shutdown (configurable via
WithShutdownTimeout(), default 30s). -
Reconcile loop (if
Reconcileris implemented). -
Error classification:
pluginerrors.Permanenterrors set phase tofailed,pluginerrors.Transienterrors set phase todegraded.
4.3. Host interface
The Host interface is passed to plugin methods and provides:
-
Logger()- Structured JSON logger. -
Telemetry()- OpenTelemetry tracing and metrics. -
ReportStatus(PluginStatus)- Update the plugin’s current phase and message. -
ReportReady()- Signal that the plugin is ready to serve traffic (enables the readiness probe).
4.4. Plugin phases (runtime)
-
installing- Initial installation in progress. -
running- Successfully installed and operating. -
degraded- Operating but with transient issues (retryable). -
failed- Permanent failure requiring intervention. -
uninstalling- Being removed.
4.5. Helpers
The SDK provides helpers for common patterns:
-
helpers/helm- Helm chart installation. -
helpers/crd- Kubernetes CRD verification. -
helpers/controllerruntime- Controller-runtime reconciler integration.
5. Plugin Controller
The plugin-controller is a Kubernetes controller that manages the lifecycle of plugin installations. It watches for PluginInstallation custom resources and reconciles the desired state.
5.1. PluginInstallation CRD
plugininstallations.plugins.fundament.io is the custom resource for plugin instances:
---
apiVersion: plugins.fundament.io/v1
kind: PluginInstallation
metadata:
name: cert-manager
spec:
image: ghcr.io/fundament-plugins/cert-manager:v1.17.2
pluginName: cert-manager
version: v1.17.2
clusterRoles: [] # optional: ClusterRoles to bind
config: {} # optional: key-value config (injected as FUNP_* env vars)
---
Status fields: phase, message, ready, observedGeneration, pluginVersion.
5.2. Installation lifecycle
When a PluginInstallation is created, the controller:
-
Validates the plugin name (must be a valid DNS label, max 56 chars).
-
Creates a namespace
plugin-{pluginName}. -
Creates a ServiceAccount
plugin-{pluginName}in that namespace. -
Creates a RoleBinding binding the ServiceAccount to the built-in
adminClusterRole within the plugin namespace. -
Optionally creates ClusterRoleBindings for any
clusterRolesspecified in the spec. -
Creates a Deployment
runtimein the plugin namespace with the specified container image. -
The Deployment includes liveness (
/healthz) and readiness (/readyz) probes. -
Plugin config values are injected as
FUNP_*environment variables. -
Polls the plugin’s
PluginMetadataServiceendpoint to track status and readiness.
All child resources are labeled with:
-
app.kubernetes.io/managed-by: plugin-controller -
plugins.fundament.io/plugin: {pluginName} -
plugins.fundament.io/installation-name -
plugins.fundament.io/installation-namespace
Deletion is handled via a finalizer; the controller cleans up child resources before removing the finalizer.
5.3. Controller phases
-
Pending- Installation created, not yet reconciled. -
Deploying- Child resources being created. -
Running- Plugin runtime reports healthy. -
Degraded- Plugin runtime reports transient issues. -
Failed- Plugin runtime reports permanent failure. -
Terminating- Being deleted, cleaning up resources.
6. Console integration
When a Plugin is installed in a Cluster, the Console UI displays menu items based on the plugin’s menu definition:
-
Organization menu (for the organization admin): Cluster-scoped CRDs (e.g. CertificateIssuers).
-
Project menu (for the project member): Namespace-scoped CRDs (e.g. Certificates, CertificateRequests).
Each menu entry can enable list, detail, and create views. Icons are specified per entry.
The Plugin Runtime may serve console UI assets at /console/ (via the ConsoleProvider interface), but it does NOT proxy data. Data access goes through the normal Kubernetes API with standard RBAC.
Plugins can declare uiHints per CRD, providing:
-
statusMapping: Maps a JSON path in the resource status to badge styles and labels (e.g. a Ready condition mapped to a green "Ready" badge).
-
formGroups: Groups related fields together in create/edit forms.
-
customComponents: Allows plugins to override the default list/detail views with custom UI components.
Upgrading is allowed within the same major version of the plugin.
7. Marketplace
The marketplace is implemented as an appstore schema in the organization-api database:
-
plugins: Plugin metadata (name, description, author, repository URL, etc.).
-
tags / categories: Classification and filtering of plugins.
-
plugin_documentation_links: Associated documentation links per plugin.
-
presets: Predefined plugin bundles (e.g. "production essentials" preset that includes cert-manager, observability, etc.).
-
installs: Tracks which plugins are installed on which clusters.
The PluginService API in organization-api provides:
-
ListPlugins()- Returns plugins with tags and categories. -
GetPluginDetail()- Returns detailed plugin info including documentation links. -
ListPresets()- Returns predefined plugin collections.
RLS policy ensures users can only view installations for clusters in their organization.
7.1. Sideloading
Plugin Definitions can be sideloaded; manually inserted into Fundament by an Organization Admin. The sideloaded Plugin Definition will only be visible within the Organization that it was sideloaded to and can only be installed in Clusters within that Organization.
7.2. Airgapped / offline support
For airgapped/offline clusters, plugins must be able to host container images on the Fundament servers (registry). This means a plugin becomes more than just a Plugin Definition file.
8. Example: cert-manager plugin
A reference implementation exists at plugins/cert-manager/:
-
definition.yamldeclares the plugin’s metadata, permissions, menu entries, and UI hints. -
plugin.goimplementsPlugin,Reconciler, andInstallerinterfaces:-
Start()checks Helm installation status, installs if needed, creates K8s client, verifies CRDs, reports ready. -
Reconcile()periodically verifies CRDs and updates status. -
Install()/Uninstall()/Upgrade()manage the Helm release.
-
-
main.goloads the definition and callspluginruntime.Run().
Scenario:
-
Organization Admin installs Plugin "cert-manager" into Cluster "foo" at version
v1.17.2. -
A
PluginInstallationCR is created;plugin-controllerreconciles it. -
plugin-controllercreates namespaceplugin-cert-manager, ServiceAccount, RoleBinding, and Deployment. -
The Plugin Runtime uses Helm to install cert-manager in its own namespace.
-
The Plugin Runtime starts hosting the metadata server.
plugin-controllerpolls the metadata endpoint and tracks plugin status and readiness. -
The Plugin Runtime starts hosting console assets at
/console/. -
An organization admin assigns 'CertManager Editor' Role to users in
{cluster=foo, project=bar, namespace=baz}. -
A user navigates to the console and opens the Certificates page, which loads UI components served by the Plugin Runtime.
-
The Certificates UI component uses the Kubernetes API to list Certificates. Since the user has the appropriate Role, kube-api allows access and the certificates are displayed.
-
Users without the appropriate Role receive an error from kube-api.