Add permissions to API keys

Hi all,

I was busy with the VPN HTTP Proxy via port 3128, so that I can access certain parts of my application from our server. Just like Balena does with the supervisor. However, if I try that, I get a 407 error. I’ve looked into the code and saw that it checks for access. If I’m correct, this part asks the API if I have access to tunnel-any or tunnel-<port>.

However, looking into the open-balena-api (if I’m correct), only tunnel-48484 is allowed for the VPN API key. It’s obviously for security reasons, but I’d like to use the VPN for my own application and allow another port to be tunneled via the HTTP proxy.

Is there any way to achieve this via openBalena? I’ve created the tunnel the same way as done here.

I know it’s for (obvious) security reasons that it’s not included by default, but because I’m using openBalena, it’d be nice if I can add this functionality for my server. Or is the only way to fork the open-balena-api and publish my own container?

Thanks in advance!

Or is the only way to fork the open-balena-api and publish my own container?

If you want to change these permissions, then this is the way.

The VPN key can only use 48484 as it’s done to allow access to the device’ supervisor API. When using the CLI tunnel command, the users key is used and that’s where the tunnel-any comes into play. I think you worked that out, but I though it good to confirm here :+1:

1 Like

Thanks for your confirmation!

I’m going to check how the tunnel command works and if I can automate it via Node.js, so I don’t need to create and maintain my own container for the open-balena-api. But it’s nice to know how it works and what my options are, so thanks!

I’ve checked how the tunnel command works, and I’ve been able to come up with something that works exactly as I want!

I’m using Node.js, so I’ve used the Node.js Balena SDK for it. This is how I’ve done it:

import { getSdk } from 'balena-sdk';
import request from 'request';

const balenaInstance = getSdk({ apiUrl: 'api.<open-balena-domain>' });
await balenaInstance.auth.login(credentials);

const [whoami, token] = Promise.all([
  balenaInstance.auth.whoami(),
  balenaInstance.auth.getToken()
]);

await new Promise((resolve, reject) => {
  request({
    uri: `http://<device-uuid>.balena:<device-port>',
    tunnel: true,
    proxy: `http://${whoami}:${token}@vpn.<open-balena-domain>:3128`
  }, (err, response) => {
    if (err) {
      reject(err);
    } else {
      resolve(response);
    }
  });
});

I don’t know if this works for Balena Cloud though, because of permissions.

It would work if you used a User-scoped API key (which you have done here) as the tunnel-any is a catch all for ports not explicitly allowed.

Yeah, but I thought that the VPN always uses its own key. But I was wrong there.
Nonetheless, thanks for pointing me in the right direction!

Hello

Maybe i don’t understand problem here, but i succesfully tunnel any port from device on Open Balena
Check this project

This is the ported tunneler to python

Example usage

Hi Adam,

Thanks for sharing your code!
There isn’t really a problem anymore, because I’ve achieved what I wanted here.

I used the wrong credentials when connecting to the VPN HTTP Proxy, which didn’t allow tunneling ports other than 48484 (supervisor). When using the right credentials (the openBalena login credentials), everything worked as expected!