Instalación de Boundary para Acceso Remoto Seguro

HashiCorp Boundary es una solución de acceso remoto basada en identidad que permite a los equipos conectarse a sistemas internos sin necesidad de VPNs ni credenciales estáticas. Boundary implementa el modelo zero-trust integrándose con proveedores de identidad existentes como Okta, GitHub o LDAP para gestionar el acceso a targets de infraestructura de forma dinámica y auditable.

Requisitos Previos

  • Ubuntu 22.04/20.04 o CentOS/Rocky Linux 8+
  • PostgreSQL 12+ para almacenamiento del controller
  • Al menos 2 vCPUs y 2 GB de RAM
  • Puertos 9200 (API), 9201 (cluster), 9202 (worker proxy) accesibles
  • KMS o clave de encriptación (se puede usar AWS KMS, GCP KMS o clave estática para pruebas)

Instalación de Boundary

# Agregar el repositorio HashiCorp (Ubuntu/Debian)
wget -O- https://apt.releases.hashicorp.com/gpg | gpg --dearmor \
  | tee /usr/share/keyrings/hashicorp-archive-keyring.gpg > /dev/null

echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] \
  https://apt.releases.hashicorp.com $(lsb_release -cs) main" \
  | tee /etc/apt/sources.list.d/hashicorp.list

apt update && apt install boundary -y

# Para CentOS/Rocky Linux
yum install -y yum-utils
yum-config-manager --add-repo https://rpm.releases.hashicorp.com/RHEL/hashicorp.repo
yum install boundary -y

# Verificar instalación
boundary version
# Instalar y configurar PostgreSQL para el controller
apt install postgresql postgresql-contrib -y
systemctl enable postgresql && systemctl start postgresql

# Crear base de datos para Boundary
sudo -u postgres psql << 'EOF'
CREATE DATABASE boundary;
CREATE USER boundary WITH ENCRYPTED PASSWORD 'password-seguro';
GRANT ALL PRIVILEGES ON DATABASE boundary TO boundary;
\c boundary
GRANT ALL ON SCHEMA public TO boundary;
EOF

Configuración del Controller

El controller gestiona la API, los metadatos y la base de datos de Boundary.

# Generar claves de encriptación (para entornos de prueba)
# En producción usar AWS KMS, GCP KMS o Azure Key Vault
boundary config encrypt -type aes256 > /dev/null

# Generar claves aleatorias
ROOT_KEY=$(openssl rand -base64 32)
WORKER_KEY=$(openssl rand -base64 32)
RECOVERY_KEY=$(openssl rand -base64 32)

echo "ROOT_KEY=$ROOT_KEY"
echo "WORKER_KEY=$WORKER_KEY"
echo "RECOVERY_KEY=$RECOVERY_KEY"

Crear el archivo de configuración del controller en /etc/boundary/controller.hcl:

# Configuración del Controller de Boundary
disable_mlock = true

controller {
  name        = "boundary-controller-1"
  description = "Controller principal de producción"

  database {
    url = "postgresql://boundary:password-seguro@localhost/boundary?sslmode=disable"
  }
}

listener "tcp" {
  address     = "0.0.0.0:9200"
  purpose     = "api"
  tls_disable = false
  tls_cert_file = "/etc/boundary/tls/boundary.crt"
  tls_key_file  = "/etc/boundary/tls/boundary.key"
}

listener "tcp" {
  address = "0.0.0.0:9201"
  purpose = "cluster"
}

# Usar claves estáticas (solo para desarrollo/pruebas)
kms "aead" {
  purpose   = "root"
  aead_type = "aes-gcm"
  key       = "tu-clave-root-base64-aqui-32-bytes"
  key_id    = "global_root"
}

kms "aead" {
  purpose   = "worker-auth"
  aead_type = "aes-gcm"
  key       = "tu-clave-worker-base64-aqui-32bytes"
  key_id    = "global_worker-auth"
}

kms "aead" {
  purpose   = "recovery"
  aead_type = "aes-gcm"
  key       = "tu-clave-recovery-base64-32-bytes"
  key_id    = "global_recovery"
}
# Inicializar la base de datos (solo la primera vez)
boundary database init -config /etc/boundary/controller.hcl

# Guardar las credenciales de admin que aparecen en la salida
# Crear el servicio systemd
cat > /etc/systemd/system/boundary-controller.service << 'EOF'
[Unit]
Description=HashiCorp Boundary Controller
Documentation=https://boundaryproject.io/docs
Requires=network-online.target
After=network-online.target

[Service]
User=boundary
Group=boundary
ExecStart=/usr/bin/boundary server -config=/etc/boundary/controller.hcl
ExecReload=/bin/kill --signal HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

# Crear usuario del sistema para Boundary
useradd --system --home /etc/boundary --shell /bin/false boundary
chown -R boundary:boundary /etc/boundary

systemctl daemon-reload
systemctl enable boundary-controller
systemctl start boundary-controller

Configuración del Worker

Los workers proxy el tráfico entre los clientes y los targets de infraestructura.

# Crear la configuración del worker en /etc/boundary/worker.hcl
cat > /etc/boundary/worker.hcl << 'EOF'
disable_mlock = true

worker {
  name        = "boundary-worker-1"
  description = "Worker en red interna"
  
  # Dirección del controller
  initial_upstreams = ["boundary-controller.miempresa.local:9201"]
  
  # Dirección pública por la que los clientes se conectan
  public_addr = "worker-publico.miempresa.com"
}

