Skip to content

Commit

Permalink
Pod Security Option support
Browse files Browse the repository at this point in the history
Added support for pod security options. These are applied to infra and passed down to the
containers as added (unless overridden).

Modified the inheritance process from infra, creating a new function Inherit() which reads the config, and marshals the compatible options into an intermediate struct `InfraInherit`
This is then unmarshaled into a container config and all of this is added to the CtrCreateOptions. Removes the need (mostly) for special additons which complicate the Container_create
code and pod creation.

resolves containers#12173

Signed-off-by: cdoern <[email protected]>
  • Loading branch information
cdoern committed Dec 27, 2021
1 parent e06631d commit 2892703
Show file tree
Hide file tree
Showing 13 changed files with 268 additions and 73 deletions.
16 changes: 8 additions & 8 deletions cmd/podman/common/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -540,14 +540,6 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
)
_ = cmd.RegisterFlagCompletionFunc(secretFlagName, AutocompleteSecrets)

securityOptFlagName := "security-opt"
createFlags.StringArrayVar(
&cf.SecurityOpt,
securityOptFlagName, []string{},
"Security Options",
)
_ = cmd.RegisterFlagCompletionFunc(securityOptFlagName, AutocompleteSecurityOption)

shmSizeFlagName := "shm-size"
createFlags.String(
shmSizeFlagName, shmSize(),
Expand Down Expand Up @@ -720,6 +712,13 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
`If a container with the same name exists, replace it`,
)
}
securityOptFlagName := "security-opt"
createFlags.StringArrayVar(
&cf.SecurityOpt,
securityOptFlagName, []string{},
"Security Options",
)
_ = cmd.RegisterFlagCompletionFunc(securityOptFlagName, AutocompleteSecurityOption)

