a5e276534c
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
202 lines
4.8 KiB
Terraform
202 lines
4.8 KiB
Terraform
# Plattformstjänsten — systemets mitt.
|
|
#
|
|
# Äger: inloggning (bcrypt via pgcrypto, HS256-JWT med roll + organisation
|
|
# i anspråken), append-only händelse-API, Live Share med serverstyrd
|
|
# filtrering, organisationsinställningar, ECM-regelpaketet och de
|
|
# märkesspecifika kopplingarna.
|
|
#
|
|
# Ser tre hemligheter och inga fler: JWT-hemligheten (delas med
|
|
# orkestern), databaslösenordet och krypteringsnyckeln för kundernas
|
|
# leverantörsuppgifter.
|
|
|
|
resource "kubernetes_deployment_v1" "plattform" {
|
|
metadata {
|
|
name = "plattform"
|
|
namespace = kubernetes_namespace_v1.denna.metadata[0].name
|
|
labels = merge(local.etiketter, { app = "plattform" })
|
|
}
|
|
|
|
spec {
|
|
replicas = var.repliker.plattform
|
|
|
|
selector {
|
|
match_labels = { app = "plattform" }
|
|
}
|
|
|
|
template {
|
|
metadata {
|
|
labels = merge(local.etiketter, { app = "plattform" })
|
|
}
|
|
|
|
spec {
|
|
# Behöver token: IRSA hämtar AWS-uppgifter genom det.
|
|
service_account_name = kubernetes_service_account_v1.plattform.metadata[0].name
|
|
|
|
security_context {
|
|
run_as_non_root = true
|
|
|
|
seccomp_profile {
|
|
type = "RuntimeDefault"
|
|
}
|
|
}
|
|
|
|
container {
|
|
name = "plattform"
|
|
image = local.tjanster.plattform.bild
|
|
|
|
port {
|
|
container_port = local.port_container
|
|
}
|
|
|
|
# Alla hemligheter kommer ur den spegling External Secrets
|
|
# gör från Secrets Manager. Ingen av dem finns i Terraforms
|
|
# tillstånd eller i något manifest.
|
|
env_from {
|
|
secret_ref {
|
|
name = "felsokning-hemligheter"
|
|
}
|
|
}
|
|
|
|
# Klienten serveras från samma domän som API:t, så CORS behöver
|
|
# inte vara öppet.
|
|
env {
|
|
name = "TILLATNA_URSPRUNG"
|
|
value = "https://${local.aws.doman}"
|
|
}
|
|
|
|
env {
|
|
name = "REGISTRERING_OPPEN"
|
|
value = var.registrering_oppen ? "true" : "false"
|
|
}
|
|
|
|
env {
|
|
name = "TILLAT_INTERNA_UPPSLAG"
|
|
value = var.tillat_interna_uppslag ? "true" : "false"
|
|
}
|
|
|
|
# Bilagorna ligger i S3. Inga nycklar behövs — tjänsten
|
|
# signerar med tjänstekontots roll via IRSA.
|
|
env {
|
|
name = "BILAGE_LAGE"
|
|
value = "s3"
|
|
}
|
|
|
|
env {
|
|
name = "S3_HINK"
|
|
value = local.aws.bilage_hink
|
|
}
|
|
|
|
env {
|
|
name = "S3_REGION"
|
|
value = local.aws.region
|
|
}
|
|
|
|
env {
|
|
name = "S3_ENDPOINT"
|
|
value = "https://s3.${local.aws.region}.amazonaws.com"
|
|
}
|
|
|
|
|
|
resources {
|
|
requests = { cpu = "100m", memory = "128Mi" }
|
|
limits = { cpu = "1", memory = "512Mi" }
|
|
}
|
|
|
|
readiness_probe {
|
|
http_get {
|
|
path = "/halsa"
|
|
port = local.port_container
|
|
}
|
|
|
|
initial_delay_seconds = 3
|
|
period_seconds = 10
|
|
}
|
|
|
|
liveness_probe {
|
|
http_get {
|
|
path = "/halsa"
|
|
port = local.port_container
|
|
}
|
|
|
|
period_seconds = 15
|
|
}
|
|
|
|
security_context {
|
|
allow_privilege_escalation = false
|
|
read_only_root_filesystem = true
|
|
|
|
capabilities {
|
|
drop = ["ALL"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_service_v1" "plattform" {
|
|
metadata {
|
|
name = "plattform"
|
|
namespace = kubernetes_namespace_v1.denna.metadata[0].name
|
|
labels = merge(local.etiketter, { app = "plattform" })
|
|
}
|
|
|
|
spec {
|
|
selector = { app = "plattform" }
|
|
|
|
port {
|
|
port = local.port_tjanst
|
|
target_port = local.port_container
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_horizontal_pod_autoscaler_v2" "plattform" {
|
|
metadata {
|
|
name = "plattform"
|
|
namespace = kubernetes_namespace_v1.denna.metadata[0].name
|
|
labels = local.etiketter
|
|
}
|
|
|
|
spec {
|
|
min_replicas = var.repliker.plattform
|
|
max_replicas = var.max_repliker.plattform
|
|
|
|
scale_target_ref {
|
|
api_version = "apps/v1"
|
|
kind = "Deployment"
|
|
name = kubernetes_deployment_v1.plattform.metadata[0].name
|
|
}
|
|
|
|
metric {
|
|
type = "Resource"
|
|
|
|
resource {
|
|
name = "cpu"
|
|
|
|
target {
|
|
type = "Utilization"
|
|
average_utilization = 70
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
resource "kubernetes_pod_disruption_budget_v1" "plattform" {
|
|
metadata {
|
|
name = "plattform"
|
|
namespace = kubernetes_namespace_v1.denna.metadata[0].name
|
|
labels = local.etiketter
|
|
}
|
|
|
|
spec {
|
|
min_available = 1
|
|
|
|
selector {
|
|
match_labels = { app = "plattform" }
|
|
}
|
|
}
|
|
}
|