Zum Hauptinhalt springen

Teleport

Teleport는 제로 트러스트 원칙 기반의 접근 제어 솔루션입니다. SSH, Kubernetes API, 웹 애플리케이션, 데이터베이스에 대한 통합 접근 관리를 제공하며, 모든 세션을 기록하고 감사합니다.

아키텍처

구성 요소

Teleport Cluster (Standalone)

  • 역할: 인증 서버(Auth) + 프록시(Proxy)
  • 이미지: public.ecr.aws/gravitational/teleport-distroless:18.7.6
  • 모드: Standalone
  • 백엔드: PostgreSQL (infra-db, postgres 역할)
  • Proxy 복제본: 2개 (워커 노드에 분산, Soft Anti-Affinity)
  • 서비스 타입: NodePort :30443

Teleport Agent (Kube Agent)

  • 역할: Kubernetes 및 웹 애플리케이션 접근 프록시
  • 이미지: public.ecr.aws/gravitational/teleport-distroless:18.7.6
  • 조인 방식: Kubernetes ServiceAccount 기반
  • 특징: envsubst init 컨테이너가 $ZOT_BASIC_AUTH, $OPENCLAW_GATEWAY_TOKEN 환경 변수를 teleport.yaml에 주입합니다.

인증 설정

로컬 인증

authentication:
type: local
localAuth: true
secondFactors:
- webauthn # FIDO2/WebAuthn 지원
- otp # TOTP (Google Authenticator 등)

조인 방법

Teleport Agent는 Kubernetes 내장 인증을 사용합니다:

joinParams:
method: kubernetes
tokenName: teleport-agent

# ProvisionToken CRD
apiVersion: resources.teleport.dev/v2
kind: TeleportProvisionToken
metadata:
name: teleport-agent
namespace: teleport
spec:
roles: [App]
join_method: kubernetes
kubernetes:
type: in_cluster
allow:
- service_account: "teleport:teleport-agent"

TLS 설정

cert-manager 연동

# Certificate 리소스
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: teleport-tls
namespace: teleport
spec:
secretName: teleport-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- lumie-infra.com
- "*.lumie-infra.com"

# Teleport에서 사용
tls:
existingSecretName: teleport-tls

데이터베이스 백엔드

PostgreSQL 설정

# Vault에서 DB 자격증명 가져오기
extraEnv:
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: infra-db-credentials
key: password

# Teleport 설정
auth:
teleportConfig:
teleport:
storage:
type: postgresql
conn_string: "host=infra-db-rw.infra-db.svc.cluster.local port=5432 dbname=teleport user=bluemayne sslmode=disable"

애플리케이션 접근

Teleport Agent는 다음 내부 서비스들을 프록시하여 안전하게 접근할 수 있도록 합니다.

apps:
# 모니터링
- name: grafana
uri: http://grafana.grafana.svc.cluster.local:80
labels:
env: prod
category: observability

# GitOps
- name: argocd
uri: http://argocd-server.argocd.svc.cluster.local:80
labels:
env: prod
category: platform

# 시크릿 관리
- name: vault
uri: http://vault.vault.svc.cluster.local:8200
labels:
env: prod
category: security
teleport.icon: kube

# Kubernetes 대시보드
- name: headlamp
uri: http://headlamp.headlamp.svc.cluster.local:80
labels:
env: prod
category: platform
teleport.icon: kube

# VPA 추천
- name: goldilocks
uri: http://goldilocks-dashboard.goldilocks.svc.cluster.local:80
labels:
env: prod
category: observability
teleport.icon: kube

# IDE
- name: code-server
uri: http://code-server.code-server.svc.cluster.local:8080
labels:
env: prod
category: applications
teleport.icon: kube

# 데이터베이스 웹 UI
- name: pgweb
uri: http://pgweb.lumie-db.svc.cluster.local:80
labels:
env: prod
category: storage
teleport.icon: postgres

