본문 바로가기
어플리케이션

VPN·점프호스트의 끝, 제로트러스트 액세스 플랫폼 Teleport

by forward error correction Circle 2026. 7. 2.
반응형

Ⅰ. Teleport 기술이란?

왜 필요한가 — "VPN 들어가서 점프호스트 거쳐서 SSH 키로 로그인"의 비용

 

2026년 시점에도 많은 조직에서 운영 인프라 접근의 표준 패턴은 다음과 같습니다 — (1) VPN을 켜고, (2) 점프호스트(bastion)에 공유 계정으로 로그인하고, (3) 거기서 다시 개인 SSH 개인키로 타깃 서버에 들어갑니다. DB 접근은 (4) 별도 비밀번호 vault에서 자격증명을 꺼내 (5) IP 화이트리스트가 걸린 RDS에 접속하고, K8s 접근은 (6) kubeconfig 파일을 슬랙으로 받습니다. 감사 로그는 (7) 각 호스트의 syslog와 (8) DB의 audit table과 (9) K8s API audit log를 따로 모아야 합니다. 이 전체가 "한 사람의 신원으로 한 액션을 했다"는 단일 진실 한 줄을 만들지 못합니다.

 

이 운영 형태가 만드는 일상적 비용은 다음과 같습니다. 첫째, SSH 키·DB 비밀번호·kubeconfig는 만료가 없습니다. 퇴사한 개발자의 키가 그대로 남아 있고, 한 번 유출되면 모든 호스트가 동시에 노출됩니다. 둘째, VPN은 네트워크 신뢰입니다 — VPN 안에 들어오면 동일 IP 대역의 모든 서비스가 보입니다. 한 번 뚫리면 lateral movement가 무제한입니다. 셋째, 점프호스트는 단일 신원이 아닙니다. 공유 계정으로 들어가서 sudo로 누가 어떤 명령을 쳤는지 사후 추적이 어렵고, last/wtmp는 위·변조가 쉽습니다. 넷째, 액세스 리뷰가 분기 1회 스프레드시트입니다. "누가 어떤 호스트·DB·클러스터에 접근 가능한가"를 묻는 질문에 즉답할 수 없습니다. 다섯째, just-in-time 권한 부여가 없습니다. 새벽 3시 인시던트에서 임시로 prod-db 접근이 필요해도 PR을 올리거나 슬랙으로 sysadmin을 깨워야 합니다. 여섯째, SOC2·ISO27001·HIPAA 감사 시점에 evidence를 모으느라 1주일이 사라집니다.

기존 방식 손으로 하면 현실의 비용
VPN + Bastion + SSH 키 authorized_keys, OpenVPN/WireGuard, 점프호스트 SSH 키 만료 부재, 퇴사자 정리 누락, 공유 계정으로 신원 추적 불가, lateral movement 무제한
Vault + IP 화이트리스트(DB) HashiCorp Vault에서 비번 발급, RDS 시큐리티 그룹 수동 관리 CIDR 폭증, 공유 비번 재사용, DB audit log를 사용자 신원과 매핑 불가
kubeconfig 슬랙 공유 aws eks update-kubeconfig 결과를 그대로 공유 cert TTL이 길어 회수 불가, namespace별 격리는 RBAC YAML 수동 관리
BeyondCorp DIY IAP·CAP·OPA·Open ID Connect 직접 조립 SSH·DB·RDP까지 protocol-aware하게 다 만드는 데 수년, 사실상 Google 규모 회사만 가능
StrongDM / HashiCorp Boundary 상용 게이트웨이 또는 Boundary 클러스터 StrongDM은 SaaS 의존·자체호스팅 약함, Boundary는 OSS지만 protocol coverage(특히 K8s·DB Web Session)가 얕음
Teleport SSO → 단명 인증서 → 단일 Proxy → SSH/K8s/DB/App/Desktop Auth Service의 etcd 또는 DynamoDB 백엔드 운영, 인증서 TTL 정책 설계, 세션 녹화 스토리지 비용

Teleport는 정확히 이 결합을 푸는 것이 목표입니다. 2015년 Gravitational이 K8s 운영 도구로 출발했고, 2016년 OSS 공개, 2020년 사명을 Teleport Inc로 변경했으며, 2026년 시점의 v17.x는 Trusted Device(디바이스 인증)·Access Lists(주기적 액세스 리뷰의 1급 객체화)·Identity Governance·Machine ID(워크로드 ID)·MCP Access까지 갖춘 라인업입니다. 라이선스는 OSS Edition AGPL-3.0(2023년 Apache-2.0에서 전환), Enterprise/Cloud는 별도 상용입니다. 라이선스 전환은 코드 자체는 그대로 보되 SaaS 재판매를 막는 의도이고, 자체 호스팅과 일반 사용은 OSS로 충분합니다.

 

