I have been diving a bit into how the balena-cli commands work and I’ve noticed a security hole. A tunnel is established by using vpn.balena-cloud.com as an HTTP proxy server using CONNECT. However, the connection from the client host to vpn.balena-cloud.com is plain TCP, it is not encrypted via SSL. The authorization scheme is HTTP BASIC, using the Balena user and the Balena token as a password. This exposes the client to a couple of security problems:
First of all, anyone with access can sniff the connection and get a user’s user ID and Balena token, exposing all the user’s resources while the token is still valid
Second, any traffic that is then sent through the tunnel is exposed (again, to sniffing)
Are there any plans to secure access? Either by using SSL, or by using the SSH proxy to establish the tunnel instead of an HTTP proxy.
Hey, thanks for reaching out. If this is the case, it sounds like it should definitely be patched. I’ve asked input from the team and we’ll let you know.
@mario, many thanks for finding and sharing this security gap. It is indeed something that we have now confirmed, and were previous unaware of. We are now discussing which of the two solutions you’ve suggested should be implemented: enabling TLS on the existing TCP connection socket (which would require changes to the backend too), or using the ssh.balena-devices.com proxy plus /usr/bin/nc on balenaOS. We will prioritise this issue, and post updates on this thread.
One comment regarding using nc. That would also enable developers and administrators to tunnel to non-exposed container ports. I’ve implemented this hack in a script (which is useful for our use-case):
remote_cmd="ip=\"\$(balena inspect \$(balena network ls --format '{{.Name}}' | grep default) | jq -r '.[].Containers[]|select(.Name|startswith(\"${container}\"))|.IPv4Address|gsub(\"/[0-9]*$\"; \"\")')\"; nc \$ip '${remote_port}'"
# Not too happy about UserKnownHostsFile=/dev/null and StrictHostKeyChecking=false, but there is no (easy) way
# to ask the user to add ssh.balena-devices.com to their known_hosts file (plus, this is what balena ssh does)
socat tcp-listen:${local_port},reuseaddr,fork "exec:ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no ${user}@ssh.balena-devices.com host ${device_uuid} ${remote_cmd}"
As of today, balenaCloud has a new, TLS-encrypted backend endpoint for use by the balena tunnel CLI command:
New: tunnel.balena-cloud.com:443 (TLS enabled)
Old: vpn.balena-cloud.com:3128
balena CLI version 12.38.5 or later makes use of the new endpoint. Access to the old endpoint will soon be closed. Therefore, balenaCloud users are advised to upgrade their CLI installations in order to continue using the balena tunnel command without disruption.
openBalena has also introduced the new tunnel endpoint starting with openBalena v3.1.2. openBalena users should match the CLI release to the openBalena release:
openBalena v3.1.2 or later: use CLI v12.38.5 or later
older openBalena releases: use older CLI releases
Thank you again @mario for reporting this issue and sharing the workarounds!