Crossplane can provision AWS VPCs, subnets, and security groups, but its true power lies in how it abstracts infrastructure away from the cloud provider.

Here’s a Crossplane configuration that sets up a basic AWS VPC with a public subnet and a security group allowing SSH access:

apiVersion: aws.upbound.io/v1beta1
kind: ProviderConfig
metadata:
  name: default
spec:
  credentials:
    source: Secret
    secretRef:
      namespace: crossplane-system
      name: aws-creds
      key: creds

---
apiVersion: ec2.aws.upbound.io/v1beta1
kind: VPC
metadata:
  name: example-vpc
spec:
  forProvider:
    region: us-east-1
    cidrBlock: 10.0.0.0/16
    enableDnsSupport: true
    enableDnsHostnames: true
    tags:
      Environment: Production

---
apiVersion: ec2.aws.upbound.io/v1beta1
kind: Subnet
metadata:
  name: example-public-subnet
spec:
  forProvider:
    region: us-east-1
    vpcIdRef:
      name: example-vpc
    cidrBlock: 10.0.1.0/24
    availabilityZone: us-east-1a
    mapPublicIpOnLaunch: true
    tags:
      Name: PublicSubnet

---
apiVersion: ec2.aws.upbound.io/v1beta1
kind: SecurityGroup
metadata:
  name: example-ssh-sg
spec:
  forProvider:
    region: us-east-1
    vpcIdRef:
      name: example-vpc
    description: "Allow SSH access"
    ingress:
      - fromPort: 22
        toPort: 22
        protocol: TCP
        cidrBlocks:
          - 0.0.0.0/0
    egress:
      - protocol: "-1"
        fromPort: 0
        toPort: 0
        cidrBlocks:
          - 0.0.0.0/0
    tags:
      Name: SSHAccess

This configuration defines three AWS resources: a Virtual Private Cloud (VPC), a public subnet within that VPC, and a security group. The ProviderConfig tells Crossplane how to authenticate with AWS. The VPC resource creates a new VPC with a specified CIDR block (10.0.0.0/16) and enables DNS support. The Subnet resource creates a subnet within the example-vpc, assigns it a CIDR block (10.0.1.0/24) in us-east-1a, and crucially, sets mapPublicIpOnLaunch to true, making it a public subnet. The SecurityGroup resource creates a security group associated with the example-vpc and configures an ingress rule to allow TCP traffic on port 22 (SSH) from any IP address (0.0.0.0/0). An egress rule is also included to allow all outbound traffic.

The ref fields, like vpcIdRef: name: example-vpc in the Subnet and SecurityGroup resources, are how Crossplane establishes relationships between resources. When Crossplane reconciles these resources, it will first ensure the example-vpc exists, then use its ID to create the example-public-subnet and example-ssh-sg. This declarative approach means you define what you want, and Crossplane figures out how to get there, including handling dependencies.

The real magic of Crossplane here is that this entire AWS infrastructure is now a Kubernetes Custom Resource (CR). You can manage your VPCs, subnets, and security groups using kubectl apply just like you manage your application deployments. This allows you to treat your cloud infrastructure as code, version it, test it, and deploy it consistently across different environments. Instead of logging into the AWS console or writing complex CloudFormation/Terraform scripts for every VPC setup, you simply create a YAML file.

A common misconception is that Crossplane simply wraps existing cloud provider tools. While it does integrate with them, Crossplane provides a unified API layer. You can define a VPC resource in Crossplane, and that same VPC definition could be used to provision infrastructure on Azure or GCP by simply changing the ProviderConfig and potentially minor spec attributes, without altering the core VPC definition itself. This is the essence of cloud-agnostic infrastructure management.

The way Crossplane manages state is also subtly different from traditional IaC. Instead of maintaining its own separate state file (like Terraform’s .tfstate), Crossplane stores the desired state and the actual observed state within Kubernetes itself, as annotations and status fields on the CRs. This leverages Kubernetes’ own robust reconciliation loop and API server for state management, simplifying operations and reducing the risk of state drift.

The next step in managing your VPC infrastructure with Crossplane would be to look into provisioning route tables and internet gateways to make your public subnet truly routable to the internet.

Want structured learning?

Take the full Crossplane course →