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

specs: Add minimum raw security profiles needed by plugins to ContainerSpec and PluginSpec #1964

Closed
wants to merge 1 commit into from

Conversation

cyli
Copy link
Contributor

@cyli cyli commented Feb 17, 2017

This adds per-architecture security profiles to the ContainerSpec (it would also have to be added the PluginSpec). These are currently the minimum options needed in security profiles to unblock plugins. This does not cover all the security options that docker run supports.

The linux raw security profile came from the documented plugin config file, under the "Linux" section. Networks, mounts, env vars, and args I assume can also already be mapped to existing ContainerSpec or ServiceSpec fields.

I have not managed to find out what else should go into a raw windows security profile.

This continues the work done in #1944, but is currently only the specs, and not any kind of implementation.

cc @diogomonica @ehazlett @aluzzardi @tiborvass

@cyli cyli force-pushed the caps-in-service-spec branch from c8d3cff to 6aa749c Compare February 17, 2017 04:13
@codecov-io
Copy link

codecov-io commented Feb 17, 2017

Codecov Report

Merging #1964 into master will increase coverage by 0.15%.
The diff coverage is n/a.

@@            Coverage Diff             @@
##           master    #1964      +/-   ##
==========================================
+ Coverage   53.47%   53.62%   +0.15%     
==========================================
  Files         109      109              
  Lines       18919    18919              
==========================================
+ Hits        10116    10146      +30     
+ Misses       7570     7535      -35     
- Partials     1233     1238       +5

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update be6e3d3...76b143b. Read the comment docs.

api/types.proto Outdated
}
}

// WindowsRawSecurityProfile provides any low level privileges a windows container needs
Copy link
Contributor

Choose a reason for hiding this comment

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

s/any/all ?

api/types.proto Outdated
repeated string capabilities = 1;

// Devices needed by the service
repeated Device devices = 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

does it make sense to have Devices if the only thing that it contains is a path string?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point - I left it in because I wasn't sure if we'd need anything else. https://github.com/opencontainers/runtime-spec/blob/master/config-linux.md#devices has a bunch of other options, but https://docs.docker.com/engine/extend/config/ only has the name, description, and path. (I figured the name and description are probably not necessary, but wasn't sure)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Do any plugins require bind mounts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, mounts is an option - ContainerSpec already has the Mounts field, though, so I thought that could be used instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Or are you suggesting that devices could also use the Mounts field?

Copy link
Contributor

@ehazlett ehazlett Feb 17, 2017

Choose a reason for hiding this comment

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

I would think we would need at least the type, path and major,minor for device support. /cc @justincormack

Copy link
Contributor

Choose a reason for hiding this comment

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

Docker (as opposed to runc) reads the device information off the host device (so you cannot create a device in the container which does not exist on the host, which is normally ok). It does need the rwm options for the device cgroups as well though, so another string.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added, thanks @justincormack

@diogomonica
Copy link
Contributor

Is this supposed to cover the minimum essential to unlock swarm plugins?

@cyli
Copy link
Contributor Author

cyli commented Feb 17, 2017

@diogomonica Yes, that is the goal. Let me update the description and title.

@cyli cyli changed the title specs: Add security profiles to ContainerSpec specs: Add minimum raw security profiles needed by plugins to ContainerSpec Feb 17, 2017
@cyli cyli force-pushed the caps-in-service-spec branch 2 times, most recently from 6ab5d00 to 5607598 Compare February 17, 2017 04:42
api/specs.proto Outdated
@@ -264,6 +264,9 @@ message ContainerSpec {
// task will exit and a new task will be rescheduled elsewhere. A container
// is considered unhealthy after `Retries` number of consecutive failures.
HealthConfig healthcheck = 16;

// SecurityProfiles specifies per-architecture security options required by the container
SecurityProfiles security_profiles = 21;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this the right wording? My understanding was that security profiles would be high-level privilege grants, but ServiceSpecs would contain low level capabilities.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure what the right wording should be. My understanding is similar, in that was that these would be low level, and security profiles would be high level grants that would map to low level capabilities.

I believe the current plan is to mapped on the CLI side, but possibly we'd need support for the mapping later in swarm (@aluzzardi brought up the point that it's easier to change types and versions of things in swarm than it is to change CLI option behavior).

