Ir al contenido

Teleport Cheat Sheet

Overview

Teleport is an open-source, zero-trust access platform that provides engineers and security teams with a secure, auditable gateway to infrastructure resources including Linux servers, Kubernetes clusters, databases, and web applications. It implements the principle of least-privilege access through Role-Based Access Control (RBAC), requires strong authentication with MFA, integrates with identity providers via SSO, and records all sessions for compliance and forensic purposes.

Unlike traditional VPN-based access models, Teleport uses short-lived cryptographic certificates instead of long-lived SSH keys or passwords. Every access request results in a certificate issued for a specific duration (typically hours, not months), scoped to the resources the user’s role permits. When the certificate expires, access is automatically revoked without any manual key rotation. This model eliminates the persistent credential problem that makes SSH key management burdensome and creates security risks.

The Teleport architecture centers on the Auth Server (certificate authority and policy engine), the Proxy Service (public access point, handles all external connections), and Nodes/Agents (lightweight agents running on protected resources). The tsh CLI is the user-facing tool for connecting to resources, and tctl is the administrative CLI for managing users, roles, tokens, and cluster configuration. Teleport also provides a Web UI for browser-based terminal access, session replay, and resource discovery.

Installation

Quick Start (Docker)

# Run a standalone Teleport for testing
docker run --rm -d \
  --name teleport \
  -p 3080:3080 \
  -p 3022:3022 \
  -p 3025:3025 \
  -v /tmp/teleport:/var/lib/teleport \
  public.ecr.aws/gravitational/teleport:latest \
  start --roles=proxy,auth,node \
  --insecure-no-tls

# Access Web UI at http://localhost:3080

Auth/Proxy Server (Linux)

# Add Teleport repository
curl https://goteleport.com/static/install.sh | bash -s 15.0.0

# Install
sudo apt install -y teleport    # Ubuntu/Debian
sudo dnf install -y teleport    # RHEL/Fedora

# Generate initial configuration
sudo teleport configure \
  --cluster-name=mycluster.example.com \
  --public-addr=mycluster.example.com:443 \
  --cert-file=/etc/ssl/certs/server.crt \
  --key-file=/etc/ssl/private/server.key \
  -o /etc/teleport.yaml

# Enable and start
sudo systemctl enable --now teleport

# Create first admin user (run on auth server)
sudo tctl users add admin --roles=editor,access --logins=root,ubuntu
# Follow the printed URL to set password and MFA

Node Agent (SSH Node)

# On the node to be enrolled
# 1. Install teleport binary (same as above)

# 2. Generate join token on auth server
sudo tctl tokens add --type=node --ttl=5m
# Copy the token

# 3. Configure node to join cluster
cat > /etc/teleport.yaml << 'EOF'
teleport:
  data_dir: /var/lib/teleport
  join_params:
    token_name: "TOKEN_FROM_ABOVE"
    method: token
  proxy_server: mycluster.example.com:443

auth_service:
  enabled: false

proxy_service:
  enabled: false

ssh_service:
  enabled: true
  labels:
    env: production
    team: ops
EOF

sudo systemctl enable --now teleport

tsh Client Installation

# macOS
brew install teleport

# Linux
curl -O https://cdn.teleport.dev/teleport-v15.0.0-linux-amd64-bin.tar.gz
tar -xzf teleport-v15.0.0-linux-amd64-bin.tar.gz
sudo mv tsh /usr/local/bin/

# Windows (via winget)
winget install Teleport.tsh

# Verify
tsh version

Configuration

Teleport Auth Server Config (/etc/teleport.yaml)

teleport:
  nodename: auth.example.com
  data_dir: /var/lib/teleport
  log:
    output: stderr
    severity: INFO

auth_service:
  enabled: true
  cluster_name: mycluster.example.com
  listen_addr: 0.0.0.0:3025
  tokens:
    - "proxy,node:REPLACE_WITH_STRONG_TOKEN"

  # GitHub SSO
  authentication:
    type: github
    second_factor: on
    webauthn:
      rp_id: mycluster.example.com

  # Session recording
  session_recording: node

proxy_service:
  enabled: true
  public_addr: mycluster.example.com:443
  listen_addr: 0.0.0.0:3080
  https_keypairs:
    - key_file: /etc/ssl/private/server.key
      cert_file: /etc/ssl/certs/server.crt
  kube_listen_addr: 0.0.0.0:3026

ssh_service:
  enabled: true
  labels:
    env: production

RBAC Role Definition

# roles/developer-role.yaml
kind: role
version: v7
metadata:
  name: developer
