Claude Code for Crossplane: Kubernetes-Native Infrastructure — Claude Skills 360 Blog
Blog / Infrastructure / Claude Code for Crossplane: Kubernetes-Native Infrastructure
Infrastructure

Claude Code for Crossplane: Kubernetes-Native Infrastructure

Published: December 23, 2026
Read time: 9 min read
By: Claude Skills 360

Crossplane turns Kubernetes into a universal control plane for cloud infrastructure. Managed Resources map 1:1 to cloud API resources. Composite Resource Definitions (XRDs) create custom Kubernetes APIs from infrastructure building blocks. Compositions define how those custom resources translate to real cloud resources. Applications request databases and buckets via Kubernetes-native API calls — no Terraform CLI, no terraform apply, just kubectl apply. Claude Code generates Crossplane XRDs, Compositions, managed resource configs, and the claim objects that teams use to self-serve infrastructure.

CLAUDE.md for Crossplane Projects

## Crossplane Stack
- Version: Crossplane 1.17+ (installed in cluster via Helm)
- Providers: provider-aws-s3, provider-aws-rds, provider-aws-ec2, provider-kubernetes
- State: Kubernetes etcd (no separate state file like Terraform)
- Auth: IRSA (AWS), Workload Identity (GCP), pod identity (Azure)
- XRDs: one per platform capability (database, bucket, cache, queue)
- Compositions: per environment variant (dev=minimal, prod=HA)
- Claims: what teams submit — in app namespaces
- GitOps: ArgoCD manages all Crossplane objects declaratively

Provider Configuration

# crossplane/providers/provider-aws.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-rds
spec:
  package: xpkg.upbound.io/upbound/provider-aws-rds:v1.14.0
  runtimeConfigRef:
    name: default

---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: default
spec:
  credentials:
    source: IRSA  # IAM Roles for Service Accounts (recommended for EKS)
# crossplane/providers/provider-aws-rds.yaml
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-rds
spec:
  package: xpkg.upbound.io/upbound/provider-aws-rds:v1.14.0

Composite Resource Definition (XRD)

# crossplane/xrds/xdatabase.yaml
# Defines the custom API that platform teams expose to developers
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xdatabases.platform.mycompany.com
spec:
  group: platform.mycompany.com
  names:
    kind: XDatabase
    plural: xdatabases
  claimNames:
    kind: Database           # What teams create in their namespaces
    plural: databases
  
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              required: [parameters]
              properties:
                parameters:
                  type: object
                  required: [engine, size, name]
                  properties:
                    engine:
                      type: string
                      enum: [postgres, mysql]
                      description: Database engine
                    size:
                      type: string
                      enum: [small, medium, large]
                      description: "small=db.t3.micro, medium=db.t3.small, large=db.r6g.large"
                    name:
                      type: string
                      pattern: '^[a-z][a-z0-9-]{2,30}$'
                    highAvailability:
                      type: boolean
                      default: false
                      description: Enable Multi-AZ (required for production)
                    storageGb:
                      type: integer
                      minimum: 20
                      maximum: 1000
                      default: 100
            status:
              type: object
              properties:
                endpoint:
                  type: string
                  description: Database connection endpoint
                port:
                  type: integer
                secretRef:
                  type: object
                  properties:
                    name:
                      type: string
                    namespace:
                      type: string

Composition

# crossplane/compositions/database-postgres-aws.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: database-postgres-aws
  labels:
    provider: aws
    engine: postgres
spec:
  compositeTypeRef:
    apiVersion: platform.mycompany.com/v1alpha1
    kind: XDatabase

  # Write connection details to a secret
  writeConnectionSecretsToNamespace: crossplane-system

  resources:
    # 1. DB Subnet Group
    - name: db-subnet-group
      base:
        apiVersion: rds.aws.upbound.io/v1beta1
        kind: SubnetGroup
        spec:
          forProvider:
            region: us-east-1
            description: "Managed by Crossplane"
            subnetIdSelector:
              matchLabels:
                access: private
          providerConfigRef:
            name: default
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: metadata.name
          toFieldPath: metadata.name
          transforms:
            - type: string
              string:
                fmt: "%s-subnet-group"

    # 2. DB Instance
    - name: rds-instance
      base:
        apiVersion: rds.aws.upbound.io/v1beta1
        kind: Instance
        spec:
          forProvider:
            region: us-east-1
            dbSubnetGroupNameSelector:
              matchControllerRef: true  # Pick subnet group from this composition
            vpcSecurityGroupIdSelector:
              matchLabels:
                role: database
            skipFinalSnapshot: true
            autoMinorVersionUpgrade: true
            backupRetentionPeriod: 7
            deletionProtection: false
          providerConfigRef:
            name: default
          writeConnectionSecretToRef:
            namespace: crossplane-system
            name: ""  # Will be patched
      patches:
        # Map size param to instance class
        - type: FromCompositeFieldPath
          fromFieldPath: spec.parameters.size
          toFieldPath: spec.forProvider.instanceClass
          transforms:
            - type: map
              map:
                small: db.t3.micro
                medium: db.t3.small
                large: db.r6g.large

        # Wire engine
        - type: FromCompositeFieldPath
          fromFieldPath: spec.parameters.engine
          toFieldPath: spec.forProvider.engine

        # Wire high availability
        - type: FromCompositeFieldPath
          fromFieldPath: spec.parameters.highAvailability
          toFieldPath: spec.forProvider.multiAz

        # Wire storage
        - type: FromCompositeFieldPath
          fromFieldPath: spec.parameters.storageGb
          toFieldPath: spec.forProvider.allocatedStorage

        # Set secret name based on XR name
        - type: FromCompositeFieldPath
          fromFieldPath: metadata.name
          toFieldPath: spec.writeConnectionSecretToRef.name
          transforms:
            - type: string
              string:
                fmt: "%s-credentials"

        # Expose endpoint in status
        - type: ToCompositeFieldPath
          fromFieldPath: status.atProvider.endpoint
          toFieldPath: status.endpoint

      connectionDetails:
        - fromFieldPath: status.atProvider.endpoint
          name: endpoint
        - fromFieldPath: status.atProvider.port
          name: port

    # 3. Create Kubernetes Secret in claim namespace
    - name: secret-copier
      base:
        apiVersion: kubernetes.crossplane.io/v1alpha2
        kind: Object
        spec:
          forProvider:
            manifest:
              apiVersion: v1
              kind: Secret
              metadata: {}
              data: {}

