Managing cloud infrastructure in a repeatable, secure, and scalable manner has always been a challenging task. With the rising complexity of modern applications and the need to empower development teams with self-service capabilities, platform engineering is emerging as a critical discipline. One of the best approaches to creating a self-service platform for Kubernetes environments is to build a platform abstraction on top of Amazon Elastic Kubernetes Service (EKS) using Crossplane—without writing raw infrastructure code such as Terraform or CloudFormation templates.

This article provides an in-depth guide on how to build such an abstraction, allowing developers to provision production-grade EKS clusters using only Kubernetes-native manifests. We will cover the concepts, steps, and code examples you need to get started, and conclude with a comprehensive discussion of the advantages and considerations.

Understanding the Core Concepts

Before diving into the implementation, it’s essential to understand the key components that make this approach possible.

  • EKS (Amazon Elastic Kubernetes Service): A managed Kubernetes service provided by AWS that handles the heavy lifting of cluster management, upgrades, and scalability.

  • Crossplane: An open-source Kubernetes add-on that allows you to provision and manage cloud infrastructure using Kubernetes custom resources. With Crossplane, infrastructure becomes declarative and Kubernetes-native.

  • Platform Abstraction: The idea of creating a higher-level interface—using Kubernetes Custom Resource Definitions (CRDs)—that hides the complexity of infrastructure provisioning. Developers can request infrastructure (like an EKS cluster) without needing to know the underlying implementation details.

The combination of these three components enables a GitOps-friendly, self-service, and code-light approach to infrastructure provisioning.

Why Avoid Traditional Infrastructure Code?

Infrastructure as Code (IaC) tools like Terraform or CloudFormation are powerful, but they introduce challenges:

  • Learning Curve: Developers must learn a new language or DSL.

  • Duplication: Each team might end up duplicating configurations.

  • Limited Kubernetes Integration: IaC is typically external to Kubernetes, making it harder to integrate directly with GitOps workflows.

By using Crossplane, you leverage Kubernetes Custom Resources to define infrastructure. This means everything—from application manifests to cluster provisioning—can be managed through the same API and GitOps pipeline.

Setting Up Crossplane on a Management Cluster

The first step in building your platform abstraction is to install Crossplane on a management cluster. This management cluster will orchestrate the provisioning of EKS clusters.

  1. Install Crossplane:

    kubectl create namespace crossplane-system
    helm repo add crossplane-stable https://charts.crossplane.io/stable
    helm repo update
    helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
  2. Verify Installation:

    kubectl get pods -n crossplane-system

    You should see pods for crossplane and crossplane-rbac-manager running.

This management cluster can be any Kubernetes cluster (including a lightweight one like kind or minikube), since it only orchestrates resources.

Configuring AWS Provider for Crossplane

To provision EKS clusters on AWS, Crossplane needs credentials and a provider configuration.

  1. Create AWS Access Key and Secret:
    Use an IAM user or role with permissions to create EKS clusters, VPCs, and related resources.

  2. Store Credentials as a Kubernetes Secret:

    kubectl create secret generic aws-creds -n crossplane-system \
    --from-literal=key=<AWS_ACCESS_KEY_ID> \
    --from-literal=secret=<AWS_SECRET_ACCESS_KEY>
  3. Install AWS Provider:

    kubectl crossplane install provider crossplane/provider-aws:v0.33.0
  4. Configure the Provider:

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

    Apply this with:

    kubectl apply -f providerconfig.yaml

This establishes Crossplane’s connection to AWS, allowing it to create and manage resources.

Defining a Composite Resource (XRD)

The magic of platform abstraction happens when you define a Composite Resource Definition (XRD). This CRD acts as the contract between developers and the platform team.

For example, let’s create a composite resource called XCluster to represent an abstract Kubernetes cluster.

apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xclusters.platform.example.org
spec:
group: platform.example.org
names:
kind: XCluster
plural: xclusters
claimNames:
kind: Cluster
plural: clusters
versions:
- name: v1alpha1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
nodeCount:
type: integer
region:
type: string