기술 정의

Teleport 인증서 기반 단일 신원 모델 위에 SSH·Kubernetes·Database·Web Application·Windows Desktop 5개 프로토콜에 대한 protocol-aware 프록시·세션 녹화·RBAC·SSO·MFA·감사 로그를 단일 디스트리뷰션으로 묶은 제로트러스트 인프라 액세스 플랫폼입니다(gravitational/teleport, Go, AGPL-3.0, v17.x 2026 현재). 모든 사용자는 SAML·OIDC·GitHub SSO로 로그인하면 X.509 인증서(웹·DB·K8s용)와 SSH 인증서(SSH용) 한 쌍을 받고, 이 인증서는 사용자명·역할·트레이트·디바이스 신뢰 상태·세션 TTL을 모두 인증서 자체에 박아 넣습니다(SSH cert의 critical options, X.509의 SAN/extensions). Auth Service가 내부 CA 역할을 하고 etcd·DynamoDB·Postgres·Firestore 중 하나를 백엔드로 사용합니다. Proxy Service는 단일 외부 진입점(443/3023/3024/3026)으로 모든 트래픽을 받고, ALPN·SNI 라우팅으로 프로토콜을 분기해 Agent 측의 reverse tunnel로 전달합니다. RBAC는 Role CRD-스타일 YAML로 정의하며, 한 Role 안에서 SSH 노드 라벨 매처·K8s 그룹·DB 사용자·앱 라벨·Windows AD 그룹을 동시에 표현합니다. 모든 세션은 구조화 이벤트 스트림(session.start/data/end, db.session.query, kube.request 등)으로 분해되어 S3·DynamoDB Stream·Athena·SIEM으로 출력됩니다.

Ⅱ. Teleport 기술 특징

특징 기술적 디자인 실무에서 의미
Certificate-only 신원 SSH/X.509 인증서가 사용자명·역할·트레이트·TTL을 캡슐화 authorized_keys 0줄, DB 비번 0개, kubeconfig는 자동 갱신, 만료가 자동 회수
Short-lived TTL(기본 12h) cert TTL 5m~30h 사이로 정책에 따라 발급 키 유출 윈도우가 시간 단위, 퇴사 처리는 SSO에서 비활성화하면 끝
Protocol-aware Proxy SSH/K8s API/Postgres wire/MySQL wire/RDP 각 프로토콜을 직접 파싱 SQL 쿼리 단위, kubectl exec 단위로 권한·감사가 가능
Reverse Tunnel Agent 노드/DB/앱이 Proxy로 outbound TLS 연결을 만들어 유지 사설망·NAT·온프렘 데이터센터에 inbound 포트 0개로 접근 가능
Session Recording SSH는 PTY 스트림, K8s exec/attach, DB는 쿼리 스트림, RDP는 실제 화면 비트맵 사후 재생 가능, SOC2 evidence가 자동 생성, S3 immutable bucket과 매끄럽게 연동
RBAC + Trait 기반 동적 권한 Role에 {{external.team}} 같은 SSO 클레임 템플릿 사용 SSO 그룹만 정리하면 노드 라벨 매처가 자동으로 권한 좁힘
Per-session MFA WebAuthn 또는 Touch ID로 세션 시작마다 추가 검증 cert가 유출돼도 세션 개시는 막힘, 민감 prod 노드에 강제 가능
Just-in-Time Access Request tsh request 명령으로 임시 역할 신청, Slack/PagerDuty로 승인 "평소엔 read-only, 인시던트 30분만 prod-admin"이 1급 객체
Trusted Clusters 루트 클러스터-리프 클러스터 양방향 신뢰, 역할 매핑 고객별 격리 클러스터를 한 SSO 신원으로 다 접근, MSP·dev/staging/prod 분리에 적합
Machine ID(tbot) CI 러너·서버·앱이 join token이나 IAM/AWS/GitHub OIDC로 인증서 받음 CI에 박힌 SSH 키·DB 비번 박멸, GitHub Actions에서 OIDC만으로 prod DB 접근
Device Trust Secure Enclave/TPM에서 단단한 디바이스 키, cert에 device-attested 클레임 "회사 노트북에서만" 같은 정책이 가능, BYOD 차단
Access Lists / Reviews N분기마다 자동 리뷰 만료, 만료 시 권한 자동 회수 SOC2 CC6.1·CC6.2의 액세스 리뷰 evidence가 시스템 안에서 자동 생성

