project/웹 개발 실무 기술 A to Z

웹 개발 실무 기술 A to Z # 22 - 멀티테넌트 웹 애플리케이션: 데이터 분리, 사용자 격리, 보안 전략

octo54 2025. 2. 25. 14:58
반응형

웹 개발 실무 기술 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 활용" 🚀