# cluster-api-provider-aws: Kubernetes APIs for AWS clusters

> The AWS implementation of Cluster API, a controller that reconciles Kubernetes custom resources into VPCs, subnets, security groups and EC2 instances, plus EKS support and a companion CLI for bootstrapping. It suits platform teams who already manage infrastructure declaratively and want clusters to be a Kubernetes object rather than a script.

**kubernetes-sigs/cluster-api-provider-aws** — Kubernetes Cluster API Provider AWS provides consistent deployment and day 2 operations of "self-managed" and EKS Kubernetes clusters on AWS.

- Repository: https://github.com/kubernetes-sigs/cluster-api-provider-aws
- Website: http://cluster-api-aws.sigs.k8s.io/
- Stars: 730 · Forks: 718
- Language: Go
- License: Apache-2.0
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/kubernetes-sigs-cluster-api-provider-aws

## What the provider actually reconciles on AWS

Cluster API brings declarative, Kubernetes-style APIs to cluster creation, configuration and management. The provider is the AWS implementation of that idea, and its feature list is a list of things it creates for you.

It manages the bootstrapping of VPCs, gateways, security groups and instances. It gives you native Kubernetes manifests and API for all of it. It does not use SSH for bootstrapping nodes, which removes a whole category of credential handling from the picture. It installs only the minimal components to bootstrap a control plane and workers, rather than a full node agent stack. It supports control planes on EC2 instances.

The network placement is deliberate rather than incidental. It deploys Kubernetes control planes into private subnets with a separate bastion server, so the control plane is not directly reachable from the internet and the bastion is how you get in.

There is also EKS support. The repository carries separate API directories for the managed service variants, including controlplane/eks/api, bootstrap/eks/api, and there is a separate controlplane/rosa/api for the ROSA path, which is a different offering from the self-managed stack.

The description of the project is precise about the intent: consistent deployment and day 2 operations of self-managed and EKS Kubernetes clusters on AWS. Both halves matter. Creation is the part everyone expects, and day 2 operations is where most of the actual work happens once you have more than a handful of clusters.

## One API across providers, and the kops and kubicorn lineage

The reason Cluster API exists as a separate project rather than a set of cloud scripts is the API itself being shared across multiple cloud providers, which allows for true AWS hybrid deployments of Kubernetes.

That shared API is what makes the provider swappable. The management cluster runs Cluster API's core controllers and this provider's controllers, and the same Cluster and Machine objects can be reconciled by a different provider when a workload moves. For a team running clusters across AWS and on-premises, or across clouds, that portability is the point rather than a side effect.

The project states that it is built atop the lessons learned from previous cluster managers such as kops and kubicorn. Both of those are now historical references, and the readme even still says that if you have an idea for a feature and think you can help kops become even more awesome, which is a leftover from when the issue tracker was shared. It is a small sign of how the project's history shows through its documentation.

The design consequence is worth spelling out. Because the interface is Kubernetes shaped, a cluster is described by a manifest rather than by a runbook, and the controller does the reconciliation. That is a different operating model from running a script that calls the cloud API, and it is the model you are buying when you adopt this provider. The infrastructure state lives in etcd, and the cloud is the thing that gets reconciled towards it.

## The version matrix, because a mismatched provider is a silent problem

This provider's versions are compatible with the following versions of Cluster API and support all Kubernetes versions that is supported by its compatible Cluster API version.

The compatibility table has two columns, Cluster API v1alpha4 (v0.4) and Cluster API v1beta1 (v1.x), and three rows of provider versions. CAPA v1alpha4 (v0.7) works with the v1alpha4 column. CAPA v1beta1 (v1.x) and CAPA v1beta2 (v2.x, main) both work with the v1beta1 column and are marked as not compatible with v1alpha4.

So the current line of the provider is the v2.x line on the main branch, and it requires a Cluster API v1beta1 or later management cluster. The old v0.7 provider is only for the v0.4 API era, which is long gone.

The release history shows how many lines are still being patched. The three most recent releases are v2.13.1, v2.12.2 and v2.11.3, and all three were published on 2026-09-30 within a couple of minutes of each other. That is a branch-per-minor-version support model, with a patch release going out to each supported minor at the same time.

The Kubernetes versions themselves follow from the Cluster API version, so you are not choosing a Kubernetes version independently. And where the AMIs come from is a separate question the readme points at a list of most recently published AMIs, because the choice of Linux distribution is exposed as pre-baked AMIs you select.

## clusterawsadm is the part you run by hand

Most of Cluster API is declarative, but bootstrapping is not, because there is a chicken and egg problem: to install the controllers you need a cluster, and to create a cluster you need the controllers installed.

clusterawsadm CLI tool provides bootstrapping, AMI, EKS, and controller related helpers. It is the tool that breaks that cycle, and it is also the tool you use for the parts of the process that are inherently one-off.

The binaries are released with each release, can be found under the assets section of the GitHub releases, and could also be installed via Homebrew on macOS and linux OS. Installing the latest release with Homebrew is:

```shell
brew install clusterawsadm
```

And there is a version check, which the documentation suggests as the way to test whether the version you installed is up-to-date:

```shell
clusterawsadm version
```

That check matters more than usual here, because a clusterawsadm that is older than the controllers it installs will fail in ways that look like permission problems. The bootstrap step typically involves the tool creating IAM roles and policies that the controller will later assume, which is the piece that has to be right before any manifest can be applied.

The AMI and EKS helpers in the same tool cover the two other things that are awkward to do by hand: building or selecting the machine images your nodes run on, and preparing the IAM and service setup that the managed service path needs.

## Building the images locally and running Tilt against a real AWS account

The contribution path is documented, and it is the part of the project that shows how a controller of this size is actually developed.

If you want to just build the CAPA containers locally, run:

```shell
  REGISTRY=docker.io/my-reg make docker-build
```

The Makefile shows what that involves. The Go version is 1.26.5 by default, the Go container image is golang:$(GO_VERSION), and the repository includes common.mk and versions.mk which the Makefile includes, following the convention of well documented makefiles. There is a Makefile target that runs the Kubernetes go-apidiff tool, which is how API compatibility is checked between versions, and that is the mechanism behind not breaking the CRD contract between provider releases.

The Dockerfile shows the container shape. It uses a multi-stage build with a builder image passed in as a build argument, a go module cache mount so dependency downloads are not repeated, and a static build with CGO_ENABLED=0 and GOOS=linux and an ARCH argument for the target architecture. The runtime image is distroless static nonroot, with the manager binary copied in and an entrypoint that runs /start.sh with the workspace manager path.

For day to day work there is a Tilt-based development environment, described in the development section of the book, and the tree carries tilt-provider.json, a devbox.json with a matching lock file, and a devcontainer directory. The Dockerfile accepts a goproxy build argument so that a build behind a restrictive network can point at a different module proxy, with the comment recommending the form docker build --build_arg $(go env GOPROXY).

## A project run by a community rather than a team

The contributing section of the readme is unusually explicit about who maintains this, and it tells you something about how decisions get made.

The maintainers would love your suggestions, contributions, and help, and in the interest of getting more new people involved they tag issues with good first issue. These are typically issues that have smaller scope but are good ways to start to get acquainted with the codebase. They encourage ALL active community participants to act as if they are maintainers, even if you do not have official write permissions, and say plainly that this is a community effort. If you have an active interest and you want to get involved, you have real power, and the instruction is not to assume that the only people who can get things done around here are the maintainers.

The process around that is documented too. The repository uses the Kubernetes bots, with a full list of the commands linked. For bugs, the ask is to spend a small amount of time giving due diligence to the issue tracker because the issue might be a duplicate, to get the logs from the cluster controllers and paste them in, and to open a new issue with a meaningful title. For features, the ask is to clearly define the use case with concrete examples, phrased as I type this and cluster-api-provider-aws does that, and to include a technical design if the feature is large, after which a work in progress pull request is the way to start.

Maintainers hold office hours every two weeks, with sessions open to all developers working on the project, hosted on a zoom video chat every other Monday at 09:00 Pacific, 12:00 Eastern and 17:00 Europe/London, published on the Kubernetes community meetings calendar. The Slack channel is #cluster-api-aws.

For an adopter, the practical read is that this is a project where a well-prepared issue is genuinely read by people who can act on it, which is unusual and useful to know when you are planning to depend on it.

## Where a Cluster API provider is the wrong tool

There are clear cases where this is the wrong choice, and they are cases of scale and of workflow rather than of technical capability.

The first is a single cluster. If you have one cluster that a human created with a wizard and nobody plans to create a second one, the management cluster you need in order to use this provider is more infrastructure than the cluster it manages. You are adding an API server, an etcd, a controller set and a bootstrap process in exchange for a declarative interface you will use a handful of times.

The second is when the imperative workflow fits. A well written Terraform or CloudFormation stack with a state file, a pipeline and a change process gives you review, diffing and rollback too. Cluster API's advantage is that the state lives in the same place as everything else Kubernetes, which is decisive when you have dozens of clusters across accounts and you want one API to query. With three clusters in one account, it is largely a preference.

The third is the dependency on the Cluster API core versions. The provider is only as stable as the core project it runs on, and the compatibility matrix shows that provider major versions map onto Cluster API API versions. An upgrade is a coordinated operation across two versioned projects, and the readme does not describe a supported upgrade path between provider majors.

