Quadlet - add support for UID and GID Mapping

Support UIDMap, GIDMap, SubUIDMap and SubGIDMap
If any of them are set disregard the deprecated Remap keys
Add tests and man

Signed-off-by: Ygal Blum <ygal.blum@gmail.com>
This commit is contained in:
Ygal Blum
2023-11-13 11:30:23 +02:00
parent 1d49773bb8
commit e35fc92c02
9 changed files with 132 additions and 14 deletions

View File

@ -159,6 +159,7 @@ Valid options for `[Container]` are listed below:
| EnvironmentHost=true | --env-host |
| Exec=/usr/bin/command | Command after image specification - /usr/bin/command |
| ExposeHostPort=50-59 | --expose 50-59 |
| GIDMap=0:10000:10 | --gidmap=0:10000:10 |
| Group=1234 | --user UID:1234 |
| GlobalArgs=--log-level=debug | --log-level=debug |
| HealthCmd="/usr/bin/command" | --health-cmd="/usr/bin/command" |
@ -197,9 +198,12 @@ Valid options for `[Container]` are listed below:
| SecurityLabelNested=true | --security-opt label=nested |
| SecurityLabelType=spc_t | --security-opt label=type:spc_t |
| ShmSize=100m | --shm-size=100m |
| SubGIDMap=gtest | --subgidname=gtest |
| SubUIDMap=utest | --subuidname=utest |
| Sysctl=name=value | --sysctl=name=value |
| Timezone=local | --tz local |
| Tmpfs=/work | --tmpfs /work |
| UIDMap=0:10000:10 | --uidmap=0:10000:10 |
| Ulimit=nofile:1000:10000 | --ulimit nofile:1000:10000 |
| User=bin | --user bin |
| UserNS=keep-id:uid=200,gid=210 | --userns keep-id:uid=200,gid=210 |
@ -315,6 +319,13 @@ to the Podman `--expose` option.
This key can be listed multiple times.
### `GIDMap=`
Run the container in a new user namespace using the supplied GID mapping.
Equivalent to the Podman `--gidmap` option.
This key can be listed multiple times.
### `GlobalArgs=`
This key contains a list of arguments passed directly between `podman` and `run`
@ -569,6 +580,16 @@ Size of /dev/shm.
This is equivalent to the Podman `--shm-size` option and generally has the form `number[unit]`
### `SubGIDMap=`
Run the container in a new user namespace using the map with name in the /etc/subgid file.
Equivalent to the Podman `--subgidname` option.
### `SubUIDMap=`
Run the container in a new user namespace using the map with name in the /etc/subuid file.
Equivalent to the Podman `--subuidname` option.
### `Sysctl=`
Configures namespaced kernel parameters for the container. The format is `Sysctl=name=value`.
@ -591,6 +612,13 @@ This key can be listed multiple times.
The timezone to run the container in.
### `UIDMap=`
Run the container in a new user namespace using the supplied UID mapping.
Equivalent to the Podman `--uidmap` option.
This key can be listed multiple times.
### `Ulimit=`
Ulimit options. Sets the ulimits values inside of the container.

View File

