본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 18. 14:27

원클릭 승인을 넘어: Snowflake에서 다단계 데이터 제품 거버넌스 구축하기

요약

Snowflake의 단일 승인 단계를 넘어, AI 코딩 어시스턴트를 활용해 다단계 데이터 제품 거버넌스 워크플로우를 구축하는 방법을 소개합니다. 기존 티켓팅 시스템의 한계를 극복하고 Snowflake 내부에서 승인 체인과 감사를 통합 관리하는 아키텍처를 제안합니다.

핵심 포인트

  • 기존 티켓팅 시스템의 컨텍스트 분리 및 수동 권한 부여 문제 지적
  • AI 코딩 어시스턴트를 활용한 Snowflake 내부 맞춤형 승인 워크플로우 구축
  • 데이터 제품, 승인 상태, 감사 로그를 동일한 스키마 내에서 통합 관리
  • 저장 프로시저를 통한 자동화된 권한 부여 및 거버넌스 강화

현대적인 데이터 플랫폼들은 **거버넌스가 적용된 데이터 공유 (governed data sharing)**에 대해 진지하게 접근하고 있습니다. Snowflake의 Internal Marketplace를 사용하면 데이터 제품을 한 번 게시하는 것만으로 조직 전반의 팀들이 액세스 제어, 태깅, 그리고 정의된 승인 단계가 내장된 상태에서 데이터 제품을 발견하고, 요청하고, 소비할 수 있게 해줍니다.

문제는 무엇일까요? "정의된 승인 단계"가 단수형이라는 점입니다. 즉, 단계가 하나뿐이라는 것입니다.

실제 기업 환경에서 민감한 데이터 제품에 대한 액세스를 승인하는 과정은 단 한 명의 참여로 끝나는 경우가 거의 없습니다. 요청자의 직속 관리자(line manager)의 승인이 필요합니다. 그다음은 데이터 소유자(data owner)입니다. 그다음은 보안 팀이나 데이터 보호 책임자(DPO) 팀입니다. 때로는 재무 팀이 필요할 수도 있습니다. 데이터의 민감도와 규제 맥락에 따라 이 체인은 2단계가 될 수도 있고 6단계가 될 수도 있습니다.

표준적인 해결책은 기업의 티켓팅 시스템 (ticketing system)을 덧붙이는 것이었습니다. 티켓 생성 → 관리자 승인 → 데이터 팀이 수동으로 액세스 권한 부여. 이 방식은 작동은 하지만 심각한 결함이 있습니다. 그리고 이 포스트는 AI 코딩 어시스턴트 (AI coding assistant)를 진정한 협업자로 활용하여, 전적으로 Snowflake 내부에서 구축한 더 깔끔한 대안을 보여줍니다.

티켓팅 우회 방식과 그 한계

티켓팅 통합 방식은 대다수의 기업이 이미 자체적인 티켓팅 시스템을 보유하고 있기 때문에 인기가 있습니다. 하지만 실제로 어떤 일이 일어나는지 살펴보십시오:

  • 컨텍스트가 분리됩니다. 승인 대화는 티켓에 존재합니다. 데이터 제품, 그 스키마, 그리고 그것이 포함하는 내용은 Snowflake나 다른 플랫폼에 존재합니다. 승인자는 어둠 속에서 승인하게 됩니다.
  • 권한 부여는 여전히 수동입니다. 데이터 팀의 누군가가 해결된 티켓을 읽고 GRANT 명령어를 수동으로 실행합니다. 이는 지루하고 오류가 발생하기 쉽습니다.
  • 강제 연결 고리가 없습니다. '승인됨'으로 표시된 티켓이 접근 권한 부여를 유발하지 않습니다. 두 시스템은 연결되어 있지 않습니다. 티켓 없이도 접근 권한이 부여될 수 있습니다. 접근 권한이 부여되지 않아도 티켓은 닫힐 수 있습니다.
  • 감사가 파편화됩니다. 컴플라이언스 팀은

거버넌스가 적용된 데이터 제품 승인 워크플로우(workflow)를 위해, 이곳은 정확히 적합한 호스트입니다. 애플리케이션은 Snowflake 테이블을 읽고 쓰며, 접근 권한을 부여하기 위해 저장 프로시저 (stored procedure)를 호출합니다. 그리고 상태, 결정, 감사(audit)를 포함한 전체 승인 체인은 관리 대상 데이터와 함께 동일한 스키마 내에 존재합니다.

