Infrastructure Provisioning with Crossplane

Providers & Managed Resources

4 min read

Providers are the heart of Crossplane, connecting to cloud APIs and managing infrastructure resources. Understanding how to configure providers and work with managed resources is essential for building your platform.

Provider Types

Crossplane supports providers for major cloud platforms and services:

# Available Provider Categories
providers:

  cloud_platforms:
    - name: provider-aws
      resources: "EC2, RDS, S3, VPC, EKS, Lambda, etc."
      package: xpkg.upbound.io/upbound/provider-family-aws

    - name: provider-gcp
      resources: "Compute, CloudSQL, GCS, VPC, GKE, etc."
      package: xpkg.upbound.io/upbound/provider-family-gcp

    - name: provider-azure
      resources: "VMs, SQL, Storage, VNet, AKS, etc."
      package: xpkg.upbound.io/upbound/provider-family-azure

  kubernetes:
    - name: provider-kubernetes
      resources: "Deployments, Services, ConfigMaps, etc."
      use_case: "Deploy apps alongside infrastructure"

    - name: provider-helm
      resources: "Helm releases"
      use_case: "Deploy Helm charts as part of compositions"

  other:
    - name: provider-terraform
      use_case: "Use Terraform modules in Crossplane"

    - name: provider-sql
      use_case: "Manage databases, users, grants"

Installing Multiple Providers

For a real platform, you'll need multiple providers:

# providers.yaml - Install AWS family providers
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-ec2
spec:
  package: xpkg.upbound.io/upbound/provider-aws-ec2:v1.1.0
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-rds
spec:
  package: xpkg.upbound.io/upbound/provider-aws-rds:v1.1.0
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-s3
spec:
  package: xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0
---
apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-iam
spec:
  package: xpkg.upbound.io/upbound/provider-aws-iam:v1.1.0
# Apply all providers
kubectl apply -f providers.yaml

# Wait for providers to be healthy
kubectl wait provider --all --for=condition=Healthy --timeout=300s

# List installed providers
kubectl get providers
# NAME               INSTALLED   HEALTHY   PACKAGE                                        AGE
# provider-aws-ec2   True        True      xpkg.upbound.io/upbound/provider-aws-ec2:v1.1.0   2m
# provider-aws-rds   True        True      xpkg.upbound.io/upbound/provider-aws-rds:v1.1.0   2m
# provider-aws-s3    True        True      xpkg.upbound.io/upbound/provider-aws-s3:v1.1.0    2m
# provider-aws-iam   True        True      xpkg.upbound.io/upbound/provider-aws-iam:v1.1.0   2m

Provider Configuration Options

Configure credentials securely:

# Option 1: Secret-based credentials (development)
---
apiVersion: v1
kind: Secret
metadata:
  name: aws-creds
  namespace: crossplane-system
type: Opaque
stringData:
  credentials: |
    [default]
    aws_access_key_id = AKIAIOSFODNN7EXAMPLE
    aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: default
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-creds
      key: credentials

---
# Option 2: IRSA (production - AWS)
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: default
spec:
  credentials:
    source: IRSA

---
# Option 3: Workload Identity (production - GCP)
apiVersion: gcp.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: default
spec:
  projectID: my-gcp-project
  credentials:
    source: InjectedIdentity

---
# Option 4: Multiple configurations (multi-account)
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: production
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-creds-prod
      key: credentials
---
apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: development
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-creds-dev
      key: credentials

Managed Resource Examples

RDS Database

# rds-instance.yaml
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
  name: production-postgres
spec:
  forProvider:
    region: us-east-1
    allocatedStorage: 20
    autoMinorVersionUpgrade: true
    backupRetentionPeriod: 7
    backupWindow: "03:00-04:00"
    dbInstanceClass: db.t3.micro
    dbName: appdb
    engine: postgres
    engineVersion: "15.4"
    instanceIdentifier: production-postgres
    maintenanceWindow: "Mon:04:00-Mon:05:00"
    multiAz: false
    passwordSecretRef:
      key: password
      name: db-password
      namespace: default
    publiclyAccessible: false
    skipFinalSnapshot: true
    storageEncrypted: true
    storageType: gp3
    username: dbadmin
    vpcSecurityGroupIdRefs:
      - name: db-security-group
    dbSubnetGroupNameRef:
      name: db-subnet-group
  providerConfigRef:
    name: default
  writeConnectionSecretToRef:
    name: postgres-connection
    namespace: default

