twingate
Awesome zero-trust VPN that several of our clients have. We're fans.
Generate/install connector for a Proxmox LXC container
For our pentest dropboxes, we love using the twingate-connector LXC.
- Run the install script (from Proxmox GUI, not SSH console).
- From the Twingate admin console, click Remote Networks > (click your remote network) and under Connectors click Add Connector.
- Click the connector (rename it if you want).
- Under Select a Deployment Method, click Proxmox and then copy/paste the appropriate tokens into the LXC install.
- Make sure for the network name, you choose a network name that is configured under
Network > Remote Networks.
Edit/refresh tokens
The tokens are stored here:
/etc/twingate/connector.conf
Uninstall a twingate connector
sudo apt purge twingate-connector
Uninstall a twingate docker connector
Get the image name (look under the NAMES column):
sudo docker ps -a
Stop it:
sudo docker rm twingate-unique-name-goes-here
Remove it:
sudo docker rm twingate-unique-name-goes-here
Update twingate connector
sudo apt update
sudo apt install -yq twingate-connector
sudo systemctl restart twingate-connector
Check that the version got updated:
twingate-connector -V
More info on the update process here
Troubleshooting connectivity
If your twingate connector isn't phoning home, check out this page.
See what's happening in the logs:
journalctl -u twingate-connector -f
Turn logging up
If the logs are kind of boring, this page well help you turn logging up to 11 (well, actually...7):
nano /etc/twingate/connector.conf
# Add this line:
echo "TWINGATE_LOG_LEVEL=7" | sudo tee -a /etc/twingate/connector.conf
Restart connector:
sudo systemctl restart twingate-connector
If things still aren't happy, review the firewall logs.
Scanning with nmap and other tools through the Twingate connector
After working with Twingate a while, I discovered that if you're connected via the VPN and try to nmap-scan a customer's network that is shared out as a resource via Twingate, the scan won't work. Here is why. Basically this article recommends you do an application-level scan of endpoints to figure out what is truly open.
When I deploy a NUC into a customer environment and let's say only the Twingate connector checks in with IP 192.168.1.7, I use a script like this to specify 192.168.1.0/24 and which ports I want to look for (like port 8006 for my Proxmox box):
#!/bin/bash
# Prompt for CIDR and ports
read -p "Enter target subnet in CIDR notation (e.g. 10.0.20.0/24): " cidr
read -p "Enter port(s) to scan, space-separated (e.g. 8006 443 22): " ports_input
# Parse CIDR
IFS='/' read -ra parts <<< "$cidr"
base_ip="${parts[0]}"
prefix="${parts[1]}"
# Parse octets
IFS='.' read -ra octets <<< "$base_ip"
IFS=' ' read -ra ports <<< "$ports_input"
# Scan functions
scan_range() {
local sub=$1
for i in $(seq 1 254); do
ip="${sub}.$i"
(
if ping -c 1 -W 1 $ip &>/dev/null 2>&1 || \
curl -sk --max-time 1 https://$ip -o /dev/null 2>/dev/null || \
curl -sk --max-time 1 http://$ip -o /dev/null 2>/dev/null; then
echo "ALIVE $ip"
fi
) &
done
}
scan_ports() {
local sub=$1
for i in $(seq 1 254); do
ip="${sub}.$i"
(
hits=()
for port in "${ports[@]}"; do
result=$(curl -sk --max-time 2 https://$ip:$port -o /dev/null -w "%{http_code}" 2>/dev/null)
if [ "$result" == "000" ]; then
result=$(curl -sk --max-time 2 http://$ip:$port -o /dev/null -w "%{http_code}" 2>/dev/null)
fi
if [ "$result" != "000" ]; then
hits+=("port $port (HTTP $result)")
fi
done
if [ ${#hits[@]} -gt 0 ]; then
echo "OPEN $ip => ${hits[*]}"
fi
) &
done
}
# Determine subnets to scan based on prefix
base="${octets[0]}.${octets[1]}"
third="${octets[2]}"
if [ "$prefix" -eq 24 ]; then
subnets=("${base}.${third}")
elif [ "$prefix" -eq 23 ]; then
subnets=("${base}.${third}" "${base}.$((third + 1))")
elif [ "$prefix" -eq 22 ]; then
subnets=("${base}.${third}" "${base}.$((third + 1))" "${base}.$((third + 2))" "${base}.$((third + 3))")
else
echo "Supported prefixes: /22, /23, /24"
exit 1
fi
echo ""
echo "=== Phase 1: Finding live hosts on ${cidr} ==="
for sub in "${subnets[@]}"; do
scan_range "$sub"
done
wait
echo ""
echo "=== Phase 2: Checking ports [${ports[*]}] on ${cidr} ==="
for sub in "${subnets[@]}"; do
scan_ports "$sub"
done
wait