아키텍처 (Architecture)

우리가 구축하고자 하는 흐름은 다음과 같습니다:

Workflow Approval Diagram

그리고 이것이 이 애플리케이션의 상위 수준 아키텍처 (high level architecture)입니다:

High Level Architecture

데이터 모델 (Data model) (5개 테이블)

테이블목적
DATA_PRODUCT게시된 데이터 제품의 레지스트리 (registry); access_role (최종 승인 시 부여되는 역할)을 보유
...

이 체인은 제품과 단계 순서(step order)를 키(key)로 사용하므로, 각 제품마다 서로 다른 체인을 가질 수 있습니다 (공개 데이터 세트는 한 단계만 필요할 수 있고, PII(개인정보)로 분류된 제품은 네 단계가 필요할 수 있습니다).

거버넌스 모델 — 엔터프라이즈 환경에서 중요한 부분

세 가지 기둥이 이 설계를 엔터프라이즈급으로 만듭니다.

1. 최소 권한 원칙 (Least Privilege): 앱은 절대 MANAGE GRANTS 권한을 갖지 않음

최종 승인은 실제 GRANT 명령을 트리거합니다. 애플리케이션 서비스 역할에 MANAGE GRANTS를 직접 부여하는 것은 심각한 과잉 권한 부여가 될 것입니다. 어떤 버그나 침해된 엔드포인트라도 무엇이든 임의로 접근 권한을 부여할 수 있기 때문입니다.

