github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/test/e2e/run_userns_test.go (about) 1 package integration 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "os/user" 8 "strings" 9 10 . "github.com/hanks177/podman/v4/test/utils" 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 . "github.com/onsi/gomega/gexec" 14 ) 15 16 var _ = Describe("Podman UserNS support", func() { 17 var ( 18 tempdir string 19 err error 20 podmanTest *PodmanTestIntegration 21 ) 22 23 BeforeEach(func() { 24 if os.Getenv("SKIP_USERNS") != "" { 25 Skip("Skip userns tests.") 26 } 27 if _, err := os.Stat("/proc/self/uid_map"); err != nil { 28 Skip("User namespaces not supported.") 29 } 30 tempdir, err = CreateTempDirInTempDir() 31 if err != nil { 32 os.Exit(1) 33 } 34 podmanTest = PodmanTestCreate(tempdir) 35 podmanTest.Setup() 36 }) 37 38 AfterEach(func() { 39 podmanTest.Cleanup() 40 f := CurrentGinkgoTestDescription() 41 processTestResult(f) 42 43 }) 44 45 It("podman uidmapping and gidmapping", func() { 46 session := podmanTest.Podman([]string{"run", "--uidmap=0:100:5000", "--gidmap=0:200:5000", "alpine", "echo", "hello"}) 47 session.WaitWithDefaultTimeout() 48 Expect(session).Should(Exit(0)) 49 Expect(session.OutputToString()).To(ContainSubstring("hello")) 50 }) 51 52 // It essentially repeats the test above but with the `-it` short option 53 // that broke execution at: 54 // https://github.com/containers/podman/pull/1066#issuecomment-403562116 55 // To avoid a potential future regression, use this as a test. 56 It("podman uidmapping and gidmapping with short-opts", func() { 57 session := podmanTest.Podman([]string{"run", "--uidmap=0:1:5000", "--gidmap=0:200:5000", "-it", "alpine", "echo", "hello"}) 58 session.WaitWithDefaultTimeout() 59 Expect(session).Should(Exit(0)) 60 Expect(session.OutputToString()).To(ContainSubstring("hello")) 61 }) 62 63 It("podman uidmapping and gidmapping with a volume", func() { 64 session := podmanTest.Podman([]string{"run", "--uidmap=0:1:500", "--gidmap=0:200:5000", "-v", "my-foo-volume:/foo:Z", "alpine", "echo", "hello"}) 65 session.WaitWithDefaultTimeout() 66 Expect(session).Should(Exit(0)) 67 Expect(session.OutputToString()).To(ContainSubstring("hello")) 68 }) 69 70 It("podman uidmapping and gidmapping --net=host", func() { 71 session := podmanTest.Podman([]string{"run", "--net=host", "--uidmap=0:1:5000", "--gidmap=0:200:5000", "alpine", "echo", "hello"}) 72 session.WaitWithDefaultTimeout() 73 Expect(session).Should(Exit(0)) 74 Expect(session.OutputToString()).To(ContainSubstring("hello")) 75 }) 76 77 It("podman --userns=keep-id", func() { 78 session := podmanTest.Podman([]string{"run", "--userns=keep-id", "alpine", "id", "-u"}) 79 session.WaitWithDefaultTimeout() 80 if os.Geteuid() == 0 { 81 Expect(session).Should(Exit(125)) 82 return 83 } 84 85 Expect(session).Should(Exit(0)) 86 uid := fmt.Sprintf("%d", os.Geteuid()) 87 Expect(session.OutputToString()).To(ContainSubstring(uid)) 88 }) 89 90 It("podman --userns=keep-id check passwd", func() { 91 SkipIfNotRootless("keep-id only works in rootless mode") 92 session := podmanTest.Podman([]string{"run", "--userns=keep-id", "alpine", "id", "-un"}) 93 session.WaitWithDefaultTimeout() 94 Expect(session).Should(Exit(0)) 95 u, err := user.Current() 96 Expect(err).To(BeNil()) 97 Expect(session.OutputToString()).To(ContainSubstring(u.Name)) 98 }) 99 100 It("podman --userns=keep-id root owns /usr", func() { 101 SkipIfNotRootless("keep-id only works in rootless mode") 102 session := podmanTest.Podman([]string{"run", "--userns=keep-id", "alpine", "stat", "-c%u", "/usr"}) 103 session.WaitWithDefaultTimeout() 104 Expect(session).Should(Exit(0)) 105 Expect(session.OutputToString()).To(Equal("0")) 106 }) 107 108 It("podman --userns=keep-id --user root:root", func() { 109 SkipIfNotRootless("keep-id only works in rootless mode") 110 session := podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", "alpine", "id", "-u"}) 111 session.WaitWithDefaultTimeout() 112 Expect(session).Should(Exit(0)) 113 Expect(session.OutputToString()).To(Equal("0")) 114 }) 115 116 It("podman run --userns=keep-id can add users", func() { 117 SkipIfNotRootless("keep-id only works in rootless mode") 118 userName := os.Getenv("USER") 119 if userName == "" { 120 Skip("Can't complete test if no username available") 121 } 122 123 ctrName := "ctr-name" 124 session := podmanTest.Podman([]string{"run", "--userns=keep-id", "--user", "root:root", "-d", "--stop-signal", "9", "--name", ctrName, fedoraMinimal, "sleep", "600"}) 125 session.WaitWithDefaultTimeout() 126 Expect(session).Should(Exit(0)) 127 128 exec1 := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "cat", "/etc/passwd"}) 129 exec1.WaitWithDefaultTimeout() 130 Expect(exec1).Should(Exit(0)) 131 Expect(exec1.OutputToString()).To(ContainSubstring(userName)) 132 133 exec2 := podmanTest.Podman([]string{"exec", "-t", "-i", ctrName, "useradd", "testuser"}) 134 exec2.WaitWithDefaultTimeout() 135 Expect(exec2).Should(Exit(0)) 136 }) 137 138 It("podman --userns=auto", func() { 139 u, err := user.Current() 140 Expect(err).To(BeNil()) 141 name := u.Name 142 if name == "root" { 143 name = "containers" 144 } 145 146 content, err := ioutil.ReadFile("/etc/subuid") 147 if err != nil { 148 Skip("cannot read /etc/subuid") 149 } 150 if !strings.Contains(string(content), name) { 151 Skip("cannot find mappings for the current user") 152 } 153 154 m := make(map[string]string) 155 for i := 0; i < 5; i++ { 156 session := podmanTest.Podman([]string{"run", "--userns=auto", "alpine", "cat", "/proc/self/uid_map"}) 157 session.WaitWithDefaultTimeout() 158 Expect(session).Should(Exit(0)) 159 l := session.OutputToString() 160 Expect(l).To(ContainSubstring("1024")) 161 m[l] = l 162 } 163 // check for no duplicates 164 Expect(m).To(HaveLen(5)) 165 }) 166 167 It("podman --userns=auto:size=%d", func() { 168 u, err := user.Current() 169 Expect(err).To(BeNil()) 170 171 name := u.Name 172 if name == "root" { 173 name = "containers" 174 } 175 176 content, err := ioutil.ReadFile("/etc/subuid") 177 if err != nil { 178 Skip("cannot read /etc/subuid") 179 } 180 if !strings.Contains(string(content), name) { 181 Skip("cannot find mappings for the current user") 182 } 183 184 session := podmanTest.Podman([]string{"run", "--userns=auto:size=500", "alpine", "cat", "/proc/self/uid_map"}) 185 session.WaitWithDefaultTimeout() 186 Expect(session).Should(Exit(0)) 187 Expect(session.OutputToString()).To(ContainSubstring("500")) 188 189 session = podmanTest.Podman([]string{"run", "--userns=auto:size=3000", "alpine", "cat", "/proc/self/uid_map"}) 190 session.WaitWithDefaultTimeout() 191 Expect(session).Should(Exit(0)) 192 Expect(session.OutputToString()).To(ContainSubstring("3000")) 193 194 session = podmanTest.Podman([]string{"run", "--userns=auto", "--user=2000:3000", "alpine", "cat", "/proc/self/uid_map"}) 195 session.WaitWithDefaultTimeout() 196 Expect(session).Should(Exit(0)) 197 Expect(session.OutputToString()).To(ContainSubstring("3001")) 198 199 session = podmanTest.Podman([]string{"run", "--userns=auto", "--user=4000:1000", "alpine", "cat", "/proc/self/uid_map"}) 200 session.WaitWithDefaultTimeout() 201 Expect(session).Should(Exit(0)) 202 Expect(session.OutputToString()).To(ContainSubstring("4001")) 203 }) 204 205 It("podman --userns=auto:uidmapping=", func() { 206 u, err := user.Current() 207 Expect(err).To(BeNil()) 208 209 name := u.Name 210 if name == "root" { 211 name = "containers" 212 } 213 214 content, err := ioutil.ReadFile("/etc/subuid") 215 if err != nil { 216 Skip("cannot read /etc/subuid") 217 } 218 if !strings.Contains(string(content), name) { 219 Skip("cannot find mappings for the current user") 220 } 221 222 session := podmanTest.Podman([]string{"run", "--userns=auto:uidmapping=0:0:1", "alpine", "cat", "/proc/self/uid_map"}) 223 session.WaitWithDefaultTimeout() 224 Expect(session).Should(Exit(0)) 225 output := session.OutputToString() 226 Expect(output).To(MatchRegexp("\\s0\\s0\\s1")) 227 228 session = podmanTest.Podman([]string{"run", "--userns=auto:size=8192,uidmapping=0:0:1", "alpine", "cat", "/proc/self/uid_map"}) 229 session.WaitWithDefaultTimeout() 230 Expect(session).Should(Exit(0)) 231 Expect(session.OutputToString()).To(ContainSubstring("8191")) 232 }) 233 234 It("podman --userns=auto:gidmapping=", func() { 235 u, err := user.Current() 236 Expect(err).To(BeNil()) 237 238 name := u.Name 239 if name == "root" { 240 name = "containers" 241 } 242 243 content, err := ioutil.ReadFile("/etc/subuid") 244 if err != nil { 245 Skip("cannot read /etc/subuid") 246 } 247 if !strings.Contains(string(content), name) { 248 Skip("cannot find mappings for the current user") 249 } 250 251 session := podmanTest.Podman([]string{"run", "--userns=auto:gidmapping=0:0:1", "alpine", "cat", "/proc/self/gid_map"}) 252 session.WaitWithDefaultTimeout() 253 Expect(session).Should(Exit(0)) 254 output := session.OutputToString() 255 Expect(output).To(MatchRegexp("\\s0\\s0\\s1")) 256 257 session = podmanTest.Podman([]string{"run", "--userns=auto:size=8192,gidmapping=0:0:1", "alpine", "cat", "/proc/self/gid_map"}) 258 session.WaitWithDefaultTimeout() 259 Expect(session).Should(Exit(0)) 260 Expect(session.OutputToString()).To(ContainSubstring("8191")) 261 }) 262 263 It("podman --userns=container:CTR", func() { 264 ctrName := "userns-ctr" 265 session := podmanTest.Podman([]string{"run", "-d", "--uidmap=0:0:1", "--uidmap=1:1:4998", "--name", ctrName, "alpine", "top"}) 266 session.WaitWithDefaultTimeout() 267 Expect(session).Should(Exit(0)) 268 269 // runc has an issue and we also need to join the IPC namespace. 270 session = podmanTest.Podman([]string{"run", "--rm", "--userns=container:" + ctrName, "--ipc=container:" + ctrName, "alpine", "cat", "/proc/self/uid_map"}) 271 session.WaitWithDefaultTimeout() 272 Expect(session).Should(Exit(0)) 273 274 Expect(session.OutputToString()).To(ContainSubstring("4998")) 275 276 session = podmanTest.Podman([]string{"run", "--rm", "--userns=container:" + ctrName, "--net=container:" + ctrName, "alpine", "cat", "/proc/self/uid_map"}) 277 session.WaitWithDefaultTimeout() 278 Expect(session).Should(Exit(0)) 279 280 Expect(session.OutputToString()).To(ContainSubstring("4998")) 281 }) 282 283 It("podman --user with volume", func() { 284 tests := []struct { 285 uid, gid, arg, vol string 286 }{ 287 {"0", "0", "0:0", "vol-0"}, 288 {"1000", "0", "1000", "vol-1"}, 289 {"1000", "1000", "1000:1000", "vol-2"}, 290 } 291 292 for _, tt := range tests { 293 session := podmanTest.Podman([]string{"run", "-d", "--user", tt.arg, "--mount", "type=volume,src=" + tt.vol + ",dst=/home/user", "alpine", "top"}) 294 session.WaitWithDefaultTimeout() 295 Expect(session).Should(Exit(0)) 296 297 inspectUID := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .UID }}", tt.vol}) 298 inspectUID.WaitWithDefaultTimeout() 299 Expect(inspectUID).Should(Exit(0)) 300 Expect(inspectUID.OutputToString()).To(Equal(tt.uid)) 301 302 // Make sure we're defaulting to 0. 303 inspectGID := podmanTest.Podman([]string{"volume", "inspect", "--format", "{{ .GID }}", tt.vol}) 304 inspectGID.WaitWithDefaultTimeout() 305 Expect(inspectGID).Should(Exit(0)) 306 Expect(inspectGID.OutputToString()).To(Equal(tt.gid)) 307 } 308 309 }) 310 It("podman PODMAN_USERNS", func() { 311 SkipIfNotRootless("keep-id only works in rootless mode") 312 313 podmanUserns, podmanUserusSet := os.LookupEnv("PODMAN_USERNS") 314 os.Setenv("PODMAN_USERNS", "keep-id") 315 defer func() { 316 if podmanUserusSet { 317 os.Setenv("PODMAN_USERNS", podmanUserns) 318 } else { 319 os.Unsetenv("PODMAN_USERNS") 320 } 321 }() 322 if IsRemote() { 323 podmanTest.RestartRemoteService() 324 } 325 326 result := podmanTest.Podman([]string{"create", ALPINE, "true"}) 327 result.WaitWithDefaultTimeout() 328 Expect(result).Should(Exit(0)) 329 330 inspect := podmanTest.Podman([]string{"inspect", "--format", "{{ .HostConfig.IDMappings }}", result.OutputToString()}) 331 inspect.WaitWithDefaultTimeout() 332 Expect(inspect.OutputToString()).To(Not(Equal("<nil>"))) 333 334 if IsRemote() { 335 podmanTest.RestartRemoteService() 336 } 337 }) 338 })