Skip to content

Commit fb21a66

Browse files
authored
🤖 feat(terraform): add long-lived cluster-admin service account (#52)
## Summary Adds Terraform-managed Kubernetes resources that create a dedicated service account with a **long-lived (legacy) token Secret** (not a projected service account token) and grants it **cluster-admin** permissions. ## Implementation - Adds the `hashicorp/kubernetes` provider and configures it against the EKS endpoint. - Creates: - Namespace `k8s-auth` - ServiceAccount `mux-admin-tf` - Secret `mux-admin-tf-token` of type `kubernetes.io/service-account-token` (with `wait_for_service_account_token = true`) - ClusterRoleBinding binding `cluster-admin` to the service account - Outputs a **sensitive** kubeconfig (`cluster_admin_service_account_kubeconfig`) that authenticates using the token from the Secret. ## Validation - `terraform fmt` - `terraform init` - `terraform plan` - `terraform apply` - `kubectl --kubeconfig <generated> get nodes -o wide` ## Risks - This grants **cluster-admin** to a long-lived token; intended as a temporary bootstrap mechanism. --- _Generated with `mux` • Model: `openai:gpt-5.2` • Thinking: `xhigh` • Cost: `$0.92`_ <!-- mux-attribution: model=openai:gpt-5.2 thinking=xhigh costs=0.92 -->
1 parent 29ff90f commit fb21a66

5 files changed

Lines changed: 173 additions & 0 deletions

File tree

‎terraform/.terraform.lock.hcl‎

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
locals {
2+
eks_get_token_args = concat(
3+
[
4+
"eks",
5+
"get-token",
6+
"--region",
7+
var.aws_region,
8+
"--cluster-name",
9+
aws_eks_cluster.this.name,
10+
"--output",
11+
"json",
12+
],
13+
var.aws_profile == null ? [] : ["--profile", var.aws_profile],
14+
)
15+
}
16+
17+
provider "kubernetes" {
18+
host = aws_eks_cluster.this.endpoint
19+
cluster_ca_certificate = base64decode(aws_eks_cluster.this.certificate_authority[0].data)
20+
21+
exec {
22+
api_version = "client.authentication.k8s.io/v1beta1"
23+
command = "aws"
24+
args = local.eks_get_token_args
25+
}
26+
}
27+
28+
resource "kubernetes_namespace_v1" "cluster_admin" {
29+
metadata {
30+
name = var.cluster_admin_namespace
31+
}
32+
}
33+
34+
resource "kubernetes_service_account_v1" "cluster_admin" {
35+
metadata {
36+
name = var.cluster_admin_service_account_name
37+
namespace = kubernetes_namespace_v1.cluster_admin.metadata[0].name
38+
}
39+
}
40+
41+
resource "kubernetes_secret_v1" "cluster_admin_token" {
42+
metadata {
43+
name = "${var.cluster_admin_service_account_name}-token"
44+
namespace = kubernetes_namespace_v1.cluster_admin.metadata[0].name
45+
46+
annotations = {
47+
"kubernetes.io/service-account.name" = kubernetes_service_account_v1.cluster_admin.metadata[0].name
48+
}
49+
}
50+
51+
type = "kubernetes.io/service-account-token"
52+
wait_for_service_account_token = true
53+
}
54+
55+
resource "kubernetes_cluster_role_binding_v1" "cluster_admin" {
56+
metadata {
57+
name = "${var.cluster_admin_service_account_name}-cluster-admin"
58+
}
59+
60+
role_ref {
61+
api_group = "rbac.authorization.k8s.io"
62+
kind = "ClusterRole"
63+
name = "cluster-admin"
64+
}
65+
66+
subject {
67+
api_group = ""
68+
kind = "ServiceAccount"
69+
name = kubernetes_service_account_v1.cluster_admin.metadata[0].name
70+
namespace = kubernetes_service_account_v1.cluster_admin.metadata[0].namespace
71+
}
72+
}
73+
74+
locals {
75+
cluster_admin_context_name = "${aws_eks_cluster.this.name}-${var.cluster_admin_service_account_name}"
76+
77+
cluster_admin_kubeconfig = yamlencode({
78+
apiVersion = "v1"
79+
kind = "Config"
80+
81+
clusters = [
82+
{
83+
name = aws_eks_cluster.this.name
84+
cluster = {
85+
server = aws_eks_cluster.this.endpoint
86+
"certificate-authority-data" = aws_eks_cluster.this.certificate_authority[0].data
87+
}
88+
},
89+
]
90+
91+
users = [
92+
{
93+
name = var.cluster_admin_service_account_name
94+
user = {
95+
token = kubernetes_secret_v1.cluster_admin_token.data["token"]
96+
}
97+
},
98+
]
99+
100+
contexts = [
101+
{
102+
name = local.cluster_admin_context_name
103+
context = {
104+
cluster = aws_eks_cluster.this.name
105+
user = var.cluster_admin_service_account_name
106+
namespace = var.cluster_admin_namespace
107+
}
108+
},
109+
]
110+
111+
"current-context" = local.cluster_admin_context_name
112+
})
113+
}

‎terraform/outputs.tf‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,27 @@ output "kubeconfig_command" {
2929
value = "aws eks update-kubeconfig --region ${var.aws_region} --name ${aws_eks_cluster.this.name}"
3030
}
3131

32+
output "cluster_admin_service_account_namespace" {
33+
description = "Namespace for the long-lived cluster-admin service account."
34+
value = kubernetes_namespace_v1.cluster_admin.metadata[0].name
35+
}
36+
37+
output "cluster_admin_service_account_name" {
38+
description = "Name of the long-lived cluster-admin service account."
39+
value = kubernetes_service_account_v1.cluster_admin.metadata[0].name
40+
}
41+
42+
output "cluster_admin_service_account_token_secret_name" {
43+
description = "Kubernetes Secret name that holds the long-lived service account token."
44+
value = kubernetes_secret_v1.cluster_admin_token.metadata[0].name
45+
}
46+
47+
output "cluster_admin_service_account_kubeconfig" {
48+
description = "Kubeconfig that authenticates using the long-lived service account token (not a projected token)."
49+
value = local.cluster_admin_kubeconfig
50+
sensitive = true
51+
}
52+
3253
output "vpc_id" {
3354
description = "VPC ID used by the EKS cluster."
3455
value = aws_vpc.this.id

‎terraform/variables.tf‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,15 @@ variable "vpc_cidr" {
3535
}
3636
}
3737

38+
variable "cluster_admin_namespace" {
39+
description = "Namespace for the long-lived cluster-admin service account."
40+
type = string
41+
default = "k8s-auth"
42+
}
43+
44+
variable "cluster_admin_service_account_name" {
45+
description = "Service account name used for long-lived cluster-admin access (backed by a token Secret)."
46+
type = string
47+
default = "mux-admin-tf"
48+
}
49+

‎terraform/versions.tf‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ terraform {
1313
source = "hashicorp/aws"
1414
version = "~> 6.0"
1515
}
16+
17+
kubernetes = {
18+
source = "hashicorp/kubernetes"
19+
version = "~> 2.0"
20+
}
1621
}
1722
}
1823

0 commit comments

Comments
 (0)