웹 개발 실무 기술 A to Z # 22 - 멀티테넌트 웹 애플리케이션: 데이터 분리, 사용자 격리, 보안 전략
웹 개발 실무 기술 A to Z
멀티테넌트(Multi-Tenant) 아키텍처는 하나의 애플리케이션이 여러 고객(테넌트)을 지원할 수 있도록 설계하는 방식입니다.
✔️ 데이터 분리 전략 → 각 테넌트의 데이터가 독립적으로 관리되도록 설정
✔️ 사용자 격리 및 보안 → 각 테넌트 간의 데이터 침범 방지
✔️ 스케일링 및 성능 최적화 → 트래픽 증가에 따른 확장 가능
이번 글에서는 멀티테넌트 웹 애플리케이션 구축 전략과 보안 최적화 방법을 설명하겠습니다.
1. 멀티테넌트 아키텍처란?
✔️ 하나의 애플리케이션이 여러 고객(테넌트)에게 서비스를 제공하는 방식
✔️ 각 테넌트가 개별적으로 데이터와 설정을 유지하지만, 하나의 애플리케이션 코드베이스를 공유
✔️ B2B SaaS(Software as a Service) 모델에서 자주 사용
✅ 멀티테넌트 아키텍처를 활용하면 여러 기업(테넌트)에게 하나의 서비스를 효율적으로 제공 가능!
2. 멀티테넌트 데이터 관리 전략
멀티테넌트 웹 애플리케이션을 설계할 때 가장 중요한 부분은 각 테넌트의 데이터를 어떻게 분리할 것인가입니다.
2-1. 테넌트별 데이터 분리 방법
전략 설명 장점 단점
단일 데이터베이스, 공유 테이블 | 하나의 DB에 테넌트 데이터를 테넌트 ID 기반으로 저장 | 유지보수 간편, 비용 절감 | 보안 위험 증가, 성능 저하 가능 |
단일 데이터베이스, 분리된 스키마 | 같은 DB 내에서 테넌트별 스키마 분리 | 보안 및 성능 균형 유지 | 관리 복잡성 증가 |
테넌트별 개별 데이터베이스 | 테넌트마다 독립된 DB를 사용 | 높은 보안 및 성능 | 유지보수 부담 증가 |
✅ 비즈니스 요구 사항에 따라 적절한 데이터 분리 전략을 선택해야 함!
2-2. PostgreSQL에서 멀티테넌트 데이터 관리
(1) 단일 테이블, 테넌트 ID 포함
CREATE TABLE users (
id SERIAL PRIMARY KEY,
tenant_id INT NOT NULL,
username VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL
);
(2) 테넌트별 스키마 분리
CREATE SCHEMA tenant1;
CREATE SCHEMA tenant2;
CREATE TABLE tenant1.users (
id SERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL
);
CREATE TABLE tenant2.users (
id SERIAL PRIMARY KEY,
username VARCHAR(100) NOT NULL,
email VARCHAR(100) NOT NULL
);
✅ 스키마를 분리하면 테넌트별 독립적인 데이터 저장 가능!
3. 사용자 인증 및 격리
멀티테넌트 환경에서는 각 테넌트별 사용자 인증 및 격리를 철저하게 관리해야 합니다.
3-1. 테넌트 기반 JWT(JSON Web Token) 인증
✔️ 사용자가 로그인하면 JWT에 tenant_id 포함
✔️ API 요청 시 tenant_id를 확인하여 데이터 필터링
(1) JWT 생성 시 테넌트 ID 포함
const jwt = require("jsonwebtoken");
function generateToken(user) {
return jwt.sign(
{ userId: user.id, tenantId: user.tenant_id },
process.env.JWT_SECRET,
{ expiresIn: "1h" }
);
}
(2) JWT 검증 미들웨어
const authMiddleware = (req, res, next) => {
const token = req.header("Authorization")?.split(" ")[1];
if (!token) return res.status(401).json({ error: "Access denied" });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = decoded;
next();
} catch (error) {
res.status(401).json({ error: "Invalid token" });
}
};
✅ 각 테넌트의 데이터 접근을 JWT 기반으로 제어 가능!
4. 테넌트별 API 요청 관리
각 테넌트가 동일한 API를 사용하지만, 각각의 데이터를 격리하여 관리해야 합니다.
4-1. Express에서 테넌트별 API 요청 처리
app.get("/users", authMiddleware, async (req, res) => {
const { tenantId } = req.user;
const users = await db.query("SELECT * FROM users WHERE tenant_id = $1", [tenantId]);
res.json(users.rows);
});
✅ 각 테넌트는 자신의 데이터만 조회 가능하도록 API 보안 적용!
5. 멀티테넌트 보안 전략
5-1. 각 테넌트 간 데이터 격리
✔️ API 요청 시 반드시 tenant_id 확인
✔️ DB에서 tenant_id 기반으로 필터링하여 데이터 조회
5-2. Rate Limiting 적용 (DDoS 방어)
npm install express-rate-limit
const rateLimit = require("express-rate-limit");
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15분 동안
max: 100, // 최대 100개 요청 허용
});
app.use("/api/", limiter);
✅ Rate Limiting을 적용하면 특정 테넌트가 과도한 API 요청을 보내는 것을 방지 가능!
6. 멀티테넌트 아키텍처 적용 전후 비교
6-1. 적용 전
- 모든 사용자가 동일한 DB 사용 → 보안 위험 증가
- 고객별 데이터 분리가 어려움 → 사용자 간 데이터 침범 가능
- 트래픽 증가 시 성능 저하 발생
6-2. 적용 후
✔️ 데이터 분리 전략 적용 → 테넌트 간 데이터 격리 유지
✔️ JWT 기반 인증 적용 → 테넌트별 사용자 인증 강화
✔️ 스케일링 가능 → 테넌트 수 증가에도 유연하게 확장 가능
✅ 멀티테넌트 아키텍처를 적용하면 확장성과 보안을 동시에 확보 가능!
7. 마무리 및 다음 글 예고
이번 글에서는 멀티테넌트 웹 애플리케이션의 데이터 분리, 사용자 격리 및 보안 전략을 살펴봤습니다.
다음 글에서는 **웹 애플리케이션 로깅 및 모니터링 (ELK Stack, Prometheus, Grafana 활용)**을 소개하겠습니다.
다음 글 예고: "웹 애플리케이션 로깅 및 모니터링 – ELK Stack, Prometheus, Grafana 활용" 🚀