* feat(deploy): keboola-deploy tag-triggered workflow + Caddyfile LE/internal modes + dev_instances TLS support
Three coordinated changes that together unblock Keboola's internal Agnes
deployment from the foot-gun where the dev VM tracks `:dev` (= last push
from anyone in the upstream repo).
1. .github/workflows/keboola-deploy.yml — new workflow
Triggered ONLY on `keboola-deploy-*` git tag pushes (not on every branch
push like release.yml). Builds an image and publishes two GHCR tags:
ghcr.io/keboola/agnes-the-ai-analyst:keboola-deploy-<git-tag-suffix>
ghcr.io/keboola/agnes-the-ai-analyst:keboola-deploy-latest
The Keboola dev VM pins to `keboola-deploy-latest`; an operator deploys
by `git tag keboola-deploy-foo && git push origin keboola-deploy-foo`.
Audit trail lives in git tags (immutable, who-tagged-what-when), no
PR-cycle needed for each deploy.
Doesn't touch Vojta/Minas/David workflow — release.yml still builds
`:dev-<slug>` for every branch push as before.
2. Caddyfile — parametrize TLS directive via $CADDY_TLS env var
PR #51 hardcoded cert-file mode (`tls /certs/fullchain.pem ...`) for
Groupon's corporate CA flow. That broke the Let's Encrypt path the
module previously supported. Now:
CADDY_TLS unset (default) → cert-file mode (Groupon corp PKI)
CADDY_TLS="tls user@x.com" → Let's Encrypt auto-issue
CADDY_TLS="tls internal" → Caddy-managed self-signed (lab/dev)
Single Caddyfile, three regimes, no per-deployment fork. Validated with
`caddy validate` in all three modes.
3. customer-instance module — dev_instances TLS + auto-set CADDY_TLS
- variables.tf: dev_instances object schema gains optional tls_mode +
domain (mirroring prod_instance). Defaults to "none" + "" so existing
callers without those fields keep current behavior.
- startup-script.sh.tpl: when tls_mode="caddy" and DOMAIN is set, write
CADDY_TLS=tls <ACME_EMAIL> (or "tls internal" when ACME_EMAIL empty)
into /opt/agnes/.env. Caddy then picks it up and the Caddyfile
substitution flips the cert source.
For an LE deploy: set tls_mode="caddy", domain="agnes-dev.example.com",
ensure DNS A-record points at the VM, and acme_email is set on the
module (or seed_admin_email is, since acme_email defaults to it).
After this lands, tag as infra-v1.6.0 so downstream infra repos can bump
their module ref without needing the upstream change tracking.
* feat(deploy): fetch optional Google OAuth credentials from Secret Manager
Mirrors the existing keboola-storage-token / agnes-<customer>-jwt-secret
pattern: VM SA reads google-oauth-client-{id,secret} secrets at boot
(if they exist + IAM is wired by caller via runtime_secrets) and writes
them into /opt/agnes/.env. Empty / missing / 403 → silent fallback
to "" so password and email auth keep working untouched.
Pairs with downstream change in agnes-infra-keboola which adds the two
secret names to runtime_secrets, granting the Keboola VM SA secretAccessor
on them. Operator pre-creates the SM containers via gcloud secrets create
google-oauth-client-{id,secret} (one-time, out of band) — values stay
in SM forever; rotation = `gcloud secrets versions add`.
This unblocks the Keboola agnes-dev deploy from PR #3 (infra) — without
GOOGLE_CLIENT_{ID,SECRET} in .env, app/auth/providers/google.is_available()
returns False and the Google sign-in button never even appears.
129 lines
4.1 KiB
HCL
129 lines
4.1 KiB
HCL
variable "gcp_project_id" {
|
|
description = "GCP project ID kde bude instance nasazená"
|
|
type = string
|
|
}
|
|
|
|
variable "region" {
|
|
description = "GCP region"
|
|
type = string
|
|
default = "europe-west1"
|
|
}
|
|
|
|
variable "zone" {
|
|
description = "GCP zone"
|
|
type = string
|
|
default = "europe-west1-b"
|
|
}
|
|
|
|
variable "customer_name" {
|
|
description = "Krátký identifikátor zákazníka (např. keboola, grpn). Použije se v prefixu resourců."
|
|
type = string
|
|
validation {
|
|
condition = can(regex("^[a-z][a-z0-9-]{1,20}$", var.customer_name))
|
|
error_message = "customer_name musí být lowercase, začínat písmenem, 2-21 znaků."
|
|
}
|
|
}
|
|
|
|
variable "prod_instance" {
|
|
description = "Prod VM konfigurace"
|
|
type = object({
|
|
name = string
|
|
machine_type = optional(string, "e2-small")
|
|
disk_size_gb = optional(number, 30)
|
|
data_disk_gb = optional(number, 50)
|
|
image_tag = optional(string, "stable")
|
|
upgrade_mode = optional(string, "auto")
|
|
tls_mode = optional(string, "caddy")
|
|
domain = optional(string, "")
|
|
})
|
|
}
|
|
|
|
variable "dev_instances" {
|
|
description = <<-EOT
|
|
Seznam dev VMs. Prázdné pole = žádné dev VMs.
|
|
|
|
tls_mode + domain are optional and default to plain HTTP on :8000. Set
|
|
tls_mode = "caddy" + domain to enable Caddy + Let's Encrypt (or whatever
|
|
CADDY_TLS env var is configured to in the Caddyfile — see Caddyfile docs).
|
|
EOT
|
|
type = list(object({
|
|
name = string
|
|
machine_type = optional(string, "e2-small")
|
|
image_tag = optional(string, "dev")
|
|
tls_mode = optional(string, "none")
|
|
domain = optional(string, "")
|
|
}))
|
|
default = []
|
|
}
|
|
|
|
variable "seed_admin_email" {
|
|
description = "Email prvního admin usera"
|
|
type = string
|
|
}
|
|
|
|
variable "enable_seed_password" {
|
|
description = "Pokud true, seed admin user dostane hned password_hash ze seed_admin_password (dev helper). Ponech false v prod — admin si heslo nastaví přes /auth/bootstrap nebo Google OAuth."
|
|
type = bool
|
|
default = false
|
|
}
|
|
|
|
variable "seed_admin_password" {
|
|
description = "Plain-text heslo pro seed admina. Použije se jen když enable_seed_password=true. POZOR: ukládá se do Terraform state."
|
|
type = string
|
|
default = ""
|
|
sensitive = true
|
|
}
|
|
|
|
variable "data_source" {
|
|
description = "Typ data source — keboola | bigquery | csv"
|
|
type = string
|
|
default = "keboola"
|
|
}
|
|
|
|
variable "keboola_stack_url" {
|
|
description = "Keboola Stack URL (pokud data_source = keboola)"
|
|
type = string
|
|
default = ""
|
|
}
|
|
|
|
variable "image_repo" {
|
|
description = "Docker image repo"
|
|
type = string
|
|
default = "ghcr.io/keboola/agnes-the-ai-analyst"
|
|
}
|
|
|
|
variable "compose_ref" {
|
|
description = "Git ref to fetch docker-compose.yml and overlays from (in keboola/agnes-the-ai-analyst). Use `main` for latest, or a tag like `stable-2026.04.47` for reproducibility."
|
|
type = string
|
|
default = "main"
|
|
}
|
|
|
|
variable "enable_monitoring" {
|
|
description = "Create uptime checks + alert policies for each VM. Requires notification_channel_ids to be useful."
|
|
type = bool
|
|
default = true
|
|
}
|
|
|
|
variable "notification_channel_ids" {
|
|
description = "Full resource IDs of GCP Monitoring notification channels (create in customer project via gcloud alpha monitoring channels create). Empty list = alerts fire but nothing is notified."
|
|
type = list(string)
|
|
default = []
|
|
}
|
|
|
|
variable "runtime_secrets" {
|
|
description = "Names of existing Secret Manager secrets the VM needs to read at runtime (e.g. Keboola Storage token). VM SA gets scoped secretAccessor on each."
|
|
type = list(string)
|
|
default = ["keboola-storage-token"]
|
|
}
|
|
|
|
variable "firewall_ssh_source_ranges" {
|
|
description = "CIDR ranges allowed to reach SSH (port 22). Default is IAP tunnel range only (use `gcloud compute ssh --tunnel-through-iap`). Override to `[\"0.0.0.0/0\"]` for unrestricted (not recommended)."
|
|
type = list(string)
|
|
default = ["35.235.240.0/20"]
|
|
}
|
|
|
|
variable "acme_email" {
|
|
description = "Email for Let's Encrypt account (used when tls_mode=caddy). Defaults to seed_admin_email if empty."
|
|
type = string
|
|
default = ""
|
|
}
|