spec:
  allow:
    # SSH access to nodes with these labels
    node_labels:
      env: ["staging", "dev"]
    logins: ["ubuntu", "ec2-user"]
    
    # Kubernetes access
    kubernetes_groups: ["developers"]
    kubernetes_labels:
      env: ["staging"]
    kubernetes_resources:
      - kind: pod
        namespace: "{{internal.traits.team}}"
        name: "*"
        verbs: ["get", "list", "exec"]
    
    # Database access
    db_labels:
      env: ["staging"]
    db_names: ["app_db"]
    db_users: ["readonly"]
    
    # App access
    app_labels:
      env: ["staging", "dev"]
    
    rules:
      - resources: ["session"]
        verbs: ["list", "read"]
  
  deny:
    # Deny access to production
    node_labels:
      env: ["production"]
  
  options:
    max_session_ttl: 8h
    require_session_mfa: false
    forward_agent: true
# Apply the role
tctl create -f roles/developer-role.yaml

# Assign role to user
tctl users update alice --set-roles=developer,access

Core Commands (tctl — Admin)

CommandDescription
tctl statusShow cluster status
tctl users lsList all users
tctl users add NAME --roles=ROLES --logins=LOGINSCreate a new user
tctl users update NAME --set-roles=ROLESUpdate user roles
tctl users rm NAMEDelete a user
tctl users reset NAMEReset user password
tctl roles lsList all roles
tctl roles get NAMEGet role details
tctl create -f role.yamlCreate/update resource from YAML
tctl get roles/NAME -o yamlExport role as YAML
tctl tokens add --type=nodeCreate a node join token
tctl tokens add --type=dbCreate a database join token
tctl tokens lsList active tokens
tctl tokens rm TOKENRemove a token
tctl nodes lsList registered nodes
tctl nodes rm UUIDRemove a node
tctl auth sign --user=NAME --out=certsIssue client certificate
tctl auth exportExport cluster CA
tctl audit-logQuery audit log
tctl request lsList access requests
tctl request approve IDApprove an access request
tctl request deny IDDeny an access request

Core Commands (tsh — User)

CommandDescription
tsh login --proxy=CLUSTER:443Authenticate to cluster
tsh logoutClear local certificates
tsh statusShow current authentication status
tsh lsList accessible SSH nodes
tsh ls -lList nodes with labels
tsh ssh USER@NODESSH into a node
tsh ssh USER@NODE COMMANDRun command on node
tsh scp FILE USER@NODE:PATHCopy file to node
tsh sessions lsList active sessions
tsh sessions export SESSION_IDExport session recording
tsh play SESSION_IDPlay a recorded session
tsh kube lsList Kubernetes clusters
tsh kube login CLUSTERConfigure kubectl for K8s cluster
tsh kube sessions lsList Kubernetes sessions
tsh db lsList accessible databases
tsh db login DB_NAMELog in to a database
tsh db connect DB_NAMEConnect to database via proxy
tsh apps lsList accessible web apps
tsh apps login APP_NAMEGet app access certificate
tsh request create --roles=adminSubmit an access request
tsh request lsList my access requests
tsh mfa addAdd an MFA device
tsh mfa lsList registered MFA devices
tsh configShow tsh configuration

Advanced Usage

Kubernetes Access

# List available K8s clusters
tsh kube ls

# Log in to a Kubernetes cluster
tsh kube login my-k8s-cluster

# Now use kubectl as normal
kubectl get pods
kubectl exec -it mypod -- bash

# Run kubectl with specific Teleport identity
tsh kubectl get pods -n production

# List active Kubernetes sessions
tsh kube sessions ls

# Join an active session (session sharing)
tsh kube sessions join SESSION_ID

Database Access

# List accessible databases
tsh db ls

# Log in to PostgreSQL
tsh db login --db-user=readonly --db-name=appdb postgres-prod

# Connect via proxy (auto-starts local proxy tunnel)
tsh db connect postgres-prod

# Or use standard psql with the tunnel
eval $(tsh db env postgres-prod)
psql

# For MySQL
tsh db login --db-user=readonly --db-name=appdb mysql-prod
tsh db connect mysql-prod

# For MongoDB
tsh db login --db-user=readonly --db-name=appdb mongo-prod
tsh db connect mongo-prod

Access Requests (Privileged Access)

# Request temporary elevated access
tsh request create \
  --roles=admin \
  --reason="Investigating production outage" \
  --reviewers=alice@example.com,bob@example.com

# Watch request status
tsh request ls

# Admin: approve a request
tctl request approve REQUEST_ID --reason="Approved for incident response"

# Admin: deny a request
tctl request deny REQUEST_ID --reason="Requires change management approval"

# User: activate approved request
tsh login --request-id=REQUEST_ID

# Check elevated session
tsh status

Session Recording and Playback

# List recorded sessions
tsh sessions ls --from=2024-01-01 --to=2024-12-31

# List sessions for a specific user
tsh sessions ls --user=alice

# Play a session in terminal
tsh play SESSION_ID

# Export session to asciicast format
tsh sessions export SESSION_ID > session.cast
# Then play with: asciinema play session.cast