여기서 가장 핵심적이고 다른 도구로 잘 대체되지 않는 결정은 두 가지입니다. (a) 인증서가 신원을 직접 운반합니다. Tailscale이나 일반 VPN이 "이 IP의 패킷은 검증된 사용자에게서 왔다"는 네트워크 단정에 그치는 반면, Teleport의 cert는 인증서 그 자체에 사용자명·역할·트레이트가 박혀 있어서 노드 측 sshd가 인증서만 보고 "이 사용자는 어떤 OS 계정으로 로그인 가능한지"를 즉시 결정합니다. (b) 프로토콜을 직접 끝낸다(terminate). 일반 TCP 프록시와 달리 Teleport Proxy는 SSH 핸드셰이크, K8s API의 mTLS, Postgres wire, MySQL wire, MongoDB wire, RDP의 그래픽 채널을 직접 파싱합니다. 이 덕에 "SELECT * FROM users WHERE id=42를 누가 prod에서 쳤는지"가 단일 감사 이벤트 한 줄로 떨어집니다.

Ⅲ. Teleport 기술 동작방식

ⅰ. 구성 요소

컴포넌트 역할 상세
Auth Service CA, 정책 엔진, 신뢰의 루트 사용자/노드/호스트 CA 한 쌍씩 보관, RBAC 정책 평가, 백엔드 etcd/DynamoDB/Firestore/Postgres
Proxy Service 데이터 평면의 단일 진입점 443(웹/ALPN)·3023(SSH proxy)·3024(reverse tunnel)·3080(HTTPS), Agent의 outbound 터널을 받아 라우팅
Node Agent(SSH) 호스트에 설치되는 sshd 대체 Auth가 발급한 host cert로 신원 증명, Proxy로 reverse tunnel 유지, OS 계정 매핑은 cert의 principals
Kubernetes Agent K8s API의 사이드카 프록시 in-cluster 에이전트가 kube-apiserver의 SA 토큰을 들고, Teleport cert의 클레임을 K8s 그룹·impersonation으로 변환
Database Service Postgres·MySQL·MongoDB·Redis·Snowflake 등 wire 프록시 RDS IAM Auth·GCP Cloud SQL Auth·Atlas X.509까지 통합, 클라이언트는 tsh proxy db를 거쳐 평범한 psql 사용
App Service 내부 웹앱 액세스(Grafana·Jenkins·Argo CD) JWT를 헤더에 주입해 앱이 신원을 알 수 있게 함, AWS/Azure 콘솔 통합도 동일 모델
Desktop Service(RDP) Windows AD 데스크톱·서버 RDP LDAPS로 AD에 short-lived 사용자 cert 등록, 화면 비트맵 녹화, 클립보드/디렉터리 공유 정책
tsh / tctl / Teleport Connect 사용자 CLI·관리자 CLI·GUI 클라이언트 tsh는 SSO 로그인·cert 보관·proxy, tctl은 RBAC/사용자/토큰 관리, Connect는 macOS/Windows/Linux GUI
Machine ID(tbot) 사람이 아닌 워크로드용 신원 발급기 CI/서버에서 OIDC·IAM·AWS instance profile 등으로 join, cert를 디스크/tmpfs로 짧게 갱신

ⅱ. 데이터 흐름

Teleport의 모든 트래픽은 두 종류의 신뢰 관계 위에서 흐릅니다 — (1) Auth가 발급한 사용자 cert를 들고 Proxy를 통해 들어가는 흐름, (2) Auth가 발급한 host cert를 들고 Agent가 Proxy로 outbound 터널을 만들어 유지하는 흐름. 사용자 흐름과 에이전트 흐름이 Proxy 안에서 만나서 양쪽 cert가 서로의 CA에 의해 검증되어야 비로소 데이터가 흐릅니다. 이 단순한 모델이 "Auth만 죽지 않으면 새 cert가 나오지 못하니 결국 만료된다"는 자기 회수 메커니즘을 만들고, "Agent는 inbound 포트가 필요 없다"는 운영 이점을 만듭니다.

한 SSH 세션의 라이프사이클을 따라가 봅니다. (1) 사용자가 tsh login --proxy=teleport.acme.com을 실행하면 브라우저가 열려 SSO(Okta/Azure AD/Google) 인증으로 OIDC/SAML 응답을 받습니다. (2) tsh가 이 응답을 Auth Service에 전달하고, Auth가 사용자의 SSO 클레임을 RBAC Role과 매칭해 SSH 인증서·X.509 인증서·OpenSSH-호환 인증서 3종 + private key를 발급합니다. (3) cert는 사용자의 ~/.tsh에 저장되고 기본 12시간 TTL로 모든 후속 명령에 자동 첨부됩니다. (4) 사용자가 tsh ssh root@web-01을 치면 tsh가 Proxy의 3023 포트에 cert를 들고 접속합니다. (5) Proxy는 cert에서 user·roles를 꺼내 RBAC를 평가하고, 라벨 매처가 web-01의 라벨과 일치하면 통과시킵니다. (6) Proxy는 web-01이 미리 만들어 유지하고 있던 reverse tunnel을 따라 Node Agent에 도달, mux 채널을 하나 엽니다. (7) Node Agent는 사용자 cert의 principals(허용 OS 계정 목록)을 보고 root로 PTY를 띄웁니다. (8) 모든 입출력 바이트가 session.start·session.data·session.end 이벤트로 분해되어 S3와 audit log 백엔드에 저장됩니다. (9) 사용자가 exit하면 cert는 그대로지만 세션은 종료, 다음 SSH는 cert가 만료될 때까지 자유롭게 가능하고, cert 만료 후엔 다시 tsh login이 필요합니다.

