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

31 views
Skip to first unread message

Felix Moessbauer

unread,
Feb 18, 2026, 5:23:42 AMFeb 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 AMFeb 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 AMFeb 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 AMFeb 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 AMFeb 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 AMFeb 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

Jan Kiszka

unread,
Feb 19, 2026, 3:07:29 AMFeb 19
to Felix Moessbauer, kas-...@googlegroups.com, christi...@siemens.com
On 18.02.26 11:23, Felix Moessbauer wrote:
Some morning shower thoughts on this:

- also introduce "isar-privileged" (as you suggested privately)
- map "isar" on "isar-privileged" but warn in kas that "isar" semantics
may change in the future, an users should use "isar-privileged"
instead

This should both push people away from isar so that we may actually
change its semantic when isar-privileged becomes rare and it may make
people already try out isar-rootless when their dependencies allow.

Jan Kiszka

unread,
Feb 19, 2026, 3:09:29 AMFeb 19
to Felix Moessbauer, kas-...@googlegroups.com, christi...@siemens.com
On 18.02.26 11:23, Felix Moessbauer wrote:
So this is definitely not working with docker, right? Then please reject
KAS_CONTAINER_ENGINE=docker and change its default for now. We are
preferring podman over docker in kas-container at this stage.

Jan

DL1FMP - Felix Moessbauer

unread,
Feb 20, 2026, 11:34:13 AMFeb 20
to Jan Kiszka, kas-...@googlegroups.com, christi...@siemens.com
This is working with docker, but docker --privileged is completely
different from a rootless podman --privileged, despite the option is
called the same.

Once things are more stable on the isar side, I'll implement support
for docker (and hopefully docker-rootless) as well.

As of today, the rootless build already works in a privileged docker
container (no change on kas side needed). However, this defeats the
point of running without non-user privileges. What we want is to make
it work in a non-privileged, non-rootless docker container (a container
started with docker run ...) and hopefully also in a rootless-docker
container (which is similar to a rootless podman container, but still
misses a lot of features).

Felix

Jan Kiszka

unread,
Feb 20, 2026, 11:52:40 AMFeb 20
to DL1FMP - Felix Moessbauer, kas-...@googlegroups.com, christi...@siemens.com
I wouldn't mind if isar-rootless via kas-container implies podman for
now (or longer if docker is not capable enough). I would mind if
isar-rootless suggests that it starts without privileges but silently
continues to use privileged docker. Right now, this kas-container
prototype breaks docker while trying to start in rootless mode.

Jan

Felix Moessbauer

unread,
Feb 26, 2026, 11:02:20 AMFeb 26
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.

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

Changes since v2:

- rebased onto next
- add support for docker and docker-rootless
- complete overhaul of the user ns subid mapping:
now supports both direct (docker) and indirect (podman)
mappings
- prohibit usage of sudo in isar-rootless mode. On rootless executors
like podman or docker-rootless, this is not strictly needed. But
on docker system this avoids accidental container breakout.
- introduce isar-privileged and map isar to isar-privileged

Note, that the various execution modes still lack CI test coverage.

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 (v3) by today. With
this kas series people already have an environment for testing.

Best regards,
Felix Moessbauer
Siemens AG

Felix Moessbauer (6):
schema: add support for isar in rootless mode
kas: add support for isar-rootless build system
extend buildsystem test to check isar-rootless configuration
kas-container: configure container for nested namespaces
kas-container: block usage of sudo in isar-rootless mode
clean: add support for cleaning isar-rootless generated data

Dockerfile | 3 +-
container-entrypoint | 55 +++++++++++++++++++
docs/format-changelog.rst | 9 +++
docs/userguide/kas-container-description.inc | 5 +-
examples/isar.yml | 4 +-
kas-container | 44 ++++++++++++++-
kas/config.py | 9 ++-
kas/libcmds.py | 2 +
kas/libkas.py | 2 +-
kas/plugins/clean.py | 31 ++++++++++-
kas/plugins/menu.py | 2 +-
kas/schema-kas.json | 6 +-
tests/test_build_system.py | 12 ++++
.../test-isar-privileged.yml | 7 +++
.../test_build_system/test-isar-rootless.yml | 7 +++
15 files changed, 184 insertions(+), 14 deletions(-)
create mode 100644 tests/test_build_system/test-isar-privileged.yml

Felix Moessbauer