listener "tcp" {
  address = "0.0.0.0:9202"
  purpose = "proxy"
}

# La misma KMS de autenticación worker que en el controller
kms "aead" {
  purpose   = "worker-auth"
  aead_type = "aes-gcm"
  key       = "tu-clave-worker-base64-aqui-32bytes"
  key_id    = "global_worker-auth"
}
EOF

# Crear servicio systemd para el worker
cat > /etc/systemd/system/boundary-worker.service << 'EOF'
[Unit]
Description=HashiCorp Boundary Worker
After=network-online.target

[Service]
User=boundary
Group=boundary
ExecStart=/usr/bin/boundary server -config=/etc/boundary/worker.hcl
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable boundary-worker
systemctl start boundary-worker

Organización de Scopes y Targets

Boundary organiza los recursos en jerarquías de scopes (global → org → project).

# Autenticarse en Boundary
export BOUNDARY_ADDR="https://boundary.miempresa.com:9200"
boundary authenticate password \
  -auth-method-id=ampw_1234567890 \
  -login-name=admin \
  -password=contraseña-inicial

# Crear una organización
boundary scopes create \
  -scope-id=global \
  -name="Mi Empresa" \
  -description="Scope de organización principal"

# Crear un proyecto dentro de la org
boundary scopes create \
  -scope-id=<org-id> \
  -name="Infraestructura Produccion" \
  -description="Servidores de producción"

# Crear un host catalog (catálogo de hosts)
boundary host-catalogs create static \
  -scope-id=<project-id> \
  -name="Servidores Web"

# Agregar hosts al catálogo
boundary hosts create static \
  -host-catalog-id=<catalog-id> \
  -name="web-01" \
  -address="192.168.1.10"

# Crear un host set
boundary host-sets create static \
  -host-catalog-id=<catalog-id> \
  -name="servidores-web-set"

# Agregar el host al host set
boundary host-sets add-hosts \
  -id=<host-set-id> \
  -host=<host-id>

# Crear el target SSH
boundary targets create ssh \
  -scope-id=<project-id> \
  -name="ssh-web-01" \
  -description="Acceso SSH a servidor web 01" \
  -default-port=22

# Asociar el host set al target
boundary targets add-host-sets \
  -id=<target-id> \
  -host-set=<host-set-id>

Inyección de Credenciales con Vault

Boundary puede obtener credenciales dinámicas de Vault y entregarlas automáticamente.

# Configurar Vault credential store en Boundary
boundary credential-stores create vault \
  -scope-id=<project-id> \
  -name="vault-produccion" \
  -vault-address="https://vault.miempresa.com:8200" \
  -vault-token="s.token-vault-aqui"

# Crear una credential library que genere claves SSH dinámicas
boundary credential-libraries create vault-ssh-certificate \
  -credential-store-id=<store-id> \
  -name="ssh-certs-produccion" \
  -vault-path="ssh/sign/my-role" \
  -username="ubuntu"

# Asociar las credenciales al target
boundary targets add-credential-sources \
  -id=<target-id> \
  -brokered-credential-source=<library-id>

Gestión de Sesiones

# Conectarse a un target (Boundary abre el túnel automáticamente)
boundary connect ssh -target-id=<target-id>

# Conectar con un usuario específico
boundary connect ssh \
  -target-id=<target-id> \
  -username=ubuntu

# Listar sesiones activas
boundary sessions list -scope-id=<project-id>

# Ver detalles de una sesión
boundary sessions read -id=<session-id>

# Cancelar una sesión activa (como administrador)
boundary sessions cancel -id=<session-id>

# Conectarse a una base de datos PostgreSQL
boundary connect postgres \
  -target-id=<db-target-id> \
  -dbname=mibase

Interfaz de Usuario Web

Boundary incluye una interfaz web en el puerto 9200 para gestión visual.

# Acceder a la UI web
# https://boundary.miempresa.com:9200

# También existe la aplicación de escritorio Boundary Desktop
# Disponible para macOS, Windows y Linux en:
# https://developer.hashicorp.com/boundary/tutorials/hcp-getting-started/hcp-getting-started-desktop-app

# Verificar el estado de la API
curl -sk https://boundary.miempresa.com:9200/v1/health | jq .

Solución de Problemas

El worker no se conecta al controller:

# Verificar conectividad al puerto de cluster
telnet boundary-controller.miempresa.local 9201

# Revisar logs del worker
journalctl -u boundary-worker -f

# Verificar que las claves KMS coinciden entre controller y worker
boundary server -config=/etc/boundary/worker.hcl -log-level=debug

Error al inicializar la base de datos:

# Verificar la URL de PostgreSQL
psql "postgresql://boundary:password@localhost/boundary?sslmode=disable" -c "\l"

# Reiniciar la inicialización (solo en entorno fresco)
boundary database init -config /etc/boundary/controller.hcl -skip-auth-method-creation

No se puede conectar al target:

# Verificar que el worker tiene alcance de red al target
boundary workers list -scope-id=global

# Ver permisos del usuario actual
boundary roles list -scope-id=<project-id>

Conclusión

HashiCorp Boundary elimina la necesidad de VPNs y credenciales estáticas al proporcionar acceso basado en identidad con sesiones auditables y credenciales dinámicas via Vault. Su arquitectura de controller/worker permite desplegar workers en redes internas sin exponer directamente los sistemas internos, lo que lo convierte en una solución robusta para entornos de producción con requisitos de seguridad estrictos.