[RFC v2 0/4] Experimental support for upcoming isar rootless mode

3 views
Skip to first unread message

Felix Moessbauer

unread,
Feb 18, 2026, 5:23:42 AM (21 hours ago) Feb 18
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
Dear kas isar users,

as a preparation for our activities to implement / try out rootless isar
builds we need a test environment to execute the build (both locally and
in CI). This test environment is provided in this patch series.

Note, that this currently has been tested on rootless podman only.
Other container runtimes (podman non-rootless, docker and docker-rootless)
have not been tested and likely don't work out of the box.

@Jan: This patchset is ONLY for testing and needs further alignment
with isar regarding a couple of interfaces. Do not merge.

Changes since v1:

- rebased onto next
- add acl tool (isar rootless host dependency)

Note, that the interfaces still have to be discussed with isar upstream.
I'm planning to send the corresponding isar series by today. With
this kas series people already have an environment for testing.

Best regards,
Felix Moessbauer
Siemens AG

Felix Moessbauer (4):
schema: add support for isar in rootless mode
kas: add support for isar-rootless build system
extend buildsystem test to check isar-rooless configuration
kas-container: configure container for nested namespaces

Dockerfile | 3 ++-
container-entrypoint | 25 +++++++++++++++++++
kas-container | 23 +++++++++++++++++
kas/libcmds.py | 2 ++
kas/libkas.py | 2 +-
kas/plugins/menu.py | 2 +-
kas/schema-kas.json | 3 ++-
tests/test_build_system.py | 8 ++++++
.../test_build_system/test-isar-rootless.yml | 7 ++++++
9 files changed, 71 insertions(+), 4 deletions(-)
create mode 100644 tests/test_build_system/test-isar-rootless.yml

--
2.51.0

Felix Moessbauer

unread,
Feb 18, 2026, 5:23:43 AM (21 hours ago) Feb 18
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
kas/schema-kas.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/kas/schema-kas.json b/kas/schema-kas.json
index e52598a7c..7244be32a 100644
--- a/kas/schema-kas.json
+++ b/kas/schema-kas.json
@@ -83,7 +83,8 @@
"enum": [
"openembedded",
"oe",
- "isar"
+ "isar",
+ "isar-rootless"
]
},
"defaults": {
--
2.51.0

Felix Moessbauer

unread,
Feb 18, 2026, 5:23:43 AM (21 hours ago) Feb 18
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
kas/libcmds.py | 2 ++
kas/libkas.py | 2 +-
kas/plugins/menu.py | 2 +-
3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/kas/libcmds.py b/kas/libcmds.py
index 05f0871ba..9b70046c1 100644
--- a/kas/libcmds.py
+++ b/kas/libcmds.py
@@ -518,6 +518,8 @@ class WriteBBConfig(Command):
fds.write(f'DISTRO ??= "{ctx.config.get_distro()}"\n')
fds.write('BBMULTICONFIG ?= '
f'"{ctx.config.get_multiconfig()}"\n')
+ if ctx.config.get_build_system() == 'isar-rootless':
+ fds.write('ISAR_ROOTLESS ?= "1"\n')

_write_bblayers_conf(ctx)
_write_local_conf(ctx)
diff --git a/kas/libkas.py b/kas/libkas.py
index 801134f42..8be53d0d9 100644
--- a/kas/libkas.py
+++ b/kas/libkas.py
@@ -405,7 +405,7 @@ def get_build_environ(build_system):
init_repo = None
if build_system in ['openembedded', 'oe']:
scripts = ['oe-init-build-env']
- elif build_system == 'isar':
+ elif build_system in ['isar', 'isar-rootless']:
scripts = ['isar-init-build-env']
else:
scripts = ['oe-init-build-env', 'isar-init-build-env']
diff --git a/kas/plugins/menu.py b/kas/plugins/menu.py
index c5bc725a7..eb9d0ca6a 100644
--- a/kas/plugins/menu.py
+++ b/kas/plugins/menu.py
@@ -50,7 +50,7 @@

- The ``build_system`` that will used. The static Kconfig string variable
``KAS_BUILD_SYSTEM`` defines this value which must be ``openembedded``,
- ``oe`` or ``isar`` is set.
+ ``oe``, ``isar`` or ``isar-rootless`` is set.

- bitbake configuration variables that will be added to the
``local_conf_header`` section of the generated configuration. All other
--
2.51.0

Felix Moessbauer

unread,
Feb 18, 2026, 5:23:44 AM (21 hours ago) Feb 18
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
For rootless nesting of the uid_ns, we need to provide a list of sub
uids/gids which can be used in the sub namespace. As each id in the
sub namespace must be mappable into the parent namespace, we need to
compute the mapping based on the layout of the parent. The following
mapping works for rootless podman with --userns=keep-id.

Note, that the default range (65k) does NOT allow to map nobody/nogroup,
in the sub-namespace, as this usually is id 65k-1 and we loose at least
one id per nesting. If we get a larger range, we just map as much as
we can and by that make nobody/nogroup usable.

With these changes we also add the uidmap and acl binaries to the
container which are needed by isar to setup the namespaces and
permissions.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
Dockerfile | 3 ++-
container-entrypoint | 25 +++++++++++++++++++++++++
kas-container | 23 +++++++++++++++++++++++
3 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/Dockerfile b/Dockerfile
index e798472c8..b3514fad8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -113,7 +113,8 @@ RUN --mount=type=cache,target=/var/cache/apt,sharing=${CACHE_SHARING} \
umoci skopeo \
python3-botocore \
bubblewrap \
- debootstrap && \
+ debootstrap \
+ uidmap acl && \
rm -f /etc/apt/apt.conf.d/use-snapshot.conf /etc/apt/apt.conf.d/keep-packages.conf && \
if [ -f "/etc/apt/sources.list.d/debian.sources~" ]; then \
mv -f /etc/apt/sources.list.d/debian.sources~ /etc/apt/sources.list.d/debian.sources; \
diff --git a/container-entrypoint b/container-entrypoint
index dee7275e8..ecc7d3e61 100755
--- a/container-entrypoint
+++ b/container-entrypoint
@@ -34,7 +34,32 @@ enable_qemu_binfmts()
done
}