# Search audit log for events
tctl audit-log query \
  --from=2024-01-15T00:00:00Z \
  --to=2024-01-16T00:00:00Z \
  --event=session.start,session.end

SSO Integration (GitHub)

# github-connector.yaml
kind: github
version: v3
metadata:
  name: github
spec:
  client_id: GITHUB_OAUTH_APP_CLIENT_ID
  client_secret: GITHUB_OAUTH_APP_CLIENT_SECRET
  redirect_url: https://mycluster.example.com/v1/webapi/github/callback
  display: "GitHub Login"
  teams_to_roles:
    - organization: myorg
      team: engineering
      roles: ["developer", "access"]
    - organization: myorg
      team: devops
      roles: ["editor", "access"]
    - organization: myorg
      team: security
      roles: ["auditor"]
# Apply GitHub SSO connector
tctl create -f github-connector.yaml

# Test SSO login
tsh login --proxy=mycluster.example.com:443 --auth=github

Enrolling Databases

# Generate database join token
tctl tokens add --type=db --ttl=10m

# Self-hosted PostgreSQL config snippet for teleport.yaml on database host
cat >> /etc/teleport.yaml << 'EOF'
db_service:
  enabled: true
  databases:
    - name: postgres-prod
      description: "Production PostgreSQL"
      protocol: postgres
      uri: localhost:5432
      labels:
        env: production
        team: backend
EOF

# For RDS (add to proxy/auth server config)
db_service:
  enabled: true
  aws:
    - types: ["rds"]
      regions: ["us-east-1"]
      tags:
        teleport: "true"

# Grant database access to Teleport
# On PostgreSQL:
CREATE USER teleport_monitor WITH LOGIN;
GRANT CONNECT ON DATABASE appdb TO teleport_monitor;
GRANT pg_monitor TO teleport_monitor;

Audit Log Integration

# Stream audit events to S3 (in config.yaml)
# audit_events_uri: s3://my-teleport-logs/events
# audit_sessions_uri: s3://my-teleport-sessions/recordings

# Query recent auth events
tctl audit-log query --event=user.login --last=24h

# Export audit log as JSON
tctl audit-log query \
  --from=2024-01-01T00:00:00Z \
  --to=2024-01-31T23:59:59Z \
  --event=session.start \
  --format=json > sessions-january.json

# Watch live audit events
tctl audit-log stream --event=session.start,session.end

Common Workflows

Onboarding a New Engineer

# Admin: create user with appropriate roles
tctl users add alice@example.com \
  --roles=developer,access \
  --logins=ubuntu,ec2-user

# Admin: send the onboarding URL to Alice (printed by above command)
# Alice: sets password and registers MFA device

# Alice: log in
tsh login --proxy=mycluster.example.com:443
# Alice: browse accessible resources
tsh ls
tsh db ls
tsh kube ls
tsh apps ls

# Alice: connect to a dev server
tsh ssh ubuntu@dev-server-01

Emergency Production Access Workflow

# Engineer: request temporary admin access
tsh request create \
  --roles=prod-admin \
  --reason="SEV-1 production database is unresponsive, need root access" \
  --reviewers=cto@example.com,oncall@example.com

# On-call lead: review and approve
tctl request approve REQUEST_ID \
  --reason="Approved for SEV-1 response"

# Engineer: activate approved access
tsh login --request-id=REQUEST_ID
tsh ssh root@prod-db-01

# After incident: revoke access
tctl request deny REQUEST_ID  # or let TTL expire

Node Inventory Management

# List all nodes with labels
tsh ls -l

# Filter by label
tsh ls env=production
tsh ls team=backend,env=staging

# Get nodes as JSON for automation
tsh ls --format=json | jq '.[] | select(.spec.labels.env=="production") | .metadata.name'

# Remove stale node registrations
tctl nodes ls --format=json | jq '.[] | select(.metadata.name=="old-node") | .metadata.name'
tctl nodes rm NODE_UUID

Tips and Best Practices

PracticeDetails
Short certificate TTLsKeep max_session_ttl at 8-12h; never issue certificates for days or months
Require MFASet second_factor: on and require_session_mfa: true for production roles
Node labels for RBACLabel every node with env, team, region — RBAC relies on label matching
Use access requestsDon’t grant standing production access; use request.roles with reviewers
Record all sessionsSet session_recording: node or proxy globally; store in S3 for compliance
Rotate join tokensCreate tokens with --ttl=5m; delete after nodes enroll
Audit log to S3Configure audit_events_uri: s3://bucket/events before going to production
Separate auth/proxyRun Auth Server on an internal-only host; Proxy is the public-facing component
Restrict tctl accessOnly trusted ops staff should have SSH access to the auth server
Regular tsh upgradesClient and server must be within 1 major version — upgrade clients when upgrading cluster
Use Teleport CloudFor smaller teams, Teleport Cloud handles auth server HA and upgrades
Review sessions regularlyUse tsh sessions ls and replay suspicious sessions promptly