Files
Claude a5e276534c Arbetslasten kopplad till AWS — kedjan är helt egen
Andra lagret läser nu basens utdata i stället för att upprepa någonting.
05-aws.tf hämtar klustret, domänen, certifikatet, registret, rollerna,
hinken och hemligheternas namn — ändras något i basen slår det igenom
här utan att en rad ändras. Autentiseringen mot klustret sker med en
färsk EKS-token i stället för en kubeconfig på disk: inget att
distribuera, inget som går ut.

Hemligheterna bor i Secrets Manager och speglas in av External Secrets
var timme. Terraform ser aldrig värdena, och det är själva poängen — en
hemlighet som passerar Terraform hamnar i tillståndsfilen. Roteras en
hemlighet följer klustret efter av sig självt.

Plattformstjänsten kör som ett tjänstekonto med IRSA. Rollen är bunden
till exakt det kontot i den namnrymden, så grannpodden på samma nod får
ingenting på köpet. Bilagorna signeras mot S3 med samma roll — inga
nycklar existerar att läcka.

Postgres-podden är borta. Händelseloggen ligger i Aurora utanför
klustret, i ett subnätlager utan routing ut, med automatisk
säkerhetskopiering och PITR. Ingressen är en ALB med ACM-certifikat i
stället för nginx, och alla tre tjänsterna delar den genom samma
gruppnamn.

Gitea med egna Actions-runners kör i samma kluster. Därmed finns inget
externt beroende kvar: källkod, bygge, register och driftsättning ligger
allt i vår AWS-miljö. Runnern och driftsättningen har varsitt
tjänstekonto med skilda roller — bygget får publicera till ECR men inte
röra klustret, driften tvärtom. Ett komprometterat bygge kan inte
driftsätta.

Gitea kör SQLite på en EBS-volym i stället för en egen Aurora-databas.
En verkstadsinstallation har en handfull utvecklare, och ytterligare en
databas att säkerhetskopiera och övervaka är kostnad utan motsvarande
nytta.

Verifierat: 96 vitest-tester, rotens lint och format:check, terraform fmt
på båda lagren och statisk referenskontroll av vardera (88 respektive 35
resurser, inga dinglande referenser, alla count-resurser indexerade).
terraform validate kunde inte köras här — registry.terraform.io är
blockerad av sessionens egress-policy — så CI-jobbet kör den.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EQg3rJsrQ1ZNTvkzmQAtt
2026-08-04 12:53:08 +00:00

99 lines
2.8 KiB
Terraform

# Trafiken utifrån och in.
#
# En ALB, skapad av lastbalanserar-kontrollern ur det här objektet.
# Certifikatet kommer från ACM och terminerar på lastbalanseraren; all
# trafik mot :80 skickas vidare till :443.
#
# Kroppsgränsen är inte kosmetisk: teknikern dokumenterar med foto och
# video. En för snäv gräns avvisar dokumentationen redan vid dörren.
resource "kubernetes_ingress_v1" "denna" {
metadata {
name = local.namn
namespace = kubernetes_namespace_v1.denna.metadata[0].name
labels = local.etiketter
annotations = {
"alb.ingress.kubernetes.io/scheme" = "internet-facing"
"alb.ingress.kubernetes.io/target-type" = "ip"
"alb.ingress.kubernetes.io/certificate-arn" = local.aws.certifikat_arn
"alb.ingress.kubernetes.io/listen-ports" = jsonencode([{ HTTP = 80 }, { HTTPS = 443 }])
"alb.ingress.kubernetes.io/ssl-redirect" = "443"
"alb.ingress.kubernetes.io/ssl-policy" = "ELBSecurityPolicy-TLS13-1-2-2021-06"
# Hälsokontrollen går mot plattformen — den vet om databasen svarar.
"alb.ingress.kubernetes.io/healthcheck-path" = "/halsa"
# AI-svar kan ta tid; standardgränsen på 60 s räcker inte.
"alb.ingress.kubernetes.io/load-balancer-attributes" = join(",", [
"idle_timeout.timeout_seconds=180",
"routing.http.drop_invalid_header_fields.enabled=true",
"access_logs.s3.enabled=false",
])
# Alla tre tjänsterna delar en lastbalanserare.
"alb.ingress.kubernetes.io/group.name" = local.namn
}
}
spec {
ingress_class_name = "alb"
rule {
host = local.aws.doman
http {
dynamic "path" {
for_each = local.routing
content {
path = path.value.prefix
path_type = "Prefix"
backend {
service {
name = path.value.till
port {
number = local.port_tjanst
}
}
}
}
}
}
}
}
depends_on = [
helm_release.lastbalanserare,
kubernetes_service_v1.web,
kubernetes_service_v1.plattform,
kubernetes_service_v1.orkester,
]
}
# DNS pekar på lastbalanseraren. Alias i stället för CNAME så att
# domänens rot kan användas om ni vill det senare.
resource "aws_route53_record" "denna" {
zone_id = local.aws.zon_id
name = local.aws.doman
type = "A"
alias {
name = kubernetes_ingress_v1.denna.status[0].load_balancer[0].ingress[0].hostname
zone_id = data.aws_lb.denna.zone_id
evaluate_target_health = true
}
}
data "aws_lb" "denna" {
tags = {
"elbv2.k8s.aws/cluster" = local.aws.kluster
"ingress.k8s.aws/stack" = local.namn
"ingress.k8s.aws/resource" = "LoadBalancer"
}
depends_on = [kubernetes_ingress_v1.denna]
}