* 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.
35 lines
1.6 KiB
Caddyfile
35 lines
1.6 KiB
Caddyfile
{$DOMAIN:localhost} {
|
|
# Cert provisioning. Driven by env var CADDY_TLS:
|
|
# - unset (default) → cert-file mode for corporate PKI (rotated by
|
|
# scripts/grpn/agnes-tls-rotate.sh into /data/state/certs/).
|
|
# - "tls <email>" → Let's Encrypt auto-issue, e.g. "tls ops@example.com"
|
|
# (used by public-internet deployments like Keboola dev).
|
|
# - "tls internal" → Caddy-managed self-signed cert (lab/dev only,
|
|
# browser warning on every visit).
|
|
#
|
|
# The {$VAR:default} substitution lets one Caddyfile serve all three
|
|
# regimes without per-deployment forks. Caddyfile parses the substituted
|
|
# string as a directive, so the value MUST start with `tls `.
|
|
{$CADDY_TLS:tls /certs/fullchain.pem /certs/privkey.pem} {
|
|
# Modern TLS only. Caddy default already excludes 1.0/1.1 in
|
|
# most builds, but pin explicitly so a future Caddy default
|
|
# change can't silently weaken our posture.
|
|
protocols tls1.2 tls1.3
|
|
}
|
|
|
|
# HSTS: tell compliant browsers to refuse plain-HTTP for this host
|
|
# for a year. Skipping `preload` so we keep an escape hatch (preload
|
|
# submission is hard-bound and blocks rollback). Skipping
|
|
# `includeSubDomains` because we don't control subdomains.
|
|
header Strict-Transport-Security "max-age=31536000"
|
|
|
|
reverse_proxy app:8000 {
|
|
# App's uvicorn runs with --proxy-headers, so stamping these
|
|
# ourselves makes OAuth callback URLs and Set-Cookie Secure
|
|
# flags resolve to https consistently. X-Forwarded-Host is
|
|
# also Caddy's default, but pinning it explicitly insures
|
|
# against future default changes.
|
|
header_up X-Forwarded-Proto https
|
|
header_up X-Forwarded-Host {host}
|
|
}
|
|
}
|