2ce68cb098
- Move db/schema.sql to supabase/migrations/ as the first supabase CLI migration (manual `db push` only, no automated runner); re-add the gebos_ingest role + grants there since init.sql never re-runs - Add gebos-postgres-passwords oneshot on db-host: syncs role passwords from sops (LoadCredential, journal-safe), makes supabase_admin SUPERUSER and hands the auth schema to supabase_auth_admin to match the upstream supabase/postgres image; add pg_hba rule for 10.0.0.0/8 - Vendor the official docker-compose (studio/kong/auth/rest/meta only, external Postgres, loopback Studio with no Kong dashboard route) plus kong.yml (trimmed) and kong-entrypoint.sh (verbatim); tested: compose config, Kong config parse, migration applied on TimescaleDB pg17 - Document decisions as ADRs 0001-0004 (migrations, passwords, vendored stack, JWT API keys incl. verify/mint procedure) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
207 lines
5.4 KiB
YAML
207 lines
5.4 KiB
YAML
_format_version: '2.1'
|
|
_transform: true
|
|
|
|
# Vendored from the official bundle (docker/volumes/api/kong.yml), with the
|
|
# routes for services we don't run removed: realtime, storage, functions,
|
|
# analytics, pg-meta (/pg/), MCP, and — deliberately — the catch-all
|
|
# dashboard route + DASHBOARD basic-auth consumer. Studio is loopback-only
|
|
# behind an SSH tunnel and must never be reachable via api.gebos.online.
|
|
#
|
|
# $VARS are substituted by kong-entrypoint.sh at container start; empty
|
|
# credential lines (unconfigured opaque keys) are stripped there too.
|
|
|
|
###
|
|
### Consumers / Users
|
|
###
|
|
consumers:
|
|
- username: anon
|
|
keyauth_credentials:
|
|
- key: $SUPABASE_ANON_KEY
|
|
- key: $SUPABASE_PUBLISHABLE_KEY
|
|
- username: service_role
|
|
keyauth_credentials:
|
|
- key: $SUPABASE_SERVICE_KEY
|
|
- key: $SUPABASE_SECRET_KEY
|
|
|
|
###
|
|
### Access Control List
|
|
###
|
|
acls:
|
|
- consumer: anon
|
|
group: anon
|
|
- consumer: service_role
|
|
group: admin
|
|
|
|
###
|
|
### API Routes
|
|
###
|
|
services:
|
|
## Open Auth routes
|
|
- name: auth-v1-open
|
|
_comment: 'Auth: /auth/v1/verify* -> http://auth:9999/verify*'
|
|
url: http://auth:9999/verify
|
|
routes:
|
|
- name: auth-v1-open
|
|
strip_path: true
|
|
paths:
|
|
- /auth/v1/verify
|
|
plugins:
|
|
- name: cors
|
|
- name: auth-v1-open-callback
|
|
_comment: 'Auth: /auth/v1/callback* -> http://auth:9999/callback*'
|
|
url: http://auth:9999/callback
|
|
routes:
|
|
- name: auth-v1-open-callback
|
|
strip_path: true
|
|
paths:
|
|
- /auth/v1/callback
|
|
plugins:
|
|
- name: cors
|
|
- name: auth-v1-open-authorize
|
|
_comment: 'Auth: /auth/v1/authorize* -> http://auth:9999/authorize*'
|
|
url: http://auth:9999/authorize
|
|
routes:
|
|
- name: auth-v1-open-authorize
|
|
strip_path: true
|
|
paths:
|
|
- /auth/v1/authorize
|
|
plugins:
|
|
- name: cors
|
|
- name: auth-v1-open-jwks
|
|
_comment: 'Auth: /auth/v1/.well-known/jwks.json -> http://auth:9999/.well-known/jwks.json'
|
|
url: http://auth:9999/.well-known/jwks.json
|
|
routes:
|
|
- name: auth-v1-open-jwks
|
|
strip_path: true
|
|
paths:
|
|
- /auth/v1/.well-known/jwks.json
|
|
plugins:
|
|
- name: cors
|
|
|
|
## Secure Auth routes
|
|
- name: auth-v1
|
|
_comment: 'Auth: /auth/v1/* -> http://auth:9999/*'
|
|
url: http://auth:9999/
|
|
routes:
|
|
- name: auth-v1-all
|
|
strip_path: true
|
|
paths:
|
|
- /auth/v1/
|
|
plugins:
|
|
- name: cors
|
|
- name: key-auth
|
|
config:
|
|
hide_credentials: false
|
|
- name: request-transformer
|
|
config:
|
|
add:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
replace:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
- name: acl
|
|
config:
|
|
hide_groups_header: true
|
|
allow:
|
|
- admin
|
|
- anon
|
|
|
|
## OpenAPI root - admin only
|
|
- name: rest-v1-openapi
|
|
_comment: 'PostgREST OpenAPI root: /rest/v1/ -> <http://rest:3000/> (admin only). See <https://github.com/orgs/supabase/discussions/42949>'
|
|
url: http://rest:3000/
|
|
routes:
|
|
- name: rest-v1-openapi-root
|
|
strip_path: true
|
|
expression: 'http.path == "/rest/v1/"'
|
|
plugins:
|
|
- name: cors
|
|
- name: key-auth
|
|
config:
|
|
hide_credentials: false
|
|
- name: request-transformer
|
|
config:
|
|
add:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
replace:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
- name: acl
|
|
config:
|
|
hide_groups_header: true
|
|
allow:
|
|
- admin
|
|
|
|
## Secure PostgREST routes
|
|
- name: rest-v1
|
|
_comment: 'PostgREST: /rest/v1/* -> http://rest:3000/*'
|
|
url: http://rest:3000/
|
|
routes:
|
|
- name: rest-v1-all
|
|
strip_path: true
|
|
paths:
|
|
- /rest/v1/
|
|
plugins:
|
|
- name: cors
|
|
- name: key-auth
|
|
config:
|
|
hide_credentials: false
|
|
- name: request-transformer
|
|
config:
|
|
add:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
replace:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
- name: acl
|
|
config:
|
|
hide_groups_header: true
|
|
allow:
|
|
- admin
|
|
- anon
|
|
|
|
## Secure GraphQL routes
|
|
- name: graphql-v1
|
|
_comment: 'PostgREST: /graphql/v1/* -> http://rest:3000/rpc/graphql'
|
|
url: http://rest:3000/rpc/graphql
|
|
routes:
|
|
- name: graphql-v1-all
|
|
strip_path: true
|
|
paths:
|
|
- /graphql/v1
|
|
plugins:
|
|
- name: cors
|
|
- name: key-auth
|
|
config:
|
|
hide_credentials: false
|
|
- name: request-transformer
|
|
config:
|
|
add:
|
|
headers:
|
|
- "Content-Profile: graphql_public"
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
replace:
|
|
headers:
|
|
- "Authorization: $LUA_AUTH_EXPR"
|
|
- name: acl
|
|
config:
|
|
hide_groups_header: true
|
|
allow:
|
|
- admin
|
|
- anon
|
|
|
|
## OAuth 2.0 Authorization Server Metadata (RFC 8414)
|
|
- name: well-known-oauth
|
|
_comment: 'Auth: /.well-known/oauth-authorization-server -> http://auth:9999/.well-known/oauth-authorization-server'
|
|
url: http://auth:9999/.well-known/oauth-authorization-server
|
|
routes:
|
|
- name: well-known-oauth
|
|
strip_path: true
|
|
paths:
|
|
- /.well-known/oauth-authorization-server
|
|
plugins:
|
|
- name: cors
|