mirror of
https://github.com/containers/podman.git
synced 2025-06-25 03:52:15 +08:00
kube: honor pod security context IDs
If the RunAsUser, RunAsGroup, SupplementalGroups settings are not overriden in the container security context, then take the value from the pod security context. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
This commit is contained in:
@ -412,22 +412,23 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||
}
|
||||
|
||||
specgenOpts := kube.CtrSpecGenOptions{
|
||||
Annotations: annotations,
|
||||
Container: initCtr,
|
||||
Image: pulledImage,
|
||||
Volumes: volumes,
|
||||
PodID: pod.ID(),
|
||||
PodName: podName,
|
||||
PodInfraID: podInfraID,
|
||||
ConfigMaps: configMaps,
|
||||
SeccompPaths: seccompPaths,
|
||||
RestartPolicy: ctrRestartPolicy,
|
||||
NetNSIsHost: p.NetNS.IsHost(),
|
||||
SecretsManager: secretsManager,
|
||||
LogDriver: options.LogDriver,
|
||||
LogOptions: options.LogOptions,
|
||||
Labels: labels,
|
||||
InitContainerType: define.AlwaysInitContainer,
|
||||
Annotations: annotations,
|
||||
ConfigMaps: configMaps,
|
||||
Container: initCtr,
|
||||
Image: pulledImage,
|
||||
InitContainerType: define.AlwaysInitContainer,
|
||||
Labels: labels,
|
||||
LogDriver: options.LogDriver,
|
||||
LogOptions: options.LogOptions,
|
||||
NetNSIsHost: p.NetNS.IsHost(),
|
||||
PodID: pod.ID(),
|
||||
PodInfraID: podInfraID,
|
||||
PodName: podName,
|
||||
PodSecurityContext: podYAML.Spec.SecurityContext,
|
||||
RestartPolicy: ctrRestartPolicy,
|
||||
SeccompPaths: seccompPaths,
|
||||
SecretsManager: secretsManager,
|
||||
Volumes: volumes,
|
||||
}
|
||||
specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
|
||||
if err != nil {
|
||||
@ -460,21 +461,22 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||
}
|
||||
|
||||
specgenOpts := kube.CtrSpecGenOptions{
|
||||
Annotations: annotations,
|
||||
Container: container,
|
||||
Image: pulledImage,
|
||||
Volumes: volumes,
|
||||
PodID: pod.ID(),
|
||||
PodName: podName,
|
||||
PodInfraID: podInfraID,
|
||||
ConfigMaps: configMaps,
|
||||
SeccompPaths: seccompPaths,
|
||||
RestartPolicy: ctrRestartPolicy,
|
||||
NetNSIsHost: p.NetNS.IsHost(),
|
||||
SecretsManager: secretsManager,
|
||||
LogDriver: options.LogDriver,
|
||||
LogOptions: options.LogOptions,
|
||||
Labels: labels,
|
||||
Annotations: annotations,
|
||||
ConfigMaps: configMaps,
|
||||
Container: container,
|
||||
Image: pulledImage,
|
||||
Labels: labels,
|
||||
LogDriver: options.LogDriver,
|
||||
LogOptions: options.LogOptions,
|
||||
NetNSIsHost: p.NetNS.IsHost(),
|
||||
PodID: pod.ID(),
|
||||
PodInfraID: podInfraID,
|
||||
PodName: podName,
|
||||
PodSecurityContext: podYAML.Spec.SecurityContext,
|
||||
RestartPolicy: ctrRestartPolicy,
|
||||
SeccompPaths: seccompPaths,
|
||||
SecretsManager: secretsManager,
|
||||
Volumes: volumes,
|
||||
}
|
||||
specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
|
||||
if err != nil {
|
||||
|
@ -133,6 +133,8 @@ type CtrSpecGenOptions struct {
|
||||
// InitContainerType sets what type the init container is
|
||||
// Note: When playing a kube yaml, the inti container type will be set to "always" only
|
||||
InitContainerType string
|
||||
// PodSecurityContext is the security context specified for the pod
|
||||
PodSecurityContext *v1.PodSecurityContext
|
||||
}
|
||||
|
||||
func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) {
|
||||
@ -188,7 +190,7 @@ func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGener
|
||||
|
||||
s.InitContainerType = opts.InitContainerType
|
||||
|
||||
setupSecurityContext(s, opts.Container.SecurityContext)
|
||||
setupSecurityContext(s, opts.Container.SecurityContext, opts.PodSecurityContext)
|
||||
err := setupLivenessProbe(s, opts.Container, opts.RestartPolicy)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to configure livenessProbe")
|
||||
@ -531,10 +533,14 @@ func makeHealthCheck(inCmd string, interval int32, retries int32, timeout int32,
|
||||
return &hc, nil
|
||||
}
|
||||
|
||||
func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.SecurityContext) {
|
||||
func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.SecurityContext, podSecurityContext *v1.PodSecurityContext) {
|
||||
if securityContext == nil {
|
||||
return
|
||||
securityContext = &v1.SecurityContext{}
|
||||
}
|
||||
if podSecurityContext == nil {
|
||||
podSecurityContext = &v1.PodSecurityContext{}
|
||||
}
|
||||
|
||||
if securityContext.ReadOnlyRootFilesystem != nil {
|
||||
s.ReadOnlyFilesystem = *securityContext.ReadOnlyRootFilesystem
|
||||
}
|
||||
@ -546,7 +552,11 @@ func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.Security
|
||||
s.NoNewPrivileges = !*securityContext.AllowPrivilegeEscalation
|
||||
}
|
||||
|
||||
if seopt := securityContext.SELinuxOptions; seopt != nil {
|
||||
seopt := securityContext.SELinuxOptions
|
||||
if seopt == nil {
|
||||
seopt = podSecurityContext.SELinuxOptions
|
||||
}
|
||||
if seopt != nil {
|
||||
if seopt.User != "" {
|
||||
s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("user:%s", seopt.User))
|
||||
}
|
||||
@ -568,14 +578,26 @@ func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.Security
|
||||
s.CapDrop = append(s.CapDrop, string(capability))
|
||||
}
|
||||
}
|
||||
if securityContext.RunAsUser != nil {
|
||||
s.User = fmt.Sprintf("%d", *securityContext.RunAsUser)
|
||||
runAsUser := securityContext.RunAsUser
|
||||
if runAsUser == nil {
|
||||
runAsUser = podSecurityContext.RunAsUser
|
||||
}
|
||||
if securityContext.RunAsGroup != nil {
|
||||
if runAsUser != nil {
|
||||
s.User = fmt.Sprintf("%d", *runAsUser)
|
||||
}
|
||||
|
||||
runAsGroup := securityContext.RunAsGroup
|
||||
if runAsGroup == nil {
|
||||
runAsGroup = podSecurityContext.RunAsGroup
|
||||
}
|
||||
if runAsGroup != nil {
|
||||
if s.User == "" {
|
||||
s.User = "0"
|
||||
}
|
||||
s.User = fmt.Sprintf("%s:%d", s.User, *securityContext.RunAsGroup)
|
||||
s.User = fmt.Sprintf("%s:%d", s.User, *runAsGroup)
|
||||
}
|
||||
for _, group := range podSecurityContext.SupplementalGroups {
|
||||
s.Groups = append(s.Groups, fmt.Sprintf("%d", group))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -326,6 +326,11 @@ spec:
|
||||
image: {{ .Image }}
|
||||
name: {{ .Name }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ if .SecurityContext }}
|
||||
securityContext:
|
||||
{{ if .RunAsUser }}runAsUser: {{ .RunAsUser }}{{- end }}
|
||||
{{ if .RunAsGroup }}runAsGroup: {{ .RunAsGroup }}{{- end }}
|
||||
{{ end }}
|
||||
containers:
|
||||
{{ with .Ctrs }}
|
||||
@ -393,6 +398,8 @@ spec:
|
||||
{{- end }}
|
||||
{{ if .SecurityContext }}
|
||||
securityContext:
|
||||
{{ if .RunAsUser }}runAsUser: {{ .RunAsUser }}{{- end }}
|
||||
{{ if .RunAsGroup }}runAsGroup: {{ .RunAsGroup }}{{- end }}
|
||||
allowPrivilegeEscalation: true
|
||||
{{ if .Caps }}
|
||||
capabilities:
|
||||
@ -758,16 +765,19 @@ func withPVCAnnotations(k, v string) pvcOption {
|
||||
|
||||
// Pod describes the options a kube yaml can be configured at pod level
|
||||
type Pod struct {
|
||||
Name string
|
||||
RestartPolicy string
|
||||
Hostname string
|
||||
HostNetwork bool
|
||||
HostAliases []HostAlias
|
||||
Ctrs []*Ctr
|
||||
InitCtrs []*Ctr
|
||||
Volumes []*Volume
|
||||
Labels map[string]string
|
||||
Annotations map[string]string
|
||||
Name string
|
||||
RestartPolicy string
|
||||
Hostname string
|
||||
HostNetwork bool
|
||||
HostAliases []HostAlias
|
||||
Ctrs []*Ctr
|
||||
InitCtrs []*Ctr
|
||||
Volumes []*Volume
|
||||
Labels map[string]string
|
||||
Annotations map[string]string
|
||||
SecurityContext bool
|
||||
RunAsUser string
|
||||
RunAsGroup string
|
||||
}
|
||||
|
||||
type HostAlias struct {
|
||||
@ -802,6 +812,24 @@ func getPod(options ...podOption) *Pod {
|
||||
|
||||
type podOption func(*Pod)
|
||||
|
||||
func withPodSecurityContext(sc bool) podOption {
|
||||
return func(p *Pod) {
|
||||
p.SecurityContext = sc
|
||||
}
|
||||
}
|
||||
|
||||
func withPodRunAsUser(runAsUser string) podOption {
|
||||
return func(p *Pod) {
|
||||
p.RunAsUser = runAsUser
|
||||
}
|
||||
}
|
||||
|
||||
func withPodRunAsGroup(runAsGroup string) podOption {
|
||||
return func(p *Pod) {
|
||||
p.RunAsGroup = runAsGroup
|
||||
}
|
||||
}
|
||||
|
||||
func withPodName(name string) podOption {
|
||||
return func(pod *Pod) {
|
||||
pod.Name = name
|
||||
@ -949,6 +977,8 @@ type Ctr struct {
|
||||
Env []Env
|
||||
EnvFrom []EnvFrom
|
||||
InitCtrType string
|
||||
RunAsUser string
|
||||
RunAsGroup string
|
||||
}
|
||||
|
||||
// getCtr takes a list of ctrOptions and returns a Ctr with sane defaults
|
||||
@ -1042,6 +1072,18 @@ func withSecurityContext(sc bool) ctrOption {
|
||||
}
|
||||
}
|
||||
|
||||
func withRunAsUser(runAsUser string) ctrOption {
|
||||
return func(c *Ctr) {
|
||||
c.RunAsUser = runAsUser
|
||||
}
|
||||
}
|
||||
|
||||
func withRunAsGroup(runAsGroup string) ctrOption {
|
||||
return func(c *Ctr) {
|
||||
c.RunAsGroup = runAsGroup
|
||||
}
|
||||
}
|
||||
|
||||
func withCapAdd(caps []string) ctrOption {
|
||||
return func(c *Ctr) {
|
||||
c.CapAdd = caps
|
||||
@ -1105,8 +1147,12 @@ func withEnvFrom(name, from string, optional bool) ctrOption {
|
||||
}
|
||||
}
|
||||
|
||||
func makeCtrNameInPod(pod *Pod, containerName string) string {
|
||||
return fmt.Sprintf("%s-%s", pod.Name, containerName)
|
||||
}
|
||||
|
||||
func getCtrNameInPod(pod *Pod) string {
|
||||
return fmt.Sprintf("%s-%s", pod.Name, defaultCtrName)
|
||||
return makeCtrNameInPod(pod, defaultCtrName)
|
||||
}
|
||||
|
||||
type HostPath struct {
|
||||
@ -3222,6 +3268,38 @@ invalid kube kind
|
||||
Expect(ls.OutputToStringArray()).To(HaveLen(1))
|
||||
})
|
||||
|
||||
It("podman play kube RunAsUser", func() {
|
||||
ctr1Name := "ctr1"
|
||||
ctr2Name := "ctr2"
|
||||
ctr1 := getCtr(withName(ctr1Name), withSecurityContext(true), withRunAsUser("101"), withRunAsGroup("102"))
|
||||
ctr2 := getCtr(withName(ctr2Name), withSecurityContext(true))
|
||||
|
||||
pod := getPod(
|
||||
withCtr(ctr1),
|
||||
withCtr(ctr2),
|
||||
withPodSecurityContext(true),
|
||||
withPodRunAsUser("103"),
|
||||
withPodRunAsGroup("104"),
|
||||
)
|
||||
|
||||
err := generateKubeYaml("pod", pod, kubeYaml)
|
||||
Expect(err).To(BeNil())
|
||||
|
||||
cmd := podmanTest.Podman([]string{"play", "kube", kubeYaml})
|
||||
cmd.WaitWithDefaultTimeout()
|
||||
Expect(cmd).Should(Exit(0))
|
||||
|
||||
// we expect the user:group as configured for the container
|
||||
inspect := podmanTest.Podman([]string{"container", "inspect", "--format", "'{{.Config.User}}'", makeCtrNameInPod(pod, ctr1Name)})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect.OutputToString()).To(Equal("'101:102'"))
|
||||
|
||||
// we expect the user:group as configured for the pod
|
||||
inspect = podmanTest.Podman([]string{"container", "inspect", "--format", "'{{.Config.User}}'", makeCtrNameInPod(pod, ctr2Name)})
|
||||
inspect.WaitWithDefaultTimeout()
|
||||
Expect(inspect.OutputToString()).To(Equal("'103:104'"))
|
||||
})
|
||||
|
||||
Describe("verify environment variables", func() {
|
||||
var maxLength int
|
||||
BeforeEach(func() {
|
||||
|
Reference in New Issue
Block a user