Modify environment/service variables through the supervisor API?

Is it possible for a service itself to change the value of environment variables (or create new ones) through the supervisor API? We have a some settings that we would like the user to control through our embedded UI (e.g., specify access keys), and that we want to be persistent through resets, but that we would also like to be able to view and modify ourselves through Balena Dashboard for support purposes.

Right now we’re using environment/service variables to do this, which works quite well from the back-end through the dashboard, but doesn’t give us a way to let the user control them through the UI. Similarly, we can change and store settings through the UI by storing the values in persistent storage on the device, but then they are much more complicated to access through the dashboard (ssh into a running service, locate the config file on the device, use vi or similar to edit it, manually restart the service or application).

Ideally, we would like to restrict which variables could be changed, but that’s less critical since the actual supervisor calls would be performed within our own code.

Thanks,

Adam

Hi @adamshapiro0,

I was about to say no, but it looks like you may be able to do it by modifying the device’s target state. This seems like a pretty extreme measure though. It may be better to have your application code interact directly or indirectly with the balenaCloud API instead? Our environment and service variables document contains links to documentation to change service variables with the SDK and the CLI.

Cheers,
James.

Hi James,

I thought about doing it through the SDK, but that would require the device to have access creds for the cloud, no? Of course we wouldn’t want to embed actual user credentials. If it’s possible to make service accounts we could potentially do that, but making a service account per customer/device and embedding the creds in the device seems like a lot of work. We would also not want any risk of that service account being used to modify a different device. Is there a way to restrict which individual devices an account can modify?

Overall though, having any sort of credentials that could be used via SDK, dashboard, etc. to do anything more than modify the environment variables feels pretty risky to me.

Is there a good/recommended way to do this? Are environment variables even the right choice?

Thanks,

Adam

Hey Adam,

My first thought would be for you to build your own API service which holds your balena API credentials, which your devices can connect to. This has the bonus that you don’t have to share your API credentials with all the devices and can perform some additional validation as needed.
Other than that all I can think of is manipulating the device state.

If you want to avoid the use of environment variables at all then there’s a couple of methods I can think of:

  1. Have a named, shared volume in which your UI can store the credentials and other services can access them from there.
  2. Build your own internal API service which your other services depend on which can hold this configuration information.

Hope that helps,
James.

Oh, one more thing. If you add the io.balena.features.balena-api: '1' label to your docker-compose.yml your container will get access to the BALENA_API_KEY environment variable, which you can use to authorise the SDK.

Thanks, James. The more I think about it, the more it seems like env variables may not be the right fit for some of these settings.

Certainly, having a device have access to BALENA_API_KEY and the back-end without being restricted to viewing/changing settings only for that specific device seems terrifying. :slightly_smiling_face:

I think for now we may just use the shared volume, which we’re already using for other data storage, and just store the config in a local file. It makes it a little more complicated for back-end support but, at least for now, we might be able to just tunnel the UI port and access it the same way a user would to avoid having to manually edit the file within an ssh session or something. Longer term we can see if there’s another alternative that works a little better.

Actually, it looks like the API key may indeed be limited to the specific device (https://www.balena.io/docs/learn/welcome/security/#device-access). Am I understanding that correctly?

Yes, the API key present on the device should only be able to manipulate settings for that device.
I think for your use-case it sounds like the shared volume is the way to go to me too. Changing device or service variables will cause the service(s) to be restarted, which may or may not be what you want. By reacting to changes on the filesystem you can have more control over how to react to changes.

Yeah agreed. If there was a way to do a bulk setting of multiple variables through the SDK that might be ok, but you don’t want the container to reset when only 1 of 3 changes have been made for example. Shared volume it is! Good to know about the API key though, in case we need it for anything down the road.

I was just about to ask a slightly more specific version of this question so I thought I’d tag along here - my deployment environment may sometimes include airgapped locations where there is no DHCP and the static IP may need to change from my preferred default (e.g. I chose 10.10.10.199 but that conflicts at a customer site). With no cloud/internet connection the change would have to come from a service. Would I be able to use a subset of the target state to adjust the network, e.g.:

TARGET_STATE='{
"apps": {
            "networks": {"New Static IP defined here as address2=10.10.10.123/24,10.10.10.1"}
        }
   }
'

The first thing I thought of was enabling DBUS and interacting with the network manager to change the static IP address. I am not completely sure of the exact set of commands that you will need to perform, but I do think it is possible. I think https://www.balena.io/docs/reference/OS/network/2.x/ should be enough to get you going and figure out how to do it though. Let us know how it goes and if you get stuck we can try to help you out further.