-
[Supabase][보안] Schedule Functions와 pg_net·Database Webhooks caller를 같이 정리할 때 Vault secret 이름과 publishable·secret key를 어떤 순서로 inventory 하나기타개발지식/풀스택개발 2026. 8. 4. 09:16
IT 리서치 노트
[Supabase][보안] Schedule Functions와 pg_net·Database Webhooks caller를 같이 정리할 때 Vault secret 이름과 publishable·secret key를 어떤 순서로 inventory 하나
Supabase에서 Schedule Functions, pg_net, Database Webhooks가 함께 붙기 시작하면 호출 경계보다 더 빨리 모호해지는 것이 caller inventory와 secret 이름이다. 2026년 8월 3일 기준 Supabase 공식 문서를 다시 보면, schedule 호출 토큰은 Vault에 두는 편을 권장하고, 새 API key는 클라이언트와 서버를 publishable key와 secret key로 나누라고 설명한다. 이 글은 Schedule Functions와 pg_net·Database Webhooks caller를 같이 정리할 때 Vault secret 이름과 publishable·secret key를 어떤 순서로 inventory 하는 편이 덜 꼬이는지 정리한 것이다.
1. 개요
결론부터 말하면 header 이름부터 통일하는 것보다 caller inventory와 secret source를 먼저 분리하는 편이 빠르다. schedule 호출, pg_net SQL 호출, Database Webhooks는 모두 backend caller 집합으로 묶고, browser client와는 publishable/secret key 수준에서 명시적으로 갈라야 한다. 그다음에 Vault secret 이름과 apikey 또는 Authorization 사용 방식을 붙이는 편이 안전하다.
즉 이 문제는 단순한 key migration이 아니라 caller inventory 문제다. 직전 Schedule Functions 분기 글이 호출 경계와 Vault 사용을 다뤘다면, 이번 글은 각 caller를 어떤 이름과 key class로 문서화해야 cutover가 덜 꼬이는지에 집중한다.
2. 어디서 실제로 막히는가
현장에서 자주 막히는 지점은 세 가지다. 첫째, schedule Functions 예제를 그대로 복사해 놓고 어떤 caller가 publishable key를 쓰는지, 어떤 caller가 secret key를 쓰는지를 문서에 남기지 않는다. 둘째, pg_net SQL 호출과 Database Webhooks를 다른 문제로 분리해서 같은 migration을 두 번 반복한다. 셋째, Edge Function 내부 admin caller와 browser client를 같은 naming 규칙 없이 운영해 Vault 이름만 늘고 실제 ownership 구분이 더 모호해진다.
Schedule Functions 문서는 secure auth token을 Vault에 두라고 권장하고, 예제에서도
project_url과publishable_key를 Vault에 저장한 뒤net.http_post에서 가져온다. API key migration 문서는 client-side는 publishable key, server-side는 secret key로 갈아타라고 적는다. pg_net 문서는 Postgres가 HTTP를 호출하는 backend caller라는 점을 분명히 한다. 이 셋을 합치면 schedule, pg_net, webhook은 같은 backend caller inventory 표에 있어야 한다는 결론이 나온다.문제는 이 inventory가 없으면 로그와 코드와 Vault 이름이 서로 연결되지 않는다는 점이다. 예를 들어 어떤 webhook route가 still legacy key를 쓰는지, 어떤 schedule job이 publishable key를 계속 쓰는지, 어떤 Edge Function admin client가 secret key를 직접 참조하는지 확인하려면 caller 이름과 secret source가 한 줄에 있어야 한다. 그렇지 않으면 key 회전이 끝났는지 끝나지 않았는지조차 판단이 늦어진다.
- 증상: 어떤 caller는 새 키로 바뀌었는데 어떤 caller는 아직 legacy 키를 쓴다.
- 실패: Vault secret 값만 저장하고 secret 이름 체계를 만들지 않는다.
- 막힘: pg_net와 webhook caller를 따로 migration으로 분리한다.
- 누락: browser client와 backend caller를 같은 key inventory에 섞어 적는다.
질문 먼저 볼 곳 실무 판단 누가 backend caller인가 schedule, pg_net, webhook 목록 같은 inventory 집합으로 묶는다 어느 키를 써야 하나 publishable vs secret key class browser와 backend를 먼저 분리한다 secret 이름은 어떻게 붙일까 Vault naming 규칙 caller별 ownership이 보이게 정한다 3. 실무에서 적용하는 순서
정리 순서는 다섯 단계가 가장 짧다. 먼저 schedule Functions, pg_net SQL, Database Webhooks, Edge admin caller, browser client를 모두 적는다. 다음으로 각 caller에 key class를 붙여 publishable과 secret을 분리한다. 세 번째로 secret source를 Vault, runtime env, public env로 나눈다. 네 번째로 Vault secret 이름을 caller 기준으로 정한다. 마지막으로 각 caller가 어떤 header 이름과 route를 쓰는지 로그와 같이 저장하고, route 필드와 API Keys 탭 값과 Vault 이름이 같은지 확인한다.
- caller 목록을 먼저 만든다.
- 각 caller에 publishable 또는 secret key class를 붙인다.
- secret source를 Vault, runtime env, public env로 나눈다.
- Vault secret 이름을 caller ownership 기준으로 짓는다.
- header 이름과 route를 같은 문서에 저장한다.
실제 운영에서는 SQL editor 쿼리, cron.schedule 이름, webhook route, Edge Function admin client 초기화 코드, Dashboard API Keys 탭을 같은 메모에 두는 편이 좋다. browser client는 publishable key만, backend caller는 secret key 또는 Vault ref만 갖게 두고, schedule과 webhook이 같은 default key를 공유한다면 그 ownership까지 적어 둬야 회전이 가능하다. 쿼리를 실행하고, route 필드를 확인하고, 로그 결과를 조회하고, Vault 이름을 복사해 대조하고, API Keys 탭 값을 저장해 두면 다음 교체가 훨씬 빨라진다. key 교체는 값 교체보다 inventory 정리가 먼저여야 한다.
caller_inventory: - name: schedule_pg_net key_class: publishable secret_source: vault:publishable_key_default header_name: apikey - name: db_webhook key_class: secret secret_source: vault:secret_key_webhook header_name: apikey - name: edge_admin key_class: secret secret_source: env:SB_SECRET_KEY header_name: Authorization이 메모가 있으면 migration 뒤에도 어떤 caller가 아직 legacy 경로인지 빠르게 찾을 수 있다. 반대로 key 이름만 남겨 두고 caller ownership을 안 적으면 회전과 회고가 항상 따로 논다.
4. 공식 문서와 예시 화면으로 확인하기
첫 자료는 Supabase Schedule Functions 문서의 핵심 권고다. scheduled Edge Function 호출 토큰은 Vault에 두는 편을 권장한다고 직접 적고 있다.
이 문장을 먼저 고정하면 schedule caller는 최소한 Vault 기준으로 inventory를 시작해야 한다는 출발점이 생긴다. 이미 Schedule Functions와 pg_net 분기 글이 호출 경계를 다뤘다면, 이번 글은 caller inventory와 key naming 순서 쪽으로 더 좁혀진 가지다.
두 번째 자료는 같은 문서의 예제 구간이다. Supabase는 project_url과 publishable_key를 Vault에 저장한 뒤 pg_net 호출에서 꺼내 쓰는 패턴을 보여 준다.
즉 secret 값만이 아니라 secret 이름 자체를 caller inventory와 같이 설계해야 한다. key migration을 진행할 때 이름 규칙이 없으면 어떤 caller가 어느 키를 쓰는지 비교가 느려진다.
세 번째 자료는 새 API key migration 문서다. Supabase는 클라이언트와 서버를 publishable key와 secret key로 분리해서 쓰라고 설명한다.
따라서 schedule caller, pg_net caller, webhook caller를 모두 같은 backend 집합으로 적되, browser client와는 명시적으로 분리해야 한다. 이 구분이 없으면 legacy service_role cutover가 언제 끝났는지 판단하기 어렵다.
네 번째 자료는 pg_net 문서의 정의다. pg_net은 결국 Postgres 안에서 비동기 HTTP 요청을 보내는 caller다. 즉 서버 측 inventory에 들어가야 한다.
Database Webhooks도 결국 이 caller 계열을 감싼 형태로 이해하면 route 분리가 쉬워진다. 같은 auth-security cluster의 old Authorization cutover 글과 이어서 보면 caller별 secret source 정리가 더 선명해진다.
caller inventory는 path, secret source, key class, header name, browser 접근 여부를 같이 적어야 쓸모가 생긴다. 어느 caller가 backend-only인지 한 표에서 보여야 한다.
이 표가 있으면 legacy key migration과 Vault naming 변경이 같은 문서에서 만난다. 이미 verify_jwt=false와 apikey 경계 글을 봤다면, 이번 표는 caller inventory 버전의 운영판이다.
실무 메모는 SQL caller와 browser caller를 한 줄로 구분할 수 있게 남겨야 한다. 어떤 Vault name이 어느 route와 연결되는지도 같이 적는 편이 좋다.
이 정도만 있어도 키 교체 후 누가 아직 legacy 키를 쓰는지 확인이 빨라진다. 특히 default secret key 하나를 여러 caller가 공유할 때 회고가 덜 꼬인다.
5. 주의사항과 리스크
첫 번째 리스크는 browser client와 backend caller를 같은 naming 규칙으로 적어 public env와 secret env가 섞이는 것이다. 두 번째 리스크는 Vault에 값만 저장하고 caller ownership이 보이지 않는 이름을 붙이는 것이다. 세 번째 리스크는 pg_net와 Database Webhooks를 따로 migration으로 다뤄 같은 정리를 반복하는 것이다. 특히 route 필드를 확인하지 않고, 로그 결과를 조회하지 않고, SQL 쿼리를 실행하지 않으면 어떤 caller가 아직 남았는지 확인이 늦어진다.
운영 전에 확인할 때는 최소한 caller 이름, route, key class, secret source, header 이름, browser 접근 여부 여섯 칸을 같은 표에 두는 편이 좋다. 그래야 key rotation과 incident 조사 문서가 같은 구조를 공유한다.
- caller inventory가 먼저고 key 교체는 그다음이다.
- browser client와 backend caller를 같은 key class로 두지 않는다.
- Vault secret 이름은 caller ownership이 보이게 짓는다.
6. 결론
Supabase에서 Schedule Functions, pg_net, Database Webhooks caller를 함께 운영할 때는 값 교체보다 inventory 정리가 먼저다. caller 목록을 만들고, publishable·secret key class를 먼저 나누고, Vault secret 이름과 header를 같은 문서에 붙이면 같은 migration을 훨씬 짧게 닫을 수 있다.
- caller 목록을 먼저 만든다.
- publishable과 secret key를 caller 기준으로 분리한다.
- Vault 이름과 route ownership을 함께 기록한다.
같은 가지의 앞단에는 Schedule Functions와 pg_net 분기 글, old Authorization cutover 글, verify_jwt=false와 apikey 경계 글, legacy key migration 글이 있다. 그 위에 이번 caller inventory 분기를 얹으면 backend caller 정리가 더 운영 문서답게 닫힌다.
7. 참고 링크
'기타개발지식 > 풀스택개발' 카테고리의 다른 글