+# For rootless nesting of the uid_ns, we need to provide a list of sub
+# uids/gids which can be used in the sub namespace. As each id in the
+# sub namespace must be mappable into the parent namespace, we need to
+# compute the mapping based on the layout of the parent. The following
+# mapping works for rootless podman with --userns=keep-id.
+# Note, that the default range (65k) does NOT allow to map nobody/nogroup,
+# in the sub-namespace, as this usually is id 65k-1 and we loose at least
+# one id per nesting. If we get a larger range, we just map as much as
+# we can and by that make nobody/nogroup usable.
+# See man user_namespaces for details.
+setup_userns_mappings()
+{
+ UID_ROW=$(sort -r /proc/self/uid_map | head -1)
+ UID_INNER=$(printf '%s' "$UID_ROW" | awk '{print $2}')
+ UID_COUNT=$(printf '%s' "$UID_ROW" | awk '{print $3}')
+ GID_ROW=$(sort -r /proc/self/gid_map | head -1)
+ GID_INNER=$(printf '%s' "$GID_ROW" | awk '{print $2}')
+ GID_COUNT=$(printf '%s' "$GID_ROW" | awk '{print $3}')
+ echo "builder:${UID_INNER}:${UID_COUNT}" | sudo tee /etc/subuid > /dev/null
+ echo "builder:${GID_INNER}:${GID_COUNT}" | sudo tee /etc/subgid > /dev/null
+}
+
# kas-isar: enable_qemu_binfmts
+# kas-isar: if [ "$KAS_ISAR_ROOTLESS" = "1" ]; then
+# kas-isar: setup_userns_mappings
+# kas-isar: fi

chown_managed_dirs()
{
diff --git a/kas-container b/kas-container
index f830312d5..54304bac3 100755
--- a/kas-container
+++ b/kas-container
@@ -67,6 +67,7 @@ usage()
printf "%b" "\nOptional arguments:\n"
printf "%b" "--isar\t\t\tUse kas-isar container to build Isar image. To force\n"
printf "%b" " \t\t\tthe use of run0 over sudo, set KAS_SUDO_CMD=run0.\n"
+ printf "%b" "--isar-rootless\t\tRun the isar build in rootless mode\n"
printf "%b" "--with-loop-dev Pass a loop device to the " \
"container. Only required if\n"
printf "%b" "\t\t\tloop-mounting is used by recipes.\n"
@@ -167,6 +168,18 @@ enable_isar_mode()
fi
}