# CI/CD 대시보드
- name: tekton
uri: http://tekton-dashboard.tekton-pipelines.svc.cluster.local:9097
rewrite:
headers:
- "Origin: http://tekton-dashboard.tekton-pipelines.svc.cluster.local:9097"
labels:
env: prod
category: applications
teleport.icon: kube

# 오브젝트 스토리지 콘솔
- name: minio
uri: http://minio-ui.minio.svc.cluster.local:9090
labels:
env: prod
category: storage
teleport.icon: kube

# 백업 UI
- name: velero
uri: http://velero-ui.velero.svc.cluster.local:3000
labels:
env: prod
category: storage
teleport.icon: kube

# 컨테이너 레지스트리
- name: zot
uri: http://zot.zot.svc.cluster.local:5000
public_addr: zot-ui.lumie-infra.com
rewrite:
headers:
- "Authorization: $ZOT_BASIC_AUTH" # envsubst를 통해 주입
labels:
env: prod
category: platform
teleport.icon: kube

# 알림 대시보드
- name: karma
uri: http://karma.alertmanager.svc.cluster.local:8080
labels:
env: prod
category: observability
teleport.icon: kube

# 웹사이트 분석
- name: umami
uri: http://umami.umami.svc.cluster.local:3000
labels:
env: prod
category: applications
teleport.icon: kube

# 문서
- name: lumie-document
uri: http://lumie-document.lumie-document.svc.cluster.local:80
public_addr: docs.lumie-infra.com
rewrite:
redirect:
- "lumie-document.lumie-document.svc.cluster.local"
labels:
env: prod
category: applications
teleport.icon: kube

# Alertmanager
- name: alertmanager
uri: http://alertmanager.alertmanager.svc.cluster.local:9093
labels:
env: prod
category: observability
teleport.icon: kube

# Prometheus
- name: prometheus
uri: http://prometheus-kube-prometheus-prometheus.prometheus.svc.cluster.local:9090
labels:
env: prod
category: observability

# Thanos Query
- name: thanos
uri: http://thanos-query.thanos.svc.cluster.local:9090
labels:
env: prod
category: observability
teleport.icon: kube

# 메시지 큐 관리
- name: rabbitmq
uri: http://rabbitmq.lumie-event.svc.cluster.local:15672
labels:
env: prod
category: platform

# Identity Provider
- name: keycloak
uri: http://keycloak-keycloakx-http.keycloak.svc.cluster.local
labels:
env: prod
category: security

# API 게이트웨이 관리
- name: kong
uri: http://kong-gateway-manager.kong.svc.cluster.local:8002
labels:
env: prod
category: platform
teleport.icon: kube

# 로컬 개발 환경
- name: tilt
uri: http://dev-workspace.lumie-dev.svc.cluster.local:10350
public_addr: tilt.lumie-infra.com
labels:
env: prod
category: applications
teleport.icon: kube

# Pixel Agents (Codex Visualization)
- name: agents
uri: http://dev-workspace.lumie-dev.svc.cluster.local:3000
public_addr: agents.lumie-infra.com
labels:
env: prod
category: applications

# AI 어시스턴트 (OpenClaw)
- name: openclaw
uri: http://openclaw.openclaw.svc.cluster.local:18789
rewrite:
headers:
- "Origin: http://openclaw.openclaw.svc.cluster.local:18789"
labels:
env: prod
category: applications
teleport.icon: kube

동적 헤더 주입 (envsubst Init 컨테이너)

Teleport는 앱 설정의 rewrite.headers 필드에서 환경 변수를 직접 확장하지 않습니다. 이를 해결하기 위해 envsubst-config init 컨테이너가 시작 시 teleport.yaml을 전처리하여 플레이스홀더를 실제 값으로 치환합니다.

현재 치환되는 변수:

  • $ZOT_BASIC_AUTH: Zot 레지스트리 Basic Auth 헤더 (teleport-app-basic-auth-zot Secret)
  • $OPENCLAW_GATEWAY_TOKEN: OpenClaw 게이트웨이 인증 토큰 (openclaw-gateway-token Secret)