unread,
Feb 26, 2026, 11:02:23 AMFeb 26
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 | 44 ++++++++++++++++++++
docs/userguide/kas-container-description.inc | 5 ++-
kas-container | 43 ++++++++++++++++++-
4 files changed, 90 insertions(+), 5 deletions(-)

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..da0c36d3a 100755
--- a/container-entrypoint
+++ b/container-entrypoint
@@ -34,6 +34,47 @@ 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: Podman maps
+# to an intermediate namespace, hence giving us a user-id map we
+# actually can use for further splitting. Docker maps directly, hence
+# we need to compute the number of sub ids we can use (which have a
+# mapping in the parent ns)
+#
+# 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_OUTER=$(printf '%s' "$UID_ROW" | awk '{print $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_OUTER=$(printf '%s' "$GID_ROW" | awk '{print $1}')
+ GID_INNER=$(printf '%s' "$GID_ROW" | awk '{print $2}')
+ GID_COUNT=$(printf '%s' "$GID_ROW" | awk '{print $3}')
+
+ # docker (direct mapping)
+ if [ "$UID_OUTER" = "1" ]; then
+ UID_INNER="$(($(id -u builder) + 1))"
+ [ "$UID_INNER" -lt "$UID_COUNT" ] && \
+ UID_COUNT="$((UID_COUNT - UID_INNER))"
+ fi
+ if [ "$GID_OUTER" = "1" ]; then
+ GID_INNER="$(($(id -g builder) + 1))"
+ [ "$GID_INNER" -lt "$GID_COUNT" ] && \
+ GID_COUNT="$((GID_COUNT - GID_INNER))"
+ fi
+
+ 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

chown_managed_dirs()
@@ -103,6 +144,9 @@ else

GOSU="gosu builder"
fi
+# after all uid / gid changes are done, setup the namespace mappings
+# kas-isar: setup_userns_mappings
+
# kas-container on rootless docker workaround
if [ -n "$USER_ID" ] && [ "$USER_ID" -ne 0 ] && \
[ "$KAS_DOCKER_ROOTLESS" = "1" ] && [ "$(stat -c %u /repo)" -eq 0 ]; then
diff --git a/docs/userguide/kas-container-description.inc b/docs/userguide/kas-container-description.inc
index 7f350138a..776251124 100644
--- a/docs/userguide/kas-container-description.inc
+++ b/docs/userguide/kas-container-description.inc
@@ -39,5 +39,6 @@ written to from the host. To completely remove all data managed by kas, use
so they can be removed from the host.

.. note::
- The ISAR build system is not compatible with rootless execution. By that,
- we fall back to the system docker or podman instance.
+ The ISAR build system is compatible with rootless execution in ``isar-rootless``
+ mode only. The ``isar`` and ``isar-privileged`` modes fall back to the system docker
+ or podman instance.
diff --git a/kas-container b/kas-container
index 9afab2557..38f4992cc 100755
--- a/kas-container
+++ b/kas-container
@@ -68,6 +68,8 @@ 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-privileged\tRun the isar build in privileged mode\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"
@@ -168,6 +170,33 @@ 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.
+ # When calling from the user session (podman or docker-rootless), this
+ # is fundamentally different from the system docker run --privileged
+ if [ "${KAS_CONTAINER_ENGINE}" = "podman" ]; then
+ KAS_RUNTIME_ARGS="${KAS_RUNTIME_ARGS} --userns=keep-id --privileged"
+ elif [ "${KAS_DOCKER_ROOTLESS}" = "1" ]; then
+ KAS_ISAR_ARGS="--privileged"
+ else
+ # we don't need --privileged, but we need to run with SYS_ADMIN
+ # to be able to unshare.
+ KAS_ISAR_ARGS=" \
+ --security-opt seccomp=unconfined \
+ --security-opt apparmor=unconfined \
+ --security-opt systempaths=unconfined \
+ --cap-add=SYS_ADMIN \
+ "
+ fi
+}
+
enable_oe_mode()
{
if [ "${KAS_CONTAINER_ENGINE}" = "podman" ]; then
@@ -362,10 +391,14 @@ esac
# parse kas-container options
while [ $# -gt 0 ]; do
case "$1" in
- --isar)
+ --isar|--isar-privileged)
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
@@ -579,8 +612,10 @@ else
sed 's/build_system:[ ]\+//')
fi