Ⅳ. Teleport 구성 및 흐름도

ⅰ. 아키텍처 다이어그램

ⅱ. 단계별 처리 흐름 — "tsh ssh root@db-01"이 도착하기까지

단계 동작 검증·관측 포인트
1 tsh login → 브라우저로 SSO 리다이렉트, 콜백으로 OIDC/SAML 응답 수령 Auth Service가 SSO 클레임을 트레이트로 매핑해 cert 발급 요청을 평가
2 Auth가 사용자 CA로 SSH cert + X.509 cert 발급, ~/.tsh에 저장(TTL 12h) tsh status로 cert principals/roles/expires 확인 가능
3 tsh ssh root@db-01 → tsh가 Proxy 3023에 cert로 인증, db-01을 라벨로 검색 Proxy가 cert에서 사용자 roles 추출, 라벨 매처를 평가하고 매칭 노드의 reverse tunnel을 찾음
4 민감 라벨이면 per-session MFA 챌린지 → WebAuthn/Touch ID 응답 실패 시 즉시 거부, 성공 시 Proxy가 단명 MFA 토큰을 첨부
5 Proxy가 db-01의 reverse tunnel을 따라 Node Agent에 mux 채널 오픈, cert 전달 Node Agent가 cert principals(예: root, ubuntu)을 보고 OS 계정 매핑
6 PTY 시작, 사용자 입력·노드 출력이 양방향 스트림으로 흐름 session.start·session.data 이벤트가 audit log로 송출
7 세션 종료 시 PTY 스트림이 *.gz 형태로 S3에 업로드 tsh play <session-id>로 그대로 재생, IP·duration·bytes도 동시 기록
8 cert TTL 만료 후 새 명령은 거부 → tsh login 재실행 SSO에서 사용자 비활성화 시점부터는 새 cert 발급 자체가 막힘 (기존 cert는 만료까지 유효)

Ⅴ. Teleport 설치 방법

설치는 4가지 형태가 있습니다 — (a) Linux 바이너리 + systemd(가장 단순, 자체 호스팅), (b) Docker / Docker Compose(빠른 PoC), (c) Helm chart on Kubernetes(Auth+Proxy를 K8s에서 운영, HA 구성 권장), (d) Teleport Cloud(Auth+Proxy는 SaaS, Agent만 자체 호스팅). 프로덕션은 (c) 또는 (d)를 권장하고, 단일 노드 PoC는 (a)가 가장 빠릅니다.

 

ⅰ. Linux 단일 노드 (PoC, v17 기준)

# 1) 패키지 저장소 등록 후 설치
curl https://goteleport.com/static/install.sh | bash -s 17.0.0

# 2) 단일 노드 구성(개발용) — auth+proxy+node 한 프로세스
sudo teleport configure -o file \
  --acme --acme-email=ops@acme.com \
  --cluster-name=teleport.acme.com \
  --public-addr=teleport.acme.com:443

# 3) systemd로 시작
sudo systemctl enable --now teleport

# 4) 첫 관리자 사용자 생성 (사용자는 Web UI 첫 접속 시 가입 토큰으로 등록)
sudo tctl users add admin --roles=editor,access --logins=root,ubuntu

 

ⅱ. Kubernetes Helm (HA 권장 패턴)

helm repo add teleport https://charts.releases.teleport.dev
helm repo update

# Auth+Proxy를 K8s에 배치, 백엔드는 DynamoDB+S3(권장 AWS 패턴)
helm install teleport-cluster teleport/teleport-cluster \
  --create-namespace --namespace teleport \
  --set clusterName=teleport.acme.com \
  --set acme=true --set acmeEmail=ops@acme.com \
  --set chartMode=aws \
  --set aws.region=ap-northeast-2 \
  --set aws.backendTable=teleport-backend \
  --set aws.auditLogTable=teleport-events \
  --set aws.sessionRecordingBucket=teleport-recordings \
  --set highAvailability.replicaCount=2 \
  --set highAvailability.certManager.enabled=true

 