# security/teleport/agent/kustomization.yaml 패치 내용 (요약)
initContainers:
- name: envsubst-config
image: zot.lumie-infra.com/library/busybox:1.37
command:
- sh
- -c
- |
sed -e "s|\$ZOT_BASIC_AUTH|$ZOT_BASIC_AUTH|g" \
-e "s|\$OPENCLAW_GATEWAY_TOKEN|$OPENCLAW_GATEWAY_TOKEN|g" \
/etc/teleport/teleport.yaml > /processed/teleport.yaml
env:
- name: ZOT_BASIC_AUTH
valueFrom:
secretKeyRef:
name: teleport-app-basic-auth-zot
key: zot
- name: OPENCLAW_GATEWAY_TOKEN
valueFrom:
secretKeyRef:
name: openclaw-gateway-token
key: token

Zot Basic Auth Secret 생성 (VaultStaticSecret):

apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: zot-basic-auth-vss
spec:
vaultAuthRef: vault/vault-auth
mount: secret
type: kv-v2
path: infrastructure/zot
refreshAfter: 1h
destination:
create: true
name: teleport-app-basic-auth-zot
transformation:
excludeRaw: true
templates:
zot:
text: 'Basic {{ printf "%s:%s" .Secrets.ZOT_USERNAME .Secrets.ZOT_PASSWORD | b64enc }}'

공개 주소 설정

일부 서비스는 외부에서도 접근 가능하도록 public_addr을 설정합니다:

- name: zot
uri: http://zot.zot.svc.cluster.local:5000
public_addr: zot-ui.lumie-infra.com # 외부 접근 가능

- name: lumie-document
uri: http://lumie-document.lumie-document.svc.cluster.local:80
public_addr: docs.lumie-infra.com # 외부 접근 가능
rewrite:
redirect:
- "lumie-document.lumie-document.svc.cluster.local" # 내부 URI로의 리다이렉트 방지

네트워크 설정

전용 NLB (0213 계정)

Teleport access plane은 전용 OCI Network Load Balancer(Layer 4 passthrough)를 통해 외부에 노출됩니다. 이 NLB는 앱 트래픽용 NLB와 분리된 독립 리소스입니다.

  • NLB 공개 IP: 158.180.89.154 (예약된 고정 IP)
  • DNS: 클러스터 apex(lumie-infra.com) 및 와일드카드(*.lumie-infra.com)가 이 NLB를 가리킴
  • 포트: 외부 :443 → 내부 NodePort :30443 (TCP passthrough, ALPN 보존)
  • 백엔드: 0213 워커 노드(worker-3/4)만 포함

Teleport Proxy Pod가 hostNetwork로 호스트 :443을 점유하는 이전 방식은 제거되었습니다. Proxy는 이제 일반 HA Pod로 워커 노드에서 실행되며 NLB → NodePort를 통해 도달합니다.

# Kustomize 패치 — teleport Service를 NodePort로 변경
patches:
- target:
kind: Service
name: teleport
patch: |-
apiVersion: v1
kind: Service
metadata:
name: teleport
spec:
type: NodePort
ports:
- name: tls
port: 443
targetPort: 443
nodePort: 30443
protocol: TCP

공개 주소

publicAddr:
- lumie-infra.com:443 # 외부 접근 (NLB 경유)
- teleport.teleport.svc.cluster.local:443 # 내부 접근

브레이크글래스 접근

Teleport가 응답하지 않는 경우 마스터 노드에 직접 SSH 후 k3s kubectl로 클러스터를 관리합니다:

# 마스터 노드 SSH (OCI 인스턴스 직접 접근)
ssh ubuntu@<master-node-ip>

# k3s kubectl 사용
sudo k3s kubectl get pods -A

사용법

CLI 설치 및 로그인

# Teleport CLI 설치
curl https://get.gravitational.com/teleport-install.sh | bash

# 로그인
tsh login --proxy=lumie-infra.com

# MFA 설정 (최초 로그인 시)
tsh mfa add

애플리케이션 접근

# 사용 가능한 앱 목록 확인
tsh apps ls

# 특정 앱에 로그인
tsh apps login grafana

# 브라우저에서 앱 열기
tsh apps open grafana

# 로컬 프록시로 접근
tsh proxy app grafana --port 8080
# 브라우저에서 http://localhost:8080 접근

Kubernetes 접근

# Kubernetes 클러스터 목록
tsh kube ls

# 클러스터 로그인
tsh kube login lumie-cluster

# kubectl 사용
kubectl get pods -n lumie

SSH 접근

# SSH 노드 목록
tsh ls

# SSH 접속
tsh ssh ubuntu@node-01

# 파일 전송
tsh scp file.txt ubuntu@node-01:/tmp/

보안 기능

세션 기록

모든 SSH 및 Kubernetes 세션이 기록됩니다:

# 세션 기록 확인
tsh recordings ls

# 특정 세션 재생
tsh play <session-id>

단기 인증서

Teleport는 단기 인증서를 발급하여 보안을 강화합니다:

  • SSH 인증서: 기본 12시간
  • Kubernetes 인증서: 기본 12시간
  • 애플리케이션 토큰: 기본 1시간

감사 로그

모든 접근 시도와 명령이 감사 로그에 기록됩니다:

# 감사 로그 확인 (관리자만)
tctl get events --format=json

고가용성

Proxy HA (2 복제본)

Auth 서버는 단일 인스턴스이며, Proxy는 2개 복제본으로 워커 노드에 분산 배치됩니다:

highAvailability:
replicaCount: 1 # Auth: 단일 인스턴스
requireAntiAffinity: false

proxy:
highAvailability:
replicaCount: 2 # Proxy: HA (워커 노드 분산)
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/component: proxy
topologyKey: kubernetes.io/hostname

전용 NLB(158.180.89.154)는 NodePort :30443을 통해 두 Proxy Pod에 고르게 트래픽을 분산합니다.

백업 및 복구

PostgreSQL 백엔드를 통해 상태가 영구 저장되므로 데이터베이스 백업으로 복구 가능합니다.

배포 설정

ArgoCD Applications

# Teleport Cluster
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: teleport
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: default
source:
repoURL: https://github.com/Lumie-Edu/lumie-infra.git
targetRevision: main
path: security/teleport
destination:
server: https://kubernetes.default.svc
namespace: teleport
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
managedNamespaceMetadata:
labels:
goldilocks.fairwinds.com/enabled: 'true'
revisionHistoryLimit: 10
---
# Teleport Agent (Kustomize 기반 배포)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: teleport-agent
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
- post-delete-finalizer.argocd.argoproj.io
- post-delete-finalizer.argocd.argoproj.io/cleanup
spec:
project: default
source:
repoURL: https://github.com/Lumie-Edu/lumie-infra.git
targetRevision: main
path: security/teleport/agent # Kustomize 경로
destination:
server: https://kubernetes.default.svc
namespace: teleport
syncPolicy:
automated:
prune: true
selfHeal: true
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
- PruneLast=true
- ServerSideApply=true
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
revisionHistoryLimit: 10

스케줄링 설정

Proxy 및 Auth Pod는 워커 노드에서 실행됩니다. 이전 방식(마스터 노드 고정 + hostNetwork :443)은 전용 NLB 도입과 함께 제거되었습니다. Proxy는 Soft Anti-Affinity로 워커 노드에 분산 배치됩니다.

# Proxy: 워커 노드 분산 배치 (Soft Anti-Affinity)
proxy:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchLabels:
app.kubernetes.io/component: proxy
topologyKey: kubernetes.io/hostname

문제 해결

연결 문제

# Teleport 상태 확인
tctl status

# 프록시 연결 테스트
tsh ping

# 인증서 확인
tsh status

로그 확인

# Teleport 클러스터 로그
kubectl logs -n teleport deployment/teleport

# Teleport Agent 로그
kubectl logs -n teleport deployment/teleport-agent

인증서 갱신

# 인증서 수동 갱신
tsh login --proxy=lumie-infra.com

# 인증서 상태 확인
tsh status

관련 문서