This XRD allows application teams to request a Cluster resource with a simple YAML manifest specifying only nodeCount and region.

Creating a Composition for EKS

Next, we map the abstract XCluster to actual AWS resources using a Composition.

apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: eks-cluster
spec:
compositeTypeRef:
apiVersion: platform.example.org/v1alpha1
kind: XCluster
resources:
- name: ekscluster
base:
apiVersion: eks.aws.crossplane.io/v1beta1
kind: Cluster
spec:
forProvider:
region: us-east-1
version: "1.27"
roleArn: arn:aws:iam::<ACCOUNT_ID>:role/CrossplaneEKSRole
resourcesVpcConfig:
subnetIds: [subnet-abc123, subnet-def456]
writeConnectionSecretToRef:
namespace: crossplane-system
name: eks-cluster-conn
patches:
- fromFieldPath: "spec.region"
toFieldPath: "spec.forProvider.region"

This Composition describes how an XCluster should translate into an actual EKS cluster, with dynamic patching from the abstract spec (e.g., region).

Creating a Platform API for Developers

Once the XRD and Composition are applied, developers can provision EKS clusters with a single manifest:

apiVersion: platform.example.org/v1alpha1
kind: Cluster
metadata:
name: team-a-cluster
spec:
nodeCount: 3
region: us-west-2

When this resource is applied, Crossplane automatically provisions an EKS cluster that matches the desired configuration—without developers writing a single line of AWS-specific infrastructure code.

Advantages of This Approach

  • Seamless GitOps: Because everything is a Kubernetes resource, it integrates directly into GitOps workflows using Argo CD or Flux.

  • Security & Governance: The platform team controls the underlying Composition, ensuring all clusters meet compliance requirements.

  • Developer Empowerment: Developers focus on their application needs (node count, region) without worrying about IAM roles or VPC settings.

  • Reusability: The same abstraction can be used for multiple teams and environments.

Example Directory Structure

A typical Git repository might look like this:

infra/
crossplane/
providerconfig.yaml
xcluster-definition.yaml
composition-eks.yaml
clusters/
team-a/
cluster.yaml
team-b/
cluster.yaml

This structure makes it easy to manage both the platform-level configuration and individual team environments.

Scaling the Platform Abstraction

As your organization grows, you can expand the abstraction by adding:

  • Parameters for node instance types (e.g., t3.medium vs. m5.large).

  • Optional add-ons like logging, monitoring, or service mesh.

  • Multi-cloud support using Crossplane providers for GCP, Azure, or on-prem clusters.

Because Crossplane is provider-agnostic, you can create a single API that provisions clusters across multiple cloud providers with minimal changes.

Conclusion

Building a platform abstraction for EKS clusters using Crossplane is a transformative approach to modern cloud infrastructure. Instead of scattering Terraform scripts, CloudFormation templates, or ad hoc automation across teams, you create a Kubernetes-native API that standardizes how infrastructure is consumed.

This strategy benefits both platform engineers and application developers:

  • Platform engineers retain control and enforce best practices by defining reusable Compositions that encapsulate networking, IAM, and security configurations.

  • Developers gain the ability to self-service infrastructure by submitting simple Kubernetes manifests that describe only what they truly care about—like cluster size or region.

The key takeaway is that no traditional infrastructure code is required from application teams. With Crossplane’s declarative approach, everything from EKS cluster creation to lifecycle management happens entirely within the Kubernetes ecosystem. This not only reduces complexity and operational overhead but also aligns perfectly with GitOps workflows, enabling continuous, version-controlled infrastructure delivery.

As organizations increasingly embrace platform engineering, Crossplane stands out as a powerful enabler, allowing you to build a secure, scalable, and developer-friendly abstraction layer on top of AWS EKS—or any other cloud provider—without the friction of legacy IaC tools. By investing in this approach today, you create a future-proof platform that accelerates developer productivity while maintaining the highest standards of governance and reliability.