Copy link
Contributor

@diogomonica diogomonica Feb 17, 2017

Choose a reason for hiding this comment

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

The major problem w/ it being in swarm is the expectation between service creation across multiple versions of the mapping.

if a service worked by doing docker service create --grant=networking my-service, and we change swarm's mapping server-side, that same cmd-line might not work in a future version of swarm.

@aaronlehmann
Copy link
Collaborator

aaronlehmann commented Feb 17, 2017 via email

@diogomonica
Copy link
Contributor

@aaronlehmann @cyli yeah, I think aggregating this into a PrivilegeProfile or something of the sort might make sense.

@cyli cyli force-pushed the caps-in-service-spec branch from 5607598 to 24b72b5 Compare February 17, 2017 17:59
@cyli
Copy link
Contributor Author

cyli commented Feb 17, 2017

Just wondering if we should centralize the declarations of what elevated privileges a service requires, including bind mounts.

I've deprecated the mounts in ContainerSpec, and moved it to the per-architecture specific profiles for now. I guess we need to be able to read from both for a while?

I think aggregating this into a PrivilegeProfile or something of the sort might make sense.

Renamed everything PrivilegeProfile instead of SecurityProfile

@aaronlehmann
Copy link
Collaborator

I've deprecated the mounts in ContainerSpec, and moved it to the per-architecture specific profiles for now. I guess we need to be able to read from both for a while?

I'm not sure we want to deprecate Mounts in ContainerSpec. I envisioned having actual mount instructions in ContainerSpec, but having mount privileges in a separate place that can easily be checked by some future authorization code. The agent would refuse to act on any mounts that aren't authorized by the privileges structure. I may be thinking about this the wrong way and encouraging an excessively complicated solution. I'd be curious to hear what @diogomonica thinks.

@diogomonica
Copy link
Contributor

@aaronlehmann having privileges in one place, and actual mount requests in a different place, is a recipe for authZ problems.

The most obvious example being the creation of a service spec that doesn't request privileges, but includes mounts, and the authz code merely checks if privileges for mount were requested, allowing it to pass by unchecked.

api/types.proto Outdated
repeated Mount mounts = 1 [(gogoproto.nullable) = false];

// Linux capabilities required by the container
repeated string capabilities = 2;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rather than string, should we just enumerate the caps listed here: https://github.com/opencontainers/runc/blob/master/libcontainer/SPEC.md#security ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you proposing it actually being an enum? What would be the path for dealing with changes in capabilities?

Slightly concerned that inspecting profiles directly becomes a bit harder, but it will definitely be a lot more compressed on the wire this way.

Copy link
Contributor Author

@cyli cyli Feb 17, 2017

Choose a reason for hiding this comment

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

If more capabilities were added, then we could add them to the enum? Are capabilities in linux every deprecated/removed?

I don't feel strongly that it should be an enum - just thought it'd be easier to check if there were invalid capabilities, etc. I'm fine with leaving it a string.

Copy link
Contributor

Choose a reason for hiding this comment

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

nothing in Linux is ever removed. They might become useless eventually. If you are going to use an enum you should probably use the real values http://lxr.free-electrons.com/source/include/uapi/linux/capability.h#L96 onwards

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm down w/ enum

@justincormack
Copy link
Contributor

Sorry what "mount privileges" are being discussed?

@cyli cyli force-pushed the caps-in-service-spec branch from 24b72b5 to 654985c Compare February 21, 2017 23:14
@cyli
Copy link
Contributor Author

cyli commented Feb 21, 2017

@justincormack @diogomonica Added the caps as an enum on the profile. PTAL

So do the mount instructions in the privileges section make sense, or should I move them back to container spec?