The fourth is cost and permission scope. The controller needs to create VPCs, subnets, security groups, instances and IAM roles, and clusterawsadm needs to create IAM on your behalf. That is a broad set of permissions in your AWS account, and some organisations will not grant it to a controller that acts continuously. A pipeline that runs Terraform with an assumed role under your change process may be the only acceptable shape for them.

And the fifth is the AWS-specific surface. This provider manages AWS. If a meaningful part of your estate is elsewhere, the shared API buys you portability of the interface but not of the implementation, and you end up running two providers.

## Against Terraform and CloudFormation, and against the previous generation

Two comparisons clarify where the value is.

The first is against Terraform or CloudFormation. The difference in approach is where the desired state lives and who reconciles it. In an infrastructure as code workflow, the state lives in a state file or a stack, and the plan is computed by comparing that state to a template. With Cluster API, the desired state is a set of Kubernetes objects, and a controller inside the management cluster continuously compares them to AWS and acts on the difference. The consequence is that Cluster API is a control loop with eventual consistency, not a plan and apply step.

That shows up in practice in both directions. Cluster API gives you the Kubernetes API for cluster lifecycle, so a cluster can be created, scaled and deleted by applying a manifest, and the same GitOps tooling that manages your workloads can manage your clusters. Terraform gives you a plan you can read before anything changes, which is a different and arguably better story for a regulated change process.

The second comparison is against the previous generation of cluster managers, kops and kubicorn. The readme is direct that this project is built atop the lessons learned from them. kops was a Kubernetes cluster manager for AWS with its own opinionated model of the cluster, and kubicorn was the Google Compute Engine one. Both are gone from this ecosystem, and the difference in approach is that both treated a cluster as the output of a command with a config file, while Cluster API treats a cluster as a resource in an API server that other controllers can act on. The price of the new model is the management cluster, and the benefit is that clusters become composable with everything else in Kubernetes.

So the deciding question is narrow. If your cluster lifecycle is already part of your Kubernetes platform, this provider is the natural fit. If it is part of your infrastructure pipeline, Cluster API adds a second source of truth rather than removing one.

## Conclusion

Adopt cluster-api-provider-aws if you run Kubernetes clusters across several AWS accounts or regions and want their lifecycle expressed as Kubernetes resources you can review, diff and template. Skip it if you have one hand-built cluster and no plan for more, since the operational overhead of a management cluster is real. Verify first that the provider version you choose matches the Cluster API version your management cluster runs, since the compatibility matrix is explicit about which pairs are supported, and confirm that the AWS features you depend on exist in the EKS variants you intend to use.

## FAQ

### What does cluster-api-provider-aws manage on AWS?

It manages the bootstrapping of VPCs, gateways, security groups and instances, with native Kubernetes manifests and API for all of it. It does not use SSH for bootstrapping nodes, deploys control planes into private subnets with a separate bastion server, and supports control planes on EC2 instances.

### How do I install the clusterawsadm CLI?

The binaries are released with each release under the assets section of the GitHub releases, and the tool can also be installed via Homebrew on macOS and Linux with brew install clusterawsadm. You can then check the version with clusterawsadm version.

### Which Cluster API version does cluster-api-provider-aws need?

The current CAPA v1beta2 line on the main branch is compatible with Cluster API v1beta1, and the older CAPA v1alpha4 (v0.7) line is the one compatible with Cluster API v1alpha4. The provider supports all Kubernetes versions supported by its compatible Cluster API version.

### Does cluster-api-provider-aws support EKS?

Yes, there is EKS support, and the repository has separate API directories for the managed service variants including controlplane/eks/api and bootstrap/eks/api, along with a controlplane/rosa/api directory for the ROSA path.

### How do I build the provider images locally?

Run REGISTRY=docker.io/my-reg make docker-build, which builds the CAPA containers locally. The Dockerfile is a multi-stage build with a go module cache mount and a static CGO_ENABLED=0 build, and the runtime image is distroless static nonroot.

### What licence does cluster-api-provider-aws use?

Apache-2.0, with the LICENSE file at the root of the repository. The repository is not archived and the last push was on 2026-10-20, with v2.13.1, v2.12.2 and v2.11.3 all published on 2026-09-30.

## Sources

- [kubernetes-sigs/cluster-api-provider-aws on GitHub](https://github.com/kubernetes-sigs/cluster-api-provider-aws)
- [License: Apache-2.0](https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/main/LICENSE)
- [Project website](http://cluster-api-aws.sigs.k8s.io/)
- [README](https://github.com/kubernetes-sigs/cluster-api-provider-aws/blob/main/README.md)
- [Releases](https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/kubernetes-sigs-cluster-api-provider-aws
