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

4 views
Skip to first unread message

Felix Moessbauer

unread,
Feb 4, 2026, 12:13:32 PM (5 days ago) Feb 4
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.

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 4, 2026, 12:13:33 PM (5 days ago) Feb 4
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 4, 2026, 12:13:36 PM (5 days ago) Feb 4
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 6dbffd255..72336b9a1 100644
--- a/kas/libcmds.py
+++ b/kas/libcmds.py
@@ -497,6 +497,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 4, 2026, 12:13:38 PM (5 days ago) Feb 4
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

Felix Moessbauer

unread,
Feb 4, 2026, 12:13:39 PM (5 days ago) Feb 4
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.

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..5727e3e56 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 && \
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 60007831b..3809744ea 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"
@@ -165,6 +166,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
@@ -363,6 +376,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
@@ -578,6 +595,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
@@ -775,5 +794,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

Jan Kiszka

unread,
Feb 4, 2026, 1:14:07 PM (5 days ago) Feb 4
to Felix Moessbauer, kas-...@googlegroups.com, christi...@siemens.com
While it technically makes sense, it is actually nothing that a project
can fully decide. It will also depend on the host kernel, and we will
have a dependency on the container image (>= trixie as you told me). So,
we will need to model this differently, I'm afraid.

Jan

--
Siemens AG, Foundational Technologies
Linux Expert Center

MOESSBAUER, Felix

unread,
Feb 5, 2026, 2:46:38 AM (5 days ago) Feb 5
to Kiszka, Jan, kas-...@googlegroups.com, Storm, Christian
Let's decide on the interfaces and requirements together with isar.
While your concerns are definitely valid, we cannot auto-detect if
things are working or not - and by that need guidance from the user.
The build system is further part of the interface between kas and kas-
container, as we need to start the container differently for rootless
and root builds.

For now, the series is just for testing the isar internal changes.

Felix

--
Siemens AG
Linux Expert Center
Friedrich-Ludwig-Bauer-Str. 3
85748 Garching, Germany

Jan Kiszka

unread,
Feb 5, 2026, 4:47:03 AM (5 days ago) Feb 5
to Moessbauer, Felix (FT RPD CED OES-DE), kas-...@googlegroups.com, Storm, Christian (FT RPD CED)
There are multiple factors, indeed, but some can be decided by kas:

1. isar is rootless-ready [project decision]
2. host kernel is recent enough [kas autodetection]
3. build distro is recent enough [kas autodetection]

So, what we would need is a hint from the kas config (1.) if it is worth
to probe the other things (2., 3.) and start the build in rootless mode.

> For now, the series is just for testing the isar internal changes.
>

Sure.
Reply all
Reply to author
Forward
0 new messages