@cyli cyli force-pushed the caps-in-service-spec branch 3 times, most recently from 2f11893 to 0ad78b5 Compare February 21, 2017 23:37
api/types.proto Outdated
@@ -883,4 +883,4 @@ message MaybeEncryptedRecord {
Algorithm algorithm = 1;
bytes data = 2;
bytes nonce = 3;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Final newline got removed here

@aaronlehmann
Copy link
Collaborator

So do the mount instructions in the privileges section make sense, or should I move them back to container spec?

I don't think they make sense in the privileges section, because they include a lot that's not related at all to privileges, such as target path inside the container, and driver options.

My thought here was to keep the mount instructions where they are now, but require a corresponding privilege grant in PrivilegeProfiles for each one. These grants could be checked by authZ code. #1964 (comment)

@diogomonica didn't seem positive about this:

having privileges in one place, and actual mount requests in a different place, is a recipe for authZ problems.

The most obvious example being the creation of a service spec that doesn't request privileges, but includes mounts, and the authz code merely checks if privileges for mount were requested, allowing it to pass by unchecked.

My thinking about this case is that the agent must refuse to act on any mount instructions that aren't accompanied by a privilege grant.

@cyli cyli force-pushed the caps-in-service-spec branch 2 times, most recently from 8e9adc2 to 3cdbd23 Compare February 22, 2017 00:42
@diogomonica
Copy link
Contributor

If you feel strongly about it, I'm ok w/ that tradeoff @aaronlehmann

@cyli
Copy link
Contributor Author

cyli commented Feb 22, 2017

Since both have to come through the specs, one in the container spec, one in the privilege profiles which are also in the container spec, would that be just copying the same stuff in 2 places? Since both have to come from the user?

@aaronlehmann
Copy link
Collaborator

If you feel strongly about it, I'm ok w/ that tradeoff

No, I don't feel strongly about it. Just trying to find the best tradeoff. The privilege profiles don't seem like the right place to place detailed mount instructions with driver options and so on. And it doesn't seem right either to have authZ code look into the ContainerSpec to see what mounts a service is requesting and make sure those mounts are okay. But I'm not sure what's best here and none of the options would be horrible for me.

Since both have to come through the specs, one in the container spec, one in the privilege profiles which are also in the container spec, would that be just copying the same stuff in 2 places? Since both have to come from the user?

It would be slightly redundant but the ContainerSpec would include detailed parameters for the mount, and PrivilegeProfile would only say "this service wants to mount /path".

// Devices needed by the service
repeated Device devices = 3;

// Rather than provide a list of all devices, just mount every device on the node
Copy link
Contributor

Choose a reason for hiding this comment

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

If this is the equivalent of allow-all-devices, then the comment should read allow read write and modify access to all devices on the node.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also better to rename the boolean to allow-all-devices

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do, thanks!

@anusha-ragunathan
Copy link
Contributor

PR takes care of adding the profiles to PluginSpec as well. Can you please update the commit title and description accordingly?

@tiborvass
Copy link

So I have an important bikeshedding problem #oxymoron.

First, PrivilegeProfile make me think that everything that is privileged is in there, but I am not sure if that's the case. Bind mounts? I start to think it's more like a HostConfig.

I also wonder if we shouldn't just not have a name at all and simply have LinuxCapabilities under a Linux field. Simply embed in ContainerSpec the capabilities and devices field, and same for pluginspec.

I can't seem to find a satisfying solution :S



// PrivilegeProfiles specifies per-architecture security configuration/permissions
message PrivilegeProfiles {

Choose a reason for hiding this comment

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

If we decide to go with this name, shouldn't this be singular?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's plural because it has profiles for both windows and linux.

@diogomonica
Copy link
Contributor

@tiborvass where will you put the sec comp profile? Inside LinuxCapabilities?

@tiborvass
Copy link

tiborvass commented Feb 22, 2017

@diogomonica a field named Seccomp of type LinuxSeccomp, under Linux field of the spec.

@diogomonica
Copy link
Contributor

/shrug

@tiborvass
Copy link

@diogomonica basically I'm wondering if it's fine to not "bundle" the various fields like Capabilities, Devices, Seccomp into one object that we have trouble finding a name for because it wouldn't be complete.

@diogomonica
Copy link
Contributor

@aluzzardi has opinions

@cyli cyli changed the title specs: Add minimum raw security profiles needed by plugins to ContainerSpec specs: Add minimum raw security profiles needed by plugins to ContainerSpec and PluginSpec Feb 22, 2017
@cyli
Copy link
Contributor Author

cyli commented Feb 22, 2017

@tiborvass: just to summarize, is your proposal:

message ContainerSpec {
    ...
    LinuxOptions linux
    WindowsOptions windows
}

message LinuxOptions {
    repeated Capabilities capabilities
    repeated Devices devices
    bool allow_all_devices
}

message WindowsOptions {
    string credential_specs
}

And similarly for plugin spec? (I have no strong opinions - happy to change if folks feel this works better)

@tiborvass
Copy link

@cyli yes. Not saying that's the best thing. Just that, we did something similar for plugins. If we are happy with a name for PrivilegeProfile then that's fine too.

@aluzzardi
Copy link
Member

Considering this is flat in docker/docker (the platform part), should we do the same here? e.g. have Capabilities at the top level which would be ignored by windows.

@cyli
Copy link
Contributor Author

cyli commented Feb 23, 2017

My preference, without any additional context, is have it in sub objects, mainly because there'd be a lot of duplication otherwise between the plugin spec and the container spec.

Within the context of translatation from swarm to docker, it seems like some translation already needs to happen for a full list of capabilities -> CapAdd and CapDrop, and from strings to the enum.

Alternately, do we want just want to copy and paste CapAdd, CapDrop (repeated strings), and Devices from the HostConfig for easier translation, instead of providing the full list of capabilities? The plugin config looks like it specifies only CapAdd: https://github.com/docker/docker/blob/master/plugin/v2/plugin_linux.go#L118.

@diogomonica
Copy link
Contributor

@aluzzardi shouldn't this be in TaskSpec instead of PluginSpec? Particularly if this will be shared by ContainerSpec later for services.

@cyli
Copy link
Contributor Author

cyli commented Feb 23, 2017

@diogomonica Oh that's true - it could go in the TaskSpec instead of both the ContainerSpec and PluginSpec - it just wouldn't apply to the NetworkAttachmentSpec runtime.

So are we ok with just going with CapAdd and CapDrop instead of the full list of Capabilities?

@diogomonica
Copy link
Contributor

@cyli is the goal to allow some kind of default? I'm worried that by going w/ cap add and cap drop we don't get to a world where the AuthZ plugin has all the information needed to do it's job, and has to rely on some external knowledge of what the current "default" is, and if current denied capability Y is enabled by not dropping it.

@cyli
Copy link
Contributor Author

cyli commented Feb 24, 2017

@diogomonica Yes, to allow the docker default, and also to make translation easier with the docker.

Agree that it's not ideal that the authz plugin would have to know about what the current docker default is, and also this means that upgrading a docker version could potentially what capabilities a service is configured with (although that's currently the case already I think).

Although possibly #1744 could help with that (if the interpolated specs interpolated the defaults (and I guess had an extra field that was the full list of capabilities?)

@diogomonica
Copy link
Contributor

Why are we trying not o have the full list of caps in the first place?

@justincormack
Copy link
Contributor

justincormack commented Feb 26, 2017 via email

@diogomonica
Copy link
Contributor

@justincormack shouldn't we have a mechanism to provide the recommended full profile an image has to run with? Ideally this would come inside of the image itself, when pulling from the hub, but adding it to the API and having the remote AuthZ plugin do the intersection between both might not be a bad way to go forward.

@cyli
Copy link
Contributor Author

cyli commented Mar 23, 2017

Just double-checking - should this be closed? Are we going to go with opaque plugin blobs and maybe Docker's HostConfig instead?

@aluzzardi
Copy link
Member

Isn't this related to profiles, in a way? We'll probably have to have something similar somewhere

@cyli
Copy link
Contributor Author

cyli commented Mar 24, 2017

@aluzzardi Profiles/high level grants I think are going to be mainly a CLI mapping for now. Possibly we want to update the HostConfig in Docker eventually? cc @diogomonica

@aaronlehmann
Copy link
Collaborator

I sort of lost track of how this fits in with everything else. It seems to overlap with #2075, but #2075 did not add the capabilities. If I understood correctly, capabilities are a hard requirement for 17.06. It sounds like we should either resurrect this to add the capabilities or open something separate, perhaps drawing on the work that took place here.

cc @aluzzardi

@cyli
Copy link
Contributor Author

cyli commented Jul 15, 2017

I think this is no longer needed as plugins will be an opaque GenericRuntimeSpec and others should use https://github.com/docker/libentitlement.

@cyli cyli closed this Jul 15, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants