Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
NestJS + Prisma2 で歩む RLS の世界
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
ynaka81
May 20, 2022
Technology
1.2k
2
Share
NestJS + Prisma2 で歩む RLS の世界
NestJS meetup Online #2 登壇資料
https://nest-jp.connpass.com/event/244015/
ynaka81
May 20, 2022
Other Decks in Technology
See All in Technology
不確実性と戦いながら見積もりを作成するプロセス/mitsumori-process
hirodragon112
1
190
ふりかえりを 「あそび」にしたら、 学習が勝手に進んだ / Playful Retros Drive Learning
katoaz
0
190
"まず試す"ためのDatabricks Apps活用法 / Databricks Apps for Early Experiments and Validation
nttcom
1
170
レガシーシステムをどう次世代に受け継ぐか
tachiiri
0
270
ADOTで始めるサーバレスアーキテクチャのオブザーバビリティ
alchemy1115
2
180
自分をひらくと次のチャレンジの敷居が下がる
sudoakiy
5
1.9k
プロダクトを育てるように生成AIによる開発プロセスを育てよう
kakehashi
PRO
1
750
Cortex Code君、今日から内製化支援担当ね。
coco_se
0
280
Oracle AI Database@Azure:サービス概要のご紹介
oracle4engineer
PRO
6
1.4k
BIツール「Omni」の紹介 @Snowflake中部UG
sagara
0
210
GitHub Advanced Security × Defender for Cloudで開発とSecOpsのサイロを超える: コードとクラウドをつなぐ、開発プラットフォームのセキュリティ
yuriemori
1
130
Podcast配信で広がったアウトプットの輪~70人と音声発信してきた7年間~/outputconf_01
fortegp05
0
230
Featured
See All Featured
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.2k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
150
A Modern Web Designer's Workflow
chriscoyier
698
190k
Darren the Foodie - Storyboard
khoart
PRO
3
3.1k
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
470
Typedesign – Prime Four
hannesfritz
42
3k
Optimising Largest Contentful Paint
csswizardry
37
3.6k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.1k
First, design no harm
axbom
PRO
2
1.2k
Amusing Abliteration
ianozsvald
1
150
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
120
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Transcript
中川 裕太 @ Beatrust SRE NestJS + Prisma2 で歩む RLS
の世界
今日の登壇内容 Today's topic 去年のちょうど今頃に運用を始めた NestJS + Prisma2 による RLS 適用の後日談です
※ 資料に載せているコードは概念的な簡易コードなのでそのままでは動きません
Agenda RLS とは NestJS + Prisma2 による RLS 実装 性能問題
の改善 1 2 3
2020年12月に Beatrust にジョイン 運用がラクにできるように色々と改善したり、セキュリティ 向上したり、インフラ作ったり API 開発したりしています 中川 裕太 Yuta
Nakagawa SRE & Tech Lead @ Beatrust @ynakaSoftTennis 社員インタビュー https://note.com/beatrust/n/n24ac6848907b
Beatrust は、会社や組織のなかで いっしょに働く人のことをもっと知り、助け合い、 そして協業しやすい状態を実現するための タレントコラボレーション プラットフォームです。 Beatrust が提供しているサービス What we
do
創業以来のユーザー数の推移 Growth 2020 年 3 月 Beatrust 創業 2021 年
1 月 1,000 名突破 2021 年 10 月 10,000 名突破 2022 年 3 月 15,000 名突破 2020 年 3 月に創業して以来、 1 年間で 1,000 名、 2 年間で 15,000 名 のユーザーに ご利用をいただいています。 ※ 2020 年 3 月から 2022 年 3 月までに Beatrust に登録された累積ユーザー数です。
導入企業とケーススタディの例 Customer stories すでに日本を代表とする大企業での導入事例があり、実際の従業員による協業・活用事例が生まれています。 普段社内の他部門を支援させていただく仕事を担当 していますが、そうした日常業務の中で、実際に Beatrust が役に立ち始めています。 生産性技術革新部 ビジネスプロセス支援グループ
ご担当者様 自分一人で悶々としているよりは話を聞いてもらっ てアドバイスをもらうことで気持ちを切り替えるこ とが大事だと強く実感できました。 ビジネス開発センター ビジネスインキュベーショ ン ご担当者様 社内にはまだ一度もお会いしたり、仕事をご一緒し たことのない方も多くいらっしゃいますが、少しで も人となりを知ることができ、心構えができて仕事 がしやすくなっています。 事業管理本部FHR・購買部 ご担当者様 国内総合証券会社 不動産デベロッパー コワーキングスペース 大手製薬メーカー 大手通信会社 大手自動車メーカー ほか、数多くの導入・トライアル実績(2022 年 4 月現在) 医療機器メーカー 大手通信機器メーカー 大手広告代理店 システムインテグレーター
RLS とは NestJS + Prisma2 による RLS 実装 性能問題 の改善
1 2 3
Multi-tenant in 1 database 1 tenant in 1 database 1
tenant in 1 instance database structure system cost migration cost security Multi-tenant でのデータベース構成
Multi-tenant in 1 database 1 tenant in 1 database 1
tenant in 1 instance database structure system cost migration cost security コストの観点から multi-tenant in 1 database を採用
アプリケーション側で tenant を WHERE 句で指定する必要がある
ダルいしミスも発生しやすい
そこで Row Level Security (RLS) PostgreSQL NestJS
ALTER TABLE "User" ENABLE ROW LEVEL SECURITY; CREATE POLICY "UserIsolationPolicy"
ON "User" USING ( "tenantId" = current_setting('app.current_tenant') ); 事前に table 単位でデータアクセスに対するポリシーを定義 PostgreSQL NestJS
実行時設定パラメータ に tenant id を指定 SET app.current_tenant = {tenant_id}; PostgreSQL
NestJS
事前定義したポリシーが正になるデータだけ取得 PostgreSQL NestJS User WHERE "tenantId" = current_setting('app.current_tenant')
アプリケーション側だけでなく DB レイヤーである種の WHERE 句をかけられる
tenant を指定しないとデータ取得できないので fail safe な作りになる
RLS とは 性能問題 の改善 1 3 NestJS + Prisma2 による
RLS 実装 2
リクエストごとに独立したコネクションを張り tenant id を設定する PostgreSQL NestJS Client Side Prisma 2
tenant 情報をリクエストの JWT から取得 PostgreSQL NestJS Client Side Prisma 2
tenant in JWT
新規にコネクションを張り tenant id を設定 PostgreSQL NestJS Client Side Prisma 2
SET app.current_tenant = {tenant_id};
tenant id に従ったデータを取得 PostgreSQL NestJS Client Side Prisma 2 User
WHERE "tenantId" = current_setting('app.current_tenant')
Client にデータを返すと同時にコネクションをクローズ PostgreSQL NestJS Client Side Prisma 2 User data
Close connection
これをどう NestJS + Prisma 2 で実装しているか
PostgreSQL NestJS Client Side Prisma 2 MW NestJS の Middleware
と Interceptor で実装 Interceptor
PostgreSQL NestJS Client Side Prisma 2 MW Middleware で Request
Scope の ContextService に情報を格納 Interceptor this.contextService.set('tenantId', jwt.tenantId)
PostgreSQL NestJS Client Side Prisma 2 MW Prisma 2 の
Middleware を使って各クエリの前に SET を実行 Interceptor @Injectable({ scope: Scope.REQUEST }) export class PrismaService extends PrismaClient { constructor(private readonly contextService: ContextService) { this.$use(async (params, next) => { const tenantId = this.contextService.get('tenantId'); await this.$executeRaw(`SET app.current_tenant='${tenantId}';`); return next(params); }); } }
PostgreSQL NestJS Client Side Prisma 2 MW 最後に Interceptor でコネクションをクローズする
Interceptor @Injectable({ scope: Scope.REQUEST }) export class PrismaInterceptor implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler<any>): Observable<any> { return next.handle().pipe( finalize(() => this.prisma.$disconnect()) ); } }
RLS とは NestJS + Prisma2 による RLS 実装 1 2
性能問題 の改善 3
RLS 適用してから数ヶ月は順調に運用できていました
が
次第に明らかになる性能問題...
アクセスが集中すると異常に遅くなる
何が起きていたのか PostgreSQL NestJS Client Side Prisma 2
コネクションを張る度に Query Engine のプロセスが立ち上がる PostgreSQL NestJS Client Side Prisma 2
Query Engine ※ Prisma 3 ならデフォルトで Node-API Library として動作するので問題化はしない可能性は高いです
プロセスなので当然実行時間は遅く全体に対して支配的 PostgreSQL NestJS Client Side Prisma 2 Query Engine <
100msec > 500msec
そこで
Query Engine でちゃんとコネクションプーリングするように変更 PostgreSQL NestJS Client Side Prisma 2 Query
Engine
つまり
Prisma 2 の Client をグローバルなシングルトンとして実装 PostgreSQL NestJS Client Side Global
Prisma 2 Query Engine MW Req Prisma 2
Request Scope の Client はメソッドをパススルー + RLS PostgreSQL NestJS Client
Side Global Prisma 2 Query Engine MW Req Prisma 2 constructor(conf?: RlsConfig) { this.user.findUnique = this._rebuildQueryMethod( client.user.findUnique ); } private _rebuildQueryMethod(method: Function) { return (client .$transaction([ this.$executeRaw( `SET app.current_tenant='${tenantId}';` ), Reflect.apply(method, client, args), this.$executeRaw( `SET app.current_tenant='';` ), ]) .then((results) => results[1])); };
tenant 情報は同様に Middleware で JWT から取得 PostgreSQL NestJS Client Side
Global Prisma 2 Query Engine MW Req Prisma 2 this.contextService.set('tenantId', jwt.tenantId)
10倍近い latency の改善
まとめ Today's summary NestJS の Request Scope を使うことで リクエストごとのRLS を実装しセキュアなデータ操作を実現
2 3 1 性能問題は発生したが Prisma 2 が推奨するグローバルなシングルトンを作ることで解決 ちょっと強引な方法でも フレームワークの思想にそった実装をするのが大事
Beatrust on note Beatrust techBlog Beatrust のオフィシャルメディア Our official media
Twitter @jp_beatrust Facebook LinkedIn note.com/beatrust 社員のバックグラウンドや、 働き方に関する記事をアップデート しています。 tech.beatrust.com Beatrust の開発者チームによる取り 組みと技術に込めた想いを掲載して いる開発者ブログです。 Beatrust のメンバーに関する記事、開発メンバーの取り組み、最新ニュースリリースなどを随時更新しています。 facebook.com/beatrust.official linkedin.com/company/beatrust