대신, 전용 권한 역할(privileged role)이 소유한 **소유자 권한 저장 프로시저 (owner's-rights stored procedure)**를 사용하십시오:

CREATE OR REPLACE PROCEDURE GOVERNANCE.APPROVAL.GRANT_PRODUCT_ACCESS(P_REQUEST_ID STRING)
  RETURNS STRING
  LANGUAGE SQL
...

앱 서비스 역할은 오직 GRANT USAGE ON PROCEDURE ... TO ROLE APP_SERVICE_ROLE 권한만 가집니다. 이 역할은 프로시저를 호출할 수는 있지만, 그 외의 다른 것은 무엇도 부여할 수 없습니다.

2. 직무 분리 (Separation of Duties): 특정 사용자가 아닌 역할(Role)에 의해 단계 정의

특정 승인자를 지정하는 방식은 취약성(사람이 퇴사하거나 다른 부서로 역할이 변경됨)을 초래하며 운영상으로도 고통스럽습니다. 대신, APPROVAL_CHAIN의 각 단계는 approver_role을 지정하며, 해당 역할의 구성원이라면 누구나 해당 단계에서 작업을 수행할 수 있습니다.

승인 대기열(approver queue)은 IS_ROLE_IN_SESSION을 사용하여 서버 측에서 필터링됩니다:

SELECT
    r.request_id,
    r.requester,
...

동일한 가드(guard)가 결정 핸들러(decision handler)에서도 실행됩니다. 현재 단계에 대해 IS_ROLE_IN_SESSION(approver_role)false인 경우, 요청은 403 Forbidden 에러를 반환합니다. Step 1 역할을 가진 사용자는 Step 2를 승인할 수 없는 식입니다.

이는 App Runtime의 ID 모델(identity model)과 자연스럽게 작동합니다. 앱 쿼리가 로그인한 사용자로 실행되기 때문에, IS_ROLE_IN_SESSION은 해당 사용자에게 실제로 부여된 역할(roles)을 반영합니다. 사칭(impersonation)이나 별도의 ID 매핑이 필요하지 않습니다.

3. 감사 가능성 (Auditability): 모든 결정에 대한 추가 전용(Append-Only) 기록

제출, 단계별 결정, 최종 승인 등 모든 상태 변경 사항은 actor (사용자 이름), actor_role (CURRENT_ROLE()), event_type, step_order, decision, comment, created_at과 함께 AUDIT_LOG에 기록됩니다. 이 테이블에는 앱 서비스 역할(app service role)에 대한 UPDATE 또는 DELETE 권한이 부여되지 않습니다. 한 번 기록되면 수정할 수 없습니다 (write-once).

이는 컴플라이언스(compliance) 팀에 필요한 기록입니다: "누가 이 PII 데이터셋에 대한 액세스를 승인했는가, 당시 어떤 역할을 보유하고 있었는가, 그리고 언제인가?"

플랫폼을 이해하는 AI 협업 도구, Cortex Code로 구축하기

이 워크플로우는 단순한 코드 완성 도구가 아닌, 진정한 공동 저자로서 Snowflake의 AI 코딩 어시스턴트인 **Cortex Code (CoCo)**와 함께 설계되고 구축되었습니다.

Plan 모드: 문제를 설명하고 검토 가능한 설계 얻기

시작 프롬프트는 대략 다음과 같았습니다:

"Internal Marketplace 외에 다단계 데이터 제품 승인 워크플로우(approval workflow)가 필요합니다. 기본 요청 흐름은 단일 단계입니다. 제가 원하는 것은 다음과 같습니다: 요청자가 제출하면, N명의 승인자가 순차적으로(역할별로 지정됨) 승인하고, 최종 승인이 실제 Snowflake GRANT를 트리거하며, 전체 감사 로그(audit log)를 남기는 것입니다. 가장 안전한 아키텍처는 무엇인가요? 권한 부여(grant) 단계에 어떤 옵션들이 있나요?"

CoCo는 즉시 코드를 작성하지 않았습니다. 대신 계획 모드(plan mode)로 진입했습니다:

  • App Runtime 및 RBAC(역할 기반 액세스 제어) 문서를 읽었습니다.
  • 최소 권한 원칙(least-privilege)에 따른 권한 부여 프로시저(grant procedure) 패턴을 식별했습니다.
  • 개인 데이터베이스 배포는 다른 역할과 공유될 수 없다는 점을 지적했습니다(애플리케이션을 망가뜨릴 수 있는, 명확하지 않은 제약 사항이었습니다).
  • 단 하나의 파일이 생성되기 전에 데이터 모델, RBAC 설계, UI 경로, 보안 트레이드오프(security tradeoffs)를 포함한 전체 구현 계획을 생성했습니다.

이 계획은 실제 작업이 시작되기 전에 검토하고 조정할 수 있었습니다.

이 부분이 플랫폼 엔지니어의 작업 방식을 바꾸는 지점입니다. 설계 결정("앱에 MANAGE GRANTS 권한을 절대 주지 마십시오; 소유자 권한을 가진 프로시저를 사용하십시오")은 우리가 사전에 제공해야 했던 지식이 아니라, 어시스턴트(CoCo)의 조사로부터 도출되었습니다.

Scaffold: 계획에서 작동하는 코드로

계획이 승인되자, CoCo는 다음을 수행했습니다:

  • 확정된 스키마 설계를 바탕으로 세 가지 SQL 설정 스크립트(데이터 모델, RBAC + 권한 부여 프로시저, 시드 데이터)를 생성했습니다.
  • Next.js App Runtime 프로젝트의 스캐폴딩(Scaffold)을 수행하고, 데이터 플랫폼 연결을 런타임 환경에서 주입된 OAuth 토큰에 연결했으며, 요청자 및 승인자 UI 경로를 구축했습니다.
  • 카탈로그 브라우징, 요청 제출, 승인자 대기열(IS_ROLE_IN_SESSION 필터 포함), 그리고 단계 진행 로직이 포함된 결정 핸들러(decision handler)를 위한 백엔드 API 경로를 작성했습니다.

저는 Next.js 개발자가 아니며, 풀스택 웹 애플리케이션 개발에 대한 지식이나 경험이 전혀 없습니다. 전체 프론트엔드는 제품 카드, 수평형 단계 진행 표시기(step progress indicator), 댓글 필드가 포함된 승인/거절 버튼 등 UX를 설명하는 반복적인 프롬프트를 기반으로 CoCo가 작성했습니다.

반복 (Iterate): 데모를 위한 역할 전환기(role-switcher), 이해관계자를 위한 다듬기

초기 배포 이후, 두 가지 후속 작업이 있었습니다:

  1. 데모를 위한 역할 격리 (Role isolation). 제 계정에는 ACCOUNTADMIN 역할이 있기 때문에, 모든 단계에서 IS_ROLE_IN_SESSIONtrue를 반환했습니다. 이로 인해 다단계 프로세스(multi-step story)가 보이지 않는 문제가 발생했습니다. 프롬프트: "ACCOUNTADMIN이 모든 역할을 보유하고 있어 데모 시 모든 사용자에게 모든 승인 단계가 표시됩니다. 프레젠테이션에서 승인 체인을 단계별로 보여줄 수 있도록 앱 내 역할 전환기(role switcher)가 필요합니다." CoCo는 각 승인 측 쿼리 실행 전에 USE SECONDARY ROLES NONE; USE ROLE <role>을 실행하는 queryAs(role, sql) 헬퍼 함수를 설계했습니다. 또한, 역할 이름(매개변수 바인딩이 불가능하여 SQL 인젝션 위험이 있음)을 통해 발생할 수 있는 SQL 인젝션을 방지하기 위해 전환기를 허용 목록(allowlist) 뒤로 제한하고, 상단 바에 <select> 드롭다운을 추가했습니다.

  2. UI 다듬기 (UI polish). 시각적 방향을 설명하는 짧은 프롬프트만으로 CSS 토큰 시스템, 사이드바 네비게이션, 연결된 수평형 스텝퍼(stepper) 컴포넌트, 로딩 스켈레톤(loading skeletons), 아이덴티티 칩(identity chip) 등 전문적인 수준의 전체 리디자인을 수행했습니다. CSS 지식은 전혀 필요하지 않았습니다.

각 반복 과정은 동일한 사이클을 따랐습니다: 평이한 언어로 필요 사항 설명 → CoCo가 계획 제안 → 검토 → 승인 → 실행. 최종 앱은 스프린트(sprint)가 아닌, 하나의 작업 세션(working session)을 통해 완성되었습니다.

제공 기능 (What You Get)

기능상세 내용
N단계 승인 체인 (N-step approval chains)데이터 제품별로 구성 가능; 제품마다 서로 다른 체인 설정 가능
...

한계 및 향후 개발 (Limitation and Future Development)

앱 런타임(App Runtime)은 퍼블릭 프리뷰(public preview) 단계입니다. 기능 및 배포 메커니즘은 GA(General Availability) 이전에 변경될 수 있습니다. 트라이얼(trial) 계정에서는 사용할 수 없으며, 유료 Snowflake 계정이 필요합니다. 이 패턴을 프로덕션(production)에 적용하기 전에 반드시 릴리스 노트(release notes)를 확인하십시오.

이것은 네이티브 마켓플레이스(native marketplace) 내부에 있는 것이 아니라, 그 옆에 위치합니다. 네이티브 내부 마켓플레이스(Internal Marketplace)의 탐색 흐름(목록 브라우징, "액세스 요청(Request Access)" 버튼)은 여전히 존재합니다. 이 커스텀 앱은 카탈로그 자체를 대체하는 것이 아니라, 요청 및 승인 상호작용을 대체합니다. 사용자가 네이티브 카탈로그를 통해 제품을 발견하기를 원한다면, 커스텀 앱은 실제 제출을 위해 클릭하는 진입점 역할을 하거나, 앱 내에서 병렬적인 카탈로그 뷰를 유지하게 됩니다.

고정된 N단계 체인 (Fixed-N chains). 위의 설계는 제품 등록 시점에 정의되는 제품당 고정된 승인 체인을 사용합니다. 동적 라우팅(예: "데이터셋에 PII 태그가 붙어 있으면 DPO 단계를 추가하고, 그렇지 않으면 건너뜀")은 확장 기능입니다. APPROVAL_CHAIN 테이블 구조가 이를 지원하지만, 라우팅 로직은 별도로 추가해야 합니다.

요약 (Wrap-Up)

내부 마켓플레이스(Internal Marketplaces)는 대규모의 거버넌스 기반 데이터 공유를 위한 올바른 방향입니다. 하지만 단일 단계 승인 흐름은 다부서 거버넌스 요구사항을 가진 기업들에게 실질적인 제약 사항입니다. 여기서 보여준 패턴 — 상태 관리를 위한 Snowflake 테이블, 최소 권한 부여를 위한 소유자 권한 프로시저(owner's-rights procedure), UI 레이어를 위한 App Runtime, 그리고 직무 분리(separation of duties)를 위한 역할 기반 단계 키잉(role-based step keying) — 은 전체 승인 체인을 마땅히 있어야 할 데이터 플랫폼 내부에 유지합니다.

이 방식 또는 그 변형을 구축한다면, 거버넌스 스토리는 다음과 같이 됩니다: 모든 액세스 결정은 플랫폼 내에서, 적절한 역할을 가진 인증된 사용자에 의해 이루어졌으며, 완전한 감사 추적(audit trail)을 남겼고, 권한 부여(grant)는 사람이 직접 키보드를 입력하는 대신 저장 프로시저(stored procedure)에 의해 실행되었습니다.

이것이 바로 귀하의 컴플라이언스(compliance) 팀이 수용할 수 있는 이야기입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0