제로 트러스트의 핵심 원칙과 인증의 관계를 분석하고, 지속적 검증, 디바이스 신뢰, 컨텍스트 기반 접근 제어, BeyondCorp 모델, 아이덴티티 인식 프록시를 설명합니다.
전통적 네트워크 보안은 "성벽과 해자" 모델이었습니다. 방화벽 안쪽은 신뢰하고, 바깥은 신뢰하지 않는 구조입니다. 하지만 클라우드, 원격 근무, BYOD(Bring Your Own Device)가 일반화되면서 "안쪽"과 "바깥쪽"의 경계가 사라졌습니다. 제로 트러스트(Zero Trust)는 "아무도 신뢰하지 않는다"는 원칙에서 출발하여, 모든 접근을 검증하는 보안 모델입니다.
모든 접근 요청을 매번 검증합니다. 네트워크 위치(사내망, VPN)만으로 신뢰하지 않고, 사용자 아이덴티티, 디바이스 상태, 위치, 시간 등 모든 가용한 데이터를 기반으로 판단합니다.
JIT(Just-In-Time) 및 JEA(Just-Enough-Access) 원칙으로, 필요한 순간에 필요한 만큼만 권한을 부여합니다. 상시 관리자 권한은 제거하고, 요청 기반 승인 프로세스를 적용합니다.
이미 공격자가 내부에 있다고 가정하고 설계합니다. 네트워크를 마이크로 세그먼트로 분리하고, E2E 암호화를 적용하며, 이상 탐지와 모니터링을 강화합니다.
제로 트러스트에서 정책 결정점(PDP, Policy Decision Point)은 접근 허용 여부를 결정하는 중앙 두뇌이고, 정책 적용점(PEP, Policy Enforcement Point)은 각 리소스 앞에서 실제 접근을 차단하거나 허용하는 관문입니다. NIST SP 800-207에서 정의한 이 구조가 제로 트러스트의 표준 아키텍처입니다.
제로 트러스트에서 인증은 일회성 이벤트가 아니라 지속적 프로세스입니다. 초기 인증 이후에도 세션 내내 신뢰 수준을 지속적으로 평가합니다.
interface TrustSignals {
// 사용자 인증 관련
authMethod: "passkey" | "mfa" | "password" | "sso";
authAge: number; // 인증 후 경과 시간 (초)
authSessionRisk: number; // 세션 위험 점수 (0~1)
// 디바이스 관련
deviceManaged: boolean; // 관리 디바이스 여부
deviceCompliant: boolean; // 보안 정책 준수 여부
deviceOs: string;
devicePatched: boolean; // 최신 패치 적용 여부
// 네트워크/위치 관련
networkType: "corporate" | "vpn" | "home" | "public";
geoLocation: string;
geoAnomalyDetected: boolean; // 불가능한 이동 감지
// 행동 관련
requestPatternNormal: boolean;
dataAccessVolume: "normal" | "elevated" | "excessive";
}
function calculateTrustScore(signals: TrustSignals): number {
let score = 100;
// 인증 방법에 따른 점수
const authScores: Record<string, number> = {
passkey: 0, // 최고 수준, 감점 없음
mfa: -5,
sso: -10,
password: -25, // 비밀번호만 사용 시 큰 감점
};
score += authScores[signals.authMethod] ?? -30;
// 인증 경과 시간 (시간이 지날수록 감점)
const hoursElapsed = signals.authAge / 3600;
score -= Math.min(hoursElapsed * 2, 20);
// 디바이스 신뢰
if (!signals.deviceManaged) score -= 15;
if (!signals.deviceCompliant) score -= 20;
if (!signals.devicePatched) score -= 10;
// 네트워크 위치
const networkScores: Record<string, number> = {
corporate: 0,
vpn: -5,
home: -10,
public: -25,
};
score += networkScores[signals.networkType] ?? -30;
// 이상 탐지
if (signals.geoAnomalyDetected) score -= 40;
if (!signals.requestPatternNormal) score -= 15;
if (signals.dataAccessVolume === "excessive") score -= 25;
else if (signals.dataAccessVolume === "elevated") score -= 10;
return Math.max(0, Math.min(100, score));
}
// 접근 결정
interface AccessDecision {
allowed: boolean;
requireStepUp: boolean; // 추가 인증 필요
restrictions: string[]; // 적용할 제한사항
}
function makeAccessDecision(
trustScore: number,
resourceSensitivity: "low" | "medium" | "high" | "critical",
): AccessDecision {
const thresholds: Record<string, number> = {
low: 30,
medium: 50,
high: 70,
critical: 85,
};
const requiredScore = thresholds[resourceSensitivity];
if (trustScore >= requiredScore) {
return { allowed: true, requireStepUp: false, restrictions: [] };
}
if (trustScore >= requiredScore - 15) {
return {
allowed: true,
requireStepUp: true,
restrictions: ["read_only", "log_enhanced"],
};
}
return {
allowed: false,
requireStepUp: false,
restrictions: ["blocked"],
};
}신뢰 점수에 따라 인증 요구 수준을 동적으로 조정하는 것이 적응적 인증(Adaptive Authentication)입니다.
제로 트러스트에서 디바이스 신뢰는 사용자 인증만큼 중요합니다. 인증된 사용자라도 감염되거나 탈옥된 디바이스에서 접근하면 위험합니다.
interface DevicePosture {
// 디바이스 식별
deviceId: string;
platform: "windows" | "macos" | "ios" | "android" | "linux";
osVersion: string;
// 관리 상태
mdmEnrolled: boolean; // MDM(Mobile Device Management) 등록
managedProfile: boolean; // 기업 프로필 적용
// 보안 상태
diskEncrypted: boolean; // 디스크 암호화
firewallEnabled: boolean; // 방화벽 활성화
antivirusActive: boolean; // 안티바이러스 동작 중
screenLockEnabled: boolean;
jailbroken: boolean; // 탈옥/루팅 여부
// 패치 상태
osUpToDate: boolean;
lastPatchDate: Date;
criticalPatchesMissing: number;
// 인증서
clientCertificateValid: boolean;
certificateExpiry: Date;
}
function evaluateDeviceTrust(posture: DevicePosture): {
trusted: boolean;
score: number;
issues: string[];
} {
const issues: string[] = [];
let score = 100;
if (posture.jailbroken) {
issues.push("탈옥/루팅된 디바이스");
return { trusted: false, score: 0, issues };
}
if (!posture.diskEncrypted) {
issues.push("디스크 암호화 미적용");
score -= 25;
}
if (!posture.screenLockEnabled) {
issues.push("화면 잠금 미설정");
score -= 20;
}
if (!posture.osUpToDate) {
issues.push("OS 업데이트 필요");
score -= 15;
}
if (posture.criticalPatchesMissing > 0) {
issues.push(`주요 패치 ${posture.criticalPatchesMissing}개 누락`);
score -= posture.criticalPatchesMissing * 10;
}
if (!posture.mdmEnrolled) {
issues.push("MDM 미등록");
score -= 15;
}
return {
trusted: score >= 60 && issues.length <= 2,
score: Math.max(0, score),
issues,
};
}BeyondCorp는 Google이 내부적으로 구현한 제로 트러스트 아키텍처로, VPN 없이 모든 직원이 인터넷을 통해 사내 서비스에 접근하는 모델입니다.
BeyondCorp의 핵심 구성 요소는 다음과 같습니다.
BeyondCorp 모델의 가장 혁신적인 부분은 VPN을 제거했다는 것입니다. 사무실에서 접근하든, 카페에서 접근하든 동일한 인증과 인가 과정을 거칩니다. 네트워크 위치가 아닌 아이덴티티가 보안의 기준이 됩니다.
아이덨티티 인식 프록시(IAP)는 제로 트러스트의 PEP 역할을 합니다. 모든 HTTP 요청을 가로채 인증 상태와 권한을 확인한 뒤 백엔드로 전달합니다.
import { IncomingMessage, ServerResponse } from "http";
import httpProxy from "http-proxy";
const proxy = httpProxy.createProxyServer({});
interface ProxyConfig {
target: string;
requiredTrustLevel: number;
requiredRoles?: string[];
allowedMethods?: string[];
}
const routeConfigs: Record<string, ProxyConfig> = {
"/admin": {
target: "http://admin-service:3000",
requiredTrustLevel: 85,
requiredRoles: ["admin"],
allowedMethods: ["GET", "POST", "PUT", "DELETE"],
},
"/api": {
target: "http://api-service:8080",
requiredTrustLevel: 50,
allowedMethods: ["GET", "POST"],
},
"/docs": {
target: "http://docs-service:3000",
requiredTrustLevel: 30,
allowedMethods: ["GET"],
},
};
async function handleRequest(
req: IncomingMessage,
res: ServerResponse,
): Promise<void> {
// 1. 토큰 검증
const token = extractBearerToken(req);
if (!token) {
redirectToLogin(res);
return;
}
const userContext = await verifyAndEnrichToken(token);
if (!userContext) {
res.writeHead(401);
res.end("인증이 필요합니다.");
return;
}
// 2. 디바이스 신뢰 확인
const devicePosture = await getDevicePosture(
req.headers["x-device-id"] as string
);
// 3. 신뢰 점수 계산
const trustScore = calculateTrustScore({
authMethod: userContext.authMethod,
authAge: Date.now() / 1000 - userContext.authTime,
authSessionRisk: userContext.sessionRisk,
deviceManaged: devicePosture.mdmEnrolled,
deviceCompliant: devicePosture.trusted,
deviceOs: devicePosture.platform,
devicePatched: devicePosture.osUpToDate,
networkType: classifyNetwork(req.socket.remoteAddress ?? ""),
geoLocation: userContext.geoLocation,
geoAnomalyDetected: await detectGeoAnomaly(userContext),
requestPatternNormal: await checkRequestPattern(userContext.userId),
dataAccessVolume: "normal",
});
// 4. 라우트별 정책 적용
const routeConfig = findRouteConfig(req.url ?? "/");
if (!routeConfig) {
res.writeHead(404);
res.end("Not Found");
return;
}
if (trustScore < routeConfig.requiredTrustLevel) {
res.writeHead(403);
res.end("신뢰 수준이 부족합니다. 추가 인증이 필요합니다.");
await logAccessDenied(userContext, req.url ?? "/", trustScore);
return;
}
// 5. 인증 정보를 헤더로 전달
req.headers["x-authenticated-user"] = userContext.userId;
req.headers["x-user-roles"] = userContext.roles.join(",");
req.headers["x-trust-score"] = trustScore.toString();
req.headers["x-device-trust"] = devicePosture.trusted.toString();
// 6. 백엔드로 프록시
proxy.web(req, res, { target: routeConfig.target });
// 7. 감사 로그
await logAccess(userContext, req.url ?? "/", trustScore, "allowed");
}interface AccessPolicy {
name: string;
description: string;
conditions: PolicyCondition[];
effect: "allow" | "deny" | "step_up";
}
type PolicyCondition =
| { type: "trust_score_min"; value: number }
| { type: "auth_method"; value: string[] }
| { type: "device_managed"; value: boolean }
| { type: "network_type"; value: string[] }
| { type: "time_range"; start: string; end: string }
| { type: "geo_country"; value: string[] };
const policies: AccessPolicy[] = [
{
name: "critical-data-access",
description: "기밀 데이터 접근 정책",
conditions: [
{ type: "trust_score_min", value: 85 },
{ type: "auth_method", value: ["passkey", "mfa"] },
{ type: "device_managed", value: true },
{ type: "geo_country", value: ["KR", "US"] },
],
effect: "allow",
},
{
name: "after-hours-restriction",
description: "근무 시간 외 접근 제한",
conditions: [
{ type: "time_range", start: "22:00", end: "06:00" },
],
effect: "step_up",
},
{
name: "public-wifi-restriction",
description: "공용 네트워크 접근 제한",
conditions: [
{ type: "network_type", value: ["public"] },
],
effect: "deny",
},
];제로 트러스트는 기술만으로 완성되지 않습니다. 조직 문화, 프로세스, 사용자 교육이 함께 변화해야 합니다. VPN을 걷어내고 IAP로 전환하는 것은 기술적 결정이지만, 직원들의 일상적 업무 방식을 바꾸는 것이므로 단계적이고 신중한 접근이 필요합니다.
제로 트러스트는 "네트워크 위치가 곧 신뢰"라는 전통적 가정을 거부하고, 모든 접근을 매번 검증하는 보안 모델입니다. 아이덴티티와 디바이스 신뢰가 보안의 중심이 되며, 지속적 검증과 적응적 인증이 핵심 메커니즘입니다. BeyondCorp는 이 모델의 가장 성숙한 구현 사례이며, IAP는 이를 기술적으로 실현하는 핵심 컴포넌트입니다.
다음 장에서는 서비스 간 통신에서의 인증 문제를 다룹니다. API 인증과 마이크로서비스 간 통신 보안을 살펴보겠습니다.
이 글이 도움이 되셨나요?
API 키 관리, OAuth Client Credentials, mTLS를 활용한 서비스 간 인증, 마이크로서비스에서의 JWT 전파, API 게이트웨이 인증 패턴을 실전 코드와 함께 설명합니다.
JWT의 클레임과 서명 알고리즘을 깊이 분석하고, 리프레시 토큰 로테이션, 토큰 저장 전략, 세션 관리 패턴, BFF 패턴을 실전 코드와 함께 설명합니다.
GDPR, PCI-DSS, SOC 2가 인증 시스템에 부과하는 구체적 요구사항, NIST 800-63B 비밀번호 가이드라인, 감사 로깅 설계, MFA 요구사항, 데이터 거주 전략을 정리합니다.