Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

⾃⼰紹介 @yudppp 株式会社HRBrain CTO 好きな⾔葉: 冪等性 Go / TypeScript / React ○△□ - https://blog.yudppp.com/ いつかSaaSのDevカンファレンス開くのが夢

Slide 3

Slide 3 text

⽬標評価管理クラウド

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

SaaSのアーキテクチャ

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

シングルテナントのメリット • ⽐較的安全 • 特定のテナントでアクセスが増えても場合に 他の会社は影響を受けない • DB障害時の影響範囲がテナントごとになる

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

マルチテナントアーキテクチャの種類 • クラウド内での単純な仮想化により、ハード ウェアのみを共有 • 1つのアプリケーションで、テナントごとに 異なるデータベースを使⽤ • 1つのアプリケーションでデータベースを共 有 (最も効率的な真のマルチテナンシー) ࢀߟ8FCΞϓϦέʔγϣϯΛϚϧνςφϯτܕ4BB4ιϦϡʔγϣϯʹม׵͢Δ IUUQTXXXJCNDPNEFWFMPQFSXPSLTKQDMPVEMJCSBSZDMNVMUJUFOBOUTBBTJOEFYIUNM

Slide 13

Slide 13 text

1つのクラウドサーバーに全ての企業 اۀ" اۀ# اۀ$ اۀ"޲͚
 "1αʔόʔ اۀ"޲͚
 %# اۀ#޲͚
 "1αʔόʔ اۀ#޲͚
 %# اۀ$޲͚
 "1αʔόʔ اۀ$޲͚
 %#

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

複雑なアプリケーションになると 絶対起きないとはいえない

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

リリース後も 継続的に機能追加によって スキーマ変更が必要に なることがわかっていた

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

⽬標や評価の情報は もちろんとても⼤事
 (⽬標が他の会社に漏れたら⼤問題)

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

全ての選択肢が なくなってしまった、、、

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

事例について 調べて⾒た

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

SmartHRさん • apartment gemからCitus Cloud(DBaaS)へ移 ⾏ • マイグレーションは⾟くなりがち • なるほど:thinking: ࢀߟͭΒ͘ͳ͍ϚϧνςφϯγʔΛٻΊͯશͯݟͤ·͢ʂ4NBSU)3σʔλϕʔεҠߦϓϩδΣΫτͷཪଆ IUUQTTQFBLFSEFDLDPNQVSJOUBJCVJMEFSTDPO

Slide 42

Slide 42 text

Viewを使ってマルチテナントを実現する⽅法 • 最も効率的な真のマルチテナンシーをViewを使って実現 する • テナント×テーブルごとにViewを作り権限管理を⾏う。 • SELECT/UPDATE/DELETEに対してはViewから⾏う • INSERTはオリジナルのテーブルに⾏う必要があり安全 かどうかはアプリケーションの実装依存になってしま う。

Slide 43

Slide 43 text

他にも⾊んな⼈に聞いたり、 調べたりしているうちに ⾒つけた

Slide 44

Slide 44 text

我らの銀の弾丸

Slide 45

Slide 45 text

Row Level Security

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

権限ごとにRoleを作って ୅දऔక໾ Ϧʔμʔ ϝϯόʔ શͯݟ͑Δਓ ࣗ෼ͷ νʔϜϝϯόʔͷΈ ݟ͑Δਓ ࣗ෼ͷ৘ใͷΈ ݟ͑Δਓ

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

これは安⼼!

Slide 60

Slide 60 text

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

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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

Slide 63

Slide 63 text

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

Slide 64

Slide 64 text

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

Slide 65

Slide 65 text

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

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

GET /usersheets 1.8[sec]

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

:thinking:

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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

Slide 75

Slide 75 text

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

Slide 76

Slide 76 text

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

Slide 77

Slide 77 text

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

Slide 78

Slide 78 text

検証結果

Slide 79

Slide 79 text

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

Slide 80

Slide 80 text

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

Slide 81

Slide 81 text

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

Slide 82

Slide 82 text

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

Slide 83

Slide 83 text

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

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

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

Slide 87

Slide 87 text

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

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

結論

Slide 91

Slide 91 text

銀の弾丸ではなかった。

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

まとめ • SaaS作る時にパフォーマンスをそこまでシビ アに作る必要がないものを安全に作りたいの であればオススメ • データが増えた時にまた別の対策が必要

Slide 96

Slide 96 text

参考資料 • 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)