@ -73,6 +73,7 @@ const (
KeyExec = "Exec"
KeyExitCodePropagation = "ExitCodePropagation"
KeyExposeHostPort = "ExposeHostPort"
KeyGIDMap = "GIDMap"
KeyGlobalArgs = "GlobalArgs"
KeyGroup = "Group"
KeyHealthCmd = "HealthCmd"
@ -132,11 +133,14 @@ const (
KeySecurityLabelType = "SecurityLabelType"
KeySetWorkingDirectory = "SetWorkingDirectory"
KeyShmSize = "ShmSize"
KeySubGIDMap = "SubGIDMap"
KeySubUIDMap = "SubUIDMap"
KeySysctl = "Sysctl"
KeyTimezone = "Timezone"
KeyTLSVerify = "TLSVerify"
KeyTmpfs = "Tmpfs"
KeyType = "Type"
KeyUIDMap = "UIDMap"
KeyUlimit = "Ulimit"
KeyUnmask = "Unmask"
KeyUser = "User"
@ -169,6 +173,7 @@ var (
KeyEnvironmentHost: true,
KeyExec: true,
KeyExposeHostPort: true,
KeyGIDMap: true,
KeyGlobalArgs: true,
KeyGroup: true,
KeyHealthCmd: true,
@ -213,9 +218,12 @@ var (
KeySecurityLabelNested: true,
KeySecurityLabelType: true,
KeyShmSize: true,
KeySubGIDMap: true,
KeySubUIDMap: true,
KeySysctl: true,
KeyTimezone: true,
KeyTmpfs: true,
KeyUIDMap: true,
KeyUlimit: true,
KeyUnmask: true,
KeyUser: true,
@ -625,12 +633,10 @@ func ConvertContainer(container *parser.UnitFile, names map[string]string, isUse
podman.addf("-w=%s", workdir)
}
if err := handleUserRemap(container, ContainerGroup, podman, isUser, true); err != nil {
if err := handleUserMappings(container, ContainerGroup, podman, isUser, true); err != nil {
return nil, err
}
handleUserNS(container, ContainerGroup, podman)
tmpfsValues := container.LookupAll(ContainerGroup, KeyTmpfs)
for _, tmpfs := range tmpfsValues {
if strings.Count(tmpfs, ":") > 1 {
@ -1091,12 +1097,10 @@ func ConvertKube(kube *parser.UnitFile, names map[string]string, isUser bool) (*
handleLogDriver(kube, KubeGroup, execStart)
if err := handleUserRemap(kube, KubeGroup, execStart, isUser, false); err != nil {
if err := handleUserMappings(kube, KubeGroup, execStart, isUser, false); err != nil {
return nil, err
}
handleUserNS(kube, KubeGroup, execStart)
addNetworks(kube, KubeGroup, service, names, execStart)
updateMaps := kube.LookupAllStrv(KubeGroup, KeyAutoUpdate)
@ -1245,12 +1249,50 @@ func handleUser(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdli
return nil
}
func handleUserRemap(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline, isUser, supportManual bool) error {
// ignore Remap keys if UserNS is set
func handleUserMappings(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline, isUser, supportManual bool) error {
mappingsDefined := false
if userns, ok := unitFile.Lookup(groupName, KeyUserNS); ok && len(userns) > 0 {
podman.add("--userns", userns)
mappingsDefined = true
}
uidMaps := unitFile.LookupAllStrv(groupName, KeyUIDMap)
mappingsDefined = mappingsDefined || len(uidMaps) > 0
for _, uidMap := range uidMaps {
podman.addf("--uidmap=%s", uidMap)
}
gidMaps := unitFile.LookupAllStrv(groupName, KeyGIDMap)
mappingsDefined = mappingsDefined || len(gidMaps) > 0
for _, gidMap := range gidMaps {
podman.addf("--gidmap=%s", gidMap)
}
if subUIDMap, ok := unitFile.Lookup(groupName, KeySubUIDMap); ok && len(subUIDMap) > 0 {
podman.add("--subuidname", subUIDMap)
mappingsDefined = true
}
if subGIDMap, ok := unitFile.Lookup(groupName, KeySubGIDMap); ok && len(subGIDMap) > 0 {
podman.add("--subgidname", subGIDMap)
mappingsDefined = true
}
if mappingsDefined {
_, hasRemapUID := unitFile.Lookup(groupName, KeyRemapUID)
_, hasRemapGID := unitFile.Lookup(groupName, KeyRemapGID)
_, RemapUsers := unitFile.LookupLast(groupName, KeyRemapUsers)
if hasRemapUID || hasRemapGID || RemapUsers {
return fmt.Errorf("deprecated Remap keys are set along with explicit mapping keys")
}
return nil
}
return handleUserRemap(unitFile, groupName, podman, isUser, supportManual)
}
func handleUserRemap(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline, isUser, supportManual bool) error {
uidMaps := unitFile.LookupAllStrv(groupName, KeyRemapUID)
gidMaps := unitFile.LookupAllStrv(groupName, KeyRemapGID)
remapUsers, _ := unitFile.LookupLast(groupName, KeyRemapUsers)
@ -1315,12 +1357,6 @@ func handleUserRemap(unitFile *parser.UnitFile, groupName string, podman *Podman
return nil
}
func handleUserNS(unitFile *parser.UnitFile, groupName string, podman *PodmanCmdline) {
if userns, ok := unitFile.Lookup(groupName, KeyUserNS); ok && len(userns) > 0 {
podman.add("--userns", userns)
}
}
func addNetworks(quadletUnitFile *parser.UnitFile, groupName string, serviceUnitFile *parser.UnitFile, names map[string]string, podman *PodmanCmdline) {
networks := quadletUnitFile.LookupAll(groupName, KeyNetwork)
for _, network := range networks {

View File

@ -0,0 +1,10 @@
## assert-failed
## assert-stderr-contains "deprecated Remap keys are set along with explicit mapping keys"
[Container]
Image=localhost/imagename
UIDMap=0:10000:10
UIDMap=10:20000:10
GIDMap=0:10000:10
GIDMap=10:20000:10
RemapUsers=auto

View File

@ -0,0 +1,11 @@
## assert-podman-args "--uidmap=0:10000:10"
## assert-podman-args "--uidmap=10:20000:10"
## assert-podman-args "--gidmap=0:10000:10"
## assert-podman-args "--gidmap=10:20000:10"
[Container]
Image=localhost/imagename
UIDMap=0:10000:10
UIDMap=10:20000:10
GIDMap=0:10000:10
GIDMap=10:20000:10

View File

@ -0,0 +1,8 @@
## assert-failed
## assert-stderr-contains "deprecated Remap keys are set along with explicit mapping keys"
[Container]
Image=localhost/imagename
SubUIDMap=utest
SubGIDMap=gtest
RemapUsers=auto

View File

@ -0,0 +1,7 @@
## assert-podman-args "--subuidname" "utest"
## assert-podman-args "--subgidname" "gtest"
[Container]
Image=localhost/imagename
SubUIDMap=utest
SubGIDMap=gtest

View File

@ -0,0 +1,7 @@
## assert-failed
## assert-stderr-contains "deprecated Remap keys are set along with explicit mapping keys"
[Container]
Image=localhost/imagename
RemapUsers=auto
UserNS=keep-id

View File

@ -0,0 +1,5 @@
## assert-podman-args "--userns" "keep-id"
[Container]
Image=localhost/imagename
UserNS=keep-id

View File

@ -690,6 +690,8 @@ BOGUS=foo
Entry("exec.container", "exec.container", 0, ""),
Entry("health.container", "health.container", 0, ""),
Entry("hostname.container", "hostname.container", 0, ""),
Entry("idmapping.container", "idmapping.container", 0, ""),
Entry("idmapping-with-remap.container", "idmapping-with-remap.container", 1, "converting \"idmapping-with-remap.container\": deprecated Remap keys are set along with explicit mapping keys"),
Entry("image.container", "image.container", 0, ""),
Entry("install.container", "install.container", 0, ""),
Entry("ip.container", "ip.container", 0, ""),
@ -726,10 +728,14 @@ BOGUS=foo
Entry("selinux.container", "selinux.container", 0, ""),
Entry("shmsize.container", "shmsize.container", 0, ""),
Entry("shortname.container", "shortname.container", 0, "Warning: shortname.container specifies the image \"shortname\" which not a fully qualified image name. This is not ideal for performance and security reasons. See the podman-pull manpage discussion of short-name-aliases.conf for details."),
Entry("subidmapping.container", "subidmapping.container", 0, ""),
Entry("subidmapping-with-remap.container", "subidmapping-with-remap.container", 1, "converting \"subidmapping-with-remap.container\": deprecated Remap keys are set along with explicit mapping keys"),
Entry("sysctl.container", "sysctl.container", 0, ""),
Entry("timezone.container", "timezone.container", 0, ""),
Entry("unmask.container", "unmask.container", 0, ""),
Entry("user.container", "user.container", 0, ""),
Entry("userns.container", "userns.container", 0, ""),
Entry("userns-with-remap.container", "userns-with-remap.container", 1, "converting \"userns-with-remap.container\": deprecated Remap keys are set along with explicit mapping keys"),
Entry("volume.container", "volume.container", 0, ""),
Entry("workingdir.container", "workingdir.container", 0, ""),
Entry("Container - global args", "globalargs.container", 0, ""),