Skip to content

cruxstack/terraform-aws-k3s

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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

module "k3s_cluster" {
  source  = "cruxstack/k3s/aws"
  version = "x.x.x"

  server_instances = {
    count            = 1
    assign_public_ip = 1
    vpc_subnet_ids   = ["subnet-0abcd1234efgh5678"]
  }

  k3s_admin_allowed_cidrs = ["x.x.x.x/32"]
}

Fetch the kubeconfig:

aws ssm get-parameter \
  --name "/prod-k3s/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
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, … }
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.