ⅲ. Agent 가입(노드 한 대를 Teleport 클러스터에 등록)

# 클러스터 측에서 join token 발급
sudo tctl tokens add --type=node --ttl=1h
# > The invite token: 2eef4b0d…  (1h 후 만료)

# 노드 측에서 가입(IAM/AWS 인스턴스 신원으로 토큰리스 가입도 가능)
sudo teleport node configure -o file \
  --token=2eef4b0d... \
  --proxy=teleport.acme.com:443 \
  --labels=env=prod,role=db,region=apne2

sudo systemctl enable --now teleport

운영 팁 · 토큰 가입 대신 IAM/EC2/AWS-IID/Kubernetes ServiceAccount/GitHub OIDC 가입을 우선 검토하세요. 토큰은 1회성이고 유효기간이 길면 leak 시 노드 위장이 가능합니다. AWS EC2의 경우 instance profile만 박아두면 join token을 아예 안 만들 수 있습니다.

6. Teleport 사용 방법

ⅰ. RBAC Role 정의 (YAML, K8s CRD 스타일)

# role-prod-db.yaml
kind: role
version: v7
metadata:
  name: prod-db-reader
spec:
  options:
    max_session_ttl: 8h
    require_session_mfa: true        # per-session MFA 강제
    record_session:
      default: best_effort
      desktop: true
  allow:
    logins: ['{{external.login}}']    # SSO 클레임에서 OS 계정 가져오기
    node_labels:
      env: 'prod'
      role: 'db'
    db_labels:
      env: 'prod'
    db_users: ['readonly']
    db_names: ['app', 'analytics']
    kubernetes_groups: ['view']
    kubernetes_labels:
      env: 'prod'
    rules:
      - resources: [session]
        verbs: [list, read]
  deny:
    db_names: ['vault', 'pii']
# 적용
sudo tctl create -f role-prod-db.yaml
sudo tctl users update alice --set-roles=prod-db-reader,access

 

ⅱ. SSH·DB·K8s 사용 한 사이클

# 로그인 한 번 (브라우저 SSO 자동 오픈)
tsh login --proxy=teleport.acme.com --auth=okta

# SSH (라벨로 노드 검색 + 매칭 한 대 직행)
tsh ls
tsh ssh ubuntu@web-01
tsh ssh --labels env=prod,role=web 'sudo systemctl status nginx'

# K8s (kubeconfig 자동 머지)
tsh kube ls
tsh kube login prod-eks
kubectl get pods -n payment
kubectl exec -it order-7d… -- bash

# DB (psql 그대로, tsh가 로컬 프록시 띄워줌)
tsh db ls
tsh db login --db-user=readonly --db-name=app prod-pg
tsh proxy db prod-pg --tunnel    # 로컬 5432 리스너
psql "host=127.0.0.1 port=5432 user=readonly dbname=app"

# 임시 권한 신청(JIT)
tsh request create --roles=prod-db-admin --reason="INC-1234 hotfix"
# Slack 으로 승인 요청 자동 발송

 

ⅲ. 운영 시 고려사항

고려사항 권장 설정
Auth Service HA 최소 2 replica + 외부 백엔드(DynamoDB Multi-AZ 또는 etcd 3 노드). 단일 노드 운영 시 Auth 다운=발급 정지=cert 만료 후 전체 잠금. "Auth만 죽으면 회사가 멈춘다"는 점을 의도적으로 설계. 멀티 AZ + 자동 백업 필수.
Proxy Service LB L4 NLB(TCP passthrough) 사용. ALB(L7)는 ALPN/SNI 라우팅을 깨뜨려 SSH/DB가 동작 안 함. TLS termination은 Proxy 자체에서 ACME 또는 cert-manager로.
Cert TTL 정책 기본 12h, prod-admin 같은 강한 권한은 1~2h. 너무 짧으면(예: 30m) 데일리 운영 마찰, 너무 길면(예: 30h) 회수 윈도우 길어짐. 8h~12h가 합리적 균형.
세션 녹화 스토리지 S3 + Object Lock(immutable) + 90일 lifecycle→Glacier. RDP 세션은 텍스트 SSH보다 50~200배 큼. 라벨링으로 prod만 long-term 보관, dev는 30일 expire.
SSO 락아웃 대비 SSO 장애·미스컨피그로 누구도 로그인 못 하는 상황 대비, break-glass 로컬 사용자 + WebAuthn 하드웨어 키 1~2개를 별도로 만들어 봉인 보관. tctl로만 생성 가능.
Trusted Cluster 인증서 rotation 루트-리프 클러스터 사이의 trust도 cert 기반. 회전 주기를 캘린더에 박지 않으면 어느 날 갑자기 모든 리프가 끊김. Auth CA rotation은 tctl auth rotate로 phased 수행.
Machine ID(tbot) 갱신 tmpfs에 cert 발급, 갱신 주기는 cert TTL의 1/2~1/3. 갱신 실패 알람을 별도 Prometheus 룰로. ECS/Nomad·systemd timer·CronJob에 따라 패턴이 달라짐.

