postiz: add Temporal sidecar; lock both stacks behind Authentik

Postiz backend was crashlooping on connect ECONNREFUSED ::1:7233 —
Postiz needs Temporal for cron/scheduled posts and the Helm chart
doesn't bundle it. Added a single-replica temporalio/auto-setup:1.28.1
Deployment in the postiz namespace, backed by the bundled
postiz-postgresql (separate `temporal` + `temporal_visibility`
databases pre-created via init container), ENABLE_ES=false (Postiz
only uses the workflow engine, not visibility search). Skips
DYNAMIC_CONFIG_FILE_PATH because that file isn't bundled in
auto-setup.

Auth audit:
- postiz: ingress now `protected = true` (Authentik forward-auth).
  Postiz also has its own login on top, but registration is no
  longer exposed to the open internet.
- instagram-poster: split into two ingresses on the same host.
  `/image/*` stays public (Meta + Telegram fetch the 9:16
  derivatives). Everything else (/healthz, /queue, /scan,
  /enqueue, /reject, /post-next) sits behind Authentik. The
  protected ingress sets dns_type=none — the public one already
  created the CF DNS record.
This commit is contained in:
Viktor Barzin 2026-05-09 09:08:21 +00:00
parent 7f7698991e
commit 8c4a370a34
No known key found for this signature in database
GPG key ID: 4056458DBDBF8863
2 changed files with 176 additions and 7 deletions

View file

@ -268,17 +268,35 @@ resource "kubernetes_service" "instagram_poster" {
}
}
# Public ingress. No UI entire host is API-only and Meta needs to fetch
# /image/<asset_id> unauthenticated to render preview cards. We therefore
# leave `protected = false` so Authentik forward-auth doesn't run on any
# path. Inbound auth is the API's own concern (Postiz webhook signature
# / shared secret as configured by the parallel agent).
module "ingress" {
# Two ingresses on the same host Traefik picks the longest path prefix.
#
# `/image/*` must be reachable WITHOUT auth so Meta's content fetcher (and
# Telegram's photo preview) can render the 9:16 derivatives we produce.
# Everything else (/queue, /scan, /enqueue, /post-next, /reject, /healthz)
# sits behind Authentik forward-auth same defense as every other UI on
# the cluster, no random caller can pop items off the approval queue.
module "ingress_image_public" {
source = "../../../../modules/kubernetes/ingress_factory"
dns_type = "proxied"
namespace = kubernetes_namespace.instagram_poster.metadata[0].name
name = "instagram-poster"
name = "instagram-poster-image"
host = "instagram-poster"
tls_secret_name = var.tls_secret_name
protected = false
ingress_path = ["/image"]
port = 80
service_name = "instagram-poster"
}
module "ingress_protected" {
source = "../../../../modules/kubernetes/ingress_factory"
dns_type = "none" # DNS record already created by the public ingress above
namespace = kubernetes_namespace.instagram_poster.metadata[0].name
name = "instagram-poster"
host = "instagram-poster"
tls_secret_name = var.tls_secret_name
protected = true
ingress_path = ["/"]
port = 80
service_name = "instagram-poster"
}