Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Docker engine does not support the parameter "--security-opt seccomp=" when executing command "docker build" #34454

Closed
chenquanzhao opened this issue Aug 9, 2017 · 15 comments

Comments

@chenquanzhao
Copy link

Description

Steps to reproduce the issue:
You can execute the command "docker build", and append the parameter "--security-opt seccomp=[SECCOMP PROFILE]" in the Linux or macOS system.

Describe the results you received:
Thus it emits the following error message:
Error response from daemon: the daemon on this platform does not support --security-opt to build

Describe the results you expected:
The command "docker build" can support the parameter "--security-opt seccomp=" when building docker image from Dockerfile in the macOS or Linux system.

Additional information you deem important (e.g. issue happens only occasionally):
Otherwise, I saw the docker engine source code (v17.06), and it has been set the SecurityOpt in HostConfig when executing RUN instruction. However, why should check the runtime OS type, and it must be windows platform in the newImageBuildOptions method?

The code is:

if runtime.GOOS != "windows" && options.SecurityOpt != nil {
	return nil, fmt.Errorf("the daemon on this platform does not support --security-opt to build")
}
func (b *Builder) create(runConfig *container.Config) (string, error) {
	resources := container.Resources{
		CgroupParent: b.options.CgroupParent,
		CPUShares:    b.options.CPUShares,
		CPUPeriod:    b.options.CPUPeriod,
		CPUQuota:     b.options.CPUQuota,
		CpusetCpus:   b.options.CPUSetCPUs,
		CpusetMems:   b.options.CPUSetMems,
		Memory:       b.options.Memory,
		MemorySwap:   b.options.MemorySwap,
		Ulimits:      b.options.Ulimits,
	}

	// TODO: why not embed a hostconfig in builder?
	hostConfig := &container.HostConfig{
		SecurityOpt: b.options.SecurityOpt,
		Isolation:   b.options.Isolation,
		ShmSize:     b.options.ShmSize,
		Resources:   resources,
		NetworkMode: container.NetworkMode(b.options.NetworkMode),
		// Set a log config to override any default value set on the daemon
		LogConfig:  defaultLogConfig,
		ExtraHosts: b.options.ExtraHosts,
	}

	// Create the container
	c, err := b.docker.ContainerCreate(types.ContainerCreateConfig{
		Config:     runConfig,
		HostConfig: hostConfig,
	})
	if err != nil {
		return "", err
	}
	for _, warning := range c.Warnings {
		fmt.Fprintf(b.Stdout, " ---> [Warning] %s\n", warning)
	}

	b.tmpContainers[c.ID] = struct{}{}
	fmt.Fprintf(b.Stdout, " ---> Running in %s\n", stringid.TruncateID(c.ID))
	return c.ID, nil
}

Output of docker version:

Server:
 Version:      17.06.0-ce
 API version:  1.30 (minimum version 1.12)
 Go version:   go1.8.3
 Git commit:   02c1d87
 Built:        Fri Jun 23 21:51:55 2017
 OS/Arch:      linux/amd64
 Experimental: true

Output of docker info:

Containers: 0
 Running: 0
 Paused: 0
 Stopped: 0
Images: 29
Server Version: 17.06.0-ce
Storage Driver: overlay2
 Backing Filesystem: extfs
 Supports d_type: true
 Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
 Volume: local
 Network: bridge host ipvlan macvlan null overlay
 Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: cfb82a876ecc11b5ca0977d1733adbe58599088a
runc version: 2d41c047c83e09a6d61d464906feb2a2f3c52aa4
init version: 949e6fa
Security Options:
 seccomp
  Profile: default
Kernel Version: 4.9.36-moby
Operating System: Alpine Linux v3.5
OSType: linux
Architecture: x86_64
CPUs: 4
Total Memory: 1.952GiB
Name: moby
ID: NL37:KZKS:2644:6E6R:2C4J:GYYZ:MHIO:NBKB:ESQ6:D7UT:JYWP:4FHF
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): true
 File Descriptors: 17
 Goroutines: 28
 System Time: 2017-08-09T01:25:51.531480835Z
 EventsListeners: 1
Registry: https://index.docker.io/v1/
Experimental: true
Insecure Registries:
 127.0.0.0/8
Live Restore Enabled: false

Additional environment details (AWS, VirtualBox, physical, etc.):

@chenquanzhao
Copy link
Author

@cpuguy83 help……

@cpuguy83
Copy link
Member

cpuguy83 commented Aug 9, 2017

Because the only security-opt that's supported on build is Windows specific (credentialspec)

@chenquanzhao
Copy link
Author

