1. Introducción
Esta guía despliega Teleport como bastión SSH usando Docker en un primer servidor, y une un segundo servidor como agente/nodo para poder conectarse a él por SSH a través del bastión, con usuarios nominales, MFA y sesiones auditadas.
2. Variables de esta guía
Todos los comandos usan los siguientes marcadores en MAYÚSCULAS. Sustitúyelos por los valores reales de tu propia red antes de ejecutar cada bloque — tu IP, tu nombre de nodo y tus tokens serán distintos a los de este ejemplo.
| Marcador | Qué es | Dónde se obtiene |
|---|---|---|
IP_BASTION_WAN | IP del bastión en la red desde la que te conectas (navegador / tsh) | La IP de esa interfaz de red en tu servidor bastión |
IP_BASTION_LAN | IP del bastión en la red donde están los servidores a proteger | La IP de la segunda interfaz de tu servidor bastión |
NOMBRE_NODO | Hostname con el que el nodo se registra en Teleport | Lo defines tú al instalar el agente (por defecto, el hostname del sistema) |
LOGIN_SISTEMA | Usuario del sistema operativo que ya existe en el nodo | El usuario con el que sueles entrar por SSH a esa máquina |
TOKEN_NODO | Token de invitación de un solo uso, caduca en el tiempo indicado | Lo genera el bastión con tctl tokens add |
CA_PIN | Huella (fingerprint) de la CA del clúster Teleport | Se muestra junto al token al generarlo |
VERSION_TELEPORT | Versión exacta de Teleport instalada en el bastión | Se consulta con docker exec teleport teleport version |
3. Arquitectura y flujo
[Red de acceso] IP_BASTION_WAN
│
▼ https://IP_BASTION_WAN:3080 (UI web + tsh)
[BASTIÓN — Docker]
Teleport auth + proxy
Interfaz de acceso: IP_BASTION_WAN
Interfaz hacia servidores: IP_BASTION_LAN
│
▲ el nodo se conecta hacia IP_BASTION_LAN:3025 (auth service)
[Red de servidores]
NODO / AGENTE (NOMBRE_NODO)
No necesita puertos entrantes
El nodo inicia la conexión hacia el bastión (túnel saliente), así que no hace falta abrir ningún puerto entrante en el servidor que se quiere proteger. El cliente (navegador o tsh) siempre entra por IP_BASTION_WAN, y el nodo siempre se une usando IP_BASTION_LAN.
4. Requisitos
- Dos servidores Ubuntu Server (22.04 o 24.04) actualizados.
- Servidor bastión con Docker Engine y Docker Compose plugin instalados (
docker compose version). - Acceso
sudo/root en ambos servidores. - El servidor bastión debe ser alcanzable, con al menos una dirección accesible para el cliente (
IP_BASTION_WAN) y una dirección alcanzable desde la red del nodo (IP_BASTION_LAN). Si solo tienes una IP, usa la misma dirección en ambos casos. - Puertos 3080/tcp y 3025/tcp abiertos en el firewall del bastión.
5. Estructura de carpetas (en el bastión)
mkdir -p /docker/teleport/data cd /docker/teleport
6. Configurar teleport.yaml
nano /docker/teleport/teleport.yaml
version: v3
teleport:
nodename: bastion
data_dir: /var/lib/teleport
log:
output: stderr
severity: INFO
auth_service:
enabled: true
listen_addr: 0.0.0.0:3025
proxy_listener_mode: multiplex
authentication:
type: local
second_factor: otp
local_auth: true
proxy_service:
enabled: true
web_listen_addr: 0.0.0.0:3080
public_addr:
- "IP_BASTION_WAN:3080"
- "IP_BASTION_LAN:3080"
ssh_service:
enabled: false
proxy_listener_mode se declara dentro de auth_service, no en proxy_service. Al no indicar ningún certificado propio, Teleport genera uno autofirmado válido para las direcciones listadas en public_addr: por eso conviene incluir tanto la IP de acceso como la IP hacia la red de servidores.7. Configurar docker-compose.yml
nano /docker/teleport/docker-compose.yml
services:
teleport:
image: public.ecr.aws/gravitational/teleport-distroless:18
container_name: teleport
restart: unless-stopped
ports:
- "3080:3080"
- "3025:3025"
volumes:
- ./data:/var/lib/teleport
- ./teleport.yaml:/etc/teleport/teleport.yaml:ro
/etc/teleport/teleport.yaml (con subcarpeta). No es necesario indicar ningún command: el entrypoint de la imagen ya arranca Teleport con esa configuración.8. Firewall del bastión
sudo ufw allow 3080/tcp sudo ufw allow 3025/tcp sudo ufw allow OpenSSH sudo ufw enable sudo ufw status
IP_BASTION_WAN y unión de nodos por IP_BASTION_LAN) en lugar de abrir los puertos a cualquier origen.9. Levantar el contenedor
cd /docker/teleport docker compose up -d docker compose logs -f teleport
Auth service is starting, Starting web proxy service y Starting SSH proxy service sin errores posteriores.10. Crear el usuario administrador
docker exec teleport tctl users add admin \ --roles=editor,access,auditor \ --logins=LOGIN_SISTEMA
El comando devuelve una URL de invitación con este formato:
https://IP_BASTION_WAN:3080/web/invite/TOKEN_DE_INVITACION
11. Instalar el cliente tsh
Windows
Descarga el instalador desde https://goteleport.com/download y ejecútalo.
Linux / macOS
curl https://goteleport.com/static/install.sh | sudo bash -s VERSION_TELEPORT tsh version
12. Instalar Teleport en el nodo
docker exec teleport teleport version
curl https://goteleport.com/static/install.sh | sudo bash -s VERSION_TELEPORT teleport version
13. Generar el token de unión
docker exec teleport tctl tokens add --type=node --ttl=1h
La salida incluye el token y el ca-pin (huella de la CA) que se usan en el siguiente paso. Anota ambos valores.
14. Configurar el agente (en el nodo)
sudo teleport node configure \ --output=file:///etc/teleport.yaml \ --proxy=IP_BASTION_LAN:3080 \ --token=TOKEN_NODO \ --ca-pin=CA_PIN
Después, edita el fichero generado y sustituye proxy_server por auth_server apuntando al puerto 3025:
sudo nano /etc/teleport.yaml
version: v3
teleport:
nodename: NOMBRE_NODO
data_dir: /var/lib/teleport
join_params:
token_name: TOKEN_NODO
method: token
auth_server: IP_BASTION_LAN:3025
log:
output: stderr
severity: INFO
format:
output: text
ca_pin: CA_PIN
diag_addr: ""
auth_service:
enabled: "no"
ssh_service:
enabled: "yes"
proxy_service:
enabled: "no"
https_keypairs: []
https_keypairs_reload_interval: 0s
acme: {}
auth_server en el puerto 3025 en lugar de proxy_server en el puerto 3080 evita el error de validación TLS del certificado autofirmado: el registro del nodo se autentica mediante el token y el ca_pin, no mediante una cadena de certificados HTTPS confiable. Más detalle en la sección 19.15. Arrancar y verificar el nodo
sudo systemctl enable teleport --now sudo systemctl status teleport
docker exec teleport tctl nodes ls
NOMBRE_NODO. En los logs del nodo, la señal de éxito es Successfully registered instance client seguido de SSH Service is starting.16. Dar acceso SSH al usuario
docker exec teleport tctl users update admin --set-logins=LOGIN_SISTEMA
LOGIN_SISTEMA debe ser un usuario que ya exista en el nodo (por ejemplo, el que usas habitualmente para entrar por SSH a esa máquina).17. Probar la conexión de extremo a extremo
tsh login --proxy=IP_BASTION_WAN:3080 --insecure --user=admin tsh ls tsh ssh LOGIN_SISTEMA@NOMBRE_NODO
También puedes conectarte desde la interfaz web abriendo https://IP_BASTION_WAN:3080, localizando el nodo en Resources y pulsando Connect.
18. Chuleta de comandos
docker compose -f /docker/teleport/docker-compose.yml ps docker compose -f /docker/teleport/docker-compose.yml logs -f teleport docker exec teleport tctl status docker exec teleport tctl users ls docker exec teleport tctl users add USUARIO --roles=access,editor,auditor --logins=LOGIN_SISTEMA docker exec teleport tctl users update USUARIO --set-logins=LOGIN_SISTEMA docker exec teleport tctl users rm USUARIO docker exec teleport tctl nodes ls docker exec teleport tctl tokens add --type=node --ttl=1h
tsh login --proxy=IP_BASTION_WAN:3080 --insecure --user=USUARIO tsh ls tsh ssh LOGIN_SISTEMA@NOMBRE_NODO tsh logout
19. Por qué usamos "--insecure" y certificado autofirmado
Al no configurar un dominio con Let's Encrypt, Teleport genera automáticamente un certificado autofirmado para la interfaz web. Ese certificado no está emitido por una autoridad reconocida por el sistema operativo ni por el navegador, así que ambos avisan de "certificado no confiable".
- El flag
--insecureentshle indica que continúe la conexión aunque no pueda validar la cadena de certificación, algo razonable en un laboratorio controlado, pero desaconsejable en producción porque expone la conexión a un posible ataque de intermediario si el atacante puede interceptar el tráfico. - El registro de nuevos nodos, en cambio, no depende de
--insecure: se protege con el token de invitación (de un solo uso y caducidad corta) y el ca-pin (huella criptográfica de la CA del clúster), que el nodo verifica antes de confiar en el bastión. - Por eso el nodo se une usando el puerto del auth service (3025) en lugar del proxy web (3080): evita la validación de certificado HTTPS del navegador, pero mantiene la autenticación fuerte mediante token + ca-pin.
--insecure.20. Errores comunes y cómo resolverlos
| Problema | Causa probable | Solución |
|---|---|---|
unexpected teleport / unexpected start |
Se indicó un command en el compose que repite el entrypoint de la imagen |
Eliminar la línea command del docker-compose.yml |
path '/etc/teleport/teleport.yaml' does not exist |
El volumen se montó en /etc/teleport.yaml en lugar de la ruta con subcarpeta |
Montar el volumen en /etc/teleport/teleport.yaml |
field proxy_listener_mode not found in type config.Proxy |
El campo se colocó en proxy_service |
Mover proxy_listener_mode a auth_service |
cannot disable multi-factor authentication |
Se intentó usar second_factor: off |
Usar second_factor: otp |
missing required webauthn configuration |
Se usó second_factor: optional sin configurar WebAuthn |
Usar second_factor: otp |
x509: certificate signed by unknown authority al unir el nodo |
El nodo intenta unirse por el proxy web (3080) y rechaza el certificado autofirmado | Unir el nodo usando auth_server en el puerto 3025 |
Failed to launch: user: unknown user ... |
El login configurado en Teleport no existe como usuario del sistema en el nodo | Ejecutar tctl users update USUARIO --set-logins=LOGIN_SISTEMA con un usuario real del nodo |
| El desplegable de logins en la UI web muestra un valor antiguo | Caché del navegador o sesión activa | Recargar con caché vacía o cerrar sesión y volver a entrar |
21. Notas para producción
Este montaje es válido para laboratorio y demostraciones. Para un entorno de producción se recomienda:
- Dominio propio + Let's Encrypt en
proxy_service, para eliminar el certificado autofirmado y el flag--insecure. - Exponer Teleport detrás de una VPN o túnel en lugar de exposición directa a internet, cuando sea posible.
- Sustituir OTP por WebAuthn / llave de hardware, o por SSO corporativo (Google Workspace, GitHub, SAML), para revocación instantánea de acceso.
- Revisar periódicamente el audit log y la grabación de sesiones SSH, incluidos en Teleport Community.
- Restringir en el firewall de cada nodo el acceso SSH directo, dejando la conexión solo a través del bastión.