TerraformPilot

DevOps

Terraform for Bottlerocket OS on Amazon EKS

Provision Bottlerocket OS Kubernetes nodes with Terraform on Amazon EKS: managed node groups, custom AMIs, settings, and automated updates.

LLuca Berton1 min read

Bottlerocket is AWS's container-optimized Linux: minimal attack surface, image-based updates, no SSH by default. It's the recommended OS for EKS managed node groups in 2026. Terraform configures it via the ami_type = "BOTTLEROCKET_x86_64" (or _ARM_64, _NVIDIA) on aws_eks_node_group.

Quick Pattern (TL;DR)

#
resource "aws_eks_node_group" "bottlerocket" {
  cluster_name    = aws_eks_cluster.this.name
  node_group_name = "bottlerocket"
  node_role_arn   = aws_iam_role.nodes.arn
  subnet_ids      = var.private_subnet_ids
 
  ami_type       = "BOTTLEROCKET_x86_64"
  instance_types = ["m7i.large"]
 
  scaling_config {
    desired_size = 3
    min_size     = 3
    max_size     = 12
  }
 
  update_config {
    max_unavailable_percentage = 33
  }
}

GPU Bottlerocket for AI Nodes

#
resource "aws_eks_node_group" "gpu" {
  cluster_name    = aws_eks_cluster.this.name
  node_group_name = "bottlerocket-gpu"
  node_role_arn   = aws_iam_role.nodes.arn
  subnet_ids      = var.private_subnet_ids
 
  ami_type       = "BOTTLEROCKET_x86_64_NVIDIA"
  instance_types = ["g5.2xlarge"]
 
  scaling_config { desired_size = 0; min_size = 0; max_size = 8 }
 
  taint {
    key    = "nvidia.com/gpu"
    value  = "true"
    effect = "NO_SCHEDULE"
  }
}

Custom Bottlerocket Settings via User Data

#
resource "aws_launch_template" "bottlerocket" {
  name_prefix   = "br-"
  image_id      = data.aws_ssm_parameter.bottlerocket.value
 
  user_data = base64encode(<<-EOT
    [settings.kubernetes]
    cluster-name = "${aws_eks_cluster.this.name}"
    api-server   = "${aws_eks_cluster.this.endpoint}"
    cluster-certificate = "${aws_eks_cluster.this.certificate_authority[0].data}"
 
    [settings.host-containers.admin]
    enabled = false
 
    [settings.kernel]
    lockdown = "integrity"
  EOT
  )
}
 
data "aws_ssm_parameter" "bottlerocket" {
  name = "/aws/service/bottlerocket/aws-k8s-1.31/x86_64/latest/image_id"
}

Best Practices

#
  • Use the SSM AMI parameter so Terraform always gets the latest patched image.
  • Disable the admin container (enabled = false) in production — keep the API surface flat.
  • Set lockdown = "integrity" for kernel module locking.
  • Use BOTTLEROCKET_x86_64_FIPS when you need FIPS 140-3.
  • Roll nodes monthly — Bottlerocket image updates ship as full images, not packages.
#
#Terraform#Bottlerocket#EKS#AWS#Container Linux

Share this article