Ⅶ. Teleport 자주 쓰는 명령어

ⅰ. 사용자 측(tsh)

명령 용도·사례
tsh login --proxy=teleport.acme.com SSO 로그인, 12h cert 발급
tsh status 현재 cert의 사용자/역할/만료/MFA 상태 확인
tsh ls --query='labels.env=="prod"' 조건부 노드 검색(predicate language)
tsh ssh root@web-01 SSH 세션 시작
tsh ssh --labels env=prod 'uptime' 매칭 노드 전체에 동일 명령 병렬 실행
tsh scp file user@host:/tmp/ 감사되는 파일 전송
tsh kube login prod-eks kubeconfig 컨텍스트 자동 추가, kubectl 그대로 사용
tsh proxy db prod-pg --tunnel 로컬 포워더, 평범한 psql/DBeaver 사용 가능
tsh request create --roles=prod-db-admin JIT 권한 신청
tsh play 8a4b... 세션 ID로 녹화된 SSH 재생
tsh logout cert 즉시 폐기(로컬 ~/.tsh 비움)

ⅱ. 관리자 측(tctl)

명령 용도
tctl users add alice --roles=access 로컬 사용자 생성(SSO 미사용 케이스)
tctl users update alice --set-roles=... 역할 갱신, 다음 cert 발급부터 반영
tctl users rm bob 사용자 제거(기존 cert는 만료까지 유효)
tctl tokens add --type=node --ttl=1h 노드 join token 발급
tctl create -f role.yaml RBAC Role/AuthConnector 등 리소스 적용
tctl get nodes 전체 노드 인벤토리(라벨 포함)
tctl get sessions --format=json 활성·과거 세션, 감사 evidence 추출
tctl auth rotate --type=user CA 회전(phased: standby→in-progress→rollback/standby)
tctl request ls / approve / deny JIT 액세스 요청 관리
tctl alerts create 클러스터 전역 알림 게시(점검·만료 안내)
tctl edit role/access EDITOR로 즉석 편집(YAML 검증 포함)

Ⅷ. Teleport 활용방안

ⅰ. 대표 활용 시나리오

시나리오 실제 구성
VPN+점프호스트 폐기 기존 OpenVPN 종료, 모든 prod EC2에 Node Agent 배포. 사용자는 SSO 한 번에 SSH+kubectl+psql 동시 사용. 화이트리스트 SG는 Teleport Proxy 한 대만 통과.
SOC2/ISO27001 evidence 자동화 Access Lists로 분기 리뷰 자동 만료, 모든 prod 접근은 세션 녹화 + 구조화 감사 이벤트로 S3 immutable 보관. 감사관 질문에 1시간 안에 답변 가능.
MSP/멀티테넌트 운영 고객별 격리 클러스터를 Trusted Cluster 리프로 구성, MSP 엔지니어는 루트 SSO 한 번으로 N개 고객 환경 접근. 고객별 Role 매핑으로 데이터 격리.
CI 비밀 박멸 GitHub Actions OIDC→Teleport Machine ID→DB cert. secrets.DB_PASSWORD 같은 정적 비밀이 0개. 만료된 cert는 자동 갱신, 유출 윈도우는 단명 TTL 이내.
인시던트 JIT 권한 평소엔 read-only, 인시던트 호출 시 tsh request create --roles=prod-admin --reason=INC-1234로 30분짜리 elevated 권한 발급. PagerDuty/Slack에서 승인.
Windows AD 통합 기존 jump RDP 서버 폐기, Desktop Service가 LDAPS로 단명 사용자 cert를 AD에 등록. RDP 화면 비트맵 녹화로 누가 무엇을 했는지 시각적으로 재생.

ⅱ. 대안 기술 비교