VPC with Subnets

# vpc.yaml
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
metadata:
  name: platform-vpc
spec:
  forProvider:
    region: us-east-1
    cidrBlock: 10.0.0.0/16
    enableDnsHostnames: true
    enableDnsSupport: true
    tags:
      Name: platform-vpc
      Environment: production
  providerConfigRef:
    name: default

---
# subnet.yaml
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
metadata:
  name: platform-subnet-a
spec:
  forProvider:
    region: us-east-1
    availabilityZone: us-east-1a
    cidrBlock: 10.0.1.0/24
    vpcIdRef:
      name: platform-vpc
    mapPublicIpOnLaunch: false
    tags:
      Name: platform-subnet-a
  providerConfigRef:
    name: default

S3 Bucket with Encryption

# s3-bucket-secure.yaml
apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
  name: app-data-bucket
spec:
  forProvider:
    region: us-east-1
    tags:
      Environment: production
  providerConfigRef:
    name: default

---
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketServerSideEncryptionConfiguration
metadata:
  name: app-data-bucket-encryption
spec:
  forProvider:
    region: us-east-1
    bucketRef:
      name: app-data-bucket
    rule:
      - applyServerSideEncryptionByDefault:
          - sseAlgorithm: AES256

---
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketVersioning
metadata:
  name: app-data-bucket-versioning
spec:
  forProvider:
    region: us-east-1
    bucketRef:
      name: app-data-bucket
    versioningConfiguration:
      - status: Enabled

---
apiVersion: s3.aws.upbound.io/v1beta1
kind: BucketPublicAccessBlock
metadata:
  name: app-data-bucket-public-access
spec:
  forProvider:
    region: us-east-1
    bucketRef:
      name: app-data-bucket
    blockPublicAcls: true
    blockPublicPolicy: true
    ignorePublicAcls: true
    restrictPublicBuckets: true

Connection Secrets

Crossplane can write connection details to Kubernetes Secrets:

# Resource with connection secret
apiVersion: rds.aws.upbound.io/v1beta1
kind: Instance
metadata:
  name: my-database
spec:
  forProvider:
    # ... configuration
  writeConnectionSecretToRef:
    name: db-connection-secret
    namespace: default

---
# The resulting secret contains:
# apiVersion: v1
# kind: Secret
# metadata:
#   name: db-connection-secret
# data:
#   endpoint: <base64-encoded-endpoint>
#   port: <base64-encoded-port>
#   username: <base64-encoded-username>
#   password: <base64-encoded-password>
# View connection details
kubectl get secret db-connection-secret -o yaml

# Use in your application
kubectl get secret db-connection-secret -o jsonpath='{.data.endpoint}' | base64 -d

Resource References

Link resources together using references:

# Reference patterns
references:

  # By name (in same namespace)
  vpcIdRef:
    name: my-vpc

  # By selector (match labels)
  vpcIdSelector:
    matchLabels:
      environment: production
      team: platform

  # By external name (existing resource)
  vpcId: vpc-0123456789abcdef0

  # Secret reference (for sensitive values)
  passwordSecretRef:
    key: password
    name: db-credentials
    namespace: crossplane-system
# Example: Security group referencing VPC
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
metadata:
  name: db-security-group
spec:
  forProvider:
    region: us-east-1
    description: "Database security group"
    vpcIdRef:
      name: platform-vpc  # References the VPC by name
    ingress:
      - fromPort: 5432
        toPort: 5432
        protocol: tcp
        cidrBlocks:
          - 10.0.0.0/16
    tags:
      Name: db-security-group

Observing Resources

Monitor your managed resources:

# List all managed resources
kubectl get managed

# Check specific resource type
kubectl get instance.rds.aws.upbound.io

# Watch resource status
kubectl get bucket -w

# Get detailed status
kubectl describe instance.rds.aws.upbound.io my-database

# Check events
kubectl get events --field-selector involvedObject.name=my-database

# View Crossplane logs for debugging
kubectl logs -n crossplane-system -l pkg.crossplane.io/provider=provider-aws-rds

In the next lesson, we'll build on these fundamentals to create Compositions and XRDs—the key to self-service infrastructure. :::