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

add cli integration for masked and readonly paths #1347

Closed
wants to merge 1 commit into from

Conversation

jessfraz
Copy link

@jessfraz jessfraz commented Sep 6, 2018

I wanted to make sure this design was okay before going any further.

This adds flags --masked-paths and --readonly-paths to the cli as a follow up from moby/moby#36644 cc @AkihiroSuda

Happy to change the design in any way you want then will add docs and tests.

@@ -183,6 +187,8 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
flags.StringVarP(&copts.user, "user", "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
flags.StringVarP(&copts.workingDir, "workdir", "w", "", "Working directory inside the container")
flags.BoolVar(&copts.autoRemove, "rm", false, "Automatically remove the container when it exits")
flags.Var(&copts.maskedPaths, "masked-paths", "Denote the paths to be masked for the container, empty implies none")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

empty implies default, not "none"?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It implies none, of "paths to be masked for the containers"

@@ -50,6 +50,19 @@ func TestRunWithContentTrust(t *testing.T) {
})
}

func TestRunMaskedPaths(t *testing.T) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WIP?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Especially we need to make sure nil and []string{} are treated differently

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah was about to add tests but waited also im confused as to if the tests from docker/docker will be moved here too?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jessfraz new tests from docker/docker should only test the API — or be unit tests 😝). Any tests using the cli should indeed be there.

