Introduction

During Christmas, I had some extra time on my hands - a perfect opportunity to catch up on tech I’d been meaning to explore. A few colleagues had been discussing about Crossplane recently, and it got me curious. What is it really about? How does it fit into the Kubernetes ecosystem? And most importantly, could it simplify the way we manage cloud infrastructure?

So, I decided to dive in and set up a small lab environment to get a better understanding of Crossplane, especially its integration with AWS. In this article, I’ll walk you through my experience, breaking down the setup process and sharing insights along the way. If you’ve been wondering about Crossplane too, this might be the perfect starting point!

For a deeper dive into Crossplane’s capabilities, you can also check out the official Crossplane documentation:

Crossplane Docs · v1.18 · Overview
Crossplane is an open source Kubernetes extension that transforms your Kubernetes cluster into a universal control plane. Crossplane lets you manage anything, anywhere, all through standard Kubernetes …

Setting Up Minikube on macOS

Before diving into Crossplane, we need a local Kubernetes cluster to get things up and running. Minikube is an excellent choice for this purpose, especially for testing and small-scale setups. Here's how you can install and configure Minikube on your MacBook with macOS.

Why Minikube?

Minikube is a lightweight Kubernetes distribution designed for local environments. It’s perfect for experimenting with Kubernetes features and tools like Crossplane without requiring a full-blown cloud setup. It also integrates seamlessly with Docker, making it an easy and efficient way to spin up a cluster on your local machine.

Installation Steps

Here’s a step-by-step guide to setting up Minikube on macOS:

  1. Install Minikube
    Use Homebrew to install Minikube: brew install minikube
  2. Install kubectl
    Kubernetes' command-line tool, kubectl, is essential for interacting with your cluster. Install it via Homebrew: brew install kubectl
  3. Install Helm (Kubernetes Package Manager)
    Helm, the Kubernetes package manager, will be needed later for deploying applications. Install it with: brew install helm
  4. Start Minikube
    Once Minikube is installed, start your cluster with minikube start
alexanderhose ~ % minikube start
😄  minikube v1.34.0 on Darwin 15.0 (arm64)
✨  Automatically selected the docker driver
📌  Using Docker Desktop driver with root privileges
👍  Starting "minikube" primary control-plane node in "minikube" cluster
🚜  Pulling base image v0.0.45 ...
💾  Downloading Kubernetes v1.31.0 preload ...
    > gcr.io/k8s-minikube/kicbase...:  441.45 MiB / 441.45 MiB  100.00% 10.57 M
    > preloaded-images-k8s-v18-v1...:  307.61 MiB / 307.61 MiB  100.00% 5.40 Mi
🔥  Creating docker container (CPUs=2, Memory=2200MB) ...
🐳  Preparing Kubernetes v1.31.0 on Docker 27.2.0 ...
    ▪ Generating certificates and keys ...
    ▪ Booting up control plane ...
    ▪ Configuring RBAC rules ...
🔗  Configuring bridge CNI (Container Networking Interface) ...
🔎  Verifying Kubernetes components...
    ▪ Using image gcr.io/k8s-minikube/storage-provisioner:v5
🌟  Enabled addons: storage-provisioner, default-storageclass
🏄  Done! kubectl is now configured to use "minikube" cluster and "default" namespace by default

Here's what you can expect during startup:

    • Minikube will automatically detect and select Docker as the driver.
    • It will pull the necessary base images and configure the cluster.

Verifying the Kubernetes Cluster Installation

Once you’ve installed Minikube, kubectl, and Helm, it’s important to verify that your Kubernetes cluster is running properly. Use the following command to check the status of the cluster:

alexanderhose ~ % kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:57085
CoreDNS is running at https://127.0.0.1:57085/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy

Adding the Crossplane Helm Repository

With the Kubernetes cluster verified, the next step is to prepare for Crossplane installation. Helm will help us install Crossplane and manage its lifecycle.

  1. Add the Crossplane Helm Repository
    Add the official Crossplane Helm chart repository
  2. Update the Helm Repository
    After adding the Crossplane repository, ensure it’s up to date
  3. List the Helm Repositories
    Confirm that the Crossplane repository has been successfully added
alexanderhose ~ % helm repo add crossplane-stable https://charts.crossplane.io/stable
"crossplane-stable" has been added to your repositories

alexanderhose ~ % helm repo update
Hang tight while we grab the latest from your chart repositories...

alexanderhose ~ % helm repo list  
NAME             	URL                                
crossplane-stable	https://charts.crossplane.io/stable

Installing Crossplane

