Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DataOpsNight#11

Avatar for Tatsuya Hanyu Tatsuya Hanyu
August 21, 2026
61

 DataOpsNight#11

Avatar for Tatsuya Hanyu

Tatsuya Hanyu

August 21, 2026

Transcript

  1. ⾃⼰紹介 • • • • 名前:⽻⼊達也(データエンジニア) ◦ X :kaeton6ster 登壇テーマ:

    ◦ データ基盤にコンテキストレイヤー導⼊し始めた話 名前:浅宮雄貴(データエンジニア) ◦ X :NeoBigmegaphone 登壇テーマ: ◦ ユーザビリティと機密保護を両⽴するガバナンス Finatext Group ©© Finatext Group
  2. DWH利活⽤の課題とアプローチ OLTPクエリをSnowflakeに変換し、⾃然⾔語問い合わせを実現するため、Skillと Semantic Layerを整備 Crest Lake Warehouse 課題① 💦 Mart

    課題② OLTPクエリをSnowflakeでも活⽤ したいが、変換⽅法がわからず、エ ンジニアも多忙で進まない... 💦 アプローチ① ⾃然⾔語で問い合わせたいが、 AIに頼っても正しい結果を毎回は作 れない... アプローチ② OLTPクエリをSnowflakeクエリに 変換するskillを作る Semantic Layerを作る Finatext Group ©© Finatext Group
  3. Skillの活⽤ Crest DB OLTPクエリをSnowflakeクエリに文法変換を行う skillを構築 skill 以下の SQLをsnowflake用に 変換してください <OLTP用のSQL>

    ルールの例 現在有効な行を抽出する effective @> now() は 2 列に展開する OLTP(range型) WHERE effective @> now() 業務ユーザー skillを使⽤してクエリを変換 Snowflake ``` WHERE effective_start_at <= current_timestamp() AND (effective_end_at IS NULL OR current_timestamp() <= effective_end_at) ``` <Snowflake用のSQL> SNOWFLAKE COCO ※ あくまで自動変換のため、クエリの正確性チェックはエンジニアに依頼 Finatext Group ©© Finatext Group Source / Lake
  4. Skillの活⽤ Lake層を前提としたクエリを Warehouse層を利用するクエリに変換 Source / Lake 変更前後での差分 • • •

    • 60行超え 3つのテーブルを結合 複雑なCASE文 サブクエリあり 変換前 • • • • select A.DISPLAY_ID as "アカウントID", P.PLAN_CODE as "契約プラン番号", BASE_FEE_AMOUNT as "基本利用料", OPTION_FEE_AMOUNT as "オプション利用料", case -- 月末時に無料トライアル期間が終了している場合の日割り計算 when SUBSCRIPTION_STATUS = 'ACTIVE' and UTL.TRIAL_END_DATE > UTL.PROCESSED_AT and UTL.TRIAL_END_DATE at time zone 'Asia/Tokyo' <= '202X-12-31 23:59:59' then FLOOR(BASE_USAGE_FEE + BASE_FEE_AMOUNT * DATE_PART( 'day', TIMESTAMP '202X-12-31 23:59:59' at time zone 'Asia/Tokyo' - UTL.TRIAL_END_DATE at time zone 'Asia/Tokyo' + interval '1 day' ) * UTL.USAGE_RATE / 365) -- 月末時に無料トライアル期間内の場合 when SUBSCRIPTION_STATUS = 'ACTIVE' and UTL.TRIAL_END_DATE at time zone 'Asia/Tokyo' > '202X-12-31 23:59:59' then 0 -- 通常利用期間 when SUBSCRIPTION_STATUS = 'ACTIVE' then FLOOR(BASE_USAGE_FEE + BASE_FEE_AMOUNT * DATE_PART( 'day', TIMESTAMP '202X-12-31 23:59:59' at time zone 'Asia/Tokyo' - UTL.PROCESSED_AT at TIME zone 'Asia/Tokyo' ) * UTL.USAGE_RATE / 365) else FLOOR(BASE_USAGE_FEE) end as "未収基本料", case -- 停止中・解約済みアカウントの遅延損害金計算 when SUBSCRIPTION_STATUS in ('SUSPENDED','CANCELLED') then FLOOR(UTL.PENALTY_AMOUNT + UTL.BASE_FEE_AMOUNT * DATE_PART( 'day', TIMESTAMP '202X-12-31 23:59:59' at time zone 'Asia/Tokyo' - UTL.PROCESSED_AT at TIME zone 'Asia/Tokyo' ) * UTL.PENALTY_RATE / 365) else FLOOR(PENALTY_AMOUNT) end as "未収遅延請求金" from USER_TRANSACTION_LOGS UTL inner join ACCOUNTS A on A.ID = UTL.ACCOUNT_ID and UTL.VALID_PERIOD @> NOW() and UTL.SYSTEM_PERIOD @> NOW() and A.VALID_PERIOD @> NOW() and A.SYSTEM_PERIOD @> NOW() inner join SUBSCRIPTION_PLANS P on UTL.PLAN_ID = P.ID and P.VALID_PERIOD @> NOW() and P.SYSTEM_PERIOD @> NOW() where (UTL.ACCOUNT_ID, UTL.PROCESSED_AT) in ( -- 最新のトランザクションのみを抽出 select ACCOUNT_ID, MAX(PROCESSED_AT) from USER_TRANSACTION_LOGS where VALID_PERIOD @> NOW() and SYSTEM_PERIOD @> NOW() and PROCESSED_AT at time zone 'Asia/Tokyo' < '202X-12-31 23:59:59' group by ACCOUNT_ID ) order by A.ID; AI変換後 約10行に短縮 結合なし(単一テーブル) 計算済みカラムを参照するだけ サブクエリ不要、 whereのみ select s.account_id as "アカウントID", s.plan_code as "契約プラン番号", s.base_fee_amount as "基本利用料", s.option_fee_amount as "オプション利用料", floor(s.accrued_base_fee) as "未収基本料", floor(s.accrued_penalty_fee) as "未収遅延 請求金" from warehouse_billing.fct_daily_billing_snapsho t as s where s.date = date() ※クエリはサンプル Finatext Group ©© Finatext Group Ware house
  5. Semantic Layer の構築 自然言語での問い合わせに適切な結果を返すには Semantic viewの整備が不可欠 • Semantic layerとは ◦

    ◦ • Snowflakeには Semantic layerの整備をサポートする autopilot機能がある ◦ • テーブルやカラムに、ビジネス上の意味や関係性を付与するレイヤー ⾃然⾔語から正確なSQLを⽣成するための「辞書」の役割を果たす auto pilot機能とは ▪ テーブルの構造やデータを解析し、初台となるセマンティックモデル(指標やディメンションの定義) を⾃動⽣成してくれる機能 ▪ ゼロから定義を記述する⼿間を⼤幅に削減し、素早い⽴ち上げが可能になる auto pilot機能を使⽤して、warehouse層に Semantic Layerを構築した Finatext Group ©© Finatext Group
  6. まとめ Crest Warehouse Lake ① Skillによって、アプリケーション DBへのクエリ をSnowflakeで使えるように変換。 Future Work

    • • Semantic Layerの定期的な更新設計、グルーピングについて Snowflakeのアップデートに追従してSkillの更新 Finatext Group ©© Finatext Group Mart ② ①で作成したクエリを使用して、 Semantic Layerを整備
  7. 設計⽅針:三段構えの分離 STAGE 01 どこで / WHERE ⼿段 / METHOD ①

    ⼊れない AWS / Athena テーブル‧カラム除去 STAGE 02 どこで / WHERE ⼿段 / METHOD ② 隠す Snowflake内 マスキングポリシー STAGE 03 どこで / WHERE ⼿段 / METHOD ③ 承認する Snowflake 承認時に権限を⼀時付与する仕組みを実装 Finatext Group ©© Finatext Group
  8. Stage 2:分析に使う機密データを、許可されていない⼈から隠す 誰に⾒せるか = ロールベース ロール どの列を隠すか = タグベース クエリ

    テーブル.カラム tagをset CURRENT_ROLE() で判定 紐づく マスキングポリシー タグ 対象ロールなら⽣値、それ以外は **** を返す ロールとタグを⽤いた権限管理 定義と適⽤を分離し、柔軟なマスキング設定を実現 Finatext Group ©© Finatext Group
  9. Stage 2:分析に使う機密データを、許可されていない⼈から隠す # dim_customers.yml — mobile_phone_numberカラム どの列を隠すか = タグベース にタグを宣言

    誰に⾒せるか = ロールベース クエリ models: ロール - name: dim_customers columns: - name: mobile_phone_number meta: CURRENT_ROLE() で判定 tag: name: SNOWFLAKE_CONFIG.TAG.PII value: PII 紐づく テーブル.カラム マスキングポリシー タグ tagをset # パイプライン実行時、 post-hook の**** macro が SET 対象ロールなら⽣値、それ以外は を返す TAG を実行 ロールとタグを⽤いた権限管理 alter table WH_SCHEMA.DIM_CUSTOMERS modify 定義と適⽤を分離し、柔軟なマスキング設定を実現 column mobile_phone_number set tag SNOWFLAKE_CONFIG.TAG.PII = 'PII'; Finatext Group ©© Finatext Group
  10. Stage 2:分析に使う機密データを、許可されていない⼈から隠す # SNOWFLAKE_CONFIG.TAG.PIIタグの定義 誰に⾒せるか = ロールベース ロール どの列を隠すか =

    タグベース クエリ テーブル.カラム resource "snowflake_tag" "pii" { … name = "PII" tagをset CURRENT_ROLE() で判定 masking_policies = [snowflake_masking_policy. pii_string.fully_qua 紐づく lified_name] マスキングポリシー } タグ 対象ロールなら⽣値、それ以外は **** を返す ロールとタグを⽤いた権限管理 定義と適⽤を分離し、柔軟なマスキング設定を実現 Finatext Group ©© Finatext Group
  11. # マスキングポリシー : snowflake_masking_policy.pii_stringの定義 Stage 2:分析に使う機密データを、許可されていない⼈から隠 resource "snowflake_masking_policy" "pii_string" {

    … 誰に⾒せるか = ロールベース どの列を隠すか = タグベース name = "PII_STRING" ロール CURRENT_ROLE() で判定 クエリ テーブル.カラム argument { name = "val" type = "STRING" } tagをset return_data_type = "STRING" body = <<-EOF 紐づく CASE マスキングポリシー タグ WHEN CURRENT_ROLE() IN (マスク解除ロール ) THEN val 対象ロールなら⽣値、それ以外は **** を返す ELSE '****' END ロールとタグを⽤いた権限管理 EOF 定義と適⽤を分離し、柔軟なマスキング設定を実現 } Finatext Group ©© Finatext Group
  12. Stage 3: 強い権限は常時持たせず、短時間だけ承認する ⚠ 強いロールを常時持つ • 承認不要 • いつでも⾒られる →

    • • 強いロール 本番データが⾒える 申請によって使⽤可能 申請者 ⭕ 必要な時だけ承認する • 通常のロール 本番データは⾒えない 常時使⽤可能 普段は本番データを⾒れないロールのみ使 える 権限付与フローを実施すると、本番データ を⾒られるロールが使えるようになる 期限切れ時に権限剥奪フローが起動し、本 番データ⾒られるロールの使⽤権限は⾃動 剥奪 Finatext Group ©© Finatext Group
  13. Stage 3: 強い権限は常時持たせず、短時間だけ承認する ⚠ 強いロールを常時持つ • 承認不要 • いつでも⾒られる 権限付与フロー

    ① slack workflowで申請 ② 他者が承認 ③ 時間限定でロールを貸与 → ⭕ 必要な時だけ承認する • • • 普段は本番データを⾒れないロールのみ使 える 権限付与フローを実施すると、本番データ を⾒られるロールが使えるようになる 期限切れ時に権限剥奪フローが起動し、本 番データ⾒られるロールの使⽤権限は⾃動 剥奪 承認者 ① 申請者 通常のロール ② ③ 権限付与 ③ grant role 強いロール to user 申請者 Finatext Group ©© Finatext Group 強いロール
  14. Stage 3: 強い権限は常時持たせず、短時間だけ承認する ⚠ 強いロールを常時持つ • 承認不要 • いつでも⾒られる 権限剥奪フロー

    ④ 期限切れで⾃動返却 → 申請者 ⭕ 必要な時だけ承認する • • • 普段は本番データを⾒れないロールのみ使 える 権限付与フローを実施すると、本番データ を⾒られるロールが使えるようになる 期限切れ時に権限剥奪フローが起動し、本 番データ⾒られるロールの使⽤権限は⾃動 剥奪 権限剥奪 ⾃動実⾏ 通常のロール ④ ④ revoke role 強いロール from user 申請者 Finatext Group ©© Finatext Group 強いロール
  15. Stage 3: 強い権限は常時持たせず、短時間だけ承認する ⚠ 強いロールを常時持つ • 承認不要 • いつでも⾒られる 2つのpoint

    時間的最⼩性 → 必要なとき、短時間だけ ⭕ 必要な時だけ承認する • • • 普段は本番データを⾒れないロールのみ使 える 権限付与フローを実施すると、本番データ を⾒られるロールが使えるようになる 期限切れ時に権限剥奪フローが起動し、本 番データ⾒られるロールの使⽤権限は⾃動 剥奪 Two Person Integrity ⼀⼈で完結させず、必ず他者 の承認を挟む Finatext Group ©© Finatext Group
  16. まとめ ― 多層の境界で、ユーザビリティと機密保護を両⽴する ユーザビリティと機密保護は⼆択ではない。データごとの「誰が‧いつ」を、多層の境界で制御する STAGE 01 ① ⼊れない 不要なデータはそもそも基盤に載せない STAGE

    02 ② 隠す 機密はロール×タグで動的にマスク STAGE 03 ③ 承認する 強い権限は常時でなく、承認を経て⼀時的に使⽤ データを守りながら、広く使ってもらう Finatext Group ©© Finatext Group
  17. Appendix: TARP (Temporal Assume Role Policy) の仕組み 権限付与フロー ① 申請

    ② 他者が承認 ③ 時間限定でロールを貸与 ① ③ 権限付与希望者がslack workflowで申請 権限剥奪フロー ④ 期限切れで⾃動返却 ② ④ 出典: https://speakerdeck.com/kevinrobot34/introduction-of-information-security-7f7b9 6b1-3ed9-4ef5-b8f6-96d428da6fc4?slide=31 Finatext Group ©© Finatext Group
  18. Appendix: ロール設計 出典: https://speakerdeck.com/kevinrobot34/privilege-and-cost-management-in-snowflake?slide=4 Service Role 層 System User 1

    Account Role Service_RW Database Access Role 層 Warehouse System User 2 Account Role Service_R Warehouse Database Role table-select Database Role ReadWrite Database Role table-create Functional Role 層 Human User A Account Role Functional_RW Warehouse Human User B tables Database Role Read Account Role Functional_R Database Role view-select views Database Role view-create Warehouse 権限の束の単位で継承させることで、メンテナンス性を維持しつつ最⼩権限を実現 Finatext Group ©© Finatext Group 33