infrastructure/k8s.tjo.cloud/modules/cluster/main.tf

361 lines
10 KiB
Terraform
Raw Normal View History

2024-07-08 20:27:08 +00:00
locals {
public_domain = "${var.cluster.api.public.subdomain}.${var.cluster.api.public.domain}"
internal_domain = "${var.cluster.api.internal.subdomain}.${var.cluster.api.internal.domain}"
cluster_internal_endpoint = "https://${local.internal_domain}:${var.cluster.api.internal.port}"
cluster_public_endpoint = "https://${local.public_domain}:${var.cluster.api.public.port}"
2024-07-08 20:27:08 +00:00
talos_controlplane_config = {
2024-07-25 15:42:08 +00:00
machine = {
2024-12-14 19:15:07 +00:00
kubelet = {
extraArgs = {
rotate-server-certificates = true
}
}
2024-07-25 15:42:08 +00:00
features = {
rbac = true
apidCheckExtKeyUsage = true
kubernetesTalosAPIAccess = {
enabled = true
allowedRoles = [
2024-07-20 11:09:30 +00:00
"os:reader"
]
2024-07-25 15:42:08 +00:00
allowedKubernetesNamespaces = [
2024-07-20 11:09:30 +00:00
"kube-system"
]
}
}
}
2024-07-25 15:42:08 +00:00
cluster = {
apiServer = {
2024-08-04 17:50:50 +00:00
certSANs = [
local.public_domain,
local.internal_domain,
2024-12-05 18:13:22 +00:00
"localhost:7445",
2024-08-04 17:50:50 +00:00
]
2024-07-25 15:42:08 +00:00
extraArgs = {
"oidc-issuer-url" = "https://id.tjo.space/application/o/k8stjocloud/",
"oidc-client-id" = "HAI6rW0EWtgmSPGKAJ3XXzubQTUut2GMeTRS2spg",
"oidc-username-claim" = "sub",
"oidc-username-prefix" = "oidc:",
"oidc-groups-claim" = "groups",
"oidc-groups-prefix" = "oidc:groups:",
}
}
2024-12-15 17:35:26 +00:00
inlineManifests = concat([
{
2024-07-25 15:42:08 +00:00
name = "proxmox-cloud-controller-manager"
contents = data.helm_template.proxmox-ccm.manifest
2024-07-20 11:09:30 +00:00
},
{
2024-07-25 15:42:08 +00:00
name = "talos-cloud-controller-manager"
contents = data.helm_template.talos-ccm.manifest
2024-07-20 11:09:30 +00:00
},
{
2024-07-25 15:42:08 +00:00
name = "promxmox-csi-plugin"
contents = data.helm_template.proxmox-csi.manifest
2024-07-20 11:09:30 +00:00
},
{
2024-07-25 15:42:08 +00:00
name = "gateway-api-crds"
contents = file("${path.module}/manifests/gateway-api.crds.yaml")
2024-07-20 11:09:30 +00:00
},
2024-12-22 12:32:22 +00:00
{
name = "oidc-admins"
contents = <<-EOF
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: id-tjo-space:admins
subjects:
- kind: Group
name: oidc:groups:k8s.tjo.cloud admin
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-admin
apiGroup: rbac.authorization.k8s.io
EOF
},
2024-07-20 11:09:30 +00:00
{
2024-07-25 15:42:08 +00:00
name = "cilium"
contents = data.helm_template.cilium.manifest
2024-07-20 11:09:30 +00:00
},
2024-12-15 17:35:26 +00:00
{
name = "cilium-bgp-advertisement"
contents = <<-EOF
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
name: pods-and-services
labels:
k8s.tjo.cloud/default: "true"
spec:
advertisements:
- advertisementType: "PodCIDR"
- advertisementType: "Service"
service:
addresses:
- ExternalIP
- LoadBalancerIP
2024-12-22 12:32:22 +00:00
selector:
matchExpressions:
- {key: somekey, operator: NotIn, values: ['never-used-value']} # match all services
2024-12-15 17:35:26 +00:00
EOF
},
{
name = "cilium-bgp-peer-config"
contents = <<-EOF
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPPeerConfig
metadata:
name: default
spec:
families:
- afi: ipv4
safi: unicast
advertisements:
matchLabels:
k8s.tjo.cloud/default: "true"
- afi: ipv6
safi: unicast
advertisements:
matchLabels:
k8s.tjo.cloud/default: "true"
EOF
},
2024-07-20 11:09:30 +00:00
{
2024-12-22 12:32:22 +00:00
name = "cilium-load-balancer-ip-pool"
2024-07-25 15:42:08 +00:00
contents = <<-EOF
2024-12-22 12:32:22 +00:00
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
2024-12-15 17:35:26 +00:00
metadata:
2024-12-22 12:32:22 +00:00
name: default
spec:
blocks:
- cidr: "${var.cluster.load_balancer_cidr.ipv4}"
- cidr: "${var.cluster.load_balancer_cidr.ipv6}"
2024-12-15 17:35:26 +00:00
EOF
},
2024-12-15 17:35:26 +00:00
],
[for name, attributes in var.hosts : {
name = "cilium-bgp-node-config-override-${name}"
contents = <<-EOF
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPClusterConfig
metadata:
name: ${name}
spec:
gracefulRestart:
enabled: true
restartTimeSeconds: 15
nodeSelector:
matchLabels:
k8s.tjo.cloud/bgp: "true"
k8s.tjo.cloud/host: ${name}
k8s.tjo.cloud/proxmox: ${var.proxmox.name}
bgpInstances:
- name: "${name}"
localASN: ${attributes.asn}
peers:
- name: "local-router-vip"
peerASN: ${attributes.asn}
peerAddress: "10.0.0.1"
peerConfigRef:
name: "default"
EOF
}
]
)
}
2024-07-08 20:27:08 +00:00
}
talos_worker_config = {
2024-07-25 15:42:08 +00:00
cluster = {
network = {
cni = {
name = "none"
2024-07-08 20:27:08 +00:00
}
2024-12-15 17:35:26 +00:00
podSubnets = [
var.cluster.pod_cidr.ipv4,
var.cluster.pod_cidr.ipv6
]
serviceSubnets = [
var.cluster.service_cidr.ipv4,
var.cluster.service_cidr.ipv6
]
}
2024-07-25 15:42:08 +00:00
proxy = {
disabled = true
2024-07-08 20:27:08 +00:00
}
}
machine = {
kubelet = {
2024-07-25 15:42:08 +00:00
extraArgs = {
rotate-server-certificates = true
cloud-provider = "external"
2024-07-08 20:27:08 +00:00
}
}
install = {
image = "factory.talos.dev/installer/${var.talos.schematic_id}:${var.talos.version}"
disk = "/dev/vda"
}
2024-12-22 12:32:22 +00:00
features = {
hostDNS = {
enabled = false
resolveMemberNames = false
forwardKubeDNSToHost = false
}
}
2024-07-08 20:27:08 +00:00
}
}
2024-07-19 20:48:07 +00:00
talos_node_config = {
for k, node in local.nodes_with_address : k => [
yamlencode({
machine = {
network = {
hostname = node.name
}
nodeLabels = {
2024-12-15 17:35:26 +00:00
"k8s.tjo.cloud/bgp" = "true"
2024-07-19 20:48:07 +00:00
"k8s.tjo.cloud/host" = node.host
"k8s.tjo.cloud/proxmox" = var.proxmox.name
2024-07-21 10:27:40 +00:00
}
2024-07-19 20:48:07 +00:00
}
}),
]
}
2024-07-08 20:27:08 +00:00
}
2024-07-19 20:48:07 +00:00
resource "talos_machine_secrets" "this" {
talos_version = var.talos.version
}
2024-07-08 20:27:08 +00:00
data "talos_machine_configuration" "controlplane" {
2024-07-14 10:19:37 +00:00
cluster_name = var.cluster.name
2024-07-08 20:27:08 +00:00
machine_type = "controlplane"
2024-08-04 17:50:50 +00:00
cluster_endpoint = local.cluster_internal_endpoint
2024-07-08 20:27:08 +00:00
machine_secrets = talos_machine_secrets.this.machine_secrets
talos_version = var.talos.version
kubernetes_version = var.talos.kubernetes
2024-07-08 20:27:08 +00:00
}
data "talos_machine_configuration" "worker" {
2024-07-14 10:19:37 +00:00
cluster_name = var.cluster.name
2024-07-08 20:27:08 +00:00
machine_type = "worker"
2024-08-04 17:50:50 +00:00
cluster_endpoint = local.cluster_internal_endpoint
2024-07-08 20:27:08 +00:00
machine_secrets = talos_machine_secrets.this.machine_secrets
talos_version = var.talos.version
kubernetes_version = var.talos.kubernetes
2024-07-08 20:27:08 +00:00
}
2024-07-10 21:13:36 +00:00
resource "talos_machine_configuration_apply" "controlplane" {
for_each = { for k, v in local.nodes_with_address : k => v if v.type == "controlplane" }
2024-07-08 20:27:08 +00:00
client_configuration = talos_machine_secrets.this.client_configuration
2024-07-10 21:13:36 +00:00
machine_configuration_input = data.talos_machine_configuration.controlplane.machine_configuration
2024-07-08 20:27:08 +00:00
node = each.value.name
endpoint = each.value.ipv4
2024-07-08 20:27:08 +00:00
2024-12-14 19:15:07 +00:00
config_patches = sensitive(concat(
2024-07-19 20:48:07 +00:00
[
yamlencode(local.talos_worker_config),
yamlencode(local.talos_controlplane_config)
],
local.talos_node_config[each.key]
2024-12-14 19:15:07 +00:00
))
2024-12-19 21:15:46 +00:00
timeouts = {
create = "1m"
update = "1m"
}
2024-07-10 21:13:36 +00:00
}
resource "talos_machine_configuration_apply" "worker" {
for_each = { for k, v in local.nodes_with_address : k => v if v.type == "worker" }
client_configuration = talos_machine_secrets.this.client_configuration
machine_configuration_input = data.talos_machine_configuration.worker.machine_configuration
node = each.value.name
endpoint = each.value.ipv4
2024-07-10 21:13:36 +00:00
2024-12-14 19:15:07 +00:00
config_patches = sensitive(concat(
2024-07-19 20:48:07 +00:00
[
yamlencode(local.talos_worker_config)
],
local.talos_node_config[each.key]
2024-12-14 19:15:07 +00:00
))
2024-12-19 21:15:46 +00:00
timeouts = {
create = "1m"
update = "1m"
}
2024-07-08 20:27:08 +00:00
}
resource "talos_machine_bootstrap" "this" {
depends_on = [
2024-07-10 21:13:36 +00:00
talos_machine_configuration_apply.controlplane,
talos_machine_configuration_apply.worker
2024-07-08 20:27:08 +00:00
]
node = local.first_controlplane_node.name
endpoint = local.first_controlplane_node.ipv4
2024-07-08 20:27:08 +00:00
client_configuration = talos_machine_secrets.this.client_configuration
}
resource "talos_cluster_kubeconfig" "this" {
2024-07-08 20:27:08 +00:00
depends_on = [
talos_machine_bootstrap.this
]
client_configuration = talos_machine_secrets.this.client_configuration
node = local.first_controlplane_node.ipv4
2024-07-08 20:27:08 +00:00
}
2024-07-19 20:48:07 +00:00
resource "local_file" "kubeconfig" {
content = talos_cluster_kubeconfig.this.kubeconfig_raw
2024-07-19 20:48:07 +00:00
filename = "${path.root}/admin.kubeconfig"
2024-07-27 09:31:15 +00:00
lifecycle {
ignore_changes = [content]
}
2024-07-19 20:48:07 +00:00
}
data "talos_client_configuration" "this" {
count = length(values({ for k, v in local.nodes_with_address : k => v if v.type == "controlplane" })) > 0 ? 1 : 0
cluster_name = var.cluster.name
client_configuration = talos_machine_secrets.this.client_configuration
endpoints = values({ for k, v in local.nodes_with_address : k => v if v.type == "controlplane" })[*].ipv4
}
resource "local_file" "talosconfig" {
count = length(values({ for k, v in local.nodes : k => v if v.type == "controlplane" })) > 0 ? 1 : 0
content = nonsensitive(data.talos_client_configuration.this[0].talos_config)
filename = "${path.root}/admin.talosconfig"
}
2025-01-03 20:59:46 +00:00
resource "dnsimple_zone_record" "api-internal-ipv4" {
for_each = { for k, v in local.nodes_with_address : k => v if v.type == "controlplane" }
2025-01-03 20:59:46 +00:00
zone_name = var.cluster.api.internal.domain
type = "A"
name = var.cluster.api.internal.subdomain
value = each.value.ipv4
ttl = 30
}
2025-01-03 20:59:46 +00:00
resource "dnsimple_zone_record" "api-internal-ipv6" {
for_each = { for k, v in local.nodes_with_address : k => v if v.type == "controlplane" }
2025-01-03 20:59:46 +00:00
zone_name = var.cluster.api.internal.domain
type = "AAAA"
name = var.cluster.api.internal.subdomain
value = each.value.ipv6
ttl = 30
}