---
title: "Crossplane"
description: "Manage PgBeam projects, databases, replicas, custom domains, cache rules, spend limits, agent credentials, policy profiles, webhook endpoints, self host enrollments, honeytokens, anomaly rules, approval rules, and query templates as Kubernetes custom resources using the Crossplane provider."
canonical: "https://pgbeam.com/docs/crossplane"
last-updated: "2026-10-29T19:01:20.000Z"
---

# Crossplane

> Manage PgBeam projects, databases, replicas, custom domains, cache rules, spend limits, agent credentials, policy profiles, webhook endpoints, self host enrollments, honeytokens, anomaly rules, approval rules, and query templates as Kubernetes custom resources using the Crossplane provider.

URL: https://pgbeam.com/docs/crossplane

Manage your PgBeam infrastructure as Kubernetes custom resources with Crossplane. The `provider-pgbeam` package provides managed resources for projects, databases, replicas, custom domains, cache rules, spend limits, agent credentials, policy profiles, webhook endpoints, self host enrollments, honeytokens, anomaly rules, approval rules, and query templates.

## Setup

### Install the provider

> The Crossplane provider is coming soon. Registry publishing is on the roadmap.

```yaml title="provider.yaml"
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-pgbeam
spec:
  package: ghcr.io/sferarc/provider-pgbeam:latest
```

```bash
kubectl apply -f provider.yaml
```

### Configure credentials

Create a Secret with your PgBeam API key, then reference it in a ProviderConfig:

```yaml title="secret.yaml"
apiVersion: v1
kind: Secret
metadata:
  name: pgbeam-credentials
  namespace: crossplane-system
type: Opaque
stringData:
  api-key: pgb_your_api_key
```

```yaml title="provider-config.yaml"
apiVersion: pgbeam.com/v1alpha1
kind: ProviderConfig
metadata:
  name: default
spec:
  apiKeySecretRef:
    name: pgbeam-credentials
    namespace: crossplane-system
    key: api-key
  baseUrl: https://api.pgbeam.com # optional
```

```bash
kubectl apply -f secret.yaml -f provider-config.yaml
```

### Create a project

```yaml title="project.yaml"
apiVersion: pgbeam.com/v1alpha1
kind: Project
metadata:
  name: my-app
spec:
  forProvider:
    orgID: org_abc123
    name: my-app
    database:
      host: my-rds.us-east-1.rds.amazonaws.com
      port: 5432
      name: mydb
      username: pgbeam
      passwordSecretRef:
        name: db-credentials
        namespace: default
        key: password
  providerConfigRef:
    name: default
```

### Apply

```bash
kubectl apply -f project.yaml
```

Crossplane creates the PgBeam project and its primary database atomically. The proxy hostname is available in `status.atProvider.proxyHost` and published to the connection secret.

```bash
kubectl get project my-app -o jsonpath='{.status.atProvider.proxyHost}'
```

## Resources

> **Every policy rule type is managed as code.** Policy profiles, honeytokens,
> anomaly rules, approval rules and query templates are managed resources, so
> the enforcement rules, the decoys, the detection sensitivity, what needs a
> human and the statements a templates-only credential may run all live in your
> reviewed IaC flow and are covered by drift detection. Approving or rejecting
> an individual held statement is an operational decision rather than
> configuration, so it stays in the dashboard, the CLI and the API.

### Project

Manages a PgBeam project with a primary database.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: Project
metadata:
  name: example
spec:
  forProvider:
    orgID: org_abc123
    name: my-app
    description: Production database proxy
    tags: ["production", "us-east-1"]
    allowedCidrs:
      [
        { cidr: "10.0.0.0/8", label: "VPC" },
        { cidr: "2001:db8::/32", label: "IPv6 range" },
      ]
    defaultPolicyProfileID: pol_01h455vb4pex5vsknk084sn02q
    residency: eu
    agentsDisabled: false
    status: active
  providerConfigRef:
    name: default
