https://github.com/cruxstack/terraform-aws-k3s
Terraform module to provision a self-managed K3s cluster on AWS EC2.
https://github.com/cruxstack/terraform-aws-k3s
aws aws-ec2 aws-ec2-instance cloudposse high-availability infrastructure k3s k3s-cluster kubernetes kubernetes-cluster kubernetes-deployment sweetops terrafo terraform-module
Last synced: about 1 month ago
JSON representation
Terraform module to provision a self-managed K3s cluster on AWS EC2.
- Host: GitHub
- URL: https://github.com/cruxstack/terraform-aws-k3s
- Owner: cruxstack
- License: mit
- Created: 2025-06-03T00:31:30.000Z (12 months ago)
- Default Branch: main
- Last Pushed: 2025-06-13T15:47:01.000Z (12 months ago)
- Last Synced: 2025-07-03T19:44:56.613Z (11 months ago)
- Topics: aws, aws-ec2, aws-ec2-instance, cloudposse, high-availability, infrastructure, k3s, k3s-cluster, kubernetes, kubernetes-cluster, kubernetes-deployment, sweetops, terrafo, terraform-module
- Language: HCL
- Homepage: https://registry.terraform.io/modules/cruxstack/k3s/aws/latest
- Size: 48.8 KB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# terraform-aws-k3s
## Overview
This module provisions a self-managed K3s cluster on AWS EC2, eliminating the
$300/month EKS control-plane fee and giving you full control over node sizing,
scaling, and networking. All nodes bootstrap themselves without external
orchestration or SSH access. In just a few lines of Terraform, you get:
- **Automated leader election**
Server nodes automatically elect a leader to initialize the control plane.
- **Kubeconfig in SSM**
The leader publishes its kubeconfig to SSM so you can fetch it securely and
start using kubectl immediately.
- **Auto-joining agents**
Worker (agent) nodes wait for the control plane to be ready, then join
automatically without manual intervention.
- **Minimal IAM footprint**
Nodes receive only the permissions they need—SSM parameter access, EC2
describe, self-termination, and CloudWatch Logs.
- **Built-in CloudWatch logging**
Every node installs the CloudWatch Agent to stream EC2 instance logs to a
dedicated log group (does not include pod logs). Retention is configurable.
- **Optional Elastic IP support**
If enabled, EIPs are allocated and attached to server nodes via a companion
EIP manager module.
- **Single shared security group**
All servers and agents share one security group. Only port 6443 is exposed
to your admin CIDRs; intra-cluster traffic is unrestricted.
## Why use this instead of EKS?
- **Avoid fixed control plane cost**
EKS control plane alone is $300/month. With this module, you pay only for
the EC2 instances you launch.
- **Simplified, lean setup**
A single EC2 instance can stand up a full K3s control plane (embedded etcd).
Perfect for dev/staging, small teams, or cost-sensitive workloads.
- **Hands-on flexibility**
You choose instance types, replica counts, spot vs on-demand, tagging, and
scaling. Updates and upgrades are fully under your control.
## Basic Usage
```hcl
module "k3s_cluster" {
source = "cruxstack/k3s/aws"
version = "x.x.x"
name = "example"
k3s_admin_allowed_cidrs = ["x.x.x.x/32"]
k3s_server_instances = {
count = 1
assign_public_ip = true
vpc_subnet_ids = ["subnet-0abcd1234efgh5678"]
}
}
```
Fetch the kubeconfig:
```bash
aws ssm get-parameter \
--name "/k3s-cluster/server/kubeconfig" \
--with-decryption \
--region us-east-1 \
--query "Parameter.Value" --output text \
> kubeconfig.yaml
export KUBECONFIG=./kubeconfig.yaml
kubectl get nodes
```
## Inputs
| Name | Description | Type | Default |
| ------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------- |
| `k3s_server_instances` | Controls number/type of K3s servers; EIP support; subnets. | `
object({
count: number
key\_name: string
vpc\_subnet\_ids: list(string)
assign\_public\_ip: bool
eip\_enabled: bool
types: list(object({type\:string,weight\:number}))
}) | `{ count=1, … }` |
| `k3s_agent_instances` | Controls number/type of K3s agents; spot settings; subnets. | `object({
count: number
key\_name: string
vpc\_subnet\_ids: list(string)
spot: object({enabled\:bool,allocation\_strategy\:string})
types: list(object({type\:string,weight\:number}))
}) | `{ count=0, … }` |
| `k3s_version` | K3s version (“stable”, “latest”, or literal). | `string` | `"stable"` |
| `k3s_admin_allowed_cidrs` | CIDRs allowed to reach API server (port 6443). | `list(string)` | `[]` |
| `ssm_param_namespace` | Base path for cluster SSM parameters (init-status, kubeconfig). | `string` | `"/k3s-cluster"` |
| `ssm_sessions` | Enable SSM Session Manager logging and specify S3 bucket. | `object({enabled:bool,logs_bucket_name:string})` | `{}` |
| `logs_group_retention` | Days to retain CloudWatch logs. | `number` | `90` |
| `vpc_security_group_ids` | Extra security group IDs to attach to each node. | `list(string)` | `[]` |
*All standard `cloudposse/label/null` inputs are also accepted.*
## Outputs
| Name | Description |
| ----------------------------- | --------------------------------------------------------------------------------- |
| `k3s_kubeconfg_ssm_parameter` | SSM path where kubeconfig is published (e.g. `"/k3s-cluster/server/kubeconfig"`). |
| `security_group_id` | ID of the security group used by all K3s instances. |
| `security_group_name` | Name of that security group. |