$30 off During Our Annual Pro Sale. View Details »

Go×RLSで複数テナントのデータを安全に扱う/secure-data-access-with-go-rls-in-multi-tenant-environment

Sh0He1666
October 02, 2023

 Go×RLSで複数テナントのデータを安全に扱う/secure-data-access-with-go-rls-in-multi-tenant-environment

Sh0He1666

October 02, 2023
Tweet

Other Decks in Programming

Transcript

  1. Go×RLSで複数テナントのデータを安全に扱う
    2023/09/28 golang.Tokyo#33
    スプリームシステム株式会社
    プロダクトディベロップメント部
    徳丸 翔平

    View Slide

  2. 自己紹介
    • 徳丸 翔平(@shohei36)
    • 普段の業務では主にJavaやGoを使ってバックエンド開発をやってます
    • Go歴はもう少しで1年といったところ
    • 低レイヤーに興味あり

    View Slide

  3. モノリスからマイクロサービスへ
    https://acropolium.com/blog/migrating-monolith-to-microservices/

    View Slide

  4. マルチテナントのデータベース戦略
    https://medium.com/one9-tech/which-database-structure-to-
    use-in-multi-tenant-application-6f1b9af09634

    View Slide

  5. マルチテナントのデータベース戦略
    https://medium.com/one9-tech/which-database-structure-to-
    use-in-multi-tenant-application-6f1b9af09634

    View Slide

  6. データベース の Row-Level Security(RLS)機能
    データの読み込み時にテーブルの行レベルでアクセスを制御するデータベースの機能
    テナントID ID NAME
    tenant01 1000 Bob
    tenant02 1000 Alice
    tenant03 1000 Taro
    tenant03 1000 Hanako
    SELECT
    ID, NAME
    FROM SOME_TABLE
    WHERE ID = ‘1000’ 「tenant02」が接続

    View Slide

  7. プログラム側も工夫が必要…
    🤔 RLSが効いたコネクションを正しく制御するには?
    🤔 DBに依存せずにトランザクションをどのように表現するか?
    🤔 テナント追加時の作業をゼロにしたい、、

    View Slide

  8. プログラム設計方針
    以下のアプローチによって実現
    • データベースセッションの環境変数にセットしたテナントIDでアク
    セス権を制御
    • Context 経由で sql.Tx を リポジトリ にパスする

    View Slide

  9. プログラム設計方針
    以下のアプローチによって実現
    • データベースセッションの環境変数にセットしたテナントIDでアク
    セス権を制御
    • Context 経由で sql.Tx を リポジトリ にパスする
    こちらのサンプルコードを使用して説明します
    https://github.com/shohei36/go-rls

    View Slide

  10. 環境
    • WSL2 Ubuntu 20.04 on Windows
    • PostgreSQL 13.2
    • Go 1.20

    View Slide

  11. サンプルコードの構成
    // アプリケーション固有のビジネスルール
    // トランザクション
    // DBなど外部システムとのアダプター
    // ドメインモデル
    // Main関数(controllerも兼ねる)
    ※サンプルコードの構成
    Clean Architecture

    View Slide

  12. 例)会員情報を更新するユースケース

    View Slide

  13. 登場人物

    View Slide

  14. DoInTxを実行
    usecase.go

    View Slide

  15. sql.DB からコネクション(sql.Conn)を取得
    transaction.go
    db.go

    View Slide

  16. DBセッションの環境変数にテナントIDをセット
    db.go

    View Slide

  17. 補足:テーブルにRLSを適用するDDL
    pgsql/init/001_ddl.sql

    View Slide

  18. sql.DBのコネクションはスレッドセーフ
    sql.DB の仕組み
    https://please-sleep.cou929.nu/go-sql-db-connection-pool.html
    公式ドキュメント
    https://pkg.go.dev/database/sql#DB

    View Slide

  19. トランザクション(sql.Tx)開始
    transaction.go DoInTx

    View Slide

  20. Context に sql.Tx をセット
    transaction.go DoInTx
    Sql.Tx を取り出すときに使うKey

    View Slide

  21. トランザクション内の処理を実行
    transaction.go DoInTx
    usecase.go

    View Slide

  22. リポジトリのUpdateメソッドをCall
    usecase.go

    View Slide

  23. DoInTx内でContextにセットしたsql.Txを取得
    transaction.go
    repository.go

    View Slide

  24. Update文を発行
    repository.go
    ※RLSが効いているので、SQLのWhereの条件にtenant_idは不要

    View Slide

  25. トランザクションをコミット
    transaction.go DoInTx

    View Slide

  26. コネクションをsql.DBに返却
    transaction.go DoInTx
    https://pkg.go.dev/database/sql#Conn.Close

    View Slide

  27. まとめ
    • Context経由でsql.Txを渡すことで、DBに依存しない形でユースケースで
    トランザクションの定義が可能に
    • 参考:https://qiita.com/arkuchy/items/659a11767912c2ec266d
    • データベースセッションの環境変数にセットしたテナントIDでアクセス権
    を制御
    • テナントのロールを追加する必要がなく、基本的にはテナント追加時の作業が不要
    • sql.DBで管理するコネクションがスレッドセーフ
    • (感想)Goはマイクロサービス向きの言語であることを実感

    View Slide

  28. Thank you for listening!

    View Slide