대안 강점 한계 vs Teleport
Tailscale / Headscale 설치 5분, NAT-traversal 우수, 메시 VPN으로 단순 네트워크 신뢰 모델 그대로 — SSH 키·DB 비번은 별도 관리, 세션 녹화·SQL 단위 감사 없음. "어디서 누가 어떻게"는 IP 수준 답
HashiCorp Boundary OSS, Vault·Consul과 통합 자연스러움, target 모델 단순 SSH 외 K8s/DB protocol-aware 깊이가 얕음, 세션 녹화는 SSH만, RBAC가 Teleport보다 단순
StrongDM 상용 SaaS, 설치 즉시 다양한 DB 어댑터 사용 가능 SaaS 락인, 자체 호스팅 약함, 라이선스 비용이 사용자수 비례. 코드는 클로즈드.
AWS SSM Session Manager AWS 네이티브, EC2 한정으로 무료, IAM 통합 AWS 락인, 멀티클라우드/온프렘 미지원, K8s/DB/RDP는 별도. RBAC는 IAM의 거친 grain.
Smallstep step-ca + CASSH cert 인증 단순화, OSS 자유도 높음 CA만 있고 프록시·녹화·RBAC·UI를 직접 조립. K8s/DB/Web 통합은 별도. PoC 좋고 풀스택은 부족.
OpenZiti OSS 제로트러스트 네트워크, mTLS overlay, SDK 애플리케이션 레벨 SDK 통합 중심, SSH/DB/K8s native UX는 약하고 공통 RBAC·세션 녹화 부재
Cloudflare Access (ZTNA) 웹앱·SSH 게이트웨이, Cloudflare 인프라 활용 SaaS 락인, K8s API/DB wire 깊이 얕음, 자체 호스팅 불가, audit 데이터의 self-custody 어려움

ⅲ. 언제 쓰면 안 되는지

상황 이유
5인 이하 단일 EC2 환경 SSM Session Manager + AWS SSO로 충분. Teleport는 Auth 운영 자체가 의미 있는 비용
SSO IdP 없음 로컬 사용자만 쓰면 SSO 클레임 기반 트레이트가 무력화됨. Teleport의 가치 절반 이상이 SSO와 결합에서 옴
네트워크 메시가 본질인 경우 머신간 P2P, 사이트간 VPN이 본 목적이면 Tailscale/WireGuard. Teleport는 사람-인프라 액세스가 1차
Air-gapped + SSO 분리 정책 완전 망분리 환경에서 SSO 의존이 정책 위반이면 부적합. (Teleport도 로컬 사용자 가능하지만 강점이 줄어듦)
일회성 점프호스트만 필요 한 명만 한두 대에 접근하면 ssh-ca + step-ca로 충분. Teleport는 RBAC·녹화·DB가 모두 켜질 때 ROI가 나옴

Ⅸ. 운영 주의사항과 트러블슈팅 

Teleport는 "한 군데에 모은 만큼 한 군데가 부서지면 큰일"이 됩니다. 다음은 도입·운영 과정에서 자주 만나는 함정과 그 처방입니다.

① Auth Service 단일 장애점 — "Auth가 죽었더니 prod에 못 들어간다"

증상: Auth가 다운된 직후엔 기존 cert로 정상 접속되다가, 한 시간쯤 지나면 "expired"로 거부되기 시작. 새 발급도 안 되고 SSO도 안 됨. 회사 전체가 prod에서 잠김.

처방: (1) Auth Service는 반드시 최소 2 replica + 외부 백엔드(DynamoDB Multi-AZ 또는 etcd 3노드)로 구성합니다. (2) break-glass 로컬 사용자 1~2명 + WebAuthn 하드웨어 키를 봉인 보관 — SSO/Auth가 동시에 망가져도 진입로를 남깁니다. (3) Auth 백엔드는 매일 스냅샷 + cross-region 복제. (4) Cert TTL을 너무 짧게 잡지 않기 — 1시간으로 박으면 Auth 1시간 다운에 모든 세션이 끊깁니다. 12h가 합리적 안전 마진입니다.

 

② L7 LB 뒤에 Proxy 배치 — "ALB 뒤에 두니 SSH가 안 통한다"

증상: 웹 UI는 잘 뜨는데 tsh ssh는 "protocol error: bad version" 또는 "ALPN unsupported". K8s exec도 끊어짐.

처방: Proxy Service는 L4 NLB(TCP passthrough)로만 노출합니다. ALB/CloudFront/Nginx가 TLS termination을 하면 ALPN/SNI가 깨져서 SSH·DB·K8s wire가 동작하지 않습니다. TLS는 Proxy 자체에서 ACME 또는 cert-manager로 종단합니다. 굳이 L7이 필요하면 "웹 UI용 ALB + 데이터플레인용 NLB" 두 LB를 분리합니다.

 

③ 세션 녹화가 디스크를 가득 채움 — "어느 날 갑자기 Audit 백엔드 OOM"

증상: SSH 세션 녹화 파일이 /var/lib/teleport/log에 누적, 또는 S3 버킷이 수 TB 단위로 부풀어 비용 폭증. RDP는 같은 1시간 세션이 SSH 대비 100배 큼.

처방: (1) 녹화 모드를 S3 + Object Lock + lifecycle 90일→Glacier→180일 expire로 설정. (2) Role 단위로 record_session.default를 off|best_effort|strict로 구분 — dev는 off, prod는 strict. (3) RDP는 별도 라벨로 짧은 lifecycle 적용. (4) 녹화 사이즈를 Prometheus 메트릭으로 export해 일일 증가율을 추적 — 평소의 5배가 갑자기 늘면 누군가 자동화 스크립트를 prod에서 돌리고 있을 신호입니다.

 

