---
name: crossplane-control-planes
description: "Build internal platform APIs with Crossplane — XRDs, Compositions, Composition Functions, and providers. Production Crossplane: ProviderConfig and provider installs, Composite Resource Definitions (XRDs) and Claims, Compositions with Composition Functions (function-patch-and-transform, function-go-templating, function-kcl), connection secrets, managed resource readiness and EnvironmentConfigs, plus packaging Configurations and Providers as OCI xpkg. Covers Crossplane vs Terraform reconciliation tradeoffs and self-service infra exposed as native Kubernetes resources."
license: MIT
---

# Crossplane Control Planes

Build internal platform APIs with Crossplane so application teams provision infrastructure through Kubernetes-native, self-service abstractions instead of raw cloud resources or Terraform modules. This skill is for platform engineers designing the contracts (XRDs), the implementation (Compositions and Composition Functions), and the provider plumbing that backs them.

## When to use it

- You want to expose a `PostgreSQLInstance` or `Bucket` Claim so app teams request infrastructure without touching AWS/GCP/Azure APIs directly.
- You're migrating from a pile of Compositions using inline `patches` to the function pipeline model (Crossplane v1.14+).
- You need connection details (endpoints, passwords) surfaced back to the consumer namespace as a Kubernetes Secret.
- You're debugging managed resources stuck in `Ready: False` or Compositions that won't select.

## How it works

The core building blocks:

- **Provider + ProviderConfig** — install a provider (e.g. `provider-aws-s3`) via a `Provider` package, then a `ProviderConfig` referencing credentials (IRSA, Workload Identity, or a Secret).
- **CompositeResourceDefinition (XRD)** — defines your API: the `spec`/`status` schema (OpenAPI), the composite (`XR`) name, and whether a namespaced **Claim** is offered.
- **Composition** — set `mode: Pipeline` and chain functions: `function-patch-and-transform` for field mapping, `function-go-templating` for loops/conditionals, `function-kcl` for typed config logic.
- **EnvironmentConfigs** — inject shared context (region, account IDs, network refs) into the pipeline without hardcoding.
- **Connection secrets** — `writeConnectionSecretToRef` / `publishConnectionDetailsTo` propagate credentials to consumers.

## Usage

```yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: xpostgres.aws
spec:
  compositeTypeRef:
    apiVersion: db.example.org/v1alpha1
    kind: XPostgreSQLInstance
  mode: Pipeline
  pipeline:
    - step: render
      functionRef:
        name: function-patch-and-transform
      input:
        apiVersion: pt.fn.crossplane.io/v1beta1
        kind: Resources
        resources:
          - name: rds
            base:
              apiVersion: rds.aws.upbound.io/v1beta1
              kind: Instance
```

Render locally before applying:

```bash
crossplane render xr.yaml composition.yaml functions.yaml
```

## Tips & gotchas

- **Functions are pods, not libraries.** Each pipeline function runs as a Deployment; a Composition that "does nothing" is often a function pod that failed to pull or start. Check `kubectl get pkgrev`.
- **Claim vs XR readiness lags.** A Claim only goes `Ready` when every composed managed resource reports `Ready: True` *and* the XR is synced — trace with `crossplane beta trace`.
- **Pin function versions.** Floating tags cause silent behavior changes; pin `Function` packages to a digest.
- **Don't mutate `status` from patches** — Crossplane owns it; use `ToCompositeFieldPath` to derive status from managed resources.

## FAQ

**Patch-and-transform or go-templating?** Use patch-and-transform for straightforward field mapping; reach for go-templating or KCL when you need loops, conditionals, or a variable number of resources.

**Claims or composites?** Offer a Claim when app teams self-serve in their own namespaces; use the cluster-scoped XR directly for platform-internal composition.

**How do I test without a cluster?** `crossplane render` evaluates the full function pipeline locally and prints the resources that would be created.
