Context & Why: Leaving Static SSH Keys Behind
Distributing public keys across 50 cloud instances and three Kubernetes clusters sounds simple until someone loses a laptop. In the beginning, dropping an engineer’s public key into ~/.ssh/authorized_keys with Ansible or cloud-init works fine. Soon, technical debt catches up. Private keys sit unencrypted on personal machines, teams rarely rotate keys, and offboarding turns into a messy scavenger hunt across dozens of hosts.
Kubernetes access creates the exact same nightmare. Handing out static admin kubeconfig files with 90-day tokens bypasses centralized identity providers and wrecks compliance. If an engineer’s workstation gets compromised, attackers inherit direct access to every production cluster recorded in that YAML file.
Teleport fixes this by introducing an identity-aware access proxy and an internal Certificate Authority (CA). Instead of relying on static credentials, engineers authenticate through SSO, GitHub, or Okta. Teleport then issues cryptographic X.509 and SSH certificates valid for just 8 to 12 hours. Once that window closes, credentials expire automatically—leaving zero persistent keys behind on endpoints.
Installation: Setting Up the Teleport Proxy and Auth Server
We’ll deploy Teleport Community Edition on an Ubuntu 22.04 LTS host with 2 vCPUs and 4 GB RAM. This single host handles both the Auth Service (which issues certificates) and the Proxy Service (which routes incoming HTTPS and SSH traffic).
Start by adding the official Gravitational repository and pulling the Teleport package:
# Download and install the Teleport public key
sudo curl https://apt.releases.teleport.dev/gpg \
-o /usr/share/keyrings/teleport-archive-keyring.asc
# Add the stable v15 repository
source /etc/os-release
echo "deb [signed-by=/usr/share/keyrings/teleport-archive-keyring.asc] \
https://apt.releases.teleport.dev/${ID?} ${VERSION_CODENAME?} stable/v15" \
| sudo tee /etc/apt/sources.list.d/teleport.list > /dev/null
# Update package lists and install teleport
sudo apt-get update
sudo apt-get install -y teleport
Generate your base configuration file next. Teleport includes a CLI helper that wires up the proxy and auth engines with existing TLS certificates:
sudo teleport configure \
--cluster-name=teleport.example.com \
--public-addr=teleport.example.com:443 \
--cert-file=/var/lib/teleport/fullchain.pem \
--key-file=/var/lib/teleport/privkey.pem \
--output=file:///etc/teleport.yaml
If you don’t have existing certs, swap out the file flags for --acme [email protected] to let Let’s Encrypt handle verification automatically. Enable and start the systemd service:
sudo systemctl enable --now teleport
sudo systemctl status teleport
Now create your first administrative user with access to root and ubuntu system accounts:
sudo tctl users add devops-admin \
--roles=editor,access \
--logins=root,ubuntu
The terminal will print a one-time onboarding link. Open it in your browser to enroll a WebAuthn hardware key (like a YubiKey) or configure an authenticator app (such as 1Password or Google Authenticator).
Configuration: Connecting Linux Nodes and Kubernetes Clusters
With the proxy up, we can link our infrastructure. Teleport uses outbound reverse tunnels, so your target servers never need port 22 exposed to the public internet.
1. Joining an External SSH Node
Generate a one-hour join token from the Teleport auth host:
sudo tctl tokens add --type=node --ttl=1h
Note the generated token and CA pin hash. On your target worker node, install the Teleport package using the earlier apt steps, then save this configuration to /etc/teleport.yaml:
version: v3
teleport:
nodename: worker-node-01
auth_token: "YOUR_GENERATED_JOIN_TOKEN"
auth_servers:
- "teleport.example.com:443"
auth_service:
enabled: "no"
proxy_service:
enabled: "no"
ssh_service:
enabled: "yes"
labels:
environment: production
tier: backend
Start the service: sudo systemctl enable --now teleport. The node dials out to teleport.example.com:443 on its own. You can lock down all inbound SSH firewall rules immediately.
2. Joining a Kubernetes Cluster
Connecting a Kubernetes cluster takes just a few Helm commands. Grab a cluster join token from your Teleport server:
sudo tctl tokens add --type=kube --ttl=1h
Switch to a workstation with administrative access to your target cluster and install the teleport-kube-agent:
helm repo add teleport https://charts.releases.teleport.dev
helm repo update
helm upgrade --install teleport-kube-agent teleport/teleport-kube-agent \
--namespace teleport \
--create-namespace \
--set kubeClusterName="production-eks" \
--set proxyAddr="teleport.example.com:443" \
--set authToken="YOUR_KUBE_JOIN_TOKEN"
The agent establishes an outbound tunnel to Teleport. When engineers send requests through the proxy, Teleport dynamically maps their identity to matching Kubernetes RBAC groups at runtime.
Verification & Monitoring: Testing Access and Auditing Sessions
Ditch raw ssh commands and static config files. Engineers now interact with everything through the unified tsh client.
Authenticating via the Client CLI
Log in through the command line:
tsh login --proxy=teleport.example.com:443 --user=devops-admin
This prompts for your password and MFA challenge. Once confirmed, Teleport drops a short-lived SSH certificate and updated kubeconfig context into your local environment.
Accessing SSH Targets
Discover servers using metadata labels and establish a shell:
# List all registered nodes in production
tsh ls environment=production
# Open an SSH shell using the temporary certificate
tsh ssh ubuntu@worker-node-01
Accessing Kubernetes
Query available clusters and point your context to production:
# Discover all clusters behind the proxy
tsh kube ls
# Switch context to the target cluster
tsh kube login production-eks
# Run standard kubectl commands normally
kubectl get nodes
kubectl get pods -n kube-system
You never shared a cloud provider IAM key or hardcoded service account secret. Teleport authenticates every individual kubectl API call on the fly.
Auditing and Session Replay
Teleport records interactive SSH sessions and tracks every raw Kubernetes API call. View active sessions or watch recorded terminal output directly from your shell:
# Inspect active SSH sessions
tsh status
# Replay a past terminal session frame by frame
tsh play <session-id>
Every command, file edit, and executed pod request lands in /var/lib/teleport/log as structured JSON. If a security incident strikes at 2 AM, your team has a tamper-proof audit trail of every keystroke across your entire stack—giving you rock-solid Zero Trust compliance without slowing down everyday engineering work.

