๋ฉํฐํ ๋ํธ ์ฑ์ ์ํ PostgreSQL ํ ์์ค ๋ณด์ ํจํด
ํ ๋ํธ ๊ฒฉ๋ฆฌ์ ์ญํ ๊ท์น์ ์ํ ์ค์ฉ์ ํจํด์ผ๋ก PostgreSQL ํ ์์ค ๋ณด์(RLS)์ ๋ฐฐ์ฐ๊ณ , ์ ๊ทผ ์ ์ด๋ฅผ ์ฑ์ด ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ ํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์ธ์.

๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐจ์์ ์ ๊ทผ ํต์ ๊ฐ ์ค์ํ ์ด์
๋น์ฆ๋์ค ์ฑ์๋ ๋ณดํต โ์ฌ์ฉ์๋ ์๊ธฐ ํ์ฌ์ ๋ฐ์ดํฐ๋ง ๋ณผ ์ ์์ด์ผ ํ๋คโ๊ฑฐ๋ โ๊ด๋ฆฌ์๋ง ํ๋ถ์ ์น์ธํ ์ ์๋คโ ๊ฐ์ ๊ท์น์ด ์์ต๋๋ค. ๋ง์ ํ์ด ์ด๋ฐ ๊ท์น์ UI๋ API์์๋ง ๊ฐ์ ํ๊ณ ๊ทธ๊ฒ์ผ๋ก ์ถฉ๋ถํ๋ค๊ณ ๊ฐ์ ํ์ฃ . ๋ฌธ์ ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฟ๋ ๊ฒฝ๋ก๊ฐ ํ๋ ๋ ๋์ด๋ ์๋ก ๋ฐ์ดํฐ ์ ์ถ ๊ฐ๋ฅ์ฑ์ด ์ปค์ง๋ค๋ ์ ์ ๋๋ค: ๋ด๋ถ ๊ด๋ฆฌ์ ๋๊ตฌ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์ก, ๋ถ์ ์ฟผ๋ฆฌ, ์ํ์ง ์๋ํฌ์ธํธ, ๋๋ ์ด๋ ํ ๊ฒ์ฌ(check)๋ฅผ ๋๋ฝํ๋ ๋ฒ๊ทธ ๋ฑ์ ๋๋ค.
ํ ๋ํธ ๊ฒฉ๋ฆฌ๋ ํ ๊ณ ๊ฐ(ํ ๋ํธ)์ด ์ค์๋ก๋ผ๋ ๋ค๋ฅธ ๊ณ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ฑฐ๋ ๋ณ๊ฒฝํ ์ ์๊ฒ ๋ง๋๋ ๊ฒ์ ๋ปํฉ๋๋ค. ์ญํ ๊ธฐ๋ฐ ์ ๊ทผ ์ ์ด๋ ๊ฐ์ ํ ๋ํธ ๋ด๋ถ์์๋ ์์ด์ ํธ, ๋งค๋์ , ์ฌ๋ฌด ๋ฑ ๊ถํ์ด ๋ค๋ฅธ ์ฌ๋๋ค์ ๊ตฌ๋ถํฉ๋๋ค. ์ด๋ฐ ๊ท์น์ ์ค๋ช ํ๊ธฐ๋ ์ฝ์ง๋ง, ์ฌ๋ฌ ๊ณณ์ ํฉ์ด์ ธ ์์ผ๋ฉด ์ผ๊ด๋๊ฒ ์ ์งํ๊ธฐ ์ด๋ ต์ต๋๋ค.
PostgreSQL์ ํ ์์ค ๋ณด์(RLS)์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ด๋ค ํ์ ๋ณผ ์ ์๊ณ ๋ณ๊ฒฝํ ์ ์๋์ง ๊ฒฐ์ ํ๊ฒ ํฉ๋๋ค. ์ฑ์ ๋ชจ๋ ์ฟผ๋ฆฌ๊ฐ ์ฌ๋ฐ๋ฅธ WHERE ์ ์ ๊ธฐ์ตํ๊ธฐ๋ฅผ ๊ธฐ๋ํ๋ ๋์ , ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ ์ฑ
์ ์๋์ผ๋ก ์ ์ฉํฉ๋๋ค.
RLS๊ฐ ๋ง๋ฅ ๋ฐฉํจ๋ ์๋๋๋ค. ์คํค๋ง ์ค๊ณ๋ ์ธ์ฆ์ ๋์ ํด์ฃผ์ง ์๊ณ , ์ด๋ฏธ ๊ฐ๋ ฅํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ถํ(์: superuser)์ ๊ฐ์ง ์ฌ๋์ ๋ง์์ฃผ์ง๋ ์์ต๋๋ค. ๋ํ ์ฝ๊ธฐ ์ ์ฑ ์ด ์๋๋ฐ ์ฐ๊ธฐ๋ง ํ์ฉ๋๋ ์์ ๋ ผ๋ฆฌ์ ์ค์๋ฅผ ๋ง์ผ๋ ค๋ฉด ์ฝ๊ธฐ์ ์ฐ๊ธฐ ๋ชจ๋์ ๋ํ ์ ์ฑ ์ ์์ฑํด์ผ ํฉ๋๋ค.
ํ์ง๋ง ์ป๋ ์ด์ ์ ๋ถ๋ช ํฉ๋๋ค:
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ๋ ๋ชจ๋ ์ฝ๋ ๊ฒฝ๋ก์ ๋ํด ํ ๋ฒ์ ๊ท์น์ ์ ์ฉ
- ์๋ก์ด ๊ธฐ๋ฅ ๋ฐฐํฌ ์ ๋ฐ์ํ๋ ์ค์ ๊ฐ์
- SQL์์ ์ ๊ทผ ๊ท์น์ ํ์ธํ ์ ์์ด ๊ฐ์ฌ๊ฐ ๋ช ํํด์ง
- API ๋ฒ๊ทธ๊ฐ ์ง๋์น ๋ ๋ ๊ฐํ ๋ฐฉ์ด์ ์ ๊ณต
์ค์ ๋น์ฉ์ ์์ง ์์ต๋๋ค. โ์ด ์ฌ์ฉ์๊ฐ ๋๊ตฌ์ธ์งโ์ โ์ด๋ค ํ ๋ํธ์ธ์งโ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ผ๊ด๋๊ฒ ์ ๋ฌํ๋ ๋ฐฉ์์ด ํ์ํ๊ณ , ์ฑ์ด ์ฑ์ฅํ ์๋ก ์ ์ฑ ์ ์ ์งํด์ผ ํฉ๋๋ค. SaaS๋ ๋ฏผ๊ฐํ ๊ณ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฃจ๋ ๋ด๋ถ ๋๊ตฌ๋ผ๋ฉด ํฌ์ ๋๋น ํจ๊ณผ๊ฐ ํฝ๋๋ค.
์ ๋ฌธ ์ฉ์ด ์์ด ๋ณด๋ ํ ์์ค ๋ณด์ ๊ธฐ์ด
ํ ์์ค ๋ณด์(RLS)์ ์ฟผ๋ฆฌ๊ฐ ๋ณผ ์ ์๊ฑฐ๋ ๋ณ๊ฒฝํ ์ ์๋ ํ์ ์๋์ผ๋ก ํํฐ๋งํฉ๋๋ค. ํ๋ฉด์ด๋ API, ๋ฆฌํฌํธ๊ฐ ๊ท์น์ ์ค์ค๋ก ๊ธฐ์ตํ๊ธฐ๋ฅผ ๊ธฐ๋ํ๋ ๋์ , ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๊ท์น์ ์ ์ฉํฉ๋๋ค.
PostgreSQL RLS์์๋ SELECT, INSERT, UPDATE, DELETE๋ง๋ค ๊ฒ์ฌ๋๋ ์ ์ฑ
์ ์์ฑํฉ๋๋ค. ์ ์ฑ
์ด โ์ด ์ฌ์ฉ์๋ ํ
๋ํธ A์ ํ๋ง ๋ณผ ์ ์๋คโ๊ณ ๋งํ๋ฉด, ์ํ ๊ด๋ฆฌ์ ํ์ด์ง๋ ์ ์ฟผ๋ฆฌ, ๊ธํ ํซํฝ์ค๋ ๊ฐ์ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
RLS๋ GRANT/REVOKE์ ๋ค๋ฆ
๋๋ค. GRANT๋ ํน์ ์ญํ ์ด ํ
์ด๋ธ์ ์ ๊ทผํ ์ ์๋์ง(๋๋ ํน์ ์ด์ ์ ๊ทผํ ์ ์๋์ง)๋ฅผ ๊ฒฐ์ ํ๊ณ , RLS๋ ๊ทธ ํ
์ด๋ธ ๋ด๋ถ์์ ์ด๋ค ํ์ ์ ๊ทผํ ์ ์๋์ง๋ฅผ ์ ํฉ๋๋ค. ๋ณดํต์ ๋์ ํจ๊ป ์๋๋ค: GRANT๋ก ํ
์ด๋ธ ์ ๊ทผ์ ์ ํํ๊ณ RLS๋ก ์ ๊ทผํ ์ ์๋ ํ์ ์ ํํฉ๋๋ค.
ํ์ค์์๋ ์ ์๋ํฉ๋๋ค. ๋ทฐ๋ ์ผ๋ฐ์ ์ผ๋ก RLS๋ฅผ ์ค์ํ๊ณ , ์กฐ์ธ๊ณผ ์๋ธ์ฟผ๋ฆฌ๋ ํํฐ๋ง๋๋ฏ๋ก ์ฌ์ฉ์๊ฐ ์กฐ์ธ์ ์ด์ฉํด ๋ค๋ฅธ ์ฌ๋์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์์ต๋๋ค. ์ ์ฑ ์ ์ด๋ค ํด๋ผ์ด์ธํธ๊ฐ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ ์ ์ฉ๋ฉ๋๋ค: ์ฑ ์ฝ๋, SQL ์ฝ์, ๋ฐฑ๊ทธ๋ผ์ด๋ ์ก, ๋ฆฌํฌํ ๋๊ตฌ ๋ฑ.
RLS๋ ํ ๋ํธ ๊ฒฉ๋ฆฌ๊ฐ ๊ฐํ๊ฒ ์๊ตฌ๋๊ฑฐ๋ ๋์ผํ ํ ์ด๋ธ์ ์ฌ๋ฌ ๋ฐฉ์์ผ๋ก ์กฐํํ๊ฑฐ๋ ๋ง์ ์ญํ ์ด ๊ฐ์ ํ ์ด๋ธ์ ๊ณต์ ํ๋ ํ๊ฒฝ(SaaS ๋ฐ ๋ด๋ถ ๋๊ตฌ)์ ์ ํฉํฉ๋๋ค. ๋จ์ผ ์ ๋ขฐ ๋ฐฑ์๋๋ง ์๋ ์์ ์ฑ์ด๋ ๋ฏผ๊ฐํ์ง ์์ ๋ฐ์ดํฐ์๋ ๊ณผํ ์ ์์ต๋๋ค. ๊ด๋ฆฌ์ ๋๊ตฌ, ๋ฐ์ดํฐ ์ถ์ถ, BI, ์คํฌ๋ฆฝํธ ๊ฐ์ ์ง์ ์ ์ด ํ๋๋ผ๋ ๋ํด์ง๋ฉด RLS๊ฐ ๋๊ฐ์ ํฉ๋๋ค.
ํ ๋ํธ, ์ญํ , ๋ฐ์ดํฐ ์์ ๊ถ์ ๋จผ์ ์ ๋ฆฌํ์ธ์
์ ์ฑ ์ ํ๋๋ ์์ฑํ๊ธฐ ์ ์ ๋๊ฐ ๋ฌด์์ ์์ ํ๋์ง ๋ช ํํ ํ์ธ์. PostgreSQL RLS๋ ๋ฐ์ดํฐ ๋ชจ๋ธ์ด ์ด๋ฏธ ํ ๋ํธ, ์ญํ , ์์ ๊ถ์ ๋ฐ์ํ๊ณ ์์ ๋ ๊ฐ์ฅ ์ ๋์ํฉ๋๋ค.
ํ
๋ํธ๋ถํฐ ์์ํ์ธ์. ๋๋ถ๋ถ์ SaaS ์ฑ์์ ๊ฐ์ฅ ๋จ์ํ ๊ท์น์: ๊ณ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ด๋ ๋ชจ๋ ๊ณต์ ํ
์ด๋ธ์๋ tenant_id๊ฐ ์๋ค์
๋๋ค. ์ธ๋ณด์ด์ค ๊ฐ์ ๋ช
๋ฐฑํ ํ
์ด๋ธ๋ฟ ์๋๋ผ ์ฒจ๋ถ ํ์ผ, ๋๊ธ, ๊ฐ์ฌ ๋ก๊ทธ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์ก ๊ฐ์ ์์ฃผ ์ํ๋ ํ
์ด๋ธ๋ ํฌํจ๋ฉ๋๋ค.
๋ค์์ผ๋ก ์ค์ ๋ก ์ฌ์ฉํ๋ ์ญํ ์ด๋ฆ์ ์ ํ์ธ์. ์งํฉ์ ์๊ณ ์ฌ๋ ์นํ์ ์ผ๋ก ์ ์งํ์ธ์: owner, manager, agent, read-only ๊ฐ์ ๋น์ฆ๋์ค ์ญํ ์ ์ ์ฑ ๊ฒ์ฌ์ ๋งคํํฉ๋๋ค(๋ฐ์ดํฐ๋ฒ ์ด์ค ์ญํ ๊ณผ๋ ๋ค๋ฆ ๋๋ค).
๊ทธ๋ค์ ๋ ์ฝ๋ ์์ ๊ถ์ ๊ฒฐ์ ํ์ธ์. ์ด๋ค ํ ์ด๋ธ์ ๋จ์ผ ์ฌ์ฉ์ ์์ (์: ๊ฐ์ธ ๋ ธํธ)์ด๊ณ , ์ด๋ค ํ ์ด๋ธ์ ํ ์์ (์: ๊ณต์ ์ธ๋ฐ์ค)์ผ ์ ์์ต๋๋ค. ๋ ๋ฐฉ์์ ๊ณํ ์์ด ์์ผ๋ฉด ์ ์ฑ ์ด ์ฝ๊ธฐ ์ด๋ ต๊ณ ์ฐํํ๊ธฐ ์ฌ์์ง๋๋ค.
๊ฐ ํ ์ด๋ธ์ ๋ํด ๊ฐ์ ์ง๋ฌธ์ ๋ตํ๋ ๋ฐฉ์์ผ๋ก ๊ท์น์ ๋ฌธ์ํํ์ธ์:
- ํ ๋ํธ ๊ฒฝ๊ณ๋ ๋ฌด์์ธ๊ฐ(์ด๋ค ์ด์ด ๊ทธ๊ฒ์ ๊ฐ์ ํ๋๊ฐ)?
- ๋๊ฐ ํ์ ์ฝ์ ์ ์๋๊ฐ(์ญํ ๊ณผ ์์ ๊ถ ๊ธฐ์ค)?
- ๋๊ฐ ํ์ ์์ฑํ๊ณ ์ ๋ฐ์ดํธํ ์ ์๋๊ฐ(์ด๋ค ์กฐ๊ฑด์์)?
- ๋๊ฐ ํ์ ์ญ์ ํ ์ ์๋๊ฐ(๋ณดํต ๊ฐ์ฅ ์๊ฒฉํจ)?
- ์ด๋ค ์์ธ๊ฐ ํ์ฉ๋๋๊ฐ(์ง์ ์ธ๋ ฅ, ์๋ํ, ๋ด๋ณด๋ด๊ธฐ ๋ฑ)?
์: โInvoicesโ๋ ๋งค๋์ ๊ฐ ํ ๋ํธ์ ๋ชจ๋ ์ธ๋ณด์ด์ค๋ฅผ ๋ณผ ์ ์๊ฒ ํ๊ณ , ์์ด์ ํธ๋ ํ ๋น๋ ๊ณ ๊ฐ์ ์ธ๋ณด์ด์ค๋ง, ์ฝ๊ธฐ ์ ์ฉ์ ์กฐํ๋ง ๊ฐ๋ฅํ๊ณ ์์ ๋ถ๊ฐ๋ก ์ ํ ์ ์์ต๋๋ค. ํ ๋ํธ ๊ฒฉ๋ฆฌ๋ ์ญ์ ์ฒ๋ผ ๋ฐ๋์ ์๊ฒฉํด์ผ ํ ๊ท์น๊ณผ ๋งค๋์ ์๊ฒ ์ถ๊ฐ ๊ฐ์์ฑ์ ์ค ์ ์๋ ์ ์ฐํ ๊ท์น์ ๋ฏธ๋ฆฌ ๋๋ ๋์ธ์. AppMaster ๊ฐ์ ๋ ธ์ฝ๋ ๋๊ตฌ๋ก ๋น๋ํ๋ค๋ฉด ์ด ๋งคํ์ UI ๊ธฐ๋์น์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ท์น์ ์ผ์น์ํค๋ ๋ฐ ๋์์ด ๋ฉ๋๋ค.
๋ฉํฐํ ๋ํธ ํ ์ด๋ธ์ ์ํ ์ค๊ณ ํจํด
๋ฉํฐํ ๋ํธ RLS๋ ํ ์ด๋ธ ๊ตฌ์กฐ๊ฐ ์์ธก ๊ฐ๋ฅํ ๋ ๊ฐ์ฅ ์ ๋์ํฉ๋๋ค. ๊ฐ ํ ์ด๋ธ์ด ํ ๋ํธ๋ฅผ ๋ค๋ฅธ ๋ฐฉ์์ผ๋ก ์ ์ฅํ๋ฉด ์ ์ฑ ์ด ํผ์ฆ์ฒ๋ผ ๋ณต์กํด์ง๋๋ค. ์ผ๊ด๋ ํํ๋ ์ ์ฑ ์ ์ฝ๊ณ ํ ์คํธํ๊ณ ์ ์งํ๊ธฐ ์ฝ๊ฒ ๋ง๋ญ๋๋ค.
๋จผ์ ํ๋์ ํ ๋ํธ ์๋ณ์๋ฅผ ์ ํ๊ณ ์ด๋์๋ ์ฌ์ฉํ์ธ์. UUID๋ ์ถ์ธกํ๊ธฐ ์ด๋ ต๊ณ ๋ง์ ์์คํ ์์ ์์ฑํ๊ธฐ ์ฌ์์ ํํ ์ฌ์ฉ๋ฉ๋๋ค. ๋ด๋ถ์ฉ์ด๋ผ๋ฉด ์ ์๋ ๊ด์ฐฎ์ต๋๋ค. ์ฌ๋์ด ์ฝ๊ธฐ ์ฌ์ด ์ฌ๋ฌ๊ทธ(์: "acme")๋ ๋ฐ๋ ์ ์์ผ๋ ํ์์ฉ์ผ๋ก ์ทจ๊ธํ๊ณ ํต์ฌ ํค๋ก๋ ์ฐ์ง ๋ง์ธ์.
ํ
๋ํธ ๋ฒ์ ๋ฐ์ดํฐ์๋ tenant_id ์ด์ ์ถ๊ฐํ๊ณ ๊ฐ๋ฅํ๋ฉด NOT NULL๋ก ๋ง๋์ธ์. ํ
๋ํธ ์์ด ์กด์ฌํ ์ ์๋ ํ์ ๋ณดํต ๋์๊ฐ ๋ฉ๋๋ค: ์ ์ญ๊ณผ ํ
๋ํธ ๋ฐ์ดํฐ๋ฅผ ํ ํ
์ด๋ธ์ ์์ผ๋ฉด RLS ์ ์ฑ
์ด ์ด๋ ต๊ณ ์ทจ์ฝํด์ง๋๋ค.
์ธ๋ฑ์ฑ์ ๋จ์ํ์ง๋ง ์ค์ํฉ๋๋ค. SaaS ์ฑ์ ๋๋ถ๋ถ ์ฟผ๋ฆฌ๋ ๋จผ์ ํ
๋ํธ๋ก ํํฐ๋งํ ๋ค ์ํ๋ ๋ ์ง ๊ฐ์ ๋น์ฆ๋์ค ํ๋๋ก ์ขํ๋๋ค. ๊ธฐ๋ณธ์ tenant_id ์ธ๋ฑ์ค์ด๊ณ , ํธ๋ํฝ์ด ๋ง์ ํ
์ด๋ธ์ (tenant_id, created_at)๋ (tenant_id, status) ๊ฐ์ ๋ณตํฉ ์ธ๋ฑ์ค๊ฐ ์ข์ต๋๋ค.
์ด๋ค ํ ์ด๋ธ์ด ์ ์ญ์ธ์ง ํ ๋ํธ ๋ฒ์์ธ์ง ๋นจ๋ฆฌ ๊ฒฐ์ ํ์ธ์. ์ ์ญ ํ ์ด๋ธ ์: ๊ตญ๊ฐ, ํตํ ์ฝ๋, ์๊ธ์ ์ ์. ํ ๋ํธ ๋ฒ์ ํ ์ด๋ธ ์: ๊ณ ๊ฐ, ์ธ๋ณด์ด์ค, ํฐ์ผ ๋ฑ ํ ๋ํธ๊ฐ ์์ ํ๋ ๊ฒ.
์ ์ง๋ณด์ ๊ฐ๋ฅํ ๊ท์น์ ์ํ๋ฉด ๋ฒ์๋ฅผ ์ข๊ฒ ์ ์งํ์ธ์:
- ํ
๋ํธ ๋ฒ์ ํ
์ด๋ธ:
tenant_id NOT NULL, RLS ํ์ฑํ, ์ ์ฑ ์ ํญ์tenant_id๋ฅผ ๊ฒ์ฌ - ์ ์ญ ์ฐธ์กฐ ํ
์ด๋ธ:
tenant_id์์, ํ ๋ํธ ์ ์ฑ ์์, ๋๋ถ๋ถ ์ญํ ์ ๋ํด ์ฝ๊ธฐ ์ ์ฉ - ๊ณต์ ๋์ง๋ง ํต์ ๋๋ ํ ์ด๋ธ: ๊ฐ๋ ๋ณ๋ก ํ ์ด๋ธ ๋ถ๋ฆฌ(์ ์ญ๊ณผ ํ ๋ํธ ํ ํผํฉ ๊ธ์ง)
AppMaster ๊ฐ์ ๋๊ตฌ๋ก ๋น๋ํ๋ฉด tenant_id๊ฐ ํ์ค ํ๋์ผ ๋ ์ผ๊ด๋ ํจํด์ ์ฌ๋ฌ ๋ชจ๋์์ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ๊ณ๋ณ: ์ฒซ ๋ฒ์งธ ํ ๋ํธ ์ ์ฑ ๋ง๋ค๊ธฐ
PostgreSQL RLS๋ก ์ป๋ ์ฒซ ๋ฒ์งธ ์ค์ฉ์ ์น๋ฆฌ๋, ํน์ ํ
์ด๋ธ์ด ํ์ฌ ์ธ์
์ ํ
๋ํธ ๋ด๋ถ์์๋ง ์ฝํ๋๋ก ํ๋ ๊ฒ์
๋๋ค. ์์ ์ ๊ฐ๋จํฉ๋๋ค: API์์ WHERE ์ ์ ์์ด๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ๋ค๋ฅธ ํ
๋ํธ์ ํ์ ๋ฐํํ์ง ์์ต๋๋ค.
๋จผ์ tenant_id ์ด์ด ์๋ ํ
์ด๋ธ์์ ์์ํ์ธ์:
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
RLS๋ฅผ ํ์ฑํํ๋ฉด ๊ธฐ๋ณธ ๋์์ด ์ฌ๋๋ค์ ๋๋ผ๊ฒ ํ ์ ์์ต๋๋ค: ์ญํ ์ด RLS์ ๋์์ธ๋ฐ ์ผ์นํ๋ ์ ์ฑ
์ด ์์ผ๋ฉด SELECT๋ 0ํ์ ๋ฐํํ๊ณ (์ฐ๊ธฐ ๋ํ ์คํจํฉ๋๋ค). ์ฒ์์๋ ์ด ์ํ๊ฐ ๋ฐ๋์งํฉ๋๋ค.
์ด์ ์ต์ํ์ ์ฝ๊ธฐ ์ ์ฑ
์ ์ถ๊ฐํ์ธ์. ์์ ๋ ์ฑ์ด ๋ก๊ทธ์ธ ํ app.tenant_id ๊ฐ์ ์ธ์
๋ณ์๋ฅผ ์ค์ ํ๋ค๊ณ ๊ฐ์ ํฉ๋๋ค:
CREATE POLICY invoices_tenant_read
ON invoices
FOR SELECT
USING (tenant_id = current_setting('app.tenant_id')::uuid);
๋ค์์ผ๋ก ์ฐ๊ธฐ ๊ท์น์ ์ถ๊ฐํ์ธ์. RLS์์ USING์ ๊ธฐ์กด ํ์ ๊ฑด๋๋ฆด ์ ์๋์ง๋ฅผ ์ ์ดํ๊ณ , WITH CHECK๋ ํ์ฉ๋๋ ์ ๊ฐ์ธ์ง ๊ฒ์ฌํฉ๋๋ค.
CREATE POLICY invoices_tenant_insert
ON invoices
FOR INSERT
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY invoices_tenant_update
ON invoices
FOR UPDATE
USING (tenant_id = current_setting('app.tenant_id')::uuid)
WITH CHECK (tenant_id = current_setting('app.tenant_id')::uuid);
CREATE POLICY invoices_tenant_delete
ON invoices
FOR DELETE
USING (tenant_id = current_setting('app.tenant_id')::uuid);
์ ์ฑ
์ ๊ธฐ๋ณธ์ ์ผ๋ก PERMISSIVE์
๋๋ค. ์ฆ ํ ์ ์ฑ
๋ง ํ์ฉํ๋ฉด ์ ๊ทผ์ด ํ์ฉ๋ฉ๋๋ค. ์ฌ๋ฌ ๊ท์น์ด ๋ชจ๋ ํต๊ณผํด์ผ ํ ๋๋ RESTRICTIVE๋ฅผ ์ ํํ์ธ์(์: โํ์ฑ ๊ณ์ ์ธ ๊ฒฝ์ฐโ ๊ฐ์ ๋ ๋ฒ์งธ ๊ฐ๋ ์ถ๊ฐ์ ์ ์ฉ).
์ ์ฑ
์ ์๊ณ ์ญํ ์ค์ฌ์ผ๋ก ์ ์งํ์ธ์. ๋ง์ OR์ ๊ฐ์ง ๊ฑฐ๋ํ ๊ท์น ํ๋ ๋์ ์ฒญ์ค๋ณ๋ก ๋ณ๋ ์ ์ฑ
์ ๋ง๋ค๋ฉด(์: invoices_tenant_read_app_user, invoices_tenant_read_support_agent) ํ
์คํธ์ ๋ฆฌ๋ทฐ๊ฐ ์ฌ์์ง๊ณ ๋์ค์ ์์ ํ๊ฒ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
ํ ๋ํธ์ ์ฌ์ฉ์ ์ปจํ ์คํธ ์์ ํ๊ฒ ์ ๋ฌํ๊ธฐ
RLS๊ฐ ์๋ํ๋ ค๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ โ๋๊ฐ ํธ์ถํ๋๊ฐโ์ โ์ด๋ค ํ ๋ํธ์ ์ํ๋๊ฐโ๋ฅผ ์์์ผ ํฉ๋๋ค. RLS ์ ์ฑ ์ ์ฟผ๋ฆฌ ์์ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ฝ์ ์ ์๋ ๊ฐ๊ณผ๋ง ๋น๊ตํ ์ ์์ผ๋ฏ๋ก ๊ทธ ์ปจํ ์คํธ๋ฅผ ์ธ์ ์ ์ ๋ฌํด์ผ ํฉ๋๋ค.
์ผ๋ฐ์ ์ธ ํจํด์ ์ธ์ฆ ํ ์ธ์
๋ณ์๋ฅผ ์ค์ ํ๊ณ ์ ์ฑ
์์ current_setting()์ผ๋ก ์ฝ๋ ๊ฒ์
๋๋ค. ์ฑ์ JWT ๊ฐ์ ๊ฒ์ผ๋ก ์ ์์ ์ฆ๋ช
ํ ๋ค ํ์ํ ํ๋(tenant_id, user_id, role)๋ง ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฐ๊ฒฐ์ ๊ธฐ๋กํฉ๋๋ค.
-- ์์ฒญ๋น(ํน์ ํธ๋์ญ์
๋น) ํ ๋ฒ ์คํ
SELECT set_config('app.tenant_id', '3f2a0c3e-9c7b-4d3f-9c5c-3c5e9c5d1a11', true);
SELECT set_config('app.user_id', '8d9c6b1a-6b6d-4e32-9c0d-2bfe6f6c1111', true);
SELECT set_config('app.role', 'support_agent', true);
-- ์ ์ฑ
์์
-- tenant_id ์ด์ UUID
USING (tenant_id = current_setting('app.tenant_id', true)::uuid);
์ธ ๋ฒ์งธ ์ธ์ true๋ฅผ ์ฐ๋ฉด ํ์ฌ ํธ๋์ญ์
์ ๋ก์ปฌํ๊ฒ ์ค์ ๋ฉ๋๋ค. ์ปค๋ฅ์
ํ๋ง์ ์ฌ์ฉํ๋ ๊ฒฝ์ฐ ์ฌ์ฌ์ฉ๋ ์ฐ๊ฒฐ์ ์ด์ ์ ํ
๋ํธ ์ปจํ
์คํธ๊ฐ ๋จ์ ์์ง ์๊ฒ ํ๋ ค๋ฉด ์ด๊ฒ์ด ์ค์ํฉ๋๋ค.
JWT ํด๋ ์์์ ์ปจํ ์คํธ ์ฑ์ฐ๊ธฐ
API๊ฐ JWT๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ํด๋ ์์ ๊ณง์ด๊ณง๋๋ก ์ ๋ขฐํ์ง ๋ง๊ณ ์ ๋ ฅ์ผ๋ก ์ทจ๊ธํ์ธ์. ํ ํฐ ์๋ช ๊ณผ ๋ง๋ฃ๋ฅผ ๊ฒ์ฆํ ๋ค ํ์ํ ํ๋(tenant_id, user_id, role)๋ง ์ธ์ ์ค์ ์ผ๋ก ๋ณต์ฌํ์ธ์. ํด๋ผ์ด์ธํธ๊ฐ ์ง์ ํค๋๋ ์ฟผ๋ฆฌ ํ๋ผ๋ฏธํฐ๋ก ์ด ๊ฐ์ ๋ณด๋ด๊ฒ ํ์ง ๋ง์ธ์.
์ปจํ ์คํธ ๋๋ฝ ๋๋ ์๋ชป๋ ๊ฐ: ๊ธฐ๋ณธ ๊ฑฐ๋ถ
์ค๊ณํ ๋ ์ค์ ๋๋ฝ์ด 0ํ์ ๋ฐํํ๋๋ก ๋ง๋์ธ์.
current_setting('app.tenant_id', true)๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ฝ ์ NULL์ ๋ฐํํฉ๋๋ค. ์ ์ ํ ํ์
์ผ๋ก ์บ์คํธ(์: ::uuid)ํด์ ํ์์ด ์๋ชป๋๋ฉด ๋น ๋ฅด๊ฒ ์คํจํ๊ฒ ํ์ธ์. ํ
๋ํธ/์ฌ์ฉ์ ์ปจํ
์คํธ๋ฅผ ์ค์ ํ ์ ์์ผ๋ฉด ์ถ์ ํ์ง ๋ง๊ณ ์์ฒญ์ ์คํจ์ํค์ธ์.
์ด ๋ฐฉ์์ ์ฟผ๋ฆฌ๊ฐ UI๋ฅผ ์ฐํํ๊ฑฐ๋ ์ ์๋ํฌ์ธํธ๊ฐ ์ถ๊ฐ๋ ๊ฒฝ์ฐ์๋ ์ ๊ทผ ์ ์ด ์ผ๊ด์ฑ์ ์ ์งํฉ๋๋ค.
์ ์ง๋ณด์ํ๊ธฐ ์ฌ์ด ์ค์ฉ์ ์ญํ ํจํด
RLS ์ ์ฑ
์ ์ฝ๊ธฐ ์ฝ๊ฒ ์ ์งํ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ์ ์ฒด(identity)์ ๊ถํ(permissions)์ ๋ถ๋ฆฌํ๋ ๊ฒ์
๋๋ค. ๊ธฐ๋ณธ์ users ํ
์ด๋ธ๊ณผ ์ฌ์ฉ์-ํ
๋ํธ-์ญํ ์ ์ฐ๊ฒฐํ๋ memberships ํ
์ด๋ธ์ ๋๋ ๊ฒ์
๋๋ค. ๊ทธ๋ฌ๋ฉด ์ ์ฑ
์ ํ ๊ฐ์ง ์ง๋ฌธ์ ๋ตํ ์ ์์ต๋๋ค: โํ์ฌ ์ฌ์ฉ์๊ฐ ์ด ํ์ ๋ํด ์ ์ ํ ๋ฉค๋ฒ์ญ์ ๊ฐ์ง๊ณ ์๋๊ฐ?โ
์ญํ ์ด๋ฆ์ ์งํจ๋ณด๋ค ์ค์ ํ๋์ ์ฐ๊ฒฐํ์ธ์. โinvoice_viewerโ๋ โinvoice_approverโ ๊ฐ์ ์ด๋ฆ์ด โmanagerโ๋ณด๋ค ์ ์ฑ ์ ๋ ์ค๋ ๊ฒฌ๋๊ณ ๋ช ํํฉ๋๋ค.
์ ์ง๋ณด์๊ฐ ์ฌ์ด ์ญํ ํจํด ๋ช ๊ฐ์ง:
- ์์ ์ ์ ์ฉ: ํ์
created_by_user_id(๋๋owner_user_id)๊ฐ ์๊ณ ์ผ์น ์ฌ๋ถ๋ฅผ ๊ฒ์ฌ - ํ ์ ์ฉ: ํ์
team_id๊ฐ ์๊ณ ์ ์ฑ ์ด ๊ฐ์ ํ ๋ํธ ๋ด์์ ์ฌ์ฉ์๊ฐ ๊ทธ ํ์ ๋ฉค๋ฒ์ธ์ง ๊ฒ์ฌ - ์น์ธ๋ ํญ๋ชฉ๋ง:
status = 'approved'์ผ ๋๋ง ์ฝ๊ธฐ ํ์ฉ, ์ฐ๊ธฐ๋ ์น์ธ์๋ง ํ์ฉ - ํผํฉ ๊ท์น: ์ฒ์์ ์๊ฒฉํ๊ฒ ์์ํ๊ณ ์์ ์์ธ๋ฅผ ์ถ๊ฐ(์: โ์ง์ํ์ ์ฝ๊ธฐ ํ์ฉ, ๋จ ํ ๋ํธ ๋ฒ์ ๋ดโ)
ํฌ๋ก์ค-ํ
๋ํธ ๊ด๋ฆฌ์(๋ค์ค ํ
๋ํธ์ ์ ๊ทผํ๋ ๊ด๋ฆฌ์)๋ ๋ง์ ํ์ด ์ค์ํ๋ ๋ถ๋ถ์
๋๋ค. ์ด๋ฅผ ์จ๊ฒจ์ง โ์ํผ์ ์ โ ์ง๋ฆ๊ธธ๋ก ์ฒ๋ฆฌํ์ง ๋ง๊ณ ๋ช
์์ ์ผ๋ก ๋ค๋ฃจ์ธ์. platform_admin ๊ฐ์ ์ ์ญ ๊ฐ๋
์ ๋ง๋ค๊ณ ์ ์ฑ
์์ ์๋์ ์ผ๋ก ๊ฒ์ฌํ๊ฒ ํ์ธ์. ๊ฐ๋ฅํ๋ฉด ํฌ๋ก์ค-ํ
๋ํธ ์ ๊ทผ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฝ๊ธฐ ์ ์ฉ์ผ๋ก ๋๊ณ ์ฐ๊ธฐ๋ ๋ ๋์ ํ๋ค์ ์๊ตฌํ์ธ์.
๋ฌธ์ํ๋ ์๊ฐ๋ณด๋ค ์ค์ํฉ๋๋ค. ๊ฐ ์ ์ฑ ์์ ์๋๋ฅผ ์ค๋ช ํ๋ ์งง์ ์ฃผ์์ ๋ฌ์๋์ธ์(์: โApprovers๋ ์ํ๋ฅผ ๋ณ๊ฒฝํ ์ ์๋ค. Viewers๋ ์น์ธ๋ ์ธ๋ณด์ด์ค๋ง ์ฝ์ ์ ์๋ค.โ). 6๊ฐ์ ํ ๊ทธ ์งง์ ์ค๋ช ์ด ์ ์ฑ ์์ ์ ํฐ ๋์์ด ๋ฉ๋๋ค.
AppMaster ๊ฐ์ ๋ ธ์ฝ๋ ๋๊ตฌ๋ก ๋น๋ํด๋ ์ด ํจํด์ ์ ํจํฉ๋๋ค. UI์ API๋ ๋น ๋ฅด๊ฒ ์์ง์ฌ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ท์น์ ๋ฉค๋ฒ์ญ๊ณผ ๋ช ํํ ์ญํ ์๋ฏธ์ ์์กดํด ์์ ์ ์ผ๋ก ์ ์ง๋ฉ๋๋ค.
์์ ์๋๋ฆฌ์ค: ์ธ๋ณด์ด์ค์ ์ง์์ ๊ฐ์ง ๊ฐ๋จํ SaaS
์์ SaaS๋ฅผ ์์ํด๋ณด์ธ์. ์ฌ๋ฌ ํ์ฌ๋ฅผ ์๋น์คํ๊ณ ๊ฐ ํ์ฌ๋ ํ๋์ ํ ๋ํธ์ ๋๋ค. ์ฑ์๋ ์ธ๋ณด์ด์ค(๊ธ์ต)์ ์ง์ ํฐ์ผ(์ผ์ ์ง์)์ด ์์ต๋๋ค. ์ฌ์ฉ์๋ agent, manager, support์ ๊ฐ์ ์ญํ ์ ๊ฐ์ง ์ ์์ต๋๋ค.
๊ฐ๋จํ ๋ฐ์ดํฐ ๋ชจ๋ธ: ๋ชจ๋ ์ธ๋ณด์ด์ค์ ํฐ์ผ ํ์ tenant_id๊ฐ ์์ต๋๋ค. ํฐ์ผ์๋ assignee_user_id๋ ์์ต๋๋ค. ์ฑ์ ๋ก๊ทธ์ธ ์งํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ธ์
์ ํ์ฌ ํ
๋ํธ์ ์ฌ์ฉ์๋ฅผ ์ค์ ํฉ๋๋ค.
PostgreSQL RLS๊ฐ ์ผ์ ์ํ์ ์ด๋ป๊ฒ ๋ฐ๊พธ๋์ง ๋ณด์ธ์.
Tenant A์ ์ฌ์ฉ์๊ฐ Tenant B์ ์ธ๋ณด์ด์ค ID๋ฅผ ์ถ์ธกํด ๋ณด๊ฑฐ๋(๋๋ UI๊ฐ ์ค์๋ก ๋ณด๋์ ๋) ์ฟผ๋ฆฌ๊ฐ ์คํ๋๋๋ผ๋, ์ ์ฑ
์ด invoice.tenant_id = current_tenant_id๋ฅผ ์๊ตฌํ๋ฏ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ 0ํ์ ๋ฐํํฉ๋๋ค. โ์ ๊ทผ ๊ฑฐ๋ถโ๊ฐ ์ ์ถ๋๋ ๋์ ๋น ๊ฒฐ๊ณผ๊ฐ ์ต๋๋ค.
ํ ํ ๋ํธ ๋ด๋ถ์์๋ ์ญํ ์ด ์ ๊ทผ์ ๋ ์ขํ๋๋ค. ๋งค๋์ ๋ ํ ๋ํธ์ ๋ชจ๋ ์ธ๋ณด์ด์ค์ ํฐ์ผ์ ๋ณด๊ณ , ์์ด์ ํธ๋ ์์ ์๊ฒ ํ ๋น๋ ํฐ์ผ๊ณผ ์์ ์ ๋๋ํํธ๋ง ๋ณผ ์ ์์ต๋๋ค. ํํฐ๊ฐ ์ ํ์ ์ผ ๋ API์์ ์ฌ๊ธฐ์ ์ค์ํ๊ธฐ ์ฝ์ต๋๋ค.
์ง์ํ์ ํน์ํ ๊ฒฝ์ฐ์
๋๋ค. ๊ณ ๊ฐ ์ง์์ ์ํด ์ธ๋ณด์ด์ค๋ฅผ ์กฐํํ ์๋ ์์ง๋ง amount, bank_account, tax_id ๊ฐ์ ๋ฏผ๊ฐํ ํ๋๋ ๋ฐ๊ฟ ์ ์์ด์ผ ํฉ๋๋ค. ํ์ค์ ์ธ ํจํด์:
- ์ง์ ์ญํ ์ ๋ํด ์ธ๋ณด์ด์ค
SELECTํ์ฉ(์ฌ์ ํ ํ ๋ํธ ๋ฒ์) UPDATE๋ โ์์ ํโ ๊ฒฝ๋ก๋ก๋ง ํ์ฉ(์: ํธ์ง ๊ฐ๋ฅํ ์ด๋ง ๋ ธ์ถํ๋ ๋ทฐ ๋๋ ๋ฏผ๊ฐ ํ๋ ๋ณ๊ฒฝ์ ๊ฑฐ๋ถํ๋ ์๊ฒฉํ ์ ๋ฐ์ดํธ ์ ์ฑ )
์ด์ โ์ค์๋ก ํํฐ๋ฅผ ์ ์ฉํ์ง ์์ APIโ ์๋๋ฆฌ์ค๋ฅผ ๋ณด์ธ์. RLS๊ฐ ์์ผ๋ฉด ํฌ๋ก์ค-ํ ๋ํธ ์ธ๋ณด์ด์ค๊ฐ ์ ์ถ๋ ์ ์์ต๋๋ค. RLS๊ฐ ์์ผ๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ธ์ ํ ๋ํธ ์ธ์ ํ์ ๋ฐํํ์ง ์์ ๋ฒ๊ทธ๋ ํ๋ฉด ๊นจ์ง์ผ๋ก ๋๋๊ณ ๋ฐ์ดํฐ ์ ์ถ๋ก ์ด์ด์ง์ง ์์ต๋๋ค.
AppMaster๋ก ์ด๋ฐ SaaS๋ฅผ ๋น๋ํ๋๋ผ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ท์น์ ๋๋ ๊ฒ์ด ์ข์ต๋๋ค. UI ๊ฒ์ฌ๋ ์ ์ฉํ์ง๋ง, ๋ฌด์ธ๊ฐ ๋น ์ก์ ๋ ๋ฒํฐ๋ ๊ฒ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ท์น์ ๋๋ค.
ํํ ์ค์์ ํํผ ๋ฐฉ๋ฒ
RLS๋ ๊ฐ๋ ฅํ์ง๋ง ์์ ์ค์๊ฐ ๋ณด์์ด โ์์ ํ ์ฒโ ํ๋ ์ํฉ์ ๋ง๋ค ์ ์์ต๋๋ค. ๋ฌธ์ ๋ ๋ณดํต ์ ํ ์ด๋ธ ์ถ๊ฐ, ์ญํ ๋ณ๊ฒฝ, ์๋ชป๋ DB ์ฌ์ฉ์๋ก ํ ์คํธํ ๋ ๋ํ๋ฉ๋๋ค.
์์ฃผ ๋ฐ์ํ๋ ์คํจ๋ ์ ํ ์ด๋ธ์์ RLS๋ฅผ ํ์ฑํํ๋ ๊ฒ์ ์๋ ๊ฒ์ ๋๋ค. ์ฃผ์ ํ ์ด๋ธ์ ๋ํด ์ ์คํ ์ ์ฑ ์ ์์ฑํ ๋ค์ โnotesโ๋ โattachmentsโ ๊ฐ์ ํ ์ด๋ธ์ ์ถ๊ฐํ๋ฉด์ ์ ์ฒด ์ ๊ทผ์ ์ด์ด๋๊ณ ๋ฐฐํฌํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ๊ท์น์ผ๋ก ๋ง๋์ธ์: ์ ํ ์ด๋ธ = RLS ํ์ฑํ + ์ ์ด๋ ํ๋์ ์ ์ฑ .
๋ ๋ค๋ฅธ ํจ์ ์ ๋์๋ณ๋ก ์ ์ฑ
์ด ์ผ์นํ์ง ์๋ ๊ฒ์
๋๋ค. INSERT๋ ํ์ฉํ์ง๋ง SELECT๋ ์ฐจ๋จํ๋ ์ ์ฑ
์ ๋ฐ์ดํฐ๋ฅผ ์์ฑํ ๋ค ๋ฐ๋ก โ๋ฐ์ดํฐ๊ฐ ์ฌ๋ผ์ก๋คโ๋ ์์ ๋ฌธ์ ๋ฅผ ๋ง๋ญ๋๋ค. ๋ฐ๋ ๊ฒฝ์ฐ๋ ๋ง์ฐฌ๊ฐ์ง์
๋๋ค: ์ฌ์ฉ์๋ ์ฝ์ ์๋ ์์ง๋ง ๋ง๋ค ์ ์์ด์ UI์์ ์ฐํํ๋ ค๊ณ ํฉ๋๋ค. ํ๋ฆ์ ์๊ฐํ์ธ์: โ์์ฑ ํ ์กฐํโ, โ์์ ํ ๋ค์ ์ด๊ธฐโ, โ์ญ์ ํ ๋ชฉ๋ก ๋ณด๊ธฐโ.
SECURITY DEFINER ํจ์๋ฅผ ์กฐ์ฌํ์ธ์. ํด๋น ํจ์๋ ํจ์ ์์ ์์ ๊ถํ์ผ๋ก ์คํ๋์ด RLS๋ฅผ ์ฐํํ ์ ์์ต๋๋ค. ์ฌ์ฉํด์ผ ํ๋ค๋ฉด ์๊ฒ ๋ง๋ค๊ณ ์
๋ ฅ์ ๊ฒ์ฆํ๋ฉฐ ๋์ SQL ์ฌ์ฉ์ ํผํ์ธ์.
๋ํ ์ฑ ์ธก ํํฐ๋ง์๋ง ์์กดํ๋ฉด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ ๊ทผ์ ์ด์ด๋์ง ๋ง์ธ์. ์ ์ค๊ณ๋ API๋ ์ ์๋ํฌ์ธํธ, ๋ฐฑ๊ทธ๋ผ์ด๋ ์ก, ๊ด๋ฆฌ์ ์คํฌ๋ฆฝํธ๊ฐ ์๊ธฐ๋ฉด ํ์ฅ๋ฉ๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ญํ ์ด ๋ชจ๋ ๊ฒ์ ์ฝ์ ์ ์๋ค๋ฉด ์ธ์ ๊ฐ ๋ฌธ์ ๊ฐ ์๊น๋๋ค.
๋ฌธ์ ๋ฅผ ์กฐ๊ธฐ์ ์ก์ผ๋ ค๋ฉด ์ค๋ฌด์ ์ธ ๊ฒ์ฌ๋ฅผ ์ ์งํ์ธ์:
- ๊ฐ์ธ ๊ด๋ฆฌ์ ๊ณ์ ์ด ์๋ ํ๋ก๋์ ์ฑ์ด ์ฌ์ฉํ๋ ๋์ผํ DB ์ญํ ๋ก ํ ์คํธ
- ํ ์ด๋ธ๋น ํ๋์ ์์ฑ ํ ์คํธ(๋ค๋ฅธ ํ ๋ํธ ์ฌ์ฉ์๊ฐ 0ํ์ ๋ณด์์ผ ํจ)
- ๊ฐ ํ
์ด๋ธ์ด ์์ํ๋ ๋์(
SELECT,INSERT,UPDATE,DELETE)์ ์ง์ํ๋์ง ํ์ธ SECURITY DEFINER์ฌ์ฉ ๊ฒํ ๋ฐ ํ์์ฑ ๋ฌธ์ํ- ์ฝ๋ ๋ฆฌ๋ทฐ์ ๋ง์ด๊ทธ๋ ์ด์ ์ฒดํฌ๋ฆฌ์คํธ์ โRLS ํ์ฑํ?โ ํญ๋ชฉ ํฌํจ
์: ์ง์ ์์ด์ ํธ๊ฐ ์ธ๋ณด์ด์ค ๋ฉ๋ชจ๋ฅผ ์์ฑํ๋๋ฐ ๋ฐ๋ก ์ฝ์ ์ ์๋ค๋ฉด ๋ณดํต INSERT ์ ์ฑ
์ ์์ง๋ง SELECT ์ ์ฑ
์ด ์๊ฑฐ๋ ์ธ์
์ ํ
๋ํธ ์ปจํ
์คํธ๊ฐ ์ค์ ๋์ง ์์๊ธฐ ๋๋ฌธ์
๋๋ค.
RLS ์ค์ ์ ๊ฒ์ฆํ๋ ๋น ๋ฅธ ์ฒดํฌ๋ฆฌ์คํธ
RLS๋ ๊ฒํ ์์ผ๋ก๋ ๋ง์ ๋ณด์ด์ง๋ง ์ค์ ์ฌ์ฉ์์๋ ์คํจํ ์ ์์ต๋๋ค. ๊ฒ์ฆ์ ์ ์ฑ ์ ์ฝ๋ ๊ฒ๋ณด๋ค ํ์ค์ ์ธ ๊ณ์ ๊ณผ ์ฟผ๋ฆฌ๋ก ๊นจ๋ณด๋ ๊ฒ์ด ๋ ์ค์ํฉ๋๋ค. ์ฑ์ด ์ฌ์ฉํ ๋ฐฉ์๋๋ก ํ ์คํธํ์ธ์.
๋จผ์ ์์ ํ ์คํธ ์ ์์ ๋ง๋์ธ์. ์ต์ ๋ ๊ฐ์ ํ ๋ํธ(Tenant A, Tenant B)๋ฅผ ์ฌ์ฉํ๊ณ ๊ฐ ํ ๋ํธ์ ์ผ๋ฐ ์ฌ์ฉ์์ ๊ด๋ฆฌ์/๋งค๋์ ์ญํ ์ ํ๋์ฉ ๋ง๋์ธ์. โ์ง์ ์์ด์ ํธโ๋ โ์ฝ๊ธฐ ์ ์ฉโ ์ญํ ์ ์ง์ํ๋ค๋ฉด ๊ทธ ๊ณ์ ๋ ์ถ๊ฐํ์ธ์.
๊ทธ๋ค์ ๋ค์๊ณผ ๊ฐ์ ๋ฐ๋ณต ๊ฐ๋ฅํ ๊ฒ์ฌ๋ฅผ ํตํด RLS๋ฅผ ์๋ฐ ํ ์คํธํ์ธ์:
- ๊ฐ ์ญํ ์ ๋ํด ํต์ฌ ๋์ ์คํ: ๋ชฉ๋ก ์กฐํ, ID๋ก ๋จ์ผ ํ ์กฐํ, ์ฝ์ , ์์ , ์ญ์ . ๊ฐ ๋์์ ๋ํด ํ์ฉ๋์ด์ผ ํ ๊ฒฝ์ฐ์ ์ฐจ๋จ๋์ด์ผ ํ ๊ฒฝ์ฐ๋ฅผ ๋ชจ๋ ์๋.
- ํ ๋ํธ ๊ฒฝ๊ณ ์ฆ๋ช : Tenant A๋ก์ Tenant B ๋ฐ์ดํฐ์ ID๋ก ์ฝ๊ธฐ/์์ ์ ์๋. ํญ์ 0ํ ๋๋ ๊ถํ ์ค๋ฅ๊ฐ ๋์์ผ ํ๋ฉฐ ์ผ๋ถ ํ์ด ๋ณด์ด๋ฉด ์ ๋ฉ๋๋ค.
- ์กฐ์ธ ๋์ถ ํ ์คํธ: ๋ณดํธ๋ ํ ์ด๋ธ์ ๋ค๋ฅธ ํ ์ด๋ธ(์กฐํ ํ ์ด๋ธ ํฌํจ)๊ณผ ์กฐ์ธํด์ ์ฐ๊ฒฐ๋ ํ์ด ์ธ๋ถ ํ ๋ํธ์์ ๋๋ ค์ค์ง ์๋์ง ํ์ธ.
- ์ปจํ ์คํธ ๋๋ฝ/์๋ชป๋ ๊ฒฝ์ฐ ์ฐจ๋จ ํ์ธ: ์์ฒญ๋น ์ค์ ํ๋ ํ ๋ํธ/์ฌ์ฉ์ ์ปจํ ์คํธ๋ฅผ ์ง์ฐ๊ณ ์ฌ์๋. โ์ปจํ ์คํธ ์์โ์ ๋ซํ(fail closed)์ด์ด์ผ ํจ. ์๋ชป๋ tenant id๋ ์๋.
- ๊ธฐ๋ณธ ์ฑ๋ฅ ํ์ธ: ์ฟผ๋ฆฌ ํ๋์ ๋ณด๊ณ ์ธ๋ฑ์ค๊ฐ ํ
๋ํธ ํํฐ ํจํด(๋ณดํต
tenant_id์ ์ ๋ ฌ/๊ฒ์ ๊ธฐ์ค)์ ์ง์ํ๋์ง ํ์ธ.
ํ ์คํธ์์ ๋๋ผ์ด ๊ฒฐ๊ณผ๊ฐ ๋์ค๋ฉด ์ ์ฑ ์ด๋ ์ปจํ ์คํธ ์ค์ ์ ๋จผ์ ๊ณ ์น์ธ์. UI๋ API๋ก ํจ์นํ๊ณ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ท์น์ด โ๋์ฒด๋ก ์ง์ผ์ง๊ธธโ ๋ฐ๋ผ๋ ์์ผ๋ก ํด๊ฒฐํ์ง ๋ง์ธ์.
๋ค์ ๋จ๊ณ: ์์ ํ๊ฒ ๋กค์์ํ๊ณ ์ผ๊ด์ฑ ์ ์งํ๊ธฐ
PostgreSQL RLS๋ฅผ ์์ ์ฅ์น๋ก ๋ค๋ฃจ์ธ์: ์ ์คํ๊ฒ ๋์ ํ๊ณ ์์ฃผ ๊ฒ์ฆํ๋ฉฐ ํ์ด ๋ฐ๋ฅด๊ธฐ ์ฌ์ด ๋จ์ํ ๊ท์น์ ์ ์งํ์ธ์.
์๊ฒ ์์ํ์ธ์. ์ ์ถ์ด ๊ฐ์ฅ ํฐ ํผํด๋ฅผ ์ฃผ๋ ํ ์ด๋ธ(๊ฒฐ์ , ์ธ๋ณด์ด์ค, ๊ฐ์ธ์ ๋ณด, ๊ณ ๊ฐ ๋ฉ์์ง)์ ์ฐ์ RLS๋ฅผ ์ ์ฉํ์ธ์. ์ด๋ฐ์ ์์ ์ฑ๊ณต์ด ๋ชจ๋์๊ฒ ์ดํด๋์ง ์์ ๋๊ท๋ชจ ๋กค์์๋ณด๋ค ๋ซ์ต๋๋ค.
์ค์ฉ์ ์ธ ๋กค์์ ์์๋ ๋ณดํต ์ด๋ ์ต๋๋ค:
- ๋จผ์ ํต์ฌ ์์ ํ ์ด๋ธ(ํ์ด ๋ช ํํ ํ๋์ ํ ๋ํธ์ ์ํ๋ ํ ์ด๋ธ)
- ๊ฐ์ธ ๋ฐ์ดํฐ(PII)๊ฐ ์๋ ํ ์ด๋ธ
- ํ ๋ํธ๋ก ํํฐ๋ง๋๋ ๊ณต์ ํ ์ด๋ธ(๋ณด๊ณ ์, ๋ถ์ ๋ฑ)
- ์กฐ์ธ ํ ์ด๋ธ๊ณผ ์ฃ์ง ์ผ์ด์ค(๋ค๋๋ค ๊ด๊ณ)
- ๊ธฐ๋ณธ์ด ์์ ๋๋ฉด ๋๋จธ์ง ํ ์ด๋ธ
ํ ์คํธ๋ฅผ ํ์๋ก ๋ง๋์ธ์. ์๋ํ๋ ํ ์คํธ๋ ์๋ก ๋ค๋ฅธ ํ ๋ํธ์ ์ญํ ๋ก ๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๊ณ ๋ณ๊ฒฝ ์ฌํญ์ ํ์ธํด์ผ ํฉ๋๋ค. โํ์ฉํด์ผ ํจโ๊ณผ โ๊ฑฐ๋ถํด์ผ ํจโ ๊ฒ์ฌ๋ฅผ ๋ชจ๋ ํฌํจํ์ธ์. ๊ณผํ์ฉ๋๋ ์ค์๋ ๋ฐ๊ฒฌ์ด ๋ฆ์์๋ก ๋น์ฉ์ด ํฝ๋๋ค.
์์ฒญ ํ๋ฆ์์ ์ธ์ ์ปจํ ์คํธ๋ฅผ ์ค์ ํ๋ ํ ๊ณณ์ ๋ช ํํ ํ์ธ์. tenant id, user id, role์ ํ ๋ฒ, ์ผ์ฐ ์ ์ฉํ๊ณ ๋์ค์ ์ถ์ธกํ์ง ๋ง์ธ์. ํธ๋์ญ์ ์ค๊ฐ์ ์ปจํ ์คํธ๋ฅผ ์ค์ ํ๋ฉด ๊ฒฐ๊ตญ ๋๋ฝ๋๊ฑฐ๋ ์ค๋๋ ๊ฐ์ผ๋ก ์ฟผ๋ฆฌํ๋ ๊ฒฝ์ฐ๊ฐ ์๊น๋๋ค.
AppMaster๋ก ๋น๋ํ ๋๋ ์์ฑ๋ ๋ฐฑ์๋ API์ PostgreSQL ์ ์ฑ ์ฌ์ด์ ์ผ๊ด์ฑ์ ๊ณํํ์ธ์. ๋ชจ๋ ์๋ํฌ์ธํธ์์ ๋์ผํ ์ธ์ ๋ณ์๋ฅผ ์ฌ์ฉํ๋๋ก ํ์คํํ๋ฉด ์ ์ฑ ์ด ์ด๋์๋ ๋์ผํ๊ฒ ๋์ํฉ๋๋ค. AppMaster๋ฅผ appmaster.io์์ ์ฌ์ฉ ์ค์ด๋ผ๋ฉด UI์์๋ ์ ๊ทผ์ ์ ํํ๋๋ผ๋ RLS๋ฅผ ํ ๋ํธ ๊ฒฉ๋ฆฌ์ ๋ํ ์ต์ข ๊ถ์๋ก ๋ค๋ฃจ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก ์คํจ๋ฅผ ๊ด์ฐฐํ์ธ์. ๊ถํ ์คํจ๋ ๋กค์์ ์งํ ํนํ ์ ์ฉํ ์ ํธ์ ๋๋ค. ๋ฐ๋ณต๋๋ ๊ฑฐ๋ถ๋ฅผ ์ถ์ ํ๊ณ , ์ค์ ๊ณต๊ฒฉ์ธ์ง, ํด๋ผ์ด์ธํธ ํ๋ก์ฐ๊ฐ ๊นจ์ง ๊ฒ์ธ์ง, ์ ์ฑ ์ด ๋๋ฌด ์๊ฒฉํ ๊ฒ์ธ์ง ์กฐ์ฌํ์ธ์.
RLS๋ฅผ ๊ฑด๊ฐํ๊ฒ ์ ์งํ๋ ์งง์ ์ต๊ด ๋ชฉ๋ก:
- ๊ธฐ๋ณธ-๊ฑฐ๋ถ ์ฌ๊ณ ๋ฐฉ์๊ณผ ์๋์ ์ธ ์์ธ ์ถ๊ฐ
- ๋ช ํํ ์ ์ฑ ์ด๋ฆ(table + action + audience)
- ์ ์ฑ ๋ณ๊ฒฝ์ ์ฝ๋ ๋ณ๊ฒฝ์ฒ๋ผ ๋ฆฌ๋ทฐ
- ๋กค์์ ์ด๊ธฐ์ ๊ฑฐ๋ถ ๋ก๊ทธ ์์ง ๋ฐ ๊ฒํ
- RLS๊ฐ ์ ์ฉ๋ ์ ํ ์ด๋ธ๋ง๋ค ์์ ํ ์คํธ ์ธํธ ์ถ๊ฐ


