MCPG
Guides
Guides7 min

Install MCPG with Pulumi

Install the MCPG operator and manage gateways with Pulumi — a typed CRD SDK, opinionated components, the config builder, and a CrossGuard policy pack that mirrors the operator's admission rules at preview.

The MCPG Pulumi offering is three packages that deliver the same capabilities as the Terraform suite in a general-purpose language (TypeScript today; Python / Go / C# / Java via multi-language packaging):

PackageRole
@mcpg/pulumi-crdstyped CRD resource classes, generated by crd2pulumi from the operator's CRD OpenAPI (all 8 mcpg.dev kinds)
@mcpg/pulumiopinionated components — Operator, Gateway, PluginSet, TrustBootstrap, Tenant, McpgStack — plus the config builder
@mcpg/pulumi-policya CrossGuard policy pack mirroring the operator's admission rules at pulumi preview

Why Pulumi maps cleanly

  • The Kubernetes provider does server-side apply by default and awaits readiness (pulumi.com/waitFor: condition=Ready) — so the operator-install ordering and gateway readiness are handled for you.
  • Secrets are encrypted in state by default; ESC is the secret/config backend; the Pulumi Kubernetes Operator gives a Pulumi-native GitOps loop.

Prerequisites

  • Node.js + the Pulumi CLI, a Pulumi state backend (Pulumi Cloud or self-managed S3/GCS/Azure-Blob/filesystem), and a kubeconfig.
  • npm i @mcpg/pulumi @mcpg/pulumi-crds (the policy pack is referenced at preview time, not imported into your program).
  • cert-manager installed in the cluster. The Operator component defaults certManager.enabled=true (the admission webhook fails closed and needs real TLS); override via operator.values.certManager for BYO TLS.

Beta note: the operator chart is not yet published to oci://ghcr.io/mcpg-dev/source-code/charts (reserved, not live). For now set operator.chartRepo to a local path or a private OCI mirror.

Quick start

ts
import { McpgStack } from "@mcpg/pulumi";

export const stack = new McpgStack("prod", {
  operator: { chartVersion: "0.1.0" },                 // installs the operator
  gateway: {
    image: { repository: "ghcr.io/mcpg-dev/gateway", tag: "v1.0.0-rc.17" },
    governance: { audit: { sinks: [{ kind: "dev.mcpg.builtin.audit.local-file" }] } },
  },
});

pulumi up installs the operator (CRDs as first-class resources, crd.install=false), seeds cluster-default trust, and creates a gateway that waits for Ready. The same program runs from Python/Go/C#/Java once the multi-language SDKs are published.

Components

Operator

Installs the chart via kubernetes.helm.v4.Chart (SSA) with the CRDs applied as explicit resources — closing the Helm-doesn't-upgrade-CRDs hazard.

ts
import { Operator } from "@mcpg/pulumi";
const op = new Operator("mcpg", { chartVersion: "0.1.0", namespace: "mcpg-system" });

Gateway + the config builder

Typed sections plus an extraConfig escape hatch merged last; readiness via the built-in waitFor annotation.

ts
import { Gateway } from "@mcpg/pulumi";
new Gateway("orders", {
  namespace: "mcpg-system",
  image: { repository: "…", tag: "…" },
  replicas: 3,
  governance: { audit: { sinks: [{ kind: "dev.mcpg.builtin.audit.local-file" }] } },
  plugins: [{ id: "db.read", source: { oci: "plugins/sql:1.4.2" }, enforce: true }],
  extraConfig: { /* anything not yet typed */ },
}, { dependsOn: op });

The assembled spec.config is the gateway's own AppConfig — see the configuration reference.

Tenant

Namespace + NetworkPolicy isolation + plugin-set + gateway — fan out a fleet with a plain loop:

ts
import { Tenant } from "@mcpg/pulumi";
for (const t of tenants) {
  new Tenant(t.name, { tenantName: t.name, gateway: { image: t.image }, pluginSet: { entries: [] } });
}

See the multi-tenant deployments guide for the tenant model these components implement.

Typed CRD SDK

@mcpg/pulumi-crds gives you the raw typed classes when you need them:

ts
import { mcpg } from "@mcpg/pulumi-crds";
new mcpg.v1alpha2.MCPGGateway("orders", {
  metadata: { namespace: "mcpg-system" },
  spec: { image: { repository: "…", tag: "…" }, config: {} },
});

Regenerate after a CRD change: nx run pulumi-mcpg-crds:codegen (the codegen-check drift gate keeps it in sync in CI). The CRD set is documented in the operator CRD reference.

Policy (CrossGuard)

Enforce the operator's admission rules before deploy:

bash
pulumi preview --policy-pack node_modules/@mcpg/pulumi-policy

Rules: gateway workload-identity one-of; plugin digest-or-cosign with an anchored certificateIdentityRegexp; plugin-set entry-id uniqueness; revocation-list 64-hex + no duplicates. The same pure validators feed MCPG's cross-tool contract test, so they never drift from admission.

Commands (Nx)

bash
nx run pulumi-mcpg-crds:codegen        # regenerate the typed SDK
nx run pulumi-mcpg-crds:codegen-check  # drift gate
nx run pulumi-mcpg:typecheck           # tsc --noEmit
nx run pulumi-mcpg-policy:test         # validator unit tests

Compatibility

@mcpg/pulumi*Operator chartCRD apiVersionPulumi@pulumi/kubernetes
0.x0.1.xv1alpha2≥ 3.x≥ v4

Secrets, GitOps, day-2

  • Secrets — reference K8s Secrets by name; unavoidable values use pulumi.secret() (encrypted in state). ESC projects signing keys / TLS / tokens from Vault / cloud KMS.
  • GitOps — run the program in-cluster via the Pulumi Kubernetes Operator (Stack CRD), or have Argo CD / Flux sync rendered manifests.
  • Day-2 / DR — declarative input edits; the Automation API scripts DR ordering (CRDs → operator → trust → CRs) and CR snapshot/restore.

See also