Now that we’ve added the Crossplane Helm repository, the next step is to install Crossplane itself. Crossplane is a Kubernetes add-on that simplifies cloud infrastructure management. It allows you to define infrastructure resources declaratively using Kubernetes manifests. In this section, we’ll install Crossplane into our Minikube cluster and verify that it’s running correctly.

Step 1: Install Crossplane Using Helm

Run the following command to install Crossplane:

alexanderhose ~ % helm install crossplane \
--namespace crossplane-system \
--create-namespace crossplane-stable/crossplane

NAME: crossplane
LAST DEPLOYED: Fri Jan  3 23:00:05 2025
NAMESPACE: crossplane-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Release: crossplane

Chart Name: crossplane
Chart Description: Crossplane is an open source Kubernetes add-on that enables platform teams to assemble infrastructure from multiple vendors, and expose higher level self-service APIs for application teams to consume.
Chart Version: 1.18.2
Chart Application Version: 1.18.2

Kube Version: v1.31.0

Here’s what this command does:

  • crossplane: The release name for the Helm installation.
  • --namespace crossplane-system: Installs Crossplane in a dedicated namespace called crossplane-system.
  • --create-namespace: Creates the namespace if it doesn’t already exist.
  • crossplane-stable/crossplane: Specifies the Crossplane chart from the previously added repository

Step 2: Verify the Deployment

Next, verify that the Crossplane pods are running:

alexanderhose ~ % kubectl get pods -n crossplane-system
NAME                                       READY   STATUS    RESTARTS   AGE
crossplane-76596b6bcd-724mq                1/1     Running   0          51s
crossplane-rbac-manager-787f89744d-xckhj   1/1     Running   0          51s

This confirms that:

  • The crossplane pod is running, which serves as the core Crossplane component.
  • The crossplane-rbac-manager pod is running, managing the necessary Role-Based Access Control (RBAC) permissions.

Interacting with the Crossplane Cluster

With Crossplane installed and running, it’s time to configure it to interact with AWS. This involves changing the Kubernetes context for easier management, creating an AWS credentials secret, and verifying the configuration.

Step 1: Set the Kubernetes Context

To streamline our interaction with the Crossplane cluster, we can set the default namespace for kubectl to crossplane-system. This saves us from repeatedly specifying the namespace in our commands:

alexanderhose ~ % kubectl config set-context --current --namespace=crossplane-system
Context "minikube" modified.

From this point forward, all kubectl commands will target the crossplane-system namespace by default.

Step 2: Generate AWS Service Account Keys

For Crossplane to manage AWS resources, it requires access credentials. Ensure you have an AWS user with CLI access and the necessary permissions for managing resources (e.g., AdministratorAccess or fine-tuned IAM policies). Generate the access keys and store them in a file named aws-credentials.txt with the following format:

[default]  
aws_access_key_id = EXAMPLEACCESSKEY  
aws_secret_access_key = EXAMPLESECRET

aws-credentials.txt

Replace EXAMPLEACCESSKEY and EXAMPLESECRET with your actual AWS access and secret keys

Step 3: Create a Kubernetes Secret

Add the AWS credentials as a Kubernetes secret to the crossplane-system namespace. This command creates a secret named aws-secret and stores the credentials securely.

alexanderhose ~ % kubectl create secret generic aws-secret --from-file=creds=./aws-credentials.txt
secret/aws-secret created

alexanderhose ~ % kubectl describe secret aws-secret
Name:         aws-secret
Namespace:    crossplane-system
Labels:       <none>
Annotations:  <none>

Type:  Opaque

Data
====
creds:  115 bytes

Step 4: Decode and Verify the Secret

You can decode the secret to verify its contents (for debugging purposes or validation). Decoding confirms that the secret was created correctly and contains the expected AWS credentials.

alexanderhose ~ % kubectl get secrets/aws-secret --template={{.data.creds}} | base64 -d

[default]
aws_access_key_id = EXAMPLEACCESSKEY
aws_secret_access_key = EXAMPLESECRET                                                                                                                                  

Installing Providers for AWS S3 and SSM

With Crossplane installed and AWS credentials configured, the next step is to install the necessary providers. Providers act as the bridge between Crossplane and cloud services, enabling you to manage resources like S3 buckets and SSM directly from Kubernetes.

Step 1: Install the AWS Providers

Crossplane requires a provider to interact with each specific AWS service. For this example, we’ll install providers for S3 and SSM (Systems Manager).

Save the following YAML files for the AWS providers:

apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-s3
spec:
  package: xpkg.upbound.io/upbound/provider-aws-s3:v1.18.3

aws-s3-provider.yaml

apiVersion: pkg.crossplane.io/v1
kind: Provider
metadata:
  name: provider-aws-ssm
spec:
  package: xpkg.upbound.io/upbound/provider-aws-ssm:v1.18.3