```

**Status:** `proxyHost`, `queriesPerSecond`, `burstSize`, `maxConnections`, `databaseCount`, `activeConnections`, `createdAt`, `updatedAt`, `primaryDatabaseID`

**Connection secret** (with `writeConnectionSecretToRef`): `proxyHost`

### Database

Manages an upstream database connection within a PgBeam project.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: Database
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01h455vb4pex5vsknk084sn02q
    host: db.example.com
    port: 5432
    name: mydb
    username: pgbeam
    sslMode: require
    role: primary
    poolRegion: us-east-1
    queryTimeoutMs: 0
    autoReadRouting: false
    cacheConfig:
      enabled: true
      ttlSeconds: 60
      maxEntries: 10000
      swrSeconds: 30
    poolConfig:
      poolSize: 20
      minPoolSize: 5
      poolMode: transaction
      maxActive: 200
    passwordSecretRef:
      name: credentials
      namespace: default
      key: password
  providerConfigRef:
    name: default
```

**Status:** `connectionString`, `createdAt`, `updatedAt`

**Connection secret** (with `writeConnectionSecretToRef`): `connectionString`

### Replica

Manages a read replica for a PgBeam database.

Replicas are immutable: the API server rejects any spec change, so delete and recreate the resource instead.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: Replica
metadata:
  name: example
spec:
  forProvider:
    databaseID: db_01h455vb4pex5vsknk084sn02q
    host: replica.db.example.com
    port: 5432
    sslMode: require
  providerConfigRef:
    name: default
```

**Status:** `createdAt`, `updatedAt`

### CustomDomain

Manages a custom domain for a PgBeam project.

CustomDomains are immutable: the API server rejects any spec change, so delete and recreate the resource instead.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: CustomDomain
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01h455vb4pex5vsknk084sn02q
    domain: db.example.com
  providerConfigRef:
    name: default
```

**Status:** `verified`, `verifiedAt`, `tlsCertExpiry`, `dnsVerificationToken`, `dnsInstructions`, `createdAt`, `updatedAt`

**Connection secret** (with `writeConnectionSecretToRef`): `dnsVerificationToken`

### CacheRule

Manages a per-query cache rule. Deletion disables caching (soft-delete).

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: CacheRule
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01h455vb4pex5vsknk084sn02q
    databaseID: db_01h455vb4pex5vsknk084sn02q
    queryHash: a1b2c3d4e5f60718
    cacheEnabled: true
    cacheTTLSeconds: 300
    cacheSWRSeconds: 60
  providerConfigRef:
    name: default
```

**Status:** `queryHash`, `normalizedSQL`, `queryType`, `callCount`, `avgLatencyMs`, `p95LatencyMs`, `avgResponseBytes`, `stabilityRate`, `recommendation`, `firstSeenAt`, `lastSeenAt`

### SpendLimit

Manages the monthly spend limit for an organization.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: SpendLimit
metadata:
  name: example
spec:
  forProvider:
    orgID: org_abc123
    spendLimit: 500
  providerConfigRef:
    name: default
```

**Status:** `orgID`, `plan`, `billingProvider`, `subscriptionStatus`, `currentPeriodEnd`, `enabled`, `customPricing`, `spendCapped`, `spendCappedAt`, `limits`, `createdAt`, `updatedAt`

### AgentCredential

Manages a scoped agent credential (a PgBeam-issued Postgres login plus a hosted MCP token) for an AI agent. The connection string and MCP token are one-time secrets returned only at creation and exposed as sensitive computed outputs; they cannot be retrieved again. To rotate the secrets, taint/replace the resource (or use the rotate endpoint out of band).

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: AgentCredential
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01h455vb4pex5vsknk084sn02q
    policyProfileID: pol_01h455vb4pex5vsknk084sn02q
    name: Claude Code (analytics)
    status: active
    principalType: agent
    expiresAt: ...
  providerConfigRef:
    name: default