Namespace-Scoped Claims

# teams/payments-team/database-claim.yaml
# Teams submit this — they never touch AWS console
apiVersion: platform.mycompany.com/v1alpha1
kind: Database
metadata:
  name: payments-db
  namespace: payments
spec:
  parameters:
    engine: postgres
    size: medium
    name: payments-db
    highAvailability: true   # Required for production
    storageGb: 200
  writeConnectionSecretToRef:
    name: payments-db-credentials  # Available in payments namespace
# teams/analytics-team/database-claim.yaml
apiVersion: platform.mycompany.com/v1alpha1
kind: Database
metadata:
  name: analytics-db
  namespace: analytics
spec:
  parameters:
    engine: postgres
    size: large
    name: analytics-db
    highAvailability: false  # Dev environment — save costs
    storageGb: 500
  writeConnectionSecretToRef:
    name: analytics-db-credentials

S3 Bucket XRD and Composition

# crossplane/xrds/xbucket.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
  name: xbuckets.platform.mycompany.com
spec:
  group: platform.mycompany.com
  names:
    kind: XBucket
    plural: xbuckets
  claimNames:
    kind: Bucket
    plural: buckets
  versions:
    - name: v1alpha1
      served: true
      referenceable: true
      schema:
        openAPIV3Schema:
          type: object
          properties:
            spec:
              type: object
              required: [parameters]
              properties:
                parameters:
                  type: object
                  required: [purpose]
                  properties:
                    purpose:
                      type: string
                      enum: [uploads, backups, artifacts, public-assets]
                    versioning:
                      type: boolean
                      default: false
                    lifecycleRuleDays:
                      type: integer
                      description: Delete objects older than N days (0 = no expiry)
                      default: 0

---
# crossplane/compositions/bucket-aws.yaml
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
  name: bucket-aws
spec:
  compositeTypeRef:
    apiVersion: platform.mycompany.com/v1alpha1
    kind: XBucket
  resources:
    - name: s3-bucket
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: Bucket
        spec:
          forProvider:
            region: us-east-1
            forceDestroy: false
          providerConfigRef:
            name: default
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: metadata.name
          toFieldPath: metadata.name
          transforms:
            - type: string
              string:
                fmt: "mycompany-%s"

    - name: bucket-versioning
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: BucketVersioning
        spec:
          forProvider:
            region: us-east-1
            versioningConfiguration:
              - status: ""  # Will be patched
            bucketSelector:
              matchControllerRef: true
      patches:
        - type: FromCompositeFieldPath
          fromFieldPath: spec.parameters.versioning
          toFieldPath: spec.forProvider.versioningConfiguration[0].status
          transforms:
            - type: convert
              convert:
                toType: string
            - type: map
              map:
                "true": Enabled
                "false": Suspended

    - name: bucket-encryption
      base:
        apiVersion: s3.aws.upbound.io/v1beta1
        kind: BucketServerSideEncryptionConfiguration
        spec:
          forProvider:
            region: us-east-1
            bucketSelector:
              matchControllerRef: true
            rule:
              - applyServerSideEncryptionByDefault:
                  - sseAlgorithm: aws:kms

Observing Composition Status

# Check claim status
kubectl get database -n payments
# NAME          SYNCED   READY   CONNECTION-SECRET          AGE
# payments-db   True     True    payments-db-credentials    5m

# Check the composite resource
kubectl get xdatabase
# NAME                     SYNCED   READY   COMPOSITION                     AGE
# payments-payments-db     True     True    database-postgres-aws           5m

# Check underlying managed resources
kubectl get instance.rds.aws.upbound.io
# NAME                     READY   SYNCED   EXTERNAL-NAME                ID
# payments-payments-db     True    True     payments-payments-db         ...

# View events if something is wrong
kubectl describe xdatabase payments-payments-db
kubectl describe instance.rds.aws.upbound.io payments-payments-db

For the Kubernetes cluster that hosts Crossplane and the applications consuming its infrastructure claims, see the Kubernetes guide for deployment patterns. For the GitOps workflow that manages Crossplane manifests declaratively, the GitOps and ArgoCD guide covers ArgoCD application management. The Claude Skills 360 bundle includes Crossplane skill sets covering XRD design, Composition authoring, and platform API patterns. Start with the free tier to try Crossplane configuration generation.

Put these ideas into practice

Claude Skills 360 gives you production-ready skills for everything in this article — and 2,350+ more. Start free or go all-in.

Back to Blog

Get 360 skills free