balena scan fails to find local device when there is one - Could not find any balenaOS devices on the local network.

Running sudo balena scan always seems to fail with: Could not find any balenaOS devices on the local network.. I’m posting here because it’s not as obvious of a bug as the balena login failure that I found in balena-io/balena-cli#1765.

When I set DEBUG=1 and verbose mode:

export DEBUG=1 ; sudo -E balena scan --verbose
[debug] original argv0="node" argv=[/usr/local/Cellar/node/14.0.0/bin/node,/usr/local/bin/balena,scan,--verbose] length=4
[debug] new argv=[/usr/local/Cellar/node/14.0.0/bin/node,/usr/local/bin/balena,scan,--verbose] length=4
Reporting scan results
Could not find any balenaOS devices on the local network.
ExpectedError: Could not find any balenaOS devices on the local network.
    at ScanCmd.run (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/build/actions-oclif/scan.js:39:19)
    at async ScanCmd._run (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/node_modules/@oclif/command/lib/command.js:44:20)
    at async Config.runCommand (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/node_modules/@oclif/config/lib/config.js:160:9)
    at async CustomMain.run (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/node_modules/@oclif/command/lib/main.js:21:9)
    at async CustomMain._run (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/node_modules/@oclif/command/lib/command.js:44:20)
    at async Promise.all (index 1)
    at async Object.run (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/build/app-oclif.js:30:9)
    at async routeCliFramework (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/build/preparser.js:36:9)
    at async Object.run (/usr/local/Cellar/balena-cli/11.31.22/libexec/lib/node_modules/balena-cli/build/app.js:14:5)

If you need help, don't hesitate in contacting our support forums at
https://forums.balena.io

For CLI bug reports or feature requests, have a look at the GitHub issues or
create a new one at: https://github.com/balena-io/balena-cli/issues/

I remember that when BalenaOS was still called “ResinOS”, I could find the devices by using (Avahi / Bonjour / ZeroConf) mDNS. So I tried a scan using dns-sd on macOS to search for devices advertising _ssh._tcp over Bonjour:

dns-sd -Z _ssh._tcp
Browsing for _ssh._tcp
DATE: ---Tue 05 May 2020---
13:59:11.932  ...STARTING...

; To direct clients to browse a different domain, substitute that domain in place of '@'
lb._dns-sd._udp                                 PTR     @

; In the list of services below, the SRV records will typically reference dot-local Multicast DNS names.
; When transferring this zone file data to your unicast DNS server, you'll need to replace those dot-local
; names with the correct fully-qualified (unicast) domain name of the target host offering the service.

_ssh._tcp                                       PTR     abcdef0-2._ssh._tcp
abcdef0-2._ssh._tcp                             SRV     0 0 22222 abcdef0-2.local. ; Replace with unicast FQDN of target host
abcdef0-2._ssh._tcp                             TXT     "" 

So, that looks to be working! It’s running on port 22222, as it did before with older versions (when it was called ResinOS).
Note: I’ve scrubbed the actual device hostname / UUID, instead calling it abcdef0 for privacy in this forum post.

I also remember that with ResinOS, it was possible to manually SSH into the device. Something like: ssh -v -p 22222 root@abcdef0-2.local. This doesn’t appear to work anymore, and it just gives Permission denied (publickey) error. I’m guessing that I would somehow need to manually add my SSH keys to the device? There was some discussion way back then about the process for adding custom SSH keys to a BalenaOS image that I seem to have forgotten. I did check that my SSH keys are known to Balena Cloud UI. They are listed under the Balena Cloud “preferences => SSH Keys” section. However, on the device, I noticed there is an unknown key in /home/root/.ssh/authorized_keys and /home/root/.ssh/authorized_keys_remote.

What key is this? How do I ensure only my key is in there and the device is secure?

As far as building and pushing an app to the device… everything else with balena-cli seems to work except scan.

I noticed after running balena ssh with export DEBUG=1 that it shows the SSH command as: /usr/bin/ssh, -t, -o, LogLevel=ERROR, -o, StrictHostKeyChecking=no, -o, UserKnownHostsFile=/dev/null, gh_trinitronx@ssh.balena-devices.com, host xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. I also noticed that dropbear is running on the device on the usual ResinOS SSH port 22222.

This differs from the original ResinOS local SSH method. So something has changed with the way balena ssh works in recent years? The OS has certainly changed, as docker command has been renamed balena now (that was confusing at first).

I also assume that balena scan must have changed somehow, or is not working properly with Bonjour / mDNS anymore?

So, I have a few main questions:

How is balena scan supposed to work?
How can I locally SSH into the device without balena ssh?
How can we be sure that our devices are secured and locked to our own SSH keys?

Hi, thanks for your post. As a start let me point you to our SSH documentation https://www.balena.io/docs/learn/manage/ssh-access/#ssh-access which will give you an overview. It’s also worth noting the differences between development and production images https://www.balena.io/docs/reference/OS/overview/2.x/#development-vs-production-images. I suspect you are using a production image and if so this would not be returned by balena scan.

The above SSH documentation outlines how to access the device using a standalone SSH client (after adding an SSH key to config.json) on a production image.

Also, please see the security page https://www.balena.io/docs/learn/welcome/security/#support-access which outlines how we use the SSH key on the device. As noted there you can remove it this will render the device inaccessible remotely for the purposes of support or repairs and updates to the base OS.

1 Like

Hi Gareth,

Thanks for the quick response! It sounds like what I needed to do was use either: tunnel mode, or balena ssh <device-uuid>.local, along with adding the SSH key via config.json. I found this file inside the resin-image-edison.hddimg after mounting via loopback device. I assume this is correct, so I’ll try that next.

I see that the local mDNS name form of balena ssh returns the SSH command I’m probably remembering from the ResinOS days:

/usr/bin/ssh, -t, -p, 22222, -o, LogLevel=ERROR, -o, StrictHostKeyChecking=no, -o, UserKnownHostsFile=/dev/null, root@<device-uuid>.local