```

**Status:** `pgUsername`, `authMethod`, `lastUsedAt`, `createdAt`, `updatedAt`, `mcpURL`

**Connection secret** (with `writeConnectionSecretToRef`): `connectionString`, `mcpToken`

### PolicyProfile

Manages a policy profile: a named bundle of agent-gateway enforcement rules (access mode, table allow/deny lists, statement-kind rules, PII masking rules, per-relation row filters, query/egress budgets, write mode, approvals, and migration safety) attached to agent credentials and enforced in the PG wire protocol. Nested-list fields (masking_rules, row_filters) and the nested statement_rules object are expressed as structured config.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: PolicyProfile
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01h455vb4pex5vsknk084sn02q
    name: Read-only analytics
    accessMode: read_only
    statementRules:
      allow: ["..."]
      deny: ["..."]
    tableAllowlist: ["..."]
    tableDenylist: ["..."]
    maskingRules: ["..."]
    budgetQueriesPerHour: 0
    budgetQueriesPerDay: 0
    maxRows: 0
    statementTimeoutMs: 0
    rowFilters: ["..."]
    writeMode: normal
    approvalMode: off
    approvalAutoMaxRows: 0
    approvalTimeoutSeconds: 300
    migrationSafety: off
    egressBytesPerDay: 0
    maxAffectedRows: 0
    contentScanMode: off
    contentScanMaxBytes: 0
    queryMode: sql
  providerConfigRef:
    name: default
```

**Status:** `createdAt`, `updatedAt`

### WebhookEndpoint

Manages a webhook endpoint that receives project audit and anomaly event deliveries. The signing secret is write-only and never returned by the API.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: WebhookEndpoint
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01j9x8y7z6w5v4u3t2s1r0q9p8
    url: https://example.com/hooks/pgbeam
    format: json
    eventTypes: ["query_blocked", "canary_tripped"]
    enabled: true
    description: Read-only access for the reporting agent
    secretSecretRef:
      name: credentials
      namespace: default
      key: secret
  providerConfigRef:
    name: default
```

**Status:** `createdAt`, `updatedAt`

### SelfHostEnrollment

Manages a self-host (BYOC) enrollment: a token a self-hosted proxy uses to authenticate to the control plane's config/audit stream. The token is a one-time secret returned only at creation and exposed as a sensitive computed output; it cannot be retrieved again. To rotate the token, replace the resource. Deletion revokes the enrollment.

SelfHostEnrollments are immutable: the API server rejects any spec change, so delete and recreate the resource instead.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: SelfHostEnrollment
metadata:
  name: example
spec:
  forProvider:
    orgID: org_abc123
    regionLabel: customer-vpc-us-east
    description: prod cluster
    expiresAt: ...
  providerConfigRef:
    name: default
```

**Status:** `createdBy`, `createdAt`, `lastSeenAt`, `revokedAt`

**Connection secret** (with `writeConnectionSecretToRef`): `token`

### Honeytoken

Manages a honeytoken: a decoy (canary) relation that no legitimate query should ever touch. Any agent statement referencing it is blocked and recorded as a canary_tripped audit event; the kill action additionally disables the tripping credential via the kill-switch. The relation does not have to exist in the upstream database: enforcement is by name, in the wire protocol, before the statement reaches Postgres.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: Honeytoken
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01j9x8y7z6w5v4u3t2s1r0q9p8
    schemaName: public
    relationName: customer_ssns
    action: audit_only
  providerConfigRef:
    name: default
```

**Status:** `createdAt`, `updatedAt`

### AnomalyRule

Manages an anomaly rule: the sensitivity of one detection metric for one project, or for one agent credential in it. Without a rule every metric resolves to the deployment default, so a credential that legitimately runs at 3am cannot be exempted and a noisy one cannot be loosened. Note the polarity of enabled: the rule IS the switch, so enabled=false silences the metric for that scope rather than deactivating the rule. One rule exists per (project, credential, metric); a second one for the same scope is a conflict. Detection runs in the control plane and re-reads the rules on every pass, so a write takes effect at the next detection pass rather than being pushed to the proxy.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: AnomalyRule
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01j9x8y7z6w5v4u3t2s1r0q9p8
    credentialID: agt_01j9x8y7z6w5v4u3t2s1r0q9p8
    metric: bytes_per_hour
    sigmaThreshold: 4.5
    floor: 100
    enabled: true
  providerConfigRef:
    name: default
```