-if [ "${BUILD_SYSTEM}" = "isar" ]; then
+if [ "${BUILD_SYSTEM}" = "isar" ] || [ "${BUILD_SYSTEM}" = "isar-privileged" ]; then
enable_isar_mode
+elif [ "${BUILD_SYSTEM}" = "isar-rootless" ]; then
+ enable_isar_rootless_mode
elif [ -z "${ISAR_MODE}" ]; then
enable_oe_mode
fi
@@ -778,5 +813,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 26, 2026, 11:02:24 AMFeb 26
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
For a smooth transition from isar to isar-rootless back to isar, we
further add a warning if the build system is "isar" regarding the
semantics. For now, isar maps to isar-privileged to not break existing
layers. After some grace period, we will be able to change the default
of isar to isar-rootless.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
examples/isar.yml | 4 ++--
kas/config.py | 9 ++++++++-
kas/libcmds.py | 2 ++
kas/libkas.py | 2 +-
kas/plugins/menu.py | 2 +-
5 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/examples/isar.yml b/examples/isar.yml
index 3b9d5c7f2..4fc5750d3 100644
--- a/examples/isar.yml
+++ b/examples/isar.yml
@@ -23,9 +23,9 @@
#

header:
- version: 14
+ version: 22

-build_system: isar
+build_system: isar-privileged

machine: qemuamd64
distro: debian-trixie
diff --git a/kas/config.py b/kas/config.py
index cebc7494a..e3792efa0 100644
--- a/kas/config.py
+++ b/kas/config.py
@@ -26,6 +26,7 @@
import os
import json
import copy
+import logging
from pathlib import Path
from .repos import Repo
from .includehandler import IncludeHandler
@@ -69,7 +70,13 @@ class Config:
"""
Returns the pre-selected build system
"""
- return self._config.get('build_system', '')
+ build_system = self._config.get('build_system', '')
+ if build_system == 'isar':
+ logging.warning(
+ "The semantics of build_system: isar might change in the "
+ "future. Please use 'isar-privileged' or 'isar-rootless'.")
+ build_system = 'isar-privileged'
+ return build_system

def find_missing_repos(self, repo_paths={}):
"""
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..ad756bddd 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.startswith('isar'):
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..9288ce73d 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``, ``isar-privileged`` or ``isar-rootless`` is set.

Felix Moessbauer

unread,
Feb 26, 2026, 11:02:28 AMFeb 26
to kas-...@googlegroups.com, jan.k...@siemens.com, christi...@siemens.com, Felix Moessbauer
To prepare a migration path from isar to isar-rootless, we also
introduce the isar-privileged entry.

Signed-off-by: Felix Moessbauer <felix.mo...@siemens.com>
---
docs/format-changelog.rst | 9 +++++++++
kas/schema-kas.json | 6 ++++--
2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/docs/format-changelog.rst b/docs/format-changelog.rst
index 8aea3a525..376af9e92 100644
--- a/docs/format-changelog.rst
+++ b/docs/format-changelog.rst
@@ -210,3 +210,12 @@ Added

- The repo layers ``prio`` can be used to control the order in which the
layers are added to the ``BBLAYERS`` bitbake variable.
+
+Version 22
+----------
+
+Added
+~~~~~
+
+- Extend the allowed values of ``build_system`` by adding ``isar-privileged``
+ and ``isar-rootless``.
diff --git a/kas/schema-kas.json b/kas/schema-kas.json
index e52598a7c..dd475b110 100644
--- a/kas/schema-kas.json
+++ b/kas/schema-kas.json
@@ -41,7 +41,7 @@
{
"type": "integer",
"minimum": 1,
- "maximum": 21
+ "maximum": 22
}
]
},
@@ -83,7 +83,9 @@
"enum": [
"openembedded",
"oe",
- "isar"
+ "isar",
+ "isar-privileged",
+ "isar-rootless"
]
},
"defaults": {
--
2.51.0

Jan Kiszka

unread,
Feb 27, 2026, 11:57:33 AMFeb 27
to Felix Moessbauer, kas-...@googlegroups.com, christi...@siemens.com
What is the transition path from our current pants-down docker usage as
normal user to rootless mode? To my understanding, one has to
initialized rootless docker mode per user via
dockerd-rootless-setuptool.sh, but then also make the classic root
socket unavailable, or docker will just stay in rootfull mode. Will
kas-isar users have to start/stop the root dockerd when switching
between repos that are already rootless-ready and those that aren't?

If there is this limitation in the docker usage, should we help users by
preferring podman as engine over docker? That way, if rootless mode is
requested and both engines are available, podman will be picked, and
dockerd can continue to run until no isar project needs it anymore. Or
are there better options?

MOESSBAUER, Felix

unread,
Mar 2, 2026, 3:52:41 AMMar 2
to Kiszka, Jan, kas-...@googlegroups.com, Storm, Christian
Yes.

> but then also make the classic root
> socket unavailable, or docker will just stay in rootfull mode.
>

No. After setting up docker-rootless, you can use the docker context
command to switch between the contexts. Which context is used boils
down to which docker endpoint (socket) we talk to (by setting the
DOCKER_HOST environment variable when calling docker).

As of kas 4.8, we already check which context is used and automatically
switch to a system docker context on isar.

Side note: I want to harden the socket switching in kas-container by
querying the socket path instead of using hard-coded assumptions in
kas-container.

> Will
> kas-isar users have to start/stop the root dockerd when switching
> between repos that are already rootless-ready and those that aren't?

No, they can run in parallel.

>
> If there is this limitation in the docker usage, should we help users by
> preferring podman as engine over docker? That way, if rootless mode is
> requested and both engines are available, podman will be picked, and
> dockerd can continue to run until no isar project needs it anymore. Or
> are there better options?

In general, I prefer podman because it IMHO better abstracts the the
system specifics from the container (i.e. the user ns double mapping to
not expose the external user mapping inside the container). It further
offers the --userns=keep-id option to map the calling user to the user
with same id inside the container (which we don't have on docker).

Apart from that, podman offers rootless mode in the distro-packaged
version, while docker only offers this in the -ce version.

Felix

>
> Jan
>
> --
> Siemens AG, Foundational Technologies
> Linux Expert Center

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

Jan Kiszka

unread,
Mar 2, 2026, 4:50:55 AMMar 2
to Moessbauer, Felix (FT RPD CED OES-DE), kas-...@googlegroups.com, Storm, Christian (FT RPD CED)
That's good to know.

>>
>> If there is this limitation in the docker usage, should we help users by
>> preferring podman as engine over docker? That way, if rootless mode is
>> requested and both engines are available, podman will be picked, and
>> dockerd can continue to run until no isar project needs it anymore. Or
>> are there better options?
>
> In general, I prefer podman because it IMHO better abstracts the the
> system specifics from the container (i.e. the user ns double mapping to
> not expose the external user mapping inside the container). It further
> offers the --userns=keep-id option to map the calling user to the user
> with same id inside the container (which we don't have on docker).
>
> Apart from that, podman offers rootless mode in the distro-packaged
> version, while docker only offers this in the -ce version.

Wait, docker.io does not support rootless, despite shipping the setup
script??

Jan Kiszka

unread,
Mar 2, 2026, 4:53:28 AMMar 2
to Moessbauer, Felix (FT RPD CED OES-DE), kas-...@googlegroups.com, Storm, Christian (FT RPD CED)
And even if it does, we should make sure that we are not using rootful
docker when there is no rootless docker context available while podman
is around.

MOESSBAUER, Felix

unread,
Mar 2, 2026, 5:05:35 AMMar 2
to Kiszka, Jan, kas-...@googlegroups.com, Storm, Christian
Ah... right. It also does ship it. It's just not in the path but under
/usr/share/docker.io/contrib/dockerd-rootless-setuptool.sh

Never tested if it actually works on docker.io.

> >
>
> And even if it does, we should make sure that we are not using rootful
> docker when there is no rootless docker context available while podman
> is around.

This is a lot of complexity. Also, docker rootless messes up the file
permissions in KAS_WORK_DIR (known limitation documented [1]). I'm not
sure if we really want to use rootless if not explicitly requested by
the user.

How about just preferring podman over docker and keeping docker as
configured by the user, namely:

1. rootless if current docker context is "rootless" and build-system
supports it (i.e. oe, isar-rootless)
2. rootfull if current docker context is "default" (in case of isar-
rootless we just don't add --privileged but use the more fine grained
options).

[1]
https://kas.readthedocs.io/en/latest/userguide/kas-container.html#building-in-a-container

Felix

>
> Jan
>
> --
> Siemens AG, Foundational Technologies
> Linux Expert Center

Jan Kiszka

unread,
Mar 2, 2026, 5:06:00 AMMar 2
to Moessbauer, Felix (FT RPD CED OES-DE), kas-...@googlegroups.com, Storm, Christian (FT RPD CED)
On 02.03.26 10:50, 'Jan Kiszka' via kas-devel wrote:
ln -s /usr/bin/docker /usr/share/docker.io/contrib/docker
PATH=/usr/share/docker.io/contrib/:$PATH dockerd-rootless-setuptool.sh install --force

But it's an undocumented PITA.

Jan Kiszka

unread,
Mar 2, 2026, 5:27:38 AMMar 2
to Moessbauer, Felix (FT RPD CED OES-DE), kas-...@googlegroups.com, Storm, Christian (FT RPD CED)
I agree that we should not default to docker in rootless mode given its
limitations. Only use it if there is no podman available. In rootfull
mode, docker should remain the default for now.

But my point was different: If there is rootless requested by the repo
but the host is not supporting it, we should not silently run docker or
podman privileged. There is sudo in place, though, and that may require
interaction.
Reply all
Reply to author
Forward
0 new messages