+enable_isar_rootless_mode()
+{
+ if [ -n "${ISAR_ROOTLESS_MODE}" ]; then
+ return
+ fi
+ ISAR_ROOTLESS_MODE=1
+ KAS_CONTAINER_IMAGE_NAME_DEFAULT="kas-isar"
+ # Use --privileged to pass the ambient capabilities into the container.
+ # This is not the same as docker --privileged!
+ KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} -e KAS_ISAR_ROOTLESS=1 --userns=keep-id --privileged"
+}
+
enable_oe_mode()
{
if [ "${KAS_CONTAINER_ENGINE}" = "podman" ]; then
@@ -365,6 +378,10 @@ while [ $# -gt 0 ]; do
enable_isar_mode
shift 1
;;
+ --isar-rootless)
+ enable_isar_rootless_mode
+ shift 1
+ ;;
--with-loop-dev)
if ! KAS_LOOP_DEV=$(/sbin/losetup -f 2>/dev/null); then
if [ "$(id -u)" -eq 0 ]; then
@@ -580,6 +597,8 @@ fi

if [ "${BUILD_SYSTEM}" = "isar" ]; then
enable_isar_mode
+elif [ "${BUILD_SYSTEM}" = "isar-rootless" ]; then
+ enable_isar_rootless_mode
elif [ -z "${ISAR_MODE}" ]; then
enable_oe_mode
fi
@@ -777,5 +796,9 @@ while [ $KAS_EXTRA_BITBAKE_ARGS -gt 0 ]; do
KAS_EXTRA_BITBAKE_ARGS=$((KAS_EXTRA_BITBAKE_ARGS - 1))
done

+if [ "${ISAR_MODE}" = "1" ] && [ "${ISAR_ROOTLESS_MODE}" = "1" ]; then
+ fatal_error "only one of --isar and --isar-rootless can be selected."
+fi
+
# shellcheck disable=SC2086
trace ${KAS_CONTAINER_COMMAND} run "$@"
--
2.51.0

Felix Moessbauer

unread,
Feb 18, 2026, 5:23:44 AM (21 hours ago) Feb 18
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
tests/test_build_system.py | 8 ++++++++
tests/test_build_system/test-isar-rootless.yml | 7 +++++++
2 files changed, 15 insertions(+)
create mode 100644 tests/test_build_system/test-isar-rootless.yml

diff --git a/tests/test_build_system.py b/tests/test_build_system.py
index b46d559a8..c0f6fe295 100644
--- a/tests/test_build_system.py
+++ b/tests/test_build_system.py
@@ -22,6 +22,7 @@

import shutil
import pytest
+import re
from kas import kas


@@ -38,6 +39,13 @@ def test_build_system(monkeykas, tmpdir):
with open('build-env', 'r') as f:
assert f.readline().strip() == 'isar'

+ kas.kas(['shell', 'test-isar-rootless.yml', '-c', 'true'])
+ with open('build-env', 'r') as f:
+ assert f.readline().strip() == 'isar'
+ with open(monkeykas.get_kbd() / 'conf/local.conf', 'r') as f:
+ assert any(re.match(r'^ISAR_ROOTLESS.*"1"', line)
+ for line in f.readlines())
+
kas.kas(['shell', 'test-openembedded.yml', '-c', 'true'])
with open('build-env', 'r') as f:
assert f.readline().strip() == 'openembedded'
diff --git a/tests/test_build_system/test-isar-rootless.yml b/tests/test_build_system/test-isar-rootless.yml
new file mode 100644
index 000000000..2f60cb63d
--- /dev/null
+++ b/tests/test_build_system/test-isar-rootless.yml
@@ -0,0 +1,7 @@
+header:
+ version: 20
+
+build_system: isar-rootless
+
+repos:
+ this:
--
2.51.0

Jan Kiszka

unread,
Feb 18, 2026, 8:52:01 AM (18 hours ago) Feb 18
to Felix Moessbauer, kas-...@googlegroups.com, christi...@siemens.com
On 18.02.26 11:23, Felix Moessbauer wrote:
> Dear kas isar users,
>
> as a preparation for our activities to implement / try out rootless isar
> builds we need a test environment to execute the build (both locally and
> in CI). This test environment is provided in this patch series.
>
> Note, that this currently has been tested on rootless podman only.
> Other container runtimes (podman non-rootless, docker and docker-rootless)
> have not been tested and likely don't work out of the box.
>
> @Jan: This patchset is ONLY for testing and needs further alignment
> with isar regarding a couple of interfaces. Do not merge.
>

Ack.

> Changes since v1:
>
> - rebased onto next
> - add acl tool (isar rootless host dependency)
>
> Note, that the interfaces still have to be discussed with isar upstream.
> I'm planning to send the corresponding isar series by today. With
> this kas series people already have an environment for testing.
>

Minimum to-do on the kas side for a non-RFC: check host kernel and
possibly container compatibility for rootless before starting a build in
that mode.

Jan

--
Siemens AG, Foundational Technologies
Linux Expert Center
Reply all
Reply to author
Forward
0 new messages