**Status:** `createdAt`, `updatedAt`

### ApprovalRule

Manages an approval rule: a named, project-scoped rule that sends the agent statements it matches to a human for approval, whatever the policy profile's approval_mode says. A rule can only add approval; no rule can exempt a statement from approval_mode. Match on statement kinds, a schema, a relation, and optionally a minimum affected-row count. The name is shown to the reviewer on every approval request the rule holds and must be unique within the project. enabled=false switches the rule off. A write is pushed to connected data planes immediately.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: ApprovalRule
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01j9x8y7z6w5v4u3t2s1r0q9p8
    name: payments deletes
    statementKinds: ["..."]
    schemaName: public
    relationName: payments
    minAffectedRows: 1000
    enabled: true
  providerConfigRef:
    name: default
```

**Status:** `createdAt`, `updatedAt`

### QueryTemplate

Manages a query template: a named, parameterized statement, scoped to a project, that a policy profile set to admit templates only lets its credentials run in place of raw SQL. A template admits a statement; it never grants access, so a statement it admits still meets the credential's whole policy. The sql is validated on every write and must be exactly one SELECT, INSERT, UPDATE or DELETE whose placeholders ($1, $2, ...) match params in order. The name must be unique within the project. enabled=false withdraws the template. A write is pushed to connected data planes immediately.

```yaml
apiVersion: pgbeam.com/v1alpha1
kind: QueryTemplate
metadata:
  name: example
spec:
  forProvider:
    projectID: prj_01j9x8y7z6w5v4u3t2s1r0q9p8
    name: open_orders_for_customer
    description: Open orders for one customer, newest first.
    sql: SELECT id, total FROM orders WHERE customer_id = $1 AND status = 'open' ORDER BY created_at DESC
    params: ["..."]
    includeSQL: false
    enabled: true
  providerConfigRef:
    name: default
```

**Status:** `statementKind`, `createdAt`, `updatedAt`

## Configuration

| Setting           | Source         | Description                                      |
| ----------------- | -------------- | ------------------------------------------------ |
| `apiKeySecretRef` | ProviderConfig | Secret reference for the API key                 |
| `baseUrl`         | ProviderConfig | API base URL (default: `https://api.pgbeam.com`) |

## Immutable fields

Crossplane never replaces a managed resource on its own. The fields below are immutable: the API server rejects an edit that changes, sets or removes them, with an error such as `projectID is immutable; delete and recreate the resource to change it`. To change one, delete the managed resource and create it again with the new value.

| Resource           | Immutable fields                                                     |
| ------------------ | -------------------------------------------------------------------- |
| Project            | `orgID`, `cloud`, `selfHosted`, `database`                           |
| Database           | `projectID`                                                          |
| Replica            | Any spec change (immutable)                                          |
| CustomDomain       | Any spec change (immutable)                                          |
| CacheRule          | `projectID`, `databaseID`, `queryHash`                               |
| SpendLimit         | `orgID`                                                              |
| AgentCredential    | `projectID`, `policyProfileID`, `name`, `principalType`, `expiresAt` |
| PolicyProfile      | `projectID`                                                          |
| WebhookEndpoint    | `projectID`                                                          |
| SelfHostEnrollment | Any spec change (immutable)                                          |
| Honeytoken         | `projectID`                                                          |
| AnomalyRule        | `projectID`                                                          |
| ApprovalRule       | `projectID`                                                          |
| QueryTemplate      | `projectID`                                                          |

## Further reading

* [Connection Pooling](/docs/pooling): pool modes and sizing
* [Caching](/docs/cache): query caching and SWR
* [Read Replicas](/docs/replicas): replica routing
* [Custom Domains](/docs/custom-domains): DNS setup and verification
* [API Keys](/docs/api-keys): managing API credentials
* [Plans](/docs/plans): plan limits and pricing