pippi.io/talos-cluster

March 9, 2026 ยท View on GitHub

This Terraform module automates the configuration of a Talos cluster.

Examples

provider "talos" {}

terraform {
  required_version = ">= 1.14"
}

module "cluster" {
  source = "git@github.com:pippi.io/talos-cluster?ref=a401732fe4c3f6b273caf84904a3110c336f94fe"

  cluster = {
    hostname = "k8s.pippi.io" # Or can be set to the VIP "192.168.1.5" if no DNS is setup
    vip      = "192.168.1.5"
    name     = "pippi"

    nodes = {
      "node1.k8s.pippi.io" = {
        type = "controlplane"
        disk = "/dev/sda"
        interfaces = {
          end0 = {
            ipv4_address_cidr = "192.168.1.11/24"
          }
        }
      }
      "node2.k8s.pippi.io" = {
        type = "worker"
        disk = "/dev/sda"
        interfaces = {
          end0 = {
            ipv4_address_cidr = "192.168.1.12/24"
          }
        }
      }
      "node3.k8s.pippi.io" = {
        type = "worker"
        disk = "/dev/disk/by-id/nvme-eui.0000000000000001234"
        interfaces = {
          end0 = {
            ipv4_address_cidr = "192.168.1.13/24"
          }
        }
      }
    }
    default_routes = {
      "0.0.0.0/0" = "192.168.1.1"
    }
    name_servers = [
      "192.168.1.1"
    ]
  }
}

Requirements

NameVersion
terraform>= 1.14
dns~> 3.4
local~> 2.6
talos~> 0.9

Providers

NameVersion
local~> 2.6
talos~> 0.9

Inputs

NameDescriptionTypeDefaultRequired
clusterTalos cluster configurastion:
perform_healthcheck: Enables or disables a healty check towards the cluster, that can be depended on for other tasks
hostname: The hostname of the talos kubernetes cluster
name: The name of the talos kubernetes cluster
disk_selector: CEL expression to filter disks in output
nodes: A map
key: The nodes hostname
value:
type: Type of the node. Valid values includes [controlplane,worker]
install_disk: The Talos install disk.
disks: Node disk configuration:
key: device
value: mountpoint
image: Custom image for installation (overrides cluster image)
labels: List of node labels
taints: List of node taints
key: Taint key
value: Taint value
effect Taint effect
interfaces:
key: interface id
value:
ipv4_address_cidr: ipv4_address_cidr address, must be a valid ipv4_address_cidr ipv4_address_cidr pattern (e.x. 10.0.0.10/24)
routes: A map of routes structured <network-ipv4_address_cidr>=
mtu: Mtu of network
trusted: Shall the interface subnet be trusted and added to the certificates SAN
bond: Bond settings for bonding NICs
mode: Mode of the bond (defaults to active-backup)
miimon: Miimon of the bond (defaults to 100)
lacp_rate: Optional lacp rate of the bond
xmit_hash_policy: Optional xmit hash policy for the bond
interfaces: List of interfaces to bond together
temporary_ip: A temporary ip for installation
encryption: Encryption options for Talos install disks
node_id: Use node_id as the encryption key
passphrase: use passphrase as the encryption key
virtual_ip: Virtual IP for controlplanes
image: Custom image for all nodes
name_servers: A list of the nameservers to use in the cluster
time_servers: A set of NTP time server hostnames used for nodes
default_routes: A map of default routes structured <network-ipv4_address_cidr>=
schedule_on_controlplanes: Enalbes scheduling on the control plane nodes
kubeadm_cert_lifetime: Lifetime of the cubeconfig kubeadm certs (defaults to 12 hours)
object({
perform_healthcheck = optional(bool, true)
hostname = string
name = string
disk_selector = optional(string, "disk.size > 50u * GB && disk.readonly == false")
nodes = map(object({
type = string
install_disk = string
disks = optional(map(string), {})
image = optional(string)
labels = optional(map(string), {})
taints = optional(map(object({
value = optional(string)
effect = string
})), {})
interfaces = map(object({
ipv4_address_cidr = string
routes = optional(map(string))
mtu = optional(number)
trusted = optional(bool, true)
primary = optional(bool, true)
bond = optional(object({
mode = optional(string, "active-backup")
miimon = optional(number, 100)
lacp_rate = optional(string)
xmit_hash_policy = optional(string)
interfaces = list(string)
}))
}))
temporary_ip = optional(string)
}))

encryption = optional(object({
node_id = optional(bool, false)
passphrase = optional(string)
}), {
node_id = true
})
virtual_ip = optional(string)
image = optional(string)
name_servers = optional(list(string), [])
time_servers = optional(set(string), [])
default_routes = optional(map(string), {})
schedule_on_controlplanes = optional(bool, false)
kubeadm_cert_lifetime = optional(string, "12h0m0s")
})
n/ayes
configfileLocal config file configuration. NB! files contains sensitive certificates:
talosconfig: Talos config file:
save_to_disk: True if talosconfig is saved to local file.
path: File path. Defaults to ~/.talos/config
owerwrite: True if existing file is owerwritten. False will merge with existing file.
kubeconfig: Kube config file:
save_to_disk: True if kubeconfig is saved to local file.
path: File path. Defaults to ~/.kube/config
owerwrite: True if existing file is owerwritten. False will merge with existing file.
object({
talosconfig = optional(object({
save_to_disk = optional(bool, false)
path = optional(string, "/.talos/config")
owerwrite = optional(bool, false)
}), {})
kubeconfig = optional(object({
save_to_disk = optional(bool, false)
path = optional(string, "
/.kube/config")
owerwrite = optional(bool, false)
}), {})
})
{}no

Resources

NameType
local_sensitive_file.kubeconfigresource
local_sensitive_file.talosconfigresource
talos_cluster_kubeconfig.thisresource
talos_machine_bootstrap.thisresource
talos_machine_configuration_apply.thisresource
talos_machine_secrets.thisresource
talos_client_configuration.thisdata source
talos_cluster_health.thisdata source
talos_machine_configuration.thisdata source
talos_machine_disks.thisdata source

Outputs

NameDescription
healthyTrue once cluster is healthy
kubeconfigThe Talos cluster kubeconfig
talosconfigThe Talos cluster talosconfig
trusted_subnetsTalos trusetd subnets added to kublet certificate SAN
worker_disksTalos workernode disks