@cpuguy83 I have a problem that I need the specific seccomp profile when executing docker build to prevent system vulnerability, such as CVE-2017-7533. I need to disable inotify_init and inotify_init1 syscall, and how can i do that?

@cpuguy83
Copy link
Member

cpuguy83 commented Aug 9, 2017 via email

@chenquanzhao
Copy link
Author

@cpuguy83 OK. Thank you……
But I have a question that why is it supported for docker run, but not supported for docker build?

@cpuguy83
Copy link
Member

@CasonChan The builder is a bit touchy in that we don't want the builder to be able to produce non-portable images. Allowing full access to --security-opt on build can open this up.... this is a little bit moot because someone can just change the daemon options and build bad images, but...

@thaJeztah
Copy link
Member

Looks like this question is answered, so closing this issue

@vabburi
Copy link

vabburi commented Jun 22, 2018

I'm trying to build a docker image for centos:7 that restricts system commands which any user (including root) can execute inside a docker machine. My intention is that I want to build an docker image with security profile that I need and then use that as my base image to build other application images thereby inheriting security profile from the base image. Is this doable? Am I missing something?
Here is a sample security profile I'm testing:

{ "defaultAction" : "SCMP_ACT_ALLOW", "syscalls": [ { "name": "mkdir", "action": "SCMP_ACT_ERRNO" }, { "name": "chown", "action":"SCMP_ACT_ERRNO" } ] }

Output of docker version:
Client:
Version: 18.03.1-ce
API version: 1.37
Go version: go1.9.4
Git commit: 3dfb834
Built: Thu May 24 22:21:27 2018
OS/Arch: linux/amd64
Experimental: false
Orchestrator: swarm

Server:
Engine:
Version: 18.03.1-ce
API version: 1.37 (minimum version 1.12)
Go version: go1.9.4
Git commit: 7390fc6/18.03.1-ce
Built: Thu May 24 22:22:43 2018
OS/Arch: linux/amd64
Experimental: false

Output of docker info:
Containers: 18
Running: 1
Paused: 0
Stopped: 17
Images: 146
Server Version: 18.03.1-ce
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file logentries splunk syslog
Swarm: inactive
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 773c489c9c1b21a6d78b5c538cd395416ec50f88
runc version: 4fc53a81fb7c994640722ac585fa9ca548971871
init version: 949e6fa
Security Options:
seccomp
Profile: default
Kernel Version: 4.14.47-56.37.amzn1.x86_64
Operating System: Amazon Linux AMI 2018.03
OSType: linux
Architecture: x86_64
CPUs: 40
Total Memory: 157.4GiB
Docker Root Dir: /var/lib/docker
Debug Mode (client): false
Debug Mode (server): false
Registry: https://index.docker.io/v1/
Labels:
Experimental: false
Insecure Registries:
Live Restore Enabled: false

@rdebath
Copy link

rdebath commented Jul 15, 2020

@cpuguy83 This is a lot moot as most people would see that error and simply change their dockerfile to:

FROM scratch
ADD image.tar.gz /
CMD ["whatever"]

@mnn
Copy link

mnn commented Aug 10, 2021

you can supply a custom default profile to the daemon.
`--secomp-profile /path/to/profile.json'

@cpuguy83 How?

# sudo docker build -t test . --secomp-profile test.json
unknown flag: --secomp-profile
See 'docker build --help'.

And what is the equivalent of --security-opt seccomp:unconfined in the json file?

This is getting ridiculous, I am just trying to update a recent ubuntu via apt-get update (in image) and I have to jump through so many hoops to do it? I am starting to wonder if docker wasn't a giant mistake... https://askubuntu.com/questions/1263284/apt-update-throws-signature-error-in-ubuntu-20-04-container-on-arm

@thaJeztah
Copy link
Member

It's an option on the daemon, so needs to be set either in the systemd unit file, or in the daemon.json configuration file for the daemon; https://docs.docker.com/engine/reference/commandline/dockerd/#daemon-configuration-file

but doing so will disable seccomp for all containers and I don't think the option currently passed through to docker build with BuildKit enabled.

And what is the equivalent of --security-opt seccomp:unconfined in the json file?

The daemon currently does not support the "named" profiles (and thus, doesn't accept unconfined until #42481 is merged/released), but you can instead create an file containing an empty JSON profile ({}) and set the location of the file as the profile.

I am just trying to update a recent ubuntu via apt-get update (in image) and I have to jump through so many hoops to do it?

What version of docker, containerd and runc are you running? I think those issues should be fixed in current patch releases.

@orodbhen
Copy link

orodbhen commented Dec 9, 2022

I fail to see how this is an image portability issue. Analogously, why would you need the same privileges to build a system as to run a process on that system? What do you do in environments where container developers have to have some kind of restrictions set? You can do this using an AuthZ plugin, or supposedly that was the intent. You can say, seccomp:unconfined is fine for build commands, but not for running. But not if it doesn't except that argument.

Basically, you have two options:

  • Never build and run on the same system
  • Require docker create always pass a more more restrictive profile than the default

You can require containers to run as non-root. But how would you prevent a container from running the su command and becoming root? All they have to do is build an image with a root password set. You can disable setresuid and the like in the profile, but then you wouldn't be able to build images anymore. Even K8s RBACs can't prevent this, as far as I'm aware.

I mean, you can use user namespaces, but those are clunky and difficult to manage on a multi-host system. Why use a client/server model, if there's so little support for actually restricting access?

@rdebath
Copy link

rdebath commented Dec 13, 2022

As I understand it this class of errors comes about because docker (slightly) mis-uses host system security filters. Because libseccomp2 is designed as a hard security filter, unknown OS calls are changed from ENOSYS to a permission denied. This breaks the C library because it uses the ENOSYS return to probe the OS calls available.

Neither libseccomp2 library nor libc will likely change their default responses because it would break the primary use case of these security filters (and/or the required error reporting). So, IMO, what should happen is that Docker should setup security filters that mark system calls that Docker doesn't know about to return ENOSYS rather than the default permission error.

This will have the effect that later versions of libc within the Docker VM will see a system call list that looks like the version of the kernel that Docker knows about and so they will fallback cleanly to support that older kernel.

@thaJeztah
Copy link
Member

There's two/three related, but distinct issues discussed in this ticket;

  1. docker build does not allow for a seccomp profile to be set for containers used during build (through --security-opt)
  2. docker build, when using BuildKit as builder, always uses the default seccomp profile, and does not inherit the daemon's setting.
  3. The default seccomp profile currently uses EPERM for syscalls that are blocked, which can cause some binaries to not fall back to alternatives (whereas ENOSYS would)

For the last one (3.), there's an open ticket, which hasn't been revisited in some time, but came up in recent discussions. While changing the default to ENOSYS is something we think is worth considering, the devil can be in the detail, and this needs to be looked into. If you're interested in that topic or have input that would help, feel free to participate on the ticket;

For 1. (the original request reported in this ticket), and 2., the best place to continue that conversation would be in the BuildKit repository, as this is where this would have to be implemented (first). There's a couple of issues that would have to be discussed (and UX to be worked on);

  • The BuildKit maintainers started work on re-designing security options for build; the intent is to make the Dockerfile more declarative on what's needed to perform the build. If a specific step in the Dockerfile requires specific privileges (which could be networking or other options), those can be defined as an option on the RUN command. This approach both allows for such options to be applied more granular (i.e., only for specific steps in the Dockerfile), and making the Dockerfile more descriptive (a user building the Dockerfile needs to grant the permissions, whereas previously the build could fail for "unclear reasons" if, for example, networking was required, but the build was started without --network=<option>). This feature is not final yet (the "labs" version of the Dockerfile syntax allows for some --security options. It does not yet allow seccomp options to be set, but does allow for "privileged" steps (be careful using those, as it effectively disables all protection)); see RUN --security in the documentation.
  • For (custom) seccomp profiles to be supported (or some other way to define what syscalls should be (un)blocked), this would likely have to be implemented through such an option, but the UX may need input / brainstorming (how to pass the (custom) profile? seccomp profiles can be difficult to write; perhaps there's a more convenient way to declare what's needed?). If you're interested in this feature, and perhaps have ideas on the UX / design, I encourage you to open a ticket in the BuildKit issue tracker (https://github.com/moby/buildkit/issues) (and add a link to this ticket).
  • For inheriting the (custom) profile as set on the daemon; this is something that would (I think) also have to be implemented in BuildKit, and have to be decided on by the BuildKit maintainers; if this is something you'd like to see implemented, I would recommend creating a separate ticket from the previous one, as it may need additional discussion: from discussions I had with the maintainers, there were some concerns, as this could lead to more "works on my machine" situations for docker build (depending on what's configured on the daemon), which is why their preference was to make security options part of the Dockerfile. That said, "I want to enforce a stricter profile" could be a compelling case, so perhaps they're open to discussing.

@xMAC94x
Copy link

xMAC94x commented May 9, 2023

--secomp-profile

--seccomp-profile
with 2 c, because i just spend 10 minutes figuring out what was wrong :) seems to work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants