diff --git a/libpod/kube.go b/libpod/kube.go index b376f9ef8f..e841419153 100644 --- a/libpod/kube.go +++ b/libpod/kube.go @@ -512,7 +512,32 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po sort.Slice(containers, func(i, j int) bool { return containers[i].CreatedTime().Before(containers[j].CreatedTime()) }) for _, ctr := range containers { - if !ctr.IsInfra() { + if ctr.IsInfra() { + // If there is an user namespace for the infra container, then register it for the entire pod. + if v, found := ctr.config.Spec.Annotations[define.UserNsAnnotation]; found { + podAnnotations[define.UserNsAnnotation] = v + } + _, _, infraDNS, _, err := containerToV1Container(ctx, ctr, getService) + if err != nil { + return nil, err + } + if infraDNS != nil { + if servers := infraDNS.Nameservers; len(servers) > 0 { + dnsInfo.Nameservers = servers + } + if searches := infraDNS.Searches; len(searches) > 0 { + dnsInfo.Searches = searches + } + if options := infraDNS.Options; len(options) > 0 { + dnsInfo.Options = options + } + } + // If the infraName is not the podID-infra, that means the user set another infra name using + // --infra-name during pod creation + if infraName != "" && infraName != p.ID()[:12]+"-infra" { + podAnnotations[define.InfraNameAnnotation] = infraName + } + } else { for k, v := range ctr.config.Spec.Annotations { if !podmanOnly && (define.IsReservedAnnotation(k)) { continue @@ -574,27 +599,6 @@ func (p *Pod) podWithContainers(ctx context.Context, containers []*Container, po vol := vol deDupPodVolumes[vol.Name] = &vol } - } else { - _, _, infraDNS, _, err := containerToV1Container(ctx, ctr, getService) - if err != nil { - return nil, err - } - if infraDNS != nil { - if servers := infraDNS.Nameservers; len(servers) > 0 { - dnsInfo.Nameservers = servers - } - if searches := infraDNS.Searches; len(searches) > 0 { - dnsInfo.Searches = searches - } - if options := infraDNS.Options; len(options) > 0 { - dnsInfo.Options = options - } - } - // If the infraName is not the podID-infra, that means the user set another infra name using - // --infra-name during pod creation - if infraName != "" && infraName != p.ID()[:12]+"-infra" { - podAnnotations[define.InfraNameAnnotation] = infraName - } } } podVolumes := []v1.Volume{} diff --git a/pkg/api/handlers/libpod/pods.go b/pkg/api/handlers/libpod/pods.go index 8bc081f160..1c2ee28505 100644 --- a/pkg/api/handlers/libpod/pods.go +++ b/pkg/api/handlers/libpod/pods.go @@ -46,6 +46,9 @@ func PodCreate(w http.ResponseWriter, r *http.Request) { infraOptions.Net = &entities.NetOptions{} infraOptions.Devices = psg.Devices infraOptions.SecurityOpt = psg.SecurityOpt + if !psg.Userns.IsDefault() { + infraOptions.UserNS = psg.Userns.String() + } if psg.ShareParent == nil { t := true psg.ShareParent = &t diff --git a/pkg/domain/infra/abi/play.go b/pkg/domain/infra/abi/play.go index ec5c1a1fc3..6374f212ba 100644 --- a/pkg/domain/infra/abi/play.go +++ b/pkg/domain/infra/abi/play.go @@ -603,10 +603,15 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY if options.Userns == "" { if v, ok := annotations[define.UserNsAnnotation]; ok { options.Userns = v + } else if v, ok := annotations[define.UserNsAnnotation+"/"+podName]; ok { + options.Userns = v + } else if podYAML.Spec.HostUsers != nil && !*podYAML.Spec.HostUsers { + options.Userns = "auto" } else { options.Userns = "host" } - if podYAML.Spec.HostUsers != nil && !*podYAML.Spec.HostUsers { + // FIXME: how to deal with explicit mappings? + if options.Userns == "private" { options.Userns = "auto" } } else if podYAML.Spec.HostUsers != nil { diff --git a/pkg/specgenutil/specgen.go b/pkg/specgenutil/specgen.go index c9dc0775d5..6cb1f154d5 100644 --- a/pkg/specgenutil/specgen.go +++ b/pkg/specgenutil/specgen.go @@ -516,6 +516,10 @@ func FillOutSpecGen(s *specgen.SpecGenerator, c *entities.ContainerCreateOptions if len(s.Annotations) == 0 { s.Annotations = annotations } + // Add the user namespace configuration to the annotations + if c.UserNS != "" { + s.Annotations[define.UserNsAnnotation] = c.UserNS + } if len(c.StorageOpts) > 0 { opts := make(map[string]string, len(c.StorageOpts)) diff --git a/pkg/specgenutil/specgenutil_test.go b/pkg/specgenutil/specgenutil_test.go index c0e93316f8..c714dc446b 100644 --- a/pkg/specgenutil/specgenutil_test.go +++ b/pkg/specgenutil/specgenutil_test.go @@ -8,6 +8,7 @@ import ( "testing" "github.com/containers/common/pkg/machine" + "github.com/containers/podman/v5/libpod/define" "github.com/containers/podman/v5/pkg/domain/entities" "github.com/containers/podman/v5/pkg/specgen" "github.com/stretchr/testify/assert" @@ -216,3 +217,16 @@ func TestGenRlimits(t *testing.T) { _, err = GenRlimits([]string{"nofile=bar:buzz"}) assert.Error(t, err, "err is not nil") } + +func TestFillOutSpecGenRecorsUserNs(t *testing.T) { + sg := specgen.NewSpecGenerator("nothing", false) + err := FillOutSpecGen(sg, &entities.ContainerCreateOptions{ + ImageVolume: "ignore", + UserNS: "keep-id", + }, []string{}) + assert.NoError(t, err) + + v, ok := sg.Annotations[define.UserNsAnnotation] + assert.True(t, ok, "UserNsAnnotation is set") + assert.Equal(t, "keep-id", v, "UserNsAnnotation is keep-id") +} diff --git a/test/system/700-play.bats b/test/system/700-play.bats index 6229a858d4..337108f817 100644 --- a/test/system/700-play.bats +++ b/test/system/700-play.bats @@ -1037,3 +1037,33 @@ spec: run_podman kube down $fname run_podman rmi $imgname } + +@test "podman kube restore user namespace" { + if ! is_rootless; then + grep -E -q "^containers:" /etc/subuid || skip "no IDs allocated for user 'containers'" + fi + + run_podman pod create --userns auto --name usernspod + run_podman create --pod usernspod $IMAGE true + + run_podman pod inspect --format {{.InfraContainerID}} usernspod + infraID="$output" + + run_podman inspect --format '{{index .Config.Annotations "io.podman.annotations.userns"}}' $infraID + assert "$output" == "auto" "user namespace should be kept" + + YAML=$PODMAN_TMPDIR/test.yml + + # Make sure the same setting is restored if the pod is recreated from the yaml + run_podman kube generate usernspod -f $YAML + cat $YAML + run_podman kube play --replace $YAML + + run_podman pod inspect --format {{.InfraContainerID}} usernspod + infraID="$output" + + run_podman inspect --format '{{index .Config.Annotations "io.podman.annotations.userns"}}' $infraID + assert "$output" == "auto" "user namespace should be kept" + + run_podman pod rm -f usernspod +}