Restricting docker-comopse update acceptance based on HWIDs

I noticed today that there doesn’t seem to be any sort of restriction on compatibility when a lockbox contains a docker-compose component. Specifically, I was able to install a docker-compose meant for one product on another, I suspect because they both use the same generic “docker-compose” hardwareID for the update system.

This seems a bit concerning since it’s potentially an easy way for a customer to brick a device using offline updates by e.g. accidentally having multiple or the wrong update on a USB drive.

Is there a facility to restrict which hardware can accept a docker-compose update based on e.g. the OS’s hardware IDs via the OTA/Torizon platform? Or is this something we would have to construct ourselves?

I saw the web interface has a facility to set compatibility with specific OS versions, which may do what I am interested in, but I do not immediately see a way to set this information via the Torizon API so that it can be integrated into our CI build system.

This also leads to a question I have on future use cases: Is it possible to ship multiple docker-compose components inside a lockbox? This is potentially something we would like to do to support multiple CPU architectures with the same update. If so, how can one ensure only the “correct” compose component is applied? Likely the containers would be the same and published as multi-architecture manifests, but I cannot say for sure that we might not need to e.g. ship additional containers on one platform but not the other)

Regards,
~BW908

Hi, I’m the Toradex AI Assistant. I’m in early beta, and I would appreciate your feedback.
The Toradex Support team will follow up with you shortly!


Hello,

I understand your concern about ensuring docker-compose updates are only applied to compatible hardware.

For restricting docker-compose updates based on hardware IDs (HWIDs) via the OTA/Torizon platform, there isn’t a direct feature within Torizon to enforce this at the docker-compose level. Typically, the HWID restrictions are applied at the OS image level, ensuring that only compatible devices receive and apply the updates. However, your approach to leveraging the OS version compatibility settings as a proxy for hardware compatibility is insightful. While this method can provide a layer of filtering, it’s not as granular or direct as having HWID-based restrictions for docker-compose components.

Integrating such compatibility checks into your CI build system, especially for docker-compose updates, would indeed require a custom solution. This could involve scripting or tooling that checks the target device’s HWID against a compatibility list before proceeding with the update. This list could be maintained as part of your CI pipeline and used to validate updates before they are pushed.

Regarding your question about shipping multiple docker-compose components inside a lockbox to support multiple CPU architectures, TorizonCore does support multi-architecture docker images, allowing you to specify different images for different architectures within the same docker-compose file. However, ensuring that only the correct docker-compose component is applied based on the CPU architecture would require careful management of your docker-compose files and possibly the use of conditional logic within those files to determine which components to run based on the detected architecture. This could be achieved by using environment variables or custom scripts that run at the start-up of your container to detect the architecture and make decisions accordingly.

In summary, while Torizon provides robust tools for managing OS updates, including HWID compatibility checks for OS images, applying similar restrictions directly to docker-compose updates requires a more tailored approach. Leveraging the OS version compatibility settings and integrating custom validation into your CI pipeline are practical steps toward achieving this. For multi-architecture support, utilizing multi-architecture docker images and conditional logic within your docker-compose files can help ensure the correct components are applied.

Best regards,
Toradex AI Assistant

Please, also check if these links can help you solve your problem:

How to Use Secure Offline Updates with Torizon OS | Toradex Developer Center.


How did you like my response?

:+1: :-1:

Greetings @bw908,

Is there a facility to restrict which hardware can accept a docker-compose update based on e.g. the OS’s hardware IDs via the OTA/Torizon platform? Or is this something we would have to construct ourselves?

Currently there’s no mechanism to do something exactly like this. The reason being that each ECU really only cares about itself. So docker-compose ECUs don’t care about the OS much. Even the compatibility you mentioned is just a web UI thing. It doesn’t actually affect the update logic. It just prevents you from doing incompatible online updates via the web UI, meaning it doesn’t really affect offline updates.

Now, in theory you could do something like this. What dictates the configuration for how docker-compose and other secondary type updates behave is the secondaries.json file. We ship a default configuration as seen here: meta-toradex-torizon/recipes-sota/config/files/secondaries.json at dunfell-5.x.y · torizon/meta-toradex-torizon · GitHub

As you can see we dictate that the hardware id is of type docker-compose. However, you can override this and supply your own configuration file for this. To do this see step 1 on this article: How to Use Subsystem Updates | Toradex Developer Center

Once you have your override configuration file in place you can dictate whatever hardware ID you want. For example something like:

{
    "docker-compose": [
        {
            "partial_verifying": false,
            "ecu_hardware_id": "docker-compose-A",
            "full_client_dir": "/var/sota/storage/docker-compose",
            "ecu_private_key": "sec.private",
            "ecu_public_key": "sec.public",
            "firmware_path": "/var/sota/storage/docker-compose/docker-compose.yml",
            "target_name_path": "/var/sota/storage/docker-compose/target_name",
            "metadata_path": "/var/sota/storage/docker-compose/metadata"
        },
        {
            "partial_verifying": false,
            "ecu_hardware_id": "docker-compose-B",
            "full_client_dir": "/var/sota/storage/docker-compose",
            "ecu_private_key": "sec.private",
            "ecu_public_key": "sec.public",
            "firmware_path": "/var/sota/storage/docker-compose/docker-compose.yml",
            "target_name_path": "/var/sota/storage/docker-compose/target_name",
            "metadata_path": "/var/sota/storage/docker-compose/metadata"
        
    ]
}

The magic here is that anything under the docker-compose header will be it’s own “seperate ECU” that uses the docker-compose update logic. So in this example I have defined 2 ECUs that use the docker-compose update logic with the only difference being ecu_hardware_id. Meaning this device would accept updates for packages that have hardware ids of docker-compose-B or docker-compose-A.

Now another thing is that you probably want to also define different file-paths for each unit here for full_client_dir, firmware_path, target_name_path, and metadata_path. Otherwise they’ll overwrite each other on updates which you may not want. Though keep in mind all of our default tools and services assume that the single docker-compose.yml on your system is at /var/sota/storage/docker-compose/docker-compose.yml. So, if you change this you may need to add or adapt several things on Torizon.

Finally, you of course need to make sure you upload your docker-compose packages with your new revised hardware ids. Though having said this I just realized TorizonCore Builder prohibits hardware ids other than docker-compose for docker-compose packages.

You can probably get around this by just uploading to our platform via the API instead. Anyways, assuming TorizonCore Builder eventually does allow this, would something like this approach I’ve described work for your process? Or is it still missing something?

All that said, let me bring this up internally cause I think what you have here is a pretty sensible and valid use-case, assuming I understood you correctly.

Best Regards,
Jeremias

Yes, on the surface it sounds like this could work - though I’m not sure I follow the issue with the sub-entries sharing the same path (at least in my perceived use case). I can see how it would be a problem if I attempt to have multiple docker-compose-X entries on the same platform; however in what I’m envisioning, since the architecture of the target machine is different, each OS would also be different and I could therefore have distinct secondaries defined for each one, e.g. one would have a docker-compose with hardware ID docker-compose-arm and the other docker-compose-x64. In this setup, wouldn’t one platform simply ignore the entry it doesn’t have declared in secondaries.json?

As a follow-on question to this, what would the workflow look like for managing and deploying a change like this on a system that may have started with just a standard ‘docker-compose’?

I’m guessing it would be a two-stage process whereby the OS is updated first to deploy a new secondaries.json, followed by the system then recognizing and pulling in the new secondary that has appeared. But what happens to (or how does one manage) any remnants from the old ‘docker-compose’ hardware ID that has been deprecated in favour of docker-compose-x?

Note I initially suggested pairing OS hardware IDs because we’ve customized those for our products accordingly but I ran into the exact issue you described in that it isn’t possible to push anything other than docker-compose for the docker HWID.

though I’m not sure I follow the issue with the sub-entries sharing the same path (at least in my perceived use case).

I think I misunderstood your point earlier when you asked:

Is it possible to ship multiple docker-compose components inside a lockbox?

I thought you meant you want the device to accept multiple docker-compose components with different HW-IDs. Now I understand you mean you want a sort of singular “master lockbox” with multiple docker-compose components with different HW-IDs. But, on each individual device you only want a single docker-compose component configured. Is that right?

If that is the case then just ignore the part of my example where I had 2 different docker-compose components configured in secondaries.json` as you would only need 1 then.

I’m guessing it would be a two-stage process whereby the OS is updated first to deploy a new secondaries.json,

Correct on already deployed devices you would need to deploy a new secondaries.json configuration with your new HW-IDs for docker-compose components.

But what happens to (or how does one manage) any remnants from the old ‘docker-compose’ hardware ID that has been deprecated in favour of docker-compose-x?

So any existing files should still remain on the system I believe. But going forward the secondary will use the new HW-ID. That said I never tried this thoroughly so I admit there may be some unforeseen interactions. I suppose instead of modifying the single existing docker-compose competent you could just add a new one alongside it. So for example you’d have the original one with HW-ID docker-compose then a new one with docker-compose-arm/arm64. That way you wouldn’t have to deal with the potential issues of modifying and transitioning the existing component and instead just start using the new component.

One other thing to note, is that since either way you’re modifying the secondary configuration of the system, you’d be subject to bullet-point 5 here: Bootloader Updates in Torizon OS | Toradex Developer Center

I know it mentions our online services, but it would still apply here since you could still put your device into a weird state, better to just avoid the possibility.

but I ran into the exact issue you described in that it isn’t possible to push anything other than docker-compose for the docker HWID.

Yeah, we never really had anyone ask to use alternative HW-IDs for the docker-compose component other than the default docker-compose designation. So we just never had to design for this possibility. It’s also why I’m a bit hesitant on any possible issues since it’s just something I’ve never thought about or tried before. To be clear adding a new docker-compose component, or any new secondary component should be fine. What I’m unsure of is the possible issues with modifying the existing component.

Best Regards,
Jeremias

Correct, each device should only accept its own specific single docker-compose from the full set available in the update.

Good suggestion on having two instances as the secondary, presumably if they are mutually exclusive in any given update lockbox then there is also no harm in using the same storage location for both the old and new update; less hassle than trying to completely phase out the “old” docker-compose hwid.

I did read bullet point 5 about bootloader secondaries; we should be okay since we effectively started on 6.x and are also already shipping a custom secondaries JSON file which includes a firmware blob for a peripheral, which already has the bootloader entrie(s) present.

Fair enough; we don’t need this right away but it is a longer-term concern for us as at some indeterminate point we will be migrating an x64 platform product (which we intend will be running the Community edition of Torizon) to a Toradex SoM due to subassembly EoL, and this is the scenario where we would like to have both the x64 OS and docker-compose bundled together with the ARM64 OS and docker-compose, for a seamless customer experience regardless of the underlying computer architecture.

This was helpful for me to understand what to get in place before that transition happens, as well as confirming the pitfall that it’s not currently possible to push anything other than docker-compose as the HWID via torizoncore-builder.

For kicks, I had a look at the lockbox builder side to see if it similarly special-cases the literal docker-compose hwid, but it is a little more flexible:

It would appear it will work “as-is” with the caveat the new custom hwid must contain the literal “docker-compose” and that e.g. “docker-compose-something” should be fine.

Perhaps the least intrusive change here would be revising the platform push to have a similar match:

since I think it’s probably a reasonable stipulation that compose-related secondaries are easily identified as such by their HWID.

As always, I appreciate the technical discussion and responsiveness to our future plans. Please keep me posted on any changes to torizoncore-builder if it is something you decide to support. :smile:

presumably if they are mutually exclusive in any given update lockbox then there is also no harm in using the same storage location for both the old and new update; less hassle than trying to completely phase out the “old” docker-compose hwid.

To be clear you can probably use the same firmware_path for the new and old docker-compose components. This just means that the docker-compose.yml file for either update gets written to the same location and would overwrite one another, but it sounds like this isn’t a concern for you. For the other paths in the configuration I would strongly suggest using a different path if possible. The full_client_dir path is where the keys and database files that pertain to that specific secondary component are stored. You probably don’t want to use the same path for the old and new docker-compose component here as that would mix up their key and metadata information and may cause strange behavior. So keep these stored separately is my suggestion.

I did read bullet point 5 about bootloader secondaries; we should be okay since we effectively started on 6.x and are also already shipping a custom secondaries JSON file which includes a firmware blob for a peripheral, which already has the bootloader entrie(s) present.

Well my warning was more for the fact that you’d be adding a new secondary component now and thus are subject to the same trappings/issues that came when we added a new secondary component in the form of bootloader updates.

Perhaps the least intrusive change here would be revising the platform push to have a similar match:

I’ve already looked into the code-base to see where we’re demanding the HW-ID be docker-compose during the push operation. That said it may not be as simple as changing this. The team will need to investigate and discuss to make sure we didn’t put this check here in the first place for some other important reason.

As always, I appreciate the technical discussion and responsiveness to our future plans. Please keep me posted on any changes to torizoncore-builder if it is something you decide to support. :smile:

As I said previously I’ll bring this topic up to our product team so we can at least get initial discussions going. I’ll try to keep you informed, though it’s still too early for me to say with any guarantee when or if something will be done here.

With all that discussed, did you have any other questions or topics related to this point? Or are you good here now?

Best Regards,
Jeremias

1 Like

I think I am all set at this point, thanks!