Mock SaaS 아키텍처 청사진
Mock SaaS 서비스를 안전하고 유연하게 운영하기 위한 엔터프라이즈 배포 구조입니다. 제로 트러스트 기반의 엄격한 테넌트 격리와 클라우드 환경의 수평 확장을 고려해 설계했습니다.
Google Cloud 아키텍처 다이어그램
또는 /service-immediately/mcp/*"| Armor[Cloud Armor: 속도 제한 정책] Armor --> Bypass[바이패스 백엔드: IAP 비활성화] Bypass --> NEG SM_IAP_Secret -.->|OAuth 자격증명 제공| IAP end subgraph Module_IAM [모듈: iam] SA[서비스 계정: mock-saas-sa] end subgraph VPC_Network [비공개 VPC 네트워크 영역] subgraph Module_Cloud_Run [모듈: cloud_run] RunService[Cloud Run 서비스: mock-saas-services-prod] end subgraph Module_VPC [모듈: vpc] Subnet[VPC 사설 서브넷] peering[VPC 피어링 연결] end subgraph Module_DB [모듈: db - AlloyDB] subgraph AlloyDB_Cluster [AlloyDB 클러스터] AlloyDB_IP[프라이머리 인스턴스 IP: 10.0.0.X] end end end SM_DB_Secret[(Secret Manager: DB 비밀번호)] SM_MCP_Secret[(Secret Manager: MCP HMAC 키)] end Client -->|HTTPS 요청| IP McpClient -->|Bearer PAT 인증 요청| IP NEG -->|비공개 수신 트래픽| RunService RunService -->|직접 VPC 발신 트래픽| Subnet Subnet -->|피어링 연결| peering peering -->|TCP 포트 5432| AlloyDB_IP SA -.->|서비스 계정 바인딩| RunService SA -.->|접근 권한 부여| SM_DB_Secret SA -.->|접근 권한 부여| SM_MCP_Secret RunService -.->|시크릿 조회| SM_DB_Secret RunService -.->|시크릿 조회| SM_MCP_Secret %% Node Colors & Styles %% style Client fill:#FFE9D6,stroke:#FF9E4A,stroke-width:2px; style McpClient fill:#F3E8FF,stroke:#A855F7,stroke-width:2px; style IP fill:#E8F0FE,stroke:#4285F4,stroke-width:2px; style LB fill:#E8F0FE,stroke:#4285F4,stroke-width:2px; style IAP fill:#E8F0FE,stroke:#4285F4,stroke-width:2px; style Armor fill:#FCE8E6,stroke:#EA4335,stroke-width:2px; style Bypass fill:#E2F0D9,stroke:#70AD47,stroke-width:2px; style NEG fill:#E8F0FE,stroke:#4285F4,stroke-width:2px; style SA fill:#FFF0F5,stroke:#DB7093,stroke-width:2px; style RunService fill:#E6F4EA,stroke:#34A853,stroke-width:2px; style Subnet fill:#F1F8F5,stroke:#82C394,stroke-width:1px,stroke-dasharray: 5 5; style peering fill:#E6F4EA,stroke:#34A853,stroke-width:2px; style VPC_Network fill:#F8FAFC,stroke:#0284c7,stroke-width:2.5px,stroke-dasharray: 6 6; style AlloyDB_Cluster fill:#FCE8E6,stroke:#EA4335,stroke-width:1px; style AlloyDB_IP fill:#FCE8E6,stroke:#EA4335,stroke-width:2px; style SM_IAP_Secret fill:#FEF7E0,stroke:#FBBC04,stroke-width:2px; style SM_DB_Secret fill:#FEF7E0,stroke:#FBBC04,stroke-width:2px; style SM_MCP_Secret fill:#FEF7E0,stroke:#FBBC04,stroke-width:2px;
보안 아키텍처
인프라 전반에 걸쳐 경계 보안, 세션별 테넌트 격리, 데이터 암호화를 기본 원칙으로 적용했습니다.
경계 접근 제어
일반 웹 사용자는 글로벌 외부 HTTPS 로드밸런서를 통해 서비스에 접속합니다. 네트워크 엣지에서 Google Cloud Armor가 비정상 트래픽과 과도한 요청을 먼저 차단하고, Identity-Aware Proxy(IAP)가 구글 계정 인증과 역할 기반 IAM 권한을 검증합니다.
Cloud Armor를 통한 MCP 엣지 보안
AI 에이전트는 프로그래밍 방식으로 MCP 엔드포인트(/work-week/mcp/*
및 /service-immediately/mcp/*)에 연결합니다.
외부 API 클라이언트의 원활한 통신을 위해 이 경로는 IAP 인증을 우회하지만, 로드밸런서 엣지에 위치한 Google Cloud Armor 보안 정책으로 철저히 보호됩니다. Cloud Armor는 요청 속도 제한(Rate Limiting), IP 차단 규칙, 웹 애플리케이션 방화벽(WAF) 룰셋을 적용해 L7 DDoS 및 무차별 대입 공격을 컨테이너 도달 전에 선제적으로 차단합니다.
비공개 네트워크 및 데이터 격리
Cloud Run 컨테이너는 비공개 VPC 네트워크를 통해 데이터베이스와 통신합니다. 서버리스 VPC 커넥터가 사설 서브넷으로 트래픽을 전달하고, VPC 피어링을 거쳐 AlloyDB 프라이머리 인스턴스(10.0.0.X)로 연결됩니다.
데이터베이스에는 공인 IP가 전혀 부여되지 않으므로 외부 인터넷에서 직접 접근할 수 없습니다.
HMAC 토큰 보안 및 Secret Manager 연동
개인 접근 토큰은 암호화된 HMAC 서명을 사용해 무상태(Stateless) 방식으로 검증합니다. 서명 키는 Google Cloud Secret Manager에 안전하게 보관되며, Cloud Run 서비스 계정 권한으로만 런타임에 읽어옵니다. 평문 자격증명 노출을 원천 방지하고 토큰 위변조를 막으면서도 세션 DB 조회 오버헤드를 없앴습니다.
확장성 및 성능 설계
대규모 동시 요청 환경에서도 안정적으로 동작하도록 완전 관리형 서버리스 아키텍처를 구성했습니다.
Cloud Run 서버리스 자동 확장
핵심 애플리케이션은 Google Cloud Run 위에서 동작합니다. CPU 사용량과 동시 요청 수에 따라 컨테이너 인스턴스가 0대에서 N대까지 유연하게 확장되며, 사용하지 않는 유휴 시간에는 0대로 줄어들어 불필요한 인프라 비용을 최소화합니다.
글로벌 엣지 라우팅 인프라
글로벌 HTTPS 로드밸런서가 서버리스 네트워크 엔드포인트 그룹(NEG)으로 트래픽을 라우팅합니다. 전 세계 클라이언트는 가장 가까운 Google Frontend(GFE) 엣지 서버로 직접 연결되어 네트워크 지연 시간이 크게 줄어들고 분산 서비스 거부 공격을 효율적으로 흡수합니다.
엔터프라이즈 데이터 처리 용량
백엔드 스토리지인 AlloyDB 클러스터는 대용량 워크로드에 맞춰 확장할 수 있습니다. 멀티 존 복제 구성과 높은 쓰기 동시성, 컬럼형 엔진을 지원하여 트랜잭션 처리(OLTP)와 실시간 분석 쿼리를 안정적으로 소화합니다.
무상태 Streamable HTTP 및 표준 SSE 듀얼 지원
백엔드 FastMCP 서버는 상태 유지형 SSE(Server-Sent Events) 대신 무상태 Streamable HTTP를 기본 전송 프로토콜로 사용합니다. 일반적인 SSE 방식은 개별 컨테이너 메모리에 세션 연결 상태를 유지하므로, Cloud Run처럼 컨테이너가 수시로 증설되거나 엣지 라우팅 경로가 바뀔 때 404 세션 오류나 연결 끊김이 발생하기 쉽습니다. 반면 무상태 Streamable HTTP는 각 요청과 응답을 독립된 트랜잭션으로 처리하므로, 어떤 컨테이너로 요청이 인입되어도 끊김 없이 처리할 수 있어 진정한 수평 확장을 보장합니다.