{"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-analytics", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-auth", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-functions", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-imgproxy", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-kong", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-meta", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-minio", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-realtime", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-rest", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-storage", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-studio", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "ServiceAccount", "metadata": {"name": "supabase-vector", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-analytics", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"privateAccessToken": "eW91ci1zdXBlci1zZWNyZXQtYW5kLWxvbmctbG9nZmxhcmUta2V5LXByaXZhdGU=", "publicAccessToken": "eW91ci1zdXBlci1zZWNyZXQtYW5kLWxvbmctbG9nZmxhcmUta2V5LXB1YmxpYw=="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-dashboard", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"openAiApiKey": "a2V5X3N1cGVyX3NlY3JldA==", "password": "dGhpc19wYXNzd29yZF9pc19pbnNlY3VyZV9hbmRfc2hvdWxkX2JlX3VwZGF0ZWQ=", "username": "c3VwYWJhc2U="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-db", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"database": "cG9zdGdyZXM=", "password": "dnp4LndDNEFrZDR4LURqNldndWg=", "password_encoded": "dnp4LndDNEFrZDR4LURqNldndWg="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-jwt", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"anonKey": "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnliMnhsSWpvaVlXNXZiaUlzSW1semN5STZJbXR1YjJVdGMzVndZV0poYzJVaUxDSnBZWFFpT2pFM056WTRNamN3T0Rjc0ltVjRjQ0k2TWpBNU1qRTROekE0TjMwLkJFbHZWemJkZ05tbHRZV3VtcnhwaWg3RU9LeU5NeXdveWtPLVo2UUZUdHc=", "secret": "NGU1M2UxZWNiOThlYjMyZWU4M2I4OTBiZWE3OWU2NzhlOTUyYzZhZTIzN2VkZjNmNjVmMzdiZjZkZDIyNjJlYg==", "serviceKey": "ZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnliMnhsSWpvaWMyVnlkbWxqWlY5eWIyeGxJaXdpYVhOeklqb2lhMjV2WlMxemRYQmhZbUZ6WlNJc0ltbGhkQ0k2TVRjM05qZ3lOekE0Tnl3aVpYaHdJam95TURreU1UZzNNRGczZlEuakVzTUZQdDFnYjhxQWkzb1VPTnNoNVROY2dYeV8zZW8wMC1TVzVjU2dLWQ=="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-meta", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"cryptoKey": "eW91ci1lbmNyeXB0aW9uLWtleS0zMi1jaGFycy1taW4="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-minio", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"password": "c2VjcmV0MTIzNA==", "user": "c3VwYS1zdG9yYWdl"}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-realtime", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"secretKeyBase": "VXBOVm50bjNjRHhISnBxOTlZTWMxVDFBUWdRcGM4a2ZZVHVSZ0JpWWExNUJMcng4ZXRRb1h6M2dadjEvdTJvcQ=="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-s3", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"accessKey": "OWQzNmQ0MzRkMjZkZGRiOTcyZGNmZjJkOTI2NjYxMmI4ZTYxOGQ2YTYzYmIwOGM2ZTEyZTdlOTYzOGQ4MDQyMQ==", "keyId": "R0s5NmQ1ZmZlOGIxMWYzYTNkYzdhMDlhNzY="}} --- {"apiVersion": "v1", "kind": "Secret", "metadata": {"name": "supabase-smtp", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "type": "Opaque", "data": {"password": "ZmFrZV9tYWlsX3Bhc3N3b3Jk", "username": "ZmFrZV9tYWlsX3VzZXI="}} --- {"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "supabase-functions-main", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "data": {"index.ts": "import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts'\n\nconsole.log('main function started')\n\nconst JWT_SECRET = Deno.env.get('JWT_SECRET')\nconst VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true'\n\nfunction getAuthToken(req: Request) {\nconst authHeader = req.headers.get('authorization')\nif (!authHeader) {\n throw new Error('Missing authorization header')\n}\nconst [bearer, token] = authHeader.split(' ')\nif (bearer !== 'Bearer') {\n throw new Error(`Auth header is not 'Bearer {token}'`)\n}\nreturn token\n}\n\nasync function verifyJWT(jwt: string): Promise {\nconst encoder = new TextEncoder()\nconst secretKey = encoder.encode(JWT_SECRET)\ntry {\n await jose.jwtVerify(jwt, secretKey)\n} catch (err) {\n console.error(err)\n return false\n}\nreturn true\n}\n\nDeno.serve(async (req: Request) => {\nif (req.method !== 'OPTIONS' && VERIFY_JWT) {\n try {\n const token = getAuthToken(req)\n const isValidJWT = await verifyJWT(token)\n\n if (!isValidJWT) {\n return new Response(JSON.stringify({ msg: 'Invalid JWT' }), {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n } catch (e) {\n console.error(e)\n return new Response(JSON.stringify({ msg: e.toString() }), {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n })\n }\n}\n\nconst url = new URL(req.url)\nconst { pathname } = url\nconst path_parts = pathname.split('/')\nconst service_name = path_parts[1]\n\nif (!service_name || service_name === '') {\n const error = { msg: 'missing function name in request' }\n return new Response(JSON.stringify(error), {\n status: 400,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n\nconst servicePath = `/home/deno/functions/${service_name}`\nconsole.error(`serving the request with ${servicePath}`)\n\nconst memoryLimitMb = 150\nconst workerTimeoutMs = 1 * 60 * 1000\nconst noModuleCache = false\nconst importMapPath = null\nconst envVarsObj = Deno.env.toObject()\nconst envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]])\n\ntry {\n const worker = await EdgeRuntime.userWorkers.create({\n servicePath,\n memoryLimitMb,\n workerTimeoutMs,\n noModuleCache,\n importMapPath,\n envVars,\n })\n return await worker.fetch(req)\n} catch (e) {\n const error = { msg: e.toString() }\n return new Response(JSON.stringify(error), {\n status: 500,\n headers: { 'Content-Type': 'application/json' },\n })\n}\n})\n"}} --- {"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "supabase-kong", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "data": {"wrapper.sh": "#!/bin/bash\n\nset -euo pipefail\n\necho \"Replacing env placeholders of /usr/local/kong/kong.yml\"\n\nsed \\\n-e \"s|\\${SUPABASE_ANON_KEY}|${SUPABASE_ANON_KEY}|\" \\\n-e \"s|\\${SUPABASE_SERVICE_KEY}|${SUPABASE_SERVICE_KEY}|\" \\\n-e \"s|\\${DASHBOARD_USERNAME}|${DASHBOARD_USERNAME}|\" \\\n-e \"s|\\${DASHBOARD_PASSWORD}|${DASHBOARD_PASSWORD}|\" \\\n/usr/local/kong/template.yml \\\n> /usr/local/kong/kong.yml\n\nexec /docker-entrypoint.sh kong docker-start\n", "template.yml": "_format_version: '2.1'\n_transform: true\n\nconsumers:\n - username: DASHBOARD\n - username: anon\n keyauth_credentials:\n - key: ${SUPABASE_ANON_KEY}\n - username: service_role\n keyauth_credentials:\n - key: ${SUPABASE_SERVICE_KEY}\nacls:\n - consumer: anon\n group: anon\n - consumer: service_role\n group: admin\nbasicauth_credentials:\n - consumer: DASHBOARD\n username: ${DASHBOARD_USERNAME}\n password: ${DASHBOARD_PASSWORD}\nservices:\n # Dedicated health endpoint used by the GCE LB BackendConfig.\n # request-termination returns 200 synchronously without hitting any\n # upstream, so the probe passes as long as the Kong proxy itself is\n # accepting requests -- same liveness semantics as the TCP check we\n # originally wanted, but using the HTTP protocol that GCE's L7\n # BackendConfig CRD actually accepts (TCP is rejected with\n # `Protocol \"TCP\" is not valid, must be one of [HTTP,HTTPS,HTTP2]`).\n #\n # URL is a RFC-2606 reserved `.invalid` hostname that never resolves.\n # We originally tried `http://127.0.0.1:8000/` here, which is Kong's\n # own proxy port -- this crashlooped the pod on startup (rollout timed\n # out waiting for new pod to become Ready). Suspected cause: Kong's\n # declarative-config parser rejects the self-reference. Since the\n # request-termination plugin short-circuits before any DNS lookup or\n # upstream connection, using a non-resolvable placeholder URL is\n # equivalent in behavior but avoids the loop detection.\n - name: healthz\n url: http://knoe.healthz.invalid/\n routes:\n - name: healthz\n strip_path: true\n paths:\n - /healthz\n plugins:\n - name: request-termination\n config:\n status_code: 200\n message: ok\n - name: auth-v1-open\n url: http://supabase-auth:9999/verify\n routes:\n - name: auth-v1-open\n strip_path: true\n paths:\n - /auth/v1/verify\n plugins:\n - name: cors\n - name: auth-v1-open-callback\n url: http://supabase-auth:9999/callback\n routes:\n - name: auth-v1-open-callback\n strip_path: true\n paths:\n - /auth/v1/callback\n plugins:\n - name: cors\n - name: auth-v1-open-authorize\n url: http://supabase-auth:9999/authorize\n routes:\n - name: auth-v1-open-authorize\n strip_path: true\n paths:\n - /auth/v1/authorize\n plugins:\n - name: cors\n - name: auth-v1\n _comment: \"GoTrue: /auth/v1/* -> http://supabase-auth:9999/*\"\n url: http://supabase-auth:9999\n routes:\n - name: auth-v1-all\n strip_path: true\n paths:\n - /auth/v1/\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: acl\n config:\n hide_groups_header: true\n allow:\n - admin\n - anon\n - name: rest-v1\n _comment: \"PostgREST: /rest/v1/* -> http://supabase-rest:3000/*\"\n url: http://supabase-rest:3000/\n routes:\n - name: rest-v1-all\n strip_path: true\n paths:\n - /rest/v1/\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: true\n - name: acl\n config:\n hide_groups_header: true\n allow:\n - admin\n - anon\n - name: graphql-v1\n _comment: 'PostgREST: /graphql/v1/* -> http://supabase-rest:3000/rpc/graphql'\n url: http://supabase-rest:3000/rpc/graphql\n routes:\n - name: graphql-v1-all\n strip_path: true\n paths:\n - /graphql/v1\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: true\n - name: request-transformer\n config:\n add:\n headers:\n - Content-Profile:graphql_public\n - name: acl\n config:\n hide_groups_header: true\n allow:\n - admin\n - anon\n - name: realtime-v1-ws\n _comment: \"Realtime: /realtime/v1/* -> ws://supabase-realtime:4000/socket/*\"\n url: http://supabase-realtime:4000/socket\n protocol: ws\n routes:\n - name: realtime-v1-ws\n strip_path: true\n paths:\n - /realtime/v1/\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: acl\n config:\n hide_groups_header: true\n allow:\n - admin\n - anon\n - name: realtime-v1-rest\n _comment: 'Realtime: /realtime/v1/* -> http://supabase-realtime:4000/api/*'\n url: http://supabase-realtime:4000/api\n protocol: http\n routes:\n - name: realtime-v1-rest\n strip_path: true\n paths:\n - /realtime/v1/api\n plugins:\n - name: cors\n - name: key-auth\n config:\n hide_credentials: false\n - name: acl\n config:\n hide_groups_header: true\n allow:\n - admin\n - anon\n - name: storage-v1\n _comment: \"Storage: /storage/v1/* -> http://supabase-storage:5000/*\"\n url: http://supabase-storage:5000/\n routes:\n - name: storage-v1-all\n strip_path: true\n paths:\n - /storage/v1/\n plugins:\n - name: cors\n - name: functions-v1\n _comment: 'Edge Functions: /functions/v1/* -> http://supabase-functions:9000/*'\n url: http://supabase-functions:9000/\n routes:\n - name: functions-v1-all\n strip_path: true\n paths:\n - /functions/v1/\n plugins:\n - name: cors\n\n\n\n\n - name: meta\n _comment: \"pg-meta: /pg/* -> http://supabase-meta:8080/*\"\n url: http://supabase-meta:8080/\n routes:\n - name: meta-all\n strip_path: true\n paths:\n - /pg/\n plugins:\n - name: key-auth\n config:\n hide_credentials: false\n - name: acl\n config:\n hide_groups_header: true\n allow:\n - admin\n - name: dashboard\n _comment: 'Studio: /* -> http://supabase-studio:3000/*'\n url: http://supabase-studio:3000/\n routes:\n - name: dashboard-all\n strip_path: true\n paths:\n - /\n plugins:\n - name: cors\n - name: basic-auth\n config:\n hide_credentials: true\n"}} --- {"apiVersion": "v1", "kind": "ConfigMap", "metadata": {"name": "supabase-vector-config", "labels": {"helm.sh/chart": "knoe-supabase-0.5.0-knoe.1", "app.kubernetes.io/name": "supabase", "app.kubernetes.io/instance": "supabase", "app.kubernetes.io/managed-by": "Helm"}}, "data": {"vector.yml": "api:\n enabled: true\n address: 0.0.0.0:9001\n\nsources:\n kubernetes_host:\n type: kubernetes_logs\n extra_label_selector: app.kubernetes.io/instance=supabase,app.kubernetes.io/name!=knoe-supabase-vector\n\ntransforms:\n project_logs:\n type: remap\n inputs:\n - kubernetes_host\n source: |-\n .project = \"default\"\n .event_message = del(.message)\n .appname = del(.kubernetes.container_name)\n del(.file)\n del(.kubernetes)\n del(.source_type)\n del(.stream)\n router:\n type: route\n inputs:\n - project_logs\n route:\n kong: '.appname == \"knoe-supabase-kong\"'\n auth: '.appname == \"knoe-supabase-auth\"'\n rest: '.appname == \"knoe-supabase-rest\"'\n realtime: '.appname == \"knoe-supabase-realtime\"'\n storage: '.appname == \"knoe-supabase-storage\"'\n functions: '.appname == \"knoe-supabase-functions\"'\n db: '.appname == \"knoe-supabase-db\"'\n # Ignores non nginx errors since they are related with kong booting up\n kong_logs:\n type: remap\n inputs:\n - router.kong\n source: |-\n req, err = parse_nginx_log(.event_message, \"combined\")\n if err == null {\n .timestamp = req.timestamp\n .metadata.request.headers.referer = req.referer\n .metadata.request.headers.user_agent = req.agent\n .metadata.request.headers.cf_connecting_ip = req.client\n .metadata.response.status_code = req.status\n url, split_err = split(req.request, \" \")\n if split_err == null {\n .metadata.request.method = url[0]\n .metadata.request.path = url[1]\n .metadata.request.protocol = url[2]\n }\n }\n if err != null {\n abort\n }\n # Ignores non nginx errors since they are related with kong booting up\n kong_err:\n type: remap\n inputs:\n - router.kong\n source: |-\n .metadata.request.method = \"GET\"\n .metadata.response.status_code = 200\n parsed, err = parse_nginx_log(.event_message, \"error\")\n if err == null {\n .timestamp = parsed.timestamp\n .severity = parsed.severity\n .metadata.request.host = parsed.host\n .metadata.request.headers.cf_connecting_ip = parsed.client\n url, err = split(parsed.request, \" \")\n if err == null {\n .metadata.request.method = url[0]\n .metadata.request.path = url[1]\n .metadata.request.protocol = url[2]\n }\n }\n if err != null {\n abort\n }\n # Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency.\n auth_logs:\n type: remap\n inputs:\n - router.auth\n source: |-\n parsed, err = parse_json(.event_message)\n if err == null {\n .metadata.timestamp = parsed.time\n .metadata = merge!(.metadata, parsed)\n }\n # PostgREST logs are structured so we separate timestamp from message using regex\n rest_logs:\n type: remap\n inputs:\n - router.rest\n source: |-\n parsed, err = parse_regex(.event_message, r'^(?P