ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Supabase][보안] pg_net와 Database Webhooks가 old Authorization 헤더를 계속 보낼 때 apikey cutover를 어디부터 다시 나누나
    기타개발지식/풀스택개발 2026. 8. 2. 20:15

    IT 리서치 노트

    [Supabase][보안] pg_net와 Database Webhooks가 old Authorization 헤더를 계속 보낼 때 apikey cutover를 어디부터 다시 나누나

    Supabase 새 API key 체계로 옮긴 뒤에도 pg_net나 Database Webhooks가 계속 실패한다면, 많은 경우 원인은 key 생성이 아니라 old Authorization Bearer 관성에 남아 있다. 2026년 8월 2일 기준 Supabase 공식 문서를 다시 보면 pg_net와 Database Webhooks는 새 secret key를 Authorization이 아니라 apikey header로 보내야 하고, scheduled function 호출용 토큰은 Vault에 두는 편을 권장한다. 이 글은 pg_net와 Database Webhooks가 old Authorization 헤더를 계속 보낼 때 apikey cutover를 어디부터 다시 나누는 편이 덜 꼬이는지 정리한 것이다.

    1. 개요

    결론부터 말하면 pg_net와 Database Webhooks의 새 API key cutover는 header 이름, secret 저장 위치, caller inventory 세 축을 같이 봐야 짧다. old Authorization Bearer가 남아 있으면 새 secret key를 발급해도 함수 전에 실패할 수 있고, Vault와 Dashboard 저장값을 같이 안 보면 누락 경로를 놓치기 쉽다.

    즉 이 문제는 단순한 key rotation이 아니다. pg_net SQL, Dashboard webhook, worker, Edge Function caller가 각각 어떤 header를 보내는지 목록을 만들고 그 목록을 하나씩 닫아야 한다.

    2. 어디서 실제로 막히는가

    현장에서 가장 흔한 막힘은 세 가지다. 첫째, secret key를 새로 만들었으니 cutover가 끝났다고 생각한다. 둘째, verify_jwt=false route를 열어 둔 뒤에도 pg_net와 webhook이 여전히 Authorization Bearer를 보내 handler 전에 실패한다. 셋째, Vault에 들어 있는 값과 Dashboard webhook 화면의 header 설정이 따로 놀아 어느 caller가 아직 old header를 쓰는지 모른다.

    Supabase migration guide는 pg_net와 Database Webhooks가 old service_role Bearer 관성을 갖고 있고, 새 secret key는 JWT가 아니므로 apikey header로 보내야 한다고 직접 적는다. Edge Functions auth 문서는 pg_net와 worker 같은 backend caller는 user JWT가 아니라 secret key caller라고 설명한다. schedule functions 문서는 이 호출용 token을 Vault에 저장하라고 권장한다. 이 셋을 합치면 문제의 중심은 '누가 무엇을 어디에 저장해 어떤 header로 보내는가'가 된다.

    • 증상: webhook이나 pg_net 호출만 401/403으로 계속 실패한다.
    • 실패: 새 secret key 발급만 끝나면 된다고 본다.
    • 막힘: Dashboard header 설정과 SQL 함수의 header 객체를 따로 관리한다.
    • 누락: Vault secret id와 실제 caller 목록을 한 표에 적지 않는다.
    질문 먼저 볼 곳 실무 판단
    무엇이 아직 실패하나 caller inventory pg_net, webhook, worker를 분리해 적는다
    header가 왜 안 맞나 SQL / Dashboard 설정 Authorization에서 apikey로 바뀌었는지 본다
    값은 어디서 읽나 Vault 또는 env var secret 저장 위치도 같이 정리한다

    3. 실무에서 적용하는 순서

    운영 순서는 다섯 단계가 가장 실용적이다. 먼저 pg_net SQL, Database Webhooks, worker, 다른 Edge Function caller inventory를 만든다. 다음으로 각 caller가 현재 Authorization을 쓰는지 apikey를 쓰는지 적는다. 세 번째로 호출용 secret을 Vault 또는 배포 환경변수로 정리한다. 네 번째로 SQL과 Dashboard 설정에서 header 이름을 동시에 바꾼다. 마지막으로 recent 2xx/4xx 비율과 old key 사용 로그를 보고 남은 caller를 지운다.

    1. caller inventory를 먼저 만든다.
    2. 각 caller의 현재 header 이름을 적는다.
    3. 호출용 secret 저장 위치를 Vault 기준으로 정리한다.
    4. SQL과 Dashboard header를 같이 바꾼다.
    5. 응답 코드와 old key 흔적으로 남은 caller를 찾는다.

    실제 점검에서는 pg_net를 부르는 SQL 함수와 Database Webhooks 화면을 같이 열어 두고, before·after header가 동일한 cutover 규칙을 따르는지 보는 편이 좋다. route 경계는 auth:'secret' 또는 verify_jwt=false로 제한하고, browser JWT route와 backend caller route를 섞지 않는 편이 안전하다. 이때 Vault secret id까지 inventory에 적어 두면 이후 key rotation 때도 재사용하기 쉽다.

    cutover_note:
    caller=database_webhook
    route=/functions/v1/outbox-dispatch
    header_name=apikey
    secret_source=vault:functions_secret_key
    last_2xx_rate=100%
    old_authorization_detected=false
    

    이 메모가 있으면 route auth 문제와 header cutover 문제를 섞지 않고, 어느 caller가 아직 old Authorization을 보내는지 바로 자를 수 있다.

    4. 공식 문서와 예시 화면으로 확인하기

    첫 공식 화면은 migration guide의 가장 중요한 문장이다. pg_net와 Database Webhooks는 예전 service_role Bearer 관성을 그대로 끌고 오기 쉽고, 새 secret key는 JWT가 아니므로 그 자리에서 바로 막힌다.

    Supabase migration guide는 pg_net와 Database Webhooks가 old Authorization Bearer 대신 apikey header로 바뀌어야 한다고 설명한다.
    Supabase migration guide는 pg_net와 Database Webhooks가 old Authorization Bearer 대신 apikey header로 바뀌어야 한다고 설명한다.

    즉 새 secret key를 만들었다는 사실과 실제 cutover 완료는 다르다. header 이름을 안 바꾸면 key 문자열만 새것으로 갈아도 함수 전에 실패한다.

    두 번째 자료는 Edge Functions auth 문서다. Supabase는 pg_net, worker, 다른 Edge Function 같은 backend caller는 user JWT가 아니라 apikey header 기반 secret caller라고 분명히 적고 있다.

    Supabase는 pg_net와 worker 계열 호출을 apikey header의 secret caller로 다뤄야 한다고 설명한다.
    Supabase는 pg_net와 worker 계열 호출을 apikey header의 secret caller로 다뤄야 한다고 설명한다.

    이미 verify_jwt=false와 apikey·Authorization 분기 글이 route 경계를 다뤘다면, 이번 글은 그 뒤에 남는 old header inventory를 닫는 단계다.

    세 번째 공식 화면은 scheduled Edge Functions 문서다. pg_cron과 pg_net로 함수를 부를 때 auth token을 Vault에 두라고 권장한다.

    Supabase는 pg_cron·pg_net 호출용 auth token을 Vault에 보관하라고 권장한다.
    Supabase는 pg_cron·pg_net 호출용 auth token을 Vault에 보관하라고 권장한다.

    header cutover를 SQL 문자열 치환 문제로만 보면 오래 간다. Vault 위치와 caller inventory를 같이 봐야 어떤 job이 아직 old header를 쓰는지 빨리 찾을 수 있다.

    네 번째 자료는 Database Webhooks 문서다. 이 경로는 브라우저가 아니라 데이터베이스 이벤트가 외부 endpoint를 두드리는 backend caller다.

    Database Webhooks는 database event가 다른 시스템으로 payload를 보내는 backend 경로라고 설명한다.
    Database Webhooks는 database event가 다른 시스템으로 payload를 보내는 backend 경로라고 설명한다.

    이 성격 때문에 브라우저 인증 문제와 같은 표에 놓으면 안 된다. webhook은 caller inventory와 header cutover 진행률로 보는 편이 자연스럽다.

    다섯 번째 자료는 old Authorization을 계속 보낼 수 있는 caller inventory 표다. pg_net job, Dashboard webhook, worker, 다른 Edge Function을 한 번에 적어야 빠뜨린 지점이 줄어든다.

    pg_net와 Database Webhooks old header cutover를 caller별로 추적하는 표다.
    pg_net와 Database Webhooks old header cutover를 caller별로 추적하는 표다.

    같은 Supabase 클러스터 안에서도 backend별 secret key rotation 글이 key 경계를 다뤘다면, 이번 표는 그 후속으로 header cutover 잔여분을 닫는 작업이다.

    마지막 자료는 before·after SQL 메모다. pg_net cutover는 추상 문장보다 실제 header 객체 한 줄이 바뀌었는지 확인하는 편이 빠르다.

    pg_net와 webhook 경로에서 Authorization을 apikey로 바꾸는 before·after 예시다.
    pg_net와 webhook 경로에서 Authorization을 apikey로 바꾸는 before·after 예시다.

    실제 cutover에서는 SQL, Dashboard header 설정, Vault secret 참조 세 군데가 모두 끝났는지 같이 체크해야 한다.

    5. 주의사항과 리스크

    첫 번째 리스크는 secret key를 새로 만들었는데도 Dashboard webhook이나 SQL 함수가 여전히 Authorization Bearer를 보내는 상태를 놓치는 것이다. 두 번째는 Vault secret ref와 Dashboard 저장값을 같은 inventory에 적지 않아 old caller가 남는 것이다. 세 번째는 backend caller route와 browser JWT route를 같은 함수로 운영해, header cutover 실패를 브라우저 인증 실패와 헷갈리는 것이다.

    운영 전에 확인할 때는 caller 이름, route, header 이름, secret 저장 위치, 최근 응답 비율 다섯 칸을 같은 표에 두는 편이 좋다. 그래야 한 번의 cutover에서 어디가 끝났고 어디가 남았는지 바로 보인다.

    • header 이름과 key 값 교체를 별개로 보지 않는다.
    • Vault와 Dashboard 저장값을 같은 inventory로 관리한다.
    • backend caller route는 browser route와 분리한다.

    6. 결론

    Supabase pg_net와 Database Webhooks의 새 API key cutover는 단순한 key rotation이 아니라 old Authorization 관성을 지우는 작업이다. caller inventory를 만들고, secret 저장 위치를 정리하고, SQL과 Dashboard header를 동시에 apikey로 바꾸면 남은 실패 경로를 훨씬 짧게 닫을 수 있다.

    • caller inventory를 먼저 만든다.
    • Authorization과 apikey를 분리해 적는다.
    • Vault와 Dashboard 저장값을 함께 정리한다.

    같은 가지의 앞단에는 verify_jwt=false와 apikey·Authorization 분기 글, backend별 secret key rotation 글, legacy key migration 글이 있다. 그 위에 이번 old header cutover runbook을 얹으면 실제 전환이 닫힌다. 이후 schedule functions와 pg_net 호출을 한 inventory에서 다시 정리해야 하는 단계라면 Vault secret과 apikey header를 호출 순서대로 나누는 후속 글을 같이 보는 편이 안전하다.

    7. 참고 링크

    1. https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys
    2. https://supabase.com/docs/guides/functions/auth
    3. https://supabase.com/docs/guides/database/webhooks
    4. https://supabase.com/docs/guides/database/extensions/pg_net
    5. https://supabase.com/docs/guides/functions/schedule-functions
Designed by Tistory.