aws-ssm-provider.yaml

Run the following commands to install the providers. These commands install the S3 and SSM providers into the crossplane-system namespace.

alexanderhose ~ % kubectl apply -f ./aws-s3-provider.yaml 
provider.pkg.crossplane.io/provider-aws-s3 created

alexanderhose ~ % kubectl apply -f ./aws-ssm-provider.yaml 
provider.pkg.crossplane.io/aws-provider-ssm created

Step 2: Configure the AWS Provider

After installing the providers, you need to configure them with the credentials stored in the secret we created earlier.

Save the following YAML files for the AWS configuration:

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

aws-provider-config.yaml

Run the following command. This step configures Crossplane to use the aws-secret for interacting with AWS resources.

alexanderhose ~ % kubectl apply -f ./aws-provider-config.yaml 
providerconfig.aws.upbound.io/provider-aws created

This configuration does the following:

  • Specifies default as the provider configuration name, which will be referenced in all AWS resource manifests.
  • Points to the aws-secret containing your AWS credentials in the crossplane-system namespace.

Before moving forward, it’s always a good idea to confirm that everything was deployed as expected. You can check the deployments in the crossplane-system namespace with:

alexanderhose ~ % kubectl get deployments -n crossplane-system

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
aws-provider-ssm              1/1     1            1           95s
crossplane                    1/1     1            1           20h
crossplane-rbac-manager       1/1     1            1           20h
provider-aws-s3               1/1     1            1           88s
upbound-provider-family-aws   1/1     1            1           103s

Deploying Your First Resource

Now that Crossplane is up and running with the necessary providers, it’s time to deploy our first AWS resource: an S3 bucket. This step will demonstrate how you can define cloud resources using Kubernetes manifests and let Crossplane handle the provisioning.

Create the S3 Bucket Manifest

First, create a file named s3-bucket.yaml with the following content:

apiVersion: s3.aws.upbound.io/v1beta1
kind: Bucket
metadata:
  labels:
    testing.upbound.io/example-name: crossplane-bucket
  name: crossplane-bucket
spec:
  forProvider:
    region: us-west-1

aws-provider-config.yaml

Here’s a quick breakdown of the manifest:

  • apiVersion and kind: These specify the type of resource, in this case, an S3 bucket.
  • metadata: Includes a name (crossplane-bucket) and a label for tracking purposes.
  • spec.forProvider: Defines specific configuration details for the bucket, like the region (us-west-1).

Deploy the S3 Bucket

Apply the manifest to your Kubernetes cluster:

alexanderhose ~ % kubectl apply -f s3-bucket.yaml
bucket.s3.aws.upbound.io/crossplane-bucket created

Now that you’ve successfully deployed your first S3 bucket with Crossplane, consider exploring how to automate additional AWS resources like SSM documents, RDS or Lambda.

Troubleshooting Deployment Issues

Sometimes, things might not go as planned. To check the details of your deployment and identify potential issues, you can use the kubectl describe command. For example:

alexanderhose ~ % kubectl describe bucket.s3.aws.upbound.io/crossplane-bucket

Status:
  At Provider:
  Conditions:
    Last Transition Time:  2025-01-04T20:32:35Z
    Message:               connect failed: cannot initialize the Terraform plugin SDK async external client: cannot get terraform setup: cannot get referenced ProviderConfig: "default": ProviderConfig.aws.upbound.io "default" not found
    Reason:                ReconcileError
    Status:                False
    Type:                  Synced

In this case, the Message field clearly indicates that the provider configuration is missing or incorrect. The key point here is to check if the metadata name of the ProviderConfig is default.

Frequently Asked Questions (FAQs)

1. What is Crossplane?

Crossplane is an open-source Kubernetes add-on that enables you to manage cloud infrastructure using Kubernetes manifests. It lets you declaratively provision and manage resources across multiple cloud providers, such as AWS, GCP, and Azure, directly from your Kubernetes cluster.

2. How do I integrate Crossplane with other AWS services?

To integrate Crossplane with AWS, you need to:

  • Deploy specific providers, such as for EC2 or Lambda, to your Kubernetes cluster. Check https://marketplace.upbound.io for additional providers.
  • Apply Kubernetes manifests for AWS resources like EC2 or Lambda, referencing the appropriate provider.

In short, you create providers and apply them in your Kubernetes cluster to establish a connection with additional AWS services.

3. Can I use Minikube for Crossplane in production?

No, you should not use Minikube for production environments. Minikube is designed for local development and testing purposes. For production use cases, you should deploy Crossplane in a robust Kubernetes environment, such as Amazon EKS, Google GKE, or Azure AKS, that supports high availability and scalability.

Share this post