mirror of https://github.com/containers/podman.git
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:
parent
82a4b8f01c
commit
9e1ee081f8
|
@ -413,21 +413,22 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||||
|
|
||||||
specgenOpts := kube.CtrSpecGenOptions{
|
specgenOpts := kube.CtrSpecGenOptions{
|
||||||
Annotations: annotations,
|
Annotations: annotations,
|
||||||
|
ConfigMaps: configMaps,
|
||||||
Container: initCtr,
|
Container: initCtr,
|
||||||
Image: pulledImage,
|
Image: pulledImage,
|
||||||
Volumes: volumes,
|
InitContainerType: define.AlwaysInitContainer,
|
||||||
PodID: pod.ID(),
|
Labels: labels,
|
||||||
PodName: podName,
|
|
||||||
PodInfraID: podInfraID,
|
|
||||||
ConfigMaps: configMaps,
|
|
||||||
SeccompPaths: seccompPaths,
|
|
||||||
RestartPolicy: ctrRestartPolicy,
|
|
||||||
NetNSIsHost: p.NetNS.IsHost(),
|
|
||||||
SecretsManager: secretsManager,
|
|
||||||
LogDriver: options.LogDriver,
|
LogDriver: options.LogDriver,
|
||||||
LogOptions: options.LogOptions,
|
LogOptions: options.LogOptions,
|
||||||
Labels: labels,
|
NetNSIsHost: p.NetNS.IsHost(),
|
||||||
InitContainerType: define.AlwaysInitContainer,
|
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)
|
specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -461,20 +462,21 @@ func (ic *ContainerEngine) playKubePod(ctx context.Context, podName string, podY
|
||||||
|
|
||||||
specgenOpts := kube.CtrSpecGenOptions{
|
specgenOpts := kube.CtrSpecGenOptions{
|
||||||
Annotations: annotations,
|
Annotations: annotations,
|
||||||
|
ConfigMaps: configMaps,
|
||||||
Container: container,
|
Container: container,
|
||||||
Image: pulledImage,
|
Image: pulledImage,
|
||||||
Volumes: volumes,
|
Labels: labels,
|
||||||
PodID: pod.ID(),
|
|
||||||
PodName: podName,
|
|
||||||
PodInfraID: podInfraID,
|
|
||||||
ConfigMaps: configMaps,
|
|
||||||
SeccompPaths: seccompPaths,
|
|
||||||
RestartPolicy: ctrRestartPolicy,
|
|
||||||
NetNSIsHost: p.NetNS.IsHost(),
|
|
||||||
SecretsManager: secretsManager,
|
|
||||||
LogDriver: options.LogDriver,
|
LogDriver: options.LogDriver,
|
||||||
LogOptions: options.LogOptions,
|
LogOptions: options.LogOptions,
|
||||||
Labels: labels,
|
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)
|
specGen, err := kube.ToSpecGen(ctx, &specgenOpts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -133,6 +133,8 @@ type CtrSpecGenOptions struct {
|
||||||
// InitContainerType sets what type the init container is
|
// InitContainerType sets what type the init container is
|
||||||
// Note: When playing a kube yaml, the inti container type will be set to "always" only
|
// Note: When playing a kube yaml, the inti container type will be set to "always" only
|
||||||
InitContainerType string
|
InitContainerType string
|
||||||
|
// PodSecurityContext is the security context specified for the pod
|
||||||
|
PodSecurityContext *v1.PodSecurityContext
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToSpecGen(ctx context.Context, opts *CtrSpecGenOptions) (*specgen.SpecGenerator, error) {
|
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
|
s.InitContainerType = opts.InitContainerType
|
||||||
|
|
||||||
setupSecurityContext(s, opts.Container.SecurityContext)
|
setupSecurityContext(s, opts.Container.SecurityContext, opts.PodSecurityContext)
|
||||||
err := setupLivenessProbe(s, opts.Container, opts.RestartPolicy)
|
err := setupLivenessProbe(s, opts.Container, opts.RestartPolicy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Failed to configure livenessProbe")
|
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
|
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 {
|
if securityContext == nil {
|
||||||
return
|
securityContext = &v1.SecurityContext{}
|
||||||
}
|
}
|
||||||
|
if podSecurityContext == nil {
|
||||||
|
podSecurityContext = &v1.PodSecurityContext{}
|
||||||
|
}
|
||||||
|
|
||||||
if securityContext.ReadOnlyRootFilesystem != nil {
|
if securityContext.ReadOnlyRootFilesystem != nil {
|
||||||
s.ReadOnlyFilesystem = *securityContext.ReadOnlyRootFilesystem
|
s.ReadOnlyFilesystem = *securityContext.ReadOnlyRootFilesystem
|
||||||
}
|
}
|
||||||
|
@ -546,7 +552,11 @@ func setupSecurityContext(s *specgen.SpecGenerator, securityContext *v1.Security
|
||||||
s.NoNewPrivileges = !*securityContext.AllowPrivilegeEscalation
|
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 != "" {
|
if seopt.User != "" {
|
||||||
s.SelinuxOpts = append(s.SelinuxOpts, fmt.Sprintf("user:%s", 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))
|
s.CapDrop = append(s.CapDrop, string(capability))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if securityContext.RunAsUser != nil {
|
runAsUser := securityContext.RunAsUser
|
||||||
s.User = fmt.Sprintf("%d", *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 == "" {
|
if s.User == "" {
|
||||||
s.User = "0"
|
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 }}
|
image: {{ .Image }}
|
||||||
name: {{ .Name }}
|
name: {{ .Name }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
{{ end }}
|
||||||
|
{{ if .SecurityContext }}
|
||||||
|
securityContext:
|
||||||
|
{{ if .RunAsUser }}runAsUser: {{ .RunAsUser }}{{- end }}
|
||||||
|
{{ if .RunAsGroup }}runAsGroup: {{ .RunAsGroup }}{{- end }}
|
||||||
{{ end }}
|
{{ end }}
|
||||||
containers:
|
containers:
|
||||||
{{ with .Ctrs }}
|
{{ with .Ctrs }}
|
||||||
|
@ -393,6 +398,8 @@ spec:
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{ if .SecurityContext }}
|
{{ if .SecurityContext }}
|
||||||
securityContext:
|
securityContext:
|
||||||
|
{{ if .RunAsUser }}runAsUser: {{ .RunAsUser }}{{- end }}
|
||||||
|
{{ if .RunAsGroup }}runAsGroup: {{ .RunAsGroup }}{{- end }}
|
||||||
allowPrivilegeEscalation: true
|
allowPrivilegeEscalation: true
|
||||||
{{ if .Caps }}
|
{{ if .Caps }}
|
||||||
capabilities:
|
capabilities:
|
||||||
|
@ -768,6 +775,9 @@ type Pod struct {
|
||||||
Volumes []*Volume
|
Volumes []*Volume
|
||||||
Labels map[string]string
|
Labels map[string]string
|
||||||
Annotations map[string]string
|
Annotations map[string]string
|
||||||
|
SecurityContext bool
|
||||||
|
RunAsUser string
|
||||||
|
RunAsGroup string
|
||||||
}
|
}
|
||||||
|
|
||||||
type HostAlias struct {
|
type HostAlias struct {
|
||||||
|
@ -802,6 +812,24 @@ func getPod(options ...podOption) *Pod {
|
||||||
|
|
||||||
type podOption func(*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 {
|
func withPodName(name string) podOption {
|
||||||
return func(pod *Pod) {
|
return func(pod *Pod) {
|
||||||
pod.Name = name
|
pod.Name = name
|
||||||
|
@ -949,6 +977,8 @@ type Ctr struct {
|
||||||
Env []Env
|
Env []Env
|
||||||
EnvFrom []EnvFrom
|
EnvFrom []EnvFrom
|
||||||
InitCtrType string
|
InitCtrType string
|
||||||
|
RunAsUser string
|
||||||
|
RunAsGroup string
|
||||||
}
|
}
|
||||||
|
|
||||||
// getCtr takes a list of ctrOptions and returns a Ctr with sane defaults
|
// 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 {
|
func withCapAdd(caps []string) ctrOption {
|
||||||
return func(c *Ctr) {
|
return func(c *Ctr) {
|
||||||
c.CapAdd = caps
|
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 {
|
func getCtrNameInPod(pod *Pod) string {
|
||||||
return fmt.Sprintf("%s-%s", pod.Name, defaultCtrName)
|
return makeCtrNameInPod(pod, defaultCtrName)
|
||||||
}
|
}
|
||||||
|
|
||||||
type HostPath struct {
|
type HostPath struct {
|
||||||
|
@ -3222,6 +3268,38 @@ invalid kube kind
|
||||||
Expect(ls.OutputToStringArray()).To(HaveLen(1))
|
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() {
|
Describe("verify environment variables", func() {
|
||||||
var maxLength int
|
var maxLength int
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
|
|
Loading…
Reference in New Issue