④ WebAuthn 미등록 사용자 락아웃 — "MFA 강제했더니 절반이 못 들어옴"

증상: require_session_mfa: true로 정책을 한 번에 적용했더니, 아직 WebAuthn 키를 등록 안 한 사용자들이 SSH 세션 시작 시점에서 차단됨. 인시던트 한복판에서 발생.

처방: (1) MFA 정책은 관찰 모드 → 경고 모드 → 강제 모드 3단계로 점진 롤아웃. (2) tctl alerts로 "X일까지 등록하지 않으면 차단됩니다" 클러스터 알림을 1주 전부터. (3) 사용자별 tctl get users -o json | jq '.[] | select(.spec.mfa | length == 0)'로 미등록자 리스트를 자동 추출해 매일 슬랙으로 송출. (4) break-glass 계정은 등록을 강제로 우선 완료하고 봉인.

 

⑤ Trusted Cluster CA 회전 누락 — "어느 날 갑자기 리프 클러스터가 모두 끊김"

증상: 1년쯤 운영 후 어느 날 새벽, 모든 trusted leaf 클러스터가 root에 join 실패. certificate has expired. 사용자는 leaf 클러스터의 노드에 접근 불가.

처방: (1) CA rotation 일정을 캘린더에 박고 분기 1회 dry-run. (2) tctl auth rotate --type=user --grace-period=48h로 phased rotation을 활용해 standby→in-progress→rolled로 순차 전환. (3) leaf 클러스터마다 trusted_cluster 리소스의 만료를 체크하는 외부 모니터(Prometheus blackbox 또는 외부 cron). (4) 회전 직전에 leaf 측 운영자에게 알림.

 

⑥ DB long-running 쿼리 끊김 — "1시간 분석 쿼리가 중간에 죽었다"

증상: 분석가가 prod에서 30분짜리 쿼리를 돌리는데, 17분쯤에 "connection reset"으로 끊어짐. cert TTL은 충분한데도 발생.

처방: (1) Database Service의 idle timeout과 max_session_ttl을 분리해 설정 — 기본값이 30분짜리 idle timeout일 수 있음. (2) 분석 워크로드는 전용 db-user(analytics_ro)와 전용 Role로 분리하고 max_session_ttl을 24h. (3) Proxy 앞단 LB의 idle timeout도 같이 늘림(NLB 기본 350초 → 4000초). (4) 길게 도는 쿼리는 tmux/screen + nohup이 아니라 airflow/dbt scheduled job + tbot Machine ID로 옮기는 게 정석.

 

⑦ 라벨 매처 정규식 실수 — "역할에 권한이 다 들어있는데도 노드가 안 보임"

증상: Role에 node_labels: { env: 'prod' }로 박았는데 tsh ls에 prod 노드가 안 나옴. 그런데 tctl get nodes로 보면 노드는 분명 prod 라벨을 갖고 있음.

처방: (1) 라벨 값에 대문자/소문자 혼용을 점검 — Prod와 prod는 다른 값입니다. (2) '^prod$'처럼 정규식을 쓰면 매처가 정규식 모드로 동작 — 의도치 않은 미스매치 발생. (3) tctl get role/foo -o yaml으로 실제 적용된 정책을 확인하고 tsh ls --query='labels.env=="prod"'로 사용자 측 입장도 검증. (4) 복잡한 매처는 predicate language로 통합 — where: resource.labels["env"] == "prod" && resource.labels["region"] != "ap-southeast-1".

 

⑧ Machine ID(tbot) 갱신 실패의 silent fail — "CI가 어느 날부터 prod-db에 못 들어간다"

증상: 평소엔 잘 도는 GitHub Actions 마이그레이션 워크플로가 갑자기 "cert expired"로 실패. 로컬에서는 정상.

처방: (1) tbot의 renewal interval은 cert TTL의 1/3로 설정 — TTL 1h면 20분마다 갱신. (2) 갱신 실패 시 즉시 알람 — tbot은 기본적으로 silent하게 갱신 시도, 실패해도 즉시 종료하지 않음. tbot.config.yaml에서 service.healthchecks: true를 켜고 Prometheus가 스크레이프. (3) OIDC 가입 토큰의 Trust 관계가 깨진 케이스도 흔함 — GitHub 조직 변경, AWS account 마이그레이션 시 join token rule을 다시 점검. (4) GitHub Actions라면 id-token: write 권한 누락이 1번 원인 — OIDC 토큰 자체를 못 발급해서 가입 실패.

반응형