subgidnameFlagName := "subgidname"
createFlags.StringVar(
Expand Down Expand Up @@ -890,6 +889,7 @@ func DefineCreateFlags(cmd *cobra.Command, cf *entities.ContainerCreateOptions,
"Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)",
)
_ = cmd.RegisterFlagCompletionFunc(deviceReadBpsFlagName, completion.AutocompleteDefault)

volumesFromFlagName := "volumes-from"
createFlags.StringArrayVar(
&cf.VolumesFrom,
Expand Down
34 changes: 33 additions & 1 deletion docs/source/markdown/podman-pod-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,38 @@ NOTE: This cannot be modified once the pod is created.

If another pod with the same name already exists, replace and remove it. The default is **false**.

#### **--security-opt**=*option*

Security Options

- `apparmor=unconfined` : Turn off apparmor confinement for the pod
- `apparmor=your-profile` : Set the apparmor confinement profile for the pod

- `label=user:USER` : Set the label user for the pod processes
- `label=role:ROLE` : Set the label role for the pod processes
- `label=type:TYPE` : Set the label process type for the pod processes
- `label=level:LEVEL` : Set the label level for the pod processes
- `label=filetype:TYPE` : Set the label file type for the pod files
- `label=disable` : Turn off label separation for the pod

Note: Labeling can be disabled for all pods/containers by setting label=false in the **containers.conf** (`/etc/containers/containers.conf` or `$HOME/.config/containers/containers.conf`) file.

- `mask=/path/1:/path/2` : The paths to mask separated by a colon. A masked path
cannot be accessed inside the containers within the pod.

- `no-new-privileges` : Disable container processes from gaining additional privileges

- `seccomp=unconfined` : Turn off seccomp confinement for the pod
- `seccomp=profile.json` : Whitelisted syscalls seccomp Json file to be used as a seccomp filter

- `proc-opts=OPTIONS` : Comma-separated list of options to use for the /proc mount. More details for the
possible mount options are specified in the **proc(5)** man page.

- **unmask**=_ALL_ or _/path/1:/path/2_, or shell expanded paths (/proc/*): Paths to unmask separated by a colon. If set to **ALL**, it will unmask all the paths that are masked or made read only by default.
The default masked paths are **/proc/acpi, /proc/kcore, /proc/keys, /proc/latency_stats, /proc/sched_debug, /proc/scsi, /proc/timer_list, /proc/timer_stats, /sys/firmware, and /sys/fs/selinux.** The default paths that are read only are **/proc/asound, /proc/bus, /proc/fs, /proc/irq, /proc/sys, /proc/sysrq-trigger, /sys/fs/cgroup**.

Note: Labeling can be disabled for all containers by setting label=false in the **containers.conf** (`/etc/containers/containers.conf` or `$HOME/.config/containers/containers.conf`) file.

#### **--share**=*namespace*

A comma-separated list of kernel namespaces to share. If none or "" is specified, no namespaces will be shared. The namespaces to choose from are ipc, net, pid, uts.
Expand Down Expand Up @@ -462,7 +494,7 @@ $ podman pod create --network net1:ip=10.89.1.5 --network net2:ip=10.89.10.10
```

## SEE ALSO
**[podman(1)](podman.1.md)**, **[podman-pod(1)](podman-pod.1.md)**
**[podman(1)](podman.1.md)**, **[podman-pod(1)](podman-pod.1.md)**, **containers.conf(1)**


## HISTORY
Expand Down
11 changes: 11 additions & 0 deletions libpod/container_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -400,3 +400,14 @@ type ContainerMiscConfig struct {
// and if so, what type: always or once are possible non-nil entries
InitContainerType string `json:"init_container_type,omitempty"`
}

type InfraInherit struct {
InfraSecurity ContainerSecurityConfig
InfraLabels []string `json:"labelopts,omitempty"`
InfraVolumes []*ContainerNamedVolume `json:"namedVolumes,omitempty"`
InfraOverlay []*ContainerOverlayVolume `json:"overlayVolumes,omitempty"`
InfraImageVolumes []*ContainerImageVolume `json:"ctrImageVolumes,omitempty"`
InfraUserVolumes []string `json:"userVolumes,omitempty"`
InfraResources *spec.LinuxResources `json:"resources,omitempty"`
InfraDevices []spec.LinuxDevice `json:"device_host_src,omitempty"`
}
36 changes: 23 additions & 13 deletions libpod/container_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,27 @@ func (c *Container) GetInspectMounts(namedVolumes []*ContainerNamedVolume, image
return inspectMounts, nil
}

// GetSecurityOptions retrives and returns the security related annotations and process information upon inspection
func (c *Container) GetSecurityOptions() []string {
ctrSpec := c.config.Spec
SecurityOpt := []string{}
if ctrSpec.Process != nil {
if ctrSpec.Process.NoNewPrivileges {
SecurityOpt = append(SecurityOpt, "no-new-privileges")
}
}
if label, ok := ctrSpec.Annotations[define.InspectAnnotationLabel]; ok {
SecurityOpt = append(SecurityOpt, fmt.Sprintf("label=%s", label))
}
if seccomp, ok := ctrSpec.Annotations[define.InspectAnnotationSeccomp]; ok {
SecurityOpt = append(SecurityOpt, fmt.Sprintf("seccomp=%s", seccomp))
}
if apparmor, ok := ctrSpec.Annotations[define.InspectAnnotationApparmor]; ok {
SecurityOpt = append(SecurityOpt, fmt.Sprintf("apparmor=%s", apparmor))
}
return SecurityOpt
}

// Parse mount options so we can populate them in the mount structure.
// The mount passed in will be modified.
func parseMountOptionsForInspect(options []string, mount *define.InspectMount) {
Expand Down Expand Up @@ -422,16 +443,14 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
hostConfig.GroupAdd = make([]string, 0, len(c.config.Groups))
hostConfig.GroupAdd = append(hostConfig.GroupAdd, c.config.Groups...)

hostConfig.SecurityOpt = []string{}
if ctrSpec.Process != nil {
if ctrSpec.Process.OOMScoreAdj != nil {
hostConfig.OomScoreAdj = *ctrSpec.Process.OOMScoreAdj
}
if ctrSpec.Process.NoNewPrivileges {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, "no-new-privileges")
}
}

hostConfig.SecurityOpt = c.GetSecurityOptions()

hostConfig.ReadonlyRootfs = ctrSpec.Root.Readonly
hostConfig.ShmSize = c.config.ShmSize
hostConfig.Runtime = "oci"
Expand All @@ -456,15 +475,6 @@ func (c *Container) generateInspectContainerHostConfig(ctrSpec *spec.Spec, named
if ctrSpec.Annotations[define.InspectAnnotationInit] == define.InspectResponseTrue {
hostConfig.Init = true
}
if label, ok := ctrSpec.Annotations[define.InspectAnnotationLabel]; ok {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("label=%s", label))
}
if seccomp, ok := ctrSpec.Annotations[define.InspectAnnotationSeccomp]; ok {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("seccomp=%s", seccomp))
}
if apparmor, ok := ctrSpec.Annotations[define.InspectAnnotationApparmor]; ok {
hostConfig.SecurityOpt = append(hostConfig.SecurityOpt, fmt.Sprintf("apparmor=%s", apparmor))
}
}

// Resource limits
Expand Down
2 changes: 2 additions & 0 deletions libpod/define/pod_inspect.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type InspectPodData struct {
BlkioDeviceReadBps []InspectBlkioThrottleDevice `json:"device_read_bps,omitempty"`
// VolumesFrom contains the containers that the pod inherits mounts from
VolumesFrom []string `json:"volumes_from,omitempty"`
// SecurityOpt contains the specified security labels and related SELinux information
SecurityOpts []string `json:"security_opt,omitempty"`
}

// InspectPodInfraConfig contains the configuration of the pod's infra
Expand Down
19 changes: 19 additions & 0 deletions libpod/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -1816,6 +1816,25 @@ func WithSelectedPasswordManagement(passwd *bool) CtrCreateOption {
}
}

// WithInfraConfig allows for inheritance of compatible config entities from the infra container
func WithInfraConfig(compatibleOptions InfraInherit) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return define.ErrCtrFinalized
}
compatMarshal, err := json.Marshal(compatibleOptions)
if err != nil {
return errors.New("Could not marshal compatible options")
}

err = json.Unmarshal(compatMarshal, ctr.config)
if err != nil {
return errors.New("Could not unmarshal compatible options into contrainer config")
}
return nil
}
}

// Pod Creation Options

// WithPodCreateCommand adds the full command plus arguments of the current
Expand Down
3 changes: 3 additions & 0 deletions libpod/pod_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,6 +586,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
var inspectMounts []define.InspectMount
var devices []define.InspectDevice
var deviceLimits []define.InspectBlkioThrottleDevice
var infraSecurity []string
if p.state.InfraContainerID != "" {
infra, err := p.runtime.GetContainer(p.state.InfraContainerID)
if err != nil {
Expand All @@ -603,6 +604,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
infraConfig.UserNS = p.UserNSMode()
namedVolumes, mounts := infra.sortUserVolumes(infra.config.Spec)
inspectMounts, err = infra.GetInspectMounts(namedVolumes, infra.config.ImageVolumes, mounts)
infraSecurity = infra.GetSecurityOptions()
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -678,6 +680,7 @@ func (p *Pod) Inspect() (*define.InspectPodData, error) {
Devices: devices,
BlkioDeviceReadBps: deviceLimits,
VolumesFrom: p.VolumesFrom(),
SecurityOpts: infraSecurity,
}

return &inspectData, nil
Expand Down
1 change: 1 addition & 0 deletions pkg/api/handlers/libpod/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func PodCreate(w http.ResponseWriter, r *http.Request) {
infraOptions := entities.NewInfraContainerCreateOptions() // options for pulling the image and FillOutSpec
infraOptions.Net = &entities.NetOptions{}
infraOptions.Devices = psg.Devices
infraOptions.SecurityOpt = psg.SecurityOpt
err = specgenutil.FillOutSpecGen(psg.InfraContainerSpec, &infraOptions, []string{}) // necessary for default values in many cases (userns, idmappings)
if err != nil {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrap(err, "error filling out specgen"))
Expand Down
4 changes: 3 additions & 1 deletion pkg/domain/entities/pods.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ type PodCreateOptions struct {
Userns specgen.Namespace `json:"-"`
Volume []string `json:"volume,omitempty"`
VolumesFrom []string `json:"volumes_from,omitempty"`
SecurityOpt []string `json:"security_opt,omitempty"`
}

// PodLogsOptions describes the options to extract pod logs.
Expand Down Expand Up @@ -230,7 +231,7 @@ type ContainerCreateOptions struct {
Rm bool
RootFS bool
Secrets []string
SecurityOpt []string
SecurityOpt []string `json:"security_opt,omitempty"`
SdNotifyMode string
ShmSize string
SignaturePolicy string
Expand Down Expand Up @@ -312,6 +313,7 @@ func ToPodSpecGen(s specgen.PodSpecGenerator, p *PodCreateOptions) (*specgen.Pod
s.Hostname = p.Hostname
s.Labels = p.Labels
s.Devices = p.Devices
s.SecurityOpt = p.SecurityOpt
s.NoInfra = !p.Infra
if p.InfraCommand != nil && len(*p.InfraCommand) > 0 {
s.InfraCommand = strings.Split(*p.InfraCommand, " ")
Expand Down
Loading

0 comments on commit 2892703

Please sign in to comment.