Esse script resolve de forma simples um problema real de operação em ambientes NSX modernos: ter um inventário confiável de todos os túneis IPSec, com status em tempo real. Abaixo está um texto que você pode usar como base para artigo técnico ou post de blog.
Por que automatizar o inventário de VPNs no NSX
Em ambientes NSX com dezenas ou centenas de túneis IPSec, depender apenas da interface gráfica para entender quais sessões estão UP, DOWN, quais IPs locais/remotos estão em uso e quais endereços de túnel foram atribuídos torna-se rapidamente inviável. Além do esforço manual, isso complica auditorias, troubleshooting e até planejamento de capacidade, especialmente em versões mais recentes do NSX, onde a separação entre Policy API e Manager API é mais evidente.
Automatizar esse inventário via API permite gerar uma visão consolidada do ambiente em segundos, integrando a informação com CMDBs, sistemas de monitoramento ou pipelines de automação já existentes.
Entendendo a arquitetura de IPSec no NSX
No NSX, uma sessão IPSec não carrega todos os dados “interessantes” em um único objeto; ela referencia outros recursos como local endpoints, peer endpoints e serviços de VPN, cada um com seus próprios campos de configuração. A API de Manager expõe uma visão mais “plana” dos objetos IPSec (/api/v1/vpn/ipsec/sessions), enquanto a Policy API é responsável pelo estado realizado e estatísticas detalhadas das sessões.
Além disso, as estatísticas e o status operacional dos túneis são expostos por um endpoint específico de statistics, que retorna tanto o estado IKE quanto o estado IPSec por túnel (tunnel_status).
O objetivo do script
O script apresentado tem um objetivo bem definido: percorrer todas as sessões IPSec configuradas no NSX e montar uma tabela com cinco campos essenciais para operação diária:
- Name: nome da sessão IPSec (display_name).
- Local Endpoint: IP configurado no local endpoint (IP de origem da VPN).
- Remote IP: IP configurado no peer endpoint (IP de destino da VPN).
- Status: estado operacional do túnel (UP, DOWN, DISABLED, etc.).
- Tunnel Interface: IP/CIDR da interface túnel interna (normalmente 169.254.x.x/30).
Com isso, o operador passa a ter uma visão clara de todos os túneis, incluindo rotas-based com VTI, em uma única saída de linha de comando, facilmente exportável para CSV, Excel ou sistemas de monitoramento.
Como o script funciona por baixo dos panos
O ponto de partida é o endpoint /api/v1/vpn/ipsec/sessions, que retorna todas as sessões IPSec do ambiente, incluindo o nome, o estado administrativo (enabled), os IDs de local endpoint, peer endpoint e a definição dos tunnel_ports. A partir dos IDs, o script consulta /api/v1/vpn/ipsec/local-endpoints e /api/v1/vpn/ipsec/peer-endpoints para mapear local_endpoint_id → local_address e peer_endpoint_id → peer_address, que são exatamente os IPs locais e remotos que se deseja exibir.
O endereço da interface túnel é extraído dos tunnel_ports, combinando ip_subnets[0].ip_addresses[0] com prefix_length, o que resulta em algo como 169.254.1.1/30 para cada sessão route-based. Para obter o status em tempo real, o script usa o policyPath presente nas tags de cada sessão (escopo policyPath) e chama o endpoint /policy/api/v1<policyPath>/statistics, de onde lê tunnel_status e ike_session_state para classificar cada túnel como UP, DOWN ou DISABLED.
Benefícios práticos e possíveis extensões
Na prática, esse script resolve três dores comuns de operação: inventário rápido de túneis, validação de configuração (IPs locais/remotos corretos) e checagem de saúde (status UP/DOWN) sem precisar navegar pela interface do NSX. Ele também serve como base para integrações mais avançadas, como alimentar um Prometheus/InfluxDB com métricas de túneis, acionar alertas em ferramentas de observabilidade ou gerar relatórios periódicos para equipes de segurança e redes.
A partir dessa fundação, é simples estender o script para incluir mais campos das estatísticas (bytes, pacotes, razões de queda), filtrar apenas túneis DOWN ou com erro, ou mesmo correlacionar as sessões com objetos de Tier‑0/Tier‑1 para montar um mapa completo de conectividade entre data centers, sites remotos e ambientes de nuvem.
Script completo:
#!/bin/bash
IP_NSX="https://NSX-MANAGER"
USERNAME="admin"
PASSWORD='SENHA_AQUI'
AUTH="-u ${USERNAME}:${PASSWORD}"
HEADER="-H Content-Type:application/json"
echo "NAME | LOCAL_ENDPOINT | REMOTE_IP | STATUS | TUNNEL_INTERFACE"
echo "---------------------------------------------------------------------"
# 1) Local endpoints (id -> local_address)
LOCAL_TSV=$(
curl -sk $AUTH $HEADER "${IP_NSX}/api/v1/vpn/ipsec/local-endpoints" \
| jq -r '.results[]? | [.id, .local_address] | @tsv'
)
# 2) Peer endpoints (id -> peer_address)
PEER_TSV=$(
curl -sk $AUTH $HEADER "${IP_NSX}/api/v1/vpn/ipsec/peer-endpoints" \
| jq -r '.results[]? | [.id, .peer_address] | @tsv'
)
declare -A LOCAL_IP
declare -A PEER_IP
while IFS=$'\t' read -r ID IP; do
[ -z "$ID" ] && continue
LOCAL_IP["$ID"]="$IP"
done <<< "$LOCAL_TSV"
while IFS=$'\t' read -r ID IP; do
[ -z "$ID" ] && continue
PEER_IP["$ID"]="$IP"
done <<< "$PEER_TSV"
# 3) Todas as sessões IPSec
curl -sk $AUTH $HEADER "${IP_NSX}/api/v1/vpn/ipsec/sessions" \
| jq -c '.results[]' \
| while read -r S; do
NAME=$(jq -r '.display_name' <<< "$S")
ENABLED=$(jq -r '.enabled' <<< "$S")
LOCAL_ID=$(jq -r '.local_endpoint_id' <<< "$S")
PEER_ID=$(jq -r '.peer_endpoint_id' <<< "$S")
# policyPath para usar a Policy API
POLICY_PATH=$(jq -r '.tags[]? | select(.scope=="policyPath") | .tag' <<< "$S")
LOCAL=${LOCAL_IP[$LOCAL_ID]:-"N/A"}
PEER=${PEER_IP[$PEER_ID]:-"N/A"}
TUN_IP=$(jq -r '.tunnel_ports[0].ip_subnets[0].ip_addresses[0] // empty' <<< "$S")
TUN_PL=$(jq -r '.tunnel_ports[0].ip_subnets[0].ip_addresses[0] as $ip
| .tunnel_ports[0].ip_subnets[0].prefix_length // empty' <<< "$S")
if [[ -n "$TUN_IP" && -n "$TUN_PL" ]]; then
TUNNEL_IF="${TUN_IP}/${TUN_PL}"
else
TUNNEL_IF="N/A"
fi
STATUS="UNKNOWN"
if [[ -n "$POLICY_PATH" && "$POLICY_PATH" != "null" ]]; then
STAT_URL="${IP_NSX}/policy/api/v1${POLICY_PATH}/statistics"
STATS=$(curl -sk $AUTH $HEADER "$STAT_URL" 2>/dev/null || echo '{}')
# 1) Prioriza tunnel_status do primeiro túnel
TS=$(jq -r '.results[0].policy_statistics[0].tunnel_statistics[0].tunnel_status // "UNKNOWN"' <<< "$STATS")
# 2) Se não tiver, cai para ike_session_state
IKE=$(jq -r '.results[0].ike_status.ike_session_state // "UNKNOWN"' <<< "$STATS")
if [[ "$TS" != "UNKNOWN" && "$TS" != "null" ]]; then
STATUS="$TS"
elif [[ "$IKE" != "UNKNOWN" && "$IKE" != "null" ]]; then
STATUS="$IKE"
else
STATUS="UNKNOWN"
fi
# Opcional: se quiser tratar sessão desabilitada explicitamente
if [[ "$ENABLED" != "true" ]]; then
STATUS="DISABLED"
fi
fi
echo "${NAME} | ${LOCAL} | ${PEER} | ${STATUS} | ${TUNNEL_IF}"
done

Comments are closed