Row Level Securityはマルチテナントの銀の弾丸になりうるのか / Row Level Security is silver bullet for multitenancy?

D68ec2463959a924ada156a278743228?s=47 yudppp
August 31, 2019

Row Level Securityはマルチテナントの銀の弾丸になりうるのか / Row Level Security is silver bullet for multitenancy?

builderscon 2019の発表資料です

D68ec2463959a924ada156a278743228?s=128

yudppp

August 31, 2019
Tweet

Transcript

  1. RowLevelSecurityは マルチテナントの 銀の弾丸になりうるのか #builderscon 2019 (20 min)

  2. ⾃⼰紹介 @yudppp 株式会社HRBrain CTO 好きな⾔葉: 冪等性 Go / TypeScript /

    React ◦△□ - https://blog.yudppp.com/ いつかSaaSのDevカンファレンス開くのが夢
  3. ⽬標評価管理クラウド

  4. 導⼊企業500社以上の HRTechのSaaSを 週2リリースのペースで 運⽤・改善を ⾏なっています。

  5. テナントとは • SaaSを利⽤する組織の単位のこと • HRBrainだと企業のこと • HRBrainだと企業の中にユーザーがいる • テナント間でのデータをやりとりはしない

  6. SaaSのアーキテクチャ

  7. アーキテクチャ • シングルテナントアーキテクチャ(ASP) • マルチテナントアーキテクチャ(SaaS)

  8. シングルテナントアーキテクチャ اۀ" اۀ# اۀ$ اۀ"޲͚
 "1αʔόʔ اۀ"޲͚
 %# اۀ"޲͚
 Πϯϑϥ

    اۀ#޲͚
 "1αʔόʔ اۀ#޲͚
 %# اۀ#޲͚
 Πϯϑϥ اۀ$޲͚
 "1αʔόʔ اۀ$޲͚
 %# اۀ$޲͚
 Πϯϑϥ
  9. シングルテナントのメリット • ⽐較的安全 • 特定のテナントでアクセスが増えても場合に 他の会社は影響を受けない • DB障害時の影響範囲がテナントごとになる

  10. シングルテナントのデメリット • サーバーが完全に分かれているのでデプロイ をテナントごとに⾏う必要がある • テナントごとにサーバーを⽤意するためコス トがかかる • 単価がすごく⾼く、リリース頻度が少ないも のであれば成り⽴つ

  11. マルチテナントとは • ⼀つのシステムで複数利⽤者組織の情報やア プリケーションを管理すること ࢀߟ4BB4޲͚4-"ΨΠυϥΠϯܦࡁ࢈ۀল IUUQXBSQEBOEMHPKQJOGPOEMKQQJEXXXNFUJHPKQDPNNJUUFFNBUFSJBMTEPXOMPBEpMFTHDKQEG

  12. マルチテナントアーキテクチャの種類 • クラウド内での単純な仮想化により、ハード ウェアのみを共有 • 1つのアプリケーションで、テナントごとに 異なるデータベースを使⽤ • 1つのアプリケーションでデータベースを共 有

    (最も効率的な真のマルチテナンシー) ࢀߟ8FCΞϓϦέʔγϣϯΛϚϧνςφϯτܕ4BB4ιϦϡʔγϣϯʹม׵͢Δ IUUQTXXXJCNDPNEFWFMPQFSXPSLTKQDMPVEMJCSBSZDMNVMUJUFOBOUTBBTJOEFYIUNM
  13. 1つのクラウドサーバーに全ての企業 اۀ" اۀ# اۀ$ اۀ"޲͚
 "1αʔόʔ اۀ"޲͚
 %# اۀ#޲͚
 "1αʔόʔ

    اۀ#޲͚
 %# اۀ$޲͚
 "1αʔόʔ اۀ$޲͚
 %#
  14. 1つのクラウドサーバーに全ての企業のメリット • 1テナントごとのスケールはしやすい • アプリケーションのリリースがテナントごと にできる(テナントごとに異なるVersionのア プリケーションがありえる) • 特定のテナントでアクセスが増えても場合に 他の会社は影響を受けにくい

  15. 1つのクラウドサーバーに全ての企業のデメリット • テナントごとにアプリケーションサーバーや データベースを個別に⽤意する必要がありコ ストが⾼い • デプロイをテナントごとに⾏う必要がある。 • こちらをシングルアーキテクチャに含めてし まう場合もある

  16. 1つのアプリケーションで異なるDBを使⽤ اۀ" اۀ# اۀ$ اۀ"޲͚
 %# "1αʔόʔ اۀ#޲͚
 %# اۀ$޲͚


    %#
  17. • 物理データベースは1つで論理データベース を分けているケースが多そう • アプリケーションは全てのテナントで同じ サーバーを利⽤する • DBを⽔平分割している状態に近いのでDB⽬ 線ではスケールさせやすい 1つのアプリケーションで異なるDBを使⽤のメリット

  18. • DBのスキーマ変更のマイグレーションをテナ ントごとに⾏う必要がある 1つのアプリケーションで異なるDBを使⽤のデメリット

  19. 1 つのアプリケーションでDBを共有 اۀ" اۀ# اۀ$ "1αʔόʔ %#

  20. • 最も効率的な真のマルチテナンシー • スキーマの変更のマイグレーションの更新が ⼀回で済む • インフラコストが⼀番安くなる 1 つのアプリケーションでDBを共有のメリット

  21. • DBに障害が起きた時に全テナントが影響を受 ける • アプリケーションが複雑になりやすい • セキュリティに不安がある 1 つのアプリケーションでDBを共有のデメリット

  22. どんな不安があるのか • あるテナントが別のテナントのデータを⾒れ てしまう可能性がある(data violation)

  23. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ こんな感じのusersテーブルがあった時に

  24. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ 本来Where句を指定するところを 4&-&$5 '30.VTFST
 8)&3&UFOBOU@JElձࣾ#z

  25. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ 本来Where句を指定するところを 4&-&$5 '30.VTFST
 8)&3&UFOBOU@JElձࣾ#z

  26. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ Where句を指定忘れてしまうと 4&-&$5 '30.VTFST

  27. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ Where句を指定忘れてしまうと 4&-&$5 '30.VTFST ΋ͪΖΜ શͯͷձࣾͷ ϝϯόʔ৘ใ͕

    औΕͯ͠·͏
  28. 複雑なアプリケーションになると 絶対起きないとはいえない

  29. これらのメリデメを受けて 弊社のケースについて考える

  30. 導⼊企業500社以上の HRTechのSaaSを 週2リリースのペースで 運⽤・改善を ⾏なっています。 弊社のケース(再訂)

  31. ビジネスモデル的に 100社導⼊しただけでは 会社が成り⽴たない

  32. マルチテナントアーキテクチャ(再訂) • クラウド内での単純な仮想化により、ハード ウェアのみを共有 • 1つのアプリケーションで、テナントごとに 異なるデータベースを使⽤ • 1つのアプリケーションでデータベースを共 有

    (最も効率的な真のマルチテナンシー)
  33. リリース後も 継続的に機能追加によって スキーマ変更が必要に なることがわかっていた

  34. マルチテナントアーキテクチャ(再訂) • クラウド内での単純な仮想化により、ハード ウェアのみを共有 • 1つのアプリケーションで、テナントごとに 異なるデータベースを使⽤ • 1つのアプリケーションでデータベースを共 有

    (最も効率的な真のマルチテナンシー)
  35. ⽬標や評価の情報は もちろんとても⼤事
 (⽬標が他の会社に漏れたら⼤問題)

  36. マルチテナントアーキテクチャ(再訂) • クラウド内での単純な仮想化により、ハード ウェアのみを共有 • 1つのアプリケーションで、テナントごとに 異なるデータベースを使⽤ • 1つのアプリケーションでデータベースを共 有

    (最も効率的な真のマルチテナンシー)
  37. 全ての選択肢が なくなってしまった、、、

  38. 何かを犠牲にするしか、、

  39. 事例について 調べて⾒た

  40. Bit Journeyさん • apartment gemを利⽤ • 1つのアプリケーションで、テナントごとに 異なるデータベースを使⽤した場合に便利に なるライブラリー? ࢀߟSBJMTENͰϚϧνςφϯτɾ΢ΣϒΞϓϦͷ࿩Λ͠·ͨ͠

    IUUQTHGYIBUFOBCMPHDPNFOUSZ
  41. SmartHRさん • apartment gemからCitus Cloud(DBaaS)へ移 ⾏ • マイグレーションは⾟くなりがち • なるほど:thinking:

    ࢀߟͭΒ͘ͳ͍ϚϧνςφϯγʔΛٻΊͯશͯݟͤ·͢ʂ4NBSU)3σʔλϕʔεҠߦϓϩδΣΫτͷཪଆ IUUQTTQFBLFSEFDLDPNQVSJOUBJCVJMEFSTDPO
  42. Viewを使ってマルチテナントを実現する⽅法 • 最も効率的な真のマルチテナンシーをViewを使って実現 する • テナント×テーブルごとにViewを作り権限管理を⾏う。 • SELECT/UPDATE/DELETEに対してはViewから⾏う • INSERTはオリジナルのテーブルに⾏う必要があり安全

    かどうかはアプリケーションの実装依存になってしま う。
  43. 他にも⾊んな⼈に聞いたり、 調べたりしているうちに ⾒つけた

  44. 我らの銀の弾丸

  45. Row Level Security

  46. Row Level Securityとは • データベーステーブル内の⾏へのアクセスを 制御できる • OracleやPostgreSQL(9.5以上)やSQL Server(13.x以上) などで実装されている

    • (以降RLSとする。)
  47. 権限ごとにRoleを作って ୅දऔక໾ Ϧʔμʔ ϝϯόʔ શͯݟ͑Δਓ ࣗ෼ͷ νʔϜϝϯόʔͷΈ ݟ͑Δਓ ࣗ෼ͷ৘ใͷΈ ݟ͑Δਓ

  48. ୅දऔక໾ ։ൃϦʔμʔ ։ൃϝϯόʔ Ӧۀ こんな感じのusersテーブルがあった時に

  49. ୅දऔక໾ Ӧۀ 代表取締役のロールでアクセスすると 4&-&$5 '30.VTFST ։ൃϦʔμʔ ։ൃϝϯόʔ

  50. ୅දऔక໾ Ӧۀ 代表取締役のロールでアクセスすると શͯݟ͑Δ 4&-&$5 '30.VTFST ։ൃϦʔμʔ ։ൃϝϯόʔ

  51. ୅දऔక໾ Ӧۀ 開発リーダーのロールでアクセスすると 4&-&$5 '30.VTFST ։ൃϦʔμʔ ։ൃϝϯόʔ

  52. ୅දऔక໾ Ӧۀ 開発リーダーのロールでアクセスすると ։ൃϝϯόʔͷ ৘ใͷΈݟ͑Δ 4&-&$5 '30.VTFST ։ൃϦʔμʔ ։ൃϝϯόʔ

  53. 雑なQuery叩いても
 権限範囲のデータしか ⾒えなくて安全

  54. マルチテナントに応⽤していく

  55. テナントごとにRoleを作る اۀ" اۀ"ͷ৘ใͷΈ ݟ͑Δ اۀ# اۀ#ͷ৘ใͷΈ ݟ͑Δ اۀ$ اۀ$ͷ৘ใͷΈ ݟ͑Δ

  56. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ こんな感じのusersテーブルがあった時に

  57. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ 会社Bのロールでアクセスすると 4&-&$5 '30.VTFST

  58. ձࣾ" ձࣾ# ձࣾ# ձࣾ$ 会社Bのロールでアクセスすると 4&-&$5 '30.VTFST ձࣾ#ͷϝϯόʔͷ ৘ใͷΈݟ͑Δ

  59. これは安⼼!

  60. Tableの実体⾃体は 全てのテナントで共通なので マイグレーションも楽々

  61. 実際に導⼊してみました (PostgreSQL v10.4)

  62. 最初の実装や検証が ⼤変そうだったけど なんとか導⼊しました。
 (リリース三ヶ⽉前に⾃分以外のメンバーが1ヶ⽉くらいで諸々対応してくれた記憶)

  63. どうやっているか① • 全てのテーブルにcompany_idのカラムを⽤意 • サブドメインをテナントごとに追加する • Ex) mosquitone.hrbrain.jp

  64. どうやっているか② • テナントごとにロールを⽤意 • RLSを利⽤するテーブルに下記のPolicyを追加 • テナントごとに別のコネクションを使う

  65. そしてリリース1ヶ⽉半前

  66. ⼤量のデータを⼊れて 確認していた時に 問題が発覚した

  67. GET /usersheets 1.8[sec]

  68. pprofで諸々確認
 (GoのPeformance計測ツール)

  69. DBアクセスしている層が 想定より数倍遅い

  70. :thinking:

  71. ⼀度試しにRLSを 使わないでみたら

  72. レイテンシーが4分の1に

  73. RLSを⼊れたことによって 起きていることはわかった

  74. ただ安全第⼀
 RLSをやめる訳にはいかない

  75. N+1とIndex周りの修正をして 1秒以内にできたのでリリース

  76. ただし根本解決はされないまま

  77. リリース後の落ち着いた タイミングで再挑戦

  78. 検証結果

  79. コネクションの使い⽅ • RLSを利⽤していない時は全てのコネクショ ンプールをまとめて管理していた。 • RLSを利⽤時はテナントごとにロールを作っ ていた結果、コネクション管理が煩雑になっ ていて、そこでオーバーヘッドが⽣じてい た。

  80. リクエストごとにコネクションを張るように変更 • Middlewareでコネクションを発⾏して、 contextに詰める(本当はcontext使いたくない) • リクエストの終了時にClose

  81. リクエストごとにコネクション貼ってみた結果 • 遅かった特定のAPIで調査 • 中央値、平均値を⾒る限りすごく速くなった。 • 速くなったが詰まる時は詰まってそう。 NFBO λΠϧ λΠϧ

    λΠϧ NBY #FGPSF NT NT NT NT T "GUFS NT NT NT NT NT
  82. テナントごとのロールについて • RLSを適応したい全てのテーブルに下記のような POLICYを追加していた。 • current_userを⽤いて、dbのユーザーをどの⾏に 対して権限があるかを判断していた。

  83. Indexについて • テーブルに下記のUNIQUE INDEXを貼っていた • リクエスト⾃体は • 叩いた時にindexが効いていなかった。

  84. EXPLAIN結果 • 全件検索してからFilterしている、、

  85. EXPLAIN結果 • company_idを必ずつけるようにすれば問題起きなかった。

  86. USINGしている中⾝がよくない • ロール名に直接company_idではなく prefixをつけていたそのせいで⾃動で INDEX効いていなかった • もともと数字だけでやろうとしていたが ロール名に数字始まりはInvalidだった。

  87. ロールの作り⽅を変更した • 下記のようにcurrent_settingを利⽤したPOLICYを 作成すればテナントごとのロールが不要だった。 • またこの場合はリクエストごとに予めテナントを セットしておく必要がある

  88. EXPLAIN結果 • ちゃんとINDEXかかった! • どちらにしてもcompany_id始まりのINDEXを貼るべき

  89. クエリーパフォーマンス • ある簡単なAPIを並列で実⾏した時に1.4倍くらい時間 がかかるようになっていた λΠϧ λΠϧ λΠϧ 3-4ͳ͠ NT NT

    NT 3-4͋Γ NT NT NT
  90. 結論

  91. 銀の弾丸ではなかった。

  92. マルチテナントにRLSを使うメリット • 安全に「最も効率的な真のマルチテナン シー」が実現できた。

  93. マルチテナントにRLSを使うデメリット • コネクションの管理が煩雑になってしまっ た。 • パフォーマンスが多少悪くなる。 • 導⼊事例が少なく検証しないとわからないこ とが多い。

  94. この先使う上での不安事項 • DBを⽔平分割していく必要が出た場合にどうするか • マイクロサービスにしてDBも垂直分割していく想 定はあるが、それでも増えた時にどうするか • 今利⽤されている⼈数の10倍、20倍のテナントが ⼊ってきた場合に問題なくRLSが動くのか •

    テナントをまたがるユーザーを作りたくなった時にど うするか
  95. まとめ • SaaS作る時にパフォーマンスをそこまでシビ アに作る必要がないものを安全に作りたいの であればオススメ • データが増えた時にまた別の対策が必要

  96. 参考資料 • SaaS 向け SLA ガイドライン - 経済産業省 (http://warp.da.ndl.go.jp/info:ndljp/pid/ 11094748/www.meti.go.jp/committee/materials/downloadfiles/g80207c05j.pdf)

    • マルチテナント SaaS データベース テナント パターン(https://docs.microsoft.com/ja- jp/azure/sql-database/saas-tenancy-app-design-patterns) • Web アプリケーションをマルチテナント型 SaaS ソリューションに変換する(https:// www.ibm.com/developerworks/jp/cloud/library/cl-multitenantsaas/index.html) • PostgreSQL: Documentation: 11: 5.7. Row Security Policies (https:// www.postgresql.org/docs/current/ddl-rowsecurity.html) • PostgreSQLのRow Level Securityを使ってマルチテナントデータを安全に扱う - HRBrain blog (https://times.hrbrain.co.jp/entry/postgresql-row-level-security)