for _, p := range paths {
if p == "none" {
if len(paths) > 1 {
return nil, errors.New("Passing 'none' and other paths is not allowed")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: error string should not be capitalized

@rroller
Copy link

rroller commented Oct 1, 2018

Any update on this and if it'll get merged?

@AkihiroSuda
Copy link
Collaborator

Can we also have --unmask-proc for simplicity?

@tiborvass
Copy link
Collaborator

@jessfraz @AkihiroSuda @vdemeester So I know this may be controversial but what do you think of putting these behind --security-opt like so --security-opt readonly-paths=... and --security-opt masked-paths=... ?

I know it's ugly because in the API it's not a security opt, but the rationale for this suggestion is that it's not necessarily obvious for users that this may have a security implication as defaults are overridden.

If we agree on this, we could have the API accept either security opts or regular run options.

Let me know what you think!

@AkihiroSuda
Copy link
Collaborator

AkihiroSuda commented Oct 12, 2018

FYI: it turned out that unshare -rmn mount -t sysfs none /sys (for /sys/class/net) requires rw/unmasked sysfs

rootless-containers/rootlesskit#23

@AkihiroSuda
Copy link
Collaborator

Maybe:

  • --security-opt readonly-paths (low-level, rarely used)
  • --security-opt masked-paths (ditto)
  • --security-opt unconfined-paths (frequently used as --security-opt unconfined-paths=/proc,/sys)

@thaJeztah
Copy link
Member

If we agree on this, we could have the API accept either security opts or regular run options.

Wondering if the API must reflect the UX, I don't think that's strictly required.

--security-opt unconfined-paths (frequently used as --security-opt unconfined-paths=/proc,/sys)

@AkihiroSuda wondering how that option would work in conjunction with the other options; should we error (conflicting options)?

I recall the original discussion on the API side of things that we preferred explicit over implicit, so providing your own set of "masked" and/or "read only" paths. That was of course from the API perspective, so UX can differentiate from that.

If we use unconfined-paths; how would the CLI determine the default set of masked paths? (I don't think there's currently an endpoint that would allow querying the default set from the daemon, other than inspecting an already created container)

@jessfraz
Copy link
Author

I'm okay with any of the options listed above :)

@tonistiigi
Copy link
Member

--security-opt unconfined-paths (frequently used as --security-opt unconfined-paths=/proc,/sys)

I don't think you can actually do --security-opt unconfined-paths=/proc,/sys because the API only supports whitelist and modifications to the default set are not allowed. Not sure if there is any usecase for actually specifying a special path from CLI though as it is quite an effort required from the user to remember to whole list of possibly insecure paths. Usually you just want to either allow all or make an excpetion to the default. How about just --security-opt systempaths=unconfined. (or protectedpaths, securitypaths, ...)

@tiborvass
Copy link
Collaborator

@tonistiigi If it's systempaths=unconfined then what's the other value for systempaths= ? confined ?

@tonistiigi
Copy link
Member

@tiborvass There is no other value. If we want then confined would mean the daemon default and if there is a good usecase we could add more names. I'm fine with a constant value. I noticed that --security-opt no-new-privileges=false uses a bool so we could use that as well.

@scher200
Copy link

@tonistiigi how is this going? I am exited to see this working

@tonistiigi
Copy link
Member

How about just --security-opt systempaths=unconfined. (or protectedpaths, securitypaths, ...)
or --security-opt unmaskedsystempaths=true --security-opt rawsystempaths=true

Does anyone have objections to this? I'm good with any of them.

@thaJeztah Might be good to add this to maintainer session today.

@thaJeztah
Copy link
Member

Does anyone have objections to this? I'm good with any of them.

UX-wise, I like that option, so (name to be discussed);

--security-opt systempaths=unconfined

Would send the equivalent of --masked-paths=[]

Concern:

  • systempaths=unconfined would disable all masked paths
  • because of the above, doing the wrong thing ("just unmask the whole shebang) is easier than doing the right thing ("specify which paths you want to unmask")

I think it's important when dealing with security configuration to make "doing the right thing" easier than "doing the wrong thing".

So; do we also want to provide a more fine-grained approach on the CLI; an option to manually provide exactly which paths to mask/mark readonly?

If yes: that would raise the question #1347 (comment)

how would the CLI determine the default set of masked paths? (I don't think there's currently an endpoint that would allow querying the default set from the daemon, other than inspecting an already created container)

Approach could then be;

Implement a defaults endpoint for containers (I think that's useful for other purposes as well, such as showing defaults for flags/options; especially if those defaults are configurable on the daemon), for example;

  • GET /v1.40/containers/-/defaults (- indenting as "no id" ? idk)
  • GET /v1.40/containers/-/json (ugh .. the trailing /json sucks haha)

When creating a container;

  1. Fetch the defaults
  2. Patch the defaults with changes from the CLI (?) (---security-opt unconfined-paths=/proc,/sys)
  3. Send the resulting masked-paths and readonly-paths over the API

@justincormack @jessfraz I know you're better at security than I am, so wondering what you think, or what suggestions you have 😅

Adding this to next week's maintainers meeting as well (this week didn't happen, due to many people travelling or at KubeCon)

@justincormack
Copy link
Member

I don't think setting the defaults makes sense, it is too confusing for different people to have different defaults. A security option to remove them all seems ok, and an API option to set them, and maybe a security option eg systempaths=/path1,/path2,... although its going to be hard to drive. Unconfined seems the most likely case and most consistent eg with seccomp.

@imbolo
Copy link

imbolo commented Dec 29, 2018

Any update ?

@scher200
Copy link

when in this expected to be released?

@tiborvass
Copy link
Collaborator

Let's roll with --security-opt systempaths=unconfined and call it a day. We can add more things later. If no one answers in disagreement, I'll consider it an agreement. Ping @thaJeztah @justincormack

@biblix
Copy link

biblix commented Mar 26, 2019

Hi @jessfraz, https://github.com/genuinetools/img#running-with-docker led me here. While this PR is still pending, is there a way to take your fix here and test img build in a unprivileged container in Kubernetes?

@thaJeztah
Copy link
Member

Let's roll with --security-opt systempaths=unconfined and call it a day. We can add more things later. If no one answers in disagreement, I'll consider it an agreement.

OK, so;

  • --security-opt systempaths=unconfined would set masked-paths=[] and readonly-paths=[]
  • no option yet to set them individually
  • no option yet to set an individual list of paths to (un)mask, make read-only/writable

Correct?

@tiborvass
Copy link
Collaborator

@thaJeztah yes. cc @justincormack

@vdemeester
Copy link
Collaborator

Needs a rebase 😅

@thaJeztah
Copy link
Member

Needs a rebase 😅

Also needs an actual implementation of the proposed changes #1347 (comment)

@tiborvass were you planning on making those?

Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me "request changes" pending the proposed changes 😅

@jessfraz
Copy link
Author

jessfraz commented Apr 4, 2019

ah okay is this on me? I can do that

@tiborvass
Copy link
Collaborator

@jessfraz I was about to do it but feel free!

@thaJeztah
Copy link
Member

@tiborvass @jessfraz I see @martencassel started working on the implementation; see #1808

@jessfraz
Copy link
Author

jessfraz commented Apr 6, 2019 via email

@elgalu
Copy link
Contributor

elgalu commented May 30, 2019

#1808 is merged

@tiborvass
Copy link
Collaborator

Thank you @jessfraz and @martencassel !

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

Successfully merging this pull request may close these issues.