Best practice to add private files/keys to image before flashing

I have Github Actions which builds up to date packages I need using the SDK and imagebuilder building my x86 image. The Github repo is public and I would like to keep it that way.

My question is, once I have my image built, e.g. openwrt-22.03.2-x86-64-generic-ext4-combined.img.gz, what is the best practice way of adding my personalized configuration and keys before flashing the image to my router?

I know I could have added thing to files/ in buildroot in the imagebuilder, but my images in GitHub Actions are uploaded to a branch and I wouldn't want my personal config and keys to be in it at that stage.

I would like to download the newly built image and then add my config and keys (ssh, vpn etc.). I've seen some mount loop options but wondering if that is the best and only way.


The only real option would be building with imagebuilder(-support) enabled - and then using that for your local modifications.

…or doing the right thing, and doing the non-CI building on your personal hardware and on your dime.


Do you have a reference to documentation on that (-support)? I don't have a local CI environment to use. Everything else in the past has been hacky at best and unmaintainable therefore this is a much better approach backed by the benefits of git and features of github, save for this gap on moving past configuration/keys over.

I'd strongly suggest to locally first, but CONFIG_IB=y may be everything necessary.

Why locally first? Everything builds fine. No issues there. I'm only asking for suggestions/ideas of taking a built image after imagebuilder was used to produce it (generic for the world to use) and adding personal configuration and files to it before flashing it to the router.

You're looking for a complicated solution to an easy problem.

The easiest method - and what everyone else does - is to rebuild the image whenever you need a change in it. It's fast and efficient, and there's no reason to go through loops just to add something to an already built image.

So basically, if you need to change a build locally, just build it locally in the first place. If anything, it will be easier than what you're trying to do.
(You can keep building your packages with github actions, then include them in your local imagebuilder run).

Unless there are other constraints you forget to mention?

Myself, I just patch relevant files under base-files recipe, but I built everything from source, but I came up with some better ideas:

For SSH keys, you can create your private package feed, which would contain single /etc/dropbear/authorized_keys file or its OpenSSH counterparts, to actually have this under some kind of version control, instead of just putting this under files/ hierarchy from top level of source directory, and use this package.

As for overriding default root password, patching /etc/shadow in base-files may be necessary, to store a hash there, or you can try to create a uci-defaults script which would do that in runtime, and package this as well, like the above - just installing different version of /etc/shadow would likely not work, because it would conflict with one from base-files, and currently I don't know about a right way to override this. However, the uci-defaults approach would likely create a tiny window, when passwordless login could be accepted, so I'm not sure if it's safe enough for you.

Why don't you just write an init script that puts the device in your desired state, encrypt that with your device's mac address as key, include it in your build and then decrypt and run it on your device automatically

Yes, I was thinking about something along these lines.

Yes, uci-defaults seems to be a use here. As you've stated, would take some encryption hoops to deal with.

I starting to agree that I can just do the image build locally. Due to limited bandwidth speeds, was trying to avoid this and let it build server side.

Most likely you can store most of your config files (sqm etc.) openly in the build as custom files, and only a few files with keys, passwords etc. are sensitive.

I include my settings as a small encrypted file in my own builds.

I use it mainly as a backup feature, so that in a possible problem situation and resetting, the router first defaults to normal default settings, but my own settings are handily stored on the flash and I can easily apply them if I want.

I use the ccrypt package for crypting/decrypting. It is small crypt package available in OpenWrt:

I manually decrypt the archive file, if necessary, by using a small script stored in the build.

My scripts for saving and restoring settings:

--- /dev/null
+++ b/files/etc/
@@ -0,0 +1,11 @@
+cp -f $1 /tmp/HNsettings.cpt
+if [ "$?" -eq 0 ] ; then
+  ccdecrypt -vf /tmp/HNsettings.cpt
+  if [ "$?" -eq 0 ] ; then
+    tar -xzv -f /tmp/HNsettings -C /etc
+    chmod 744 /etc/dropbear/authorized_keys
+    sync
+  fi

--- /dev/null
+++ b/files/etc/
@@ -0,0 +1,13 @@
+cd /etc
+tar -czv -f /tmp/HNsettings \
+  config/network config/wireless config/firewall config/dhcp config/sqm \
+  config/luci_statistics config/bcp38 \
+  dropbear/authorized_keys adblock/adblock.whitelist crontabs/root
+if [ "$?" -eq 0 ] ; then
+  ccencrypt -vf /tmp/HNsettings
+  if [ "$?" -eq 0 ] ; then
+    cp -f /tmp/HNsettings.cpt /etc/HNsettings.$1.cpt
+  fi
1 Like

Is this package kept up to date? Worried being an older initiative has it suffered from brute force vulnerabilities or other exploits not yet fixed?

Oracle used to (and may still) offer two free lifetime VMs. If you're only building for one target it should be sufficient.

1 Like