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

[carry 2663] Add capabilities support to stack/service commands #2687

Merged
merged 4 commits into from
Sep 8, 2020

Conversation

thaJeztah
Copy link
Member

@thaJeztah thaJeztah commented Aug 25, 2020

carries #2663

closes #1940
closes #2199
closes #2663

Fixes moby/moby#25885

- What I did

This PR supersedes #1940 and #2199. I removed the support of privileged option from the original PR as I believe privileged containers involve more than just having the complete set of capabilities (eg. no user namespace, the unconfined AppArmor profile is used, etc...).

  1. docker stack deploy now supports cap_add and cap_drop options ;
  2. docker service create|update now support --cap-add and --cap-drop flags. For the update command and unlike most of other options, those flags don't have -add & -rm variants as this would make a poor UX (eg. --cap-add-add & --cap-drop-rm). Instead, updateCapabilities takes care of stripping caps provided to --cap-add from CapabilityDrop (and vice versa) ;
  3. docker service inspect --pretty displays the list of added caps and dropped caps ;

- How I did it

  1. The service converter transforming compose types into API types has been updated to add capabilities to ServiceSpec;
  2. A new function with the logic described above and named updateCapabilities() has been introduced and is called by updateService ;
  3. The pretty formatter has been updated to include added and dropped caps ;

- How to verify it

docker stack deploy
$ cat docker-compose.yaml
version: "3.7"
services:
  test:
    image: ollijanatuinen/capsh
    cap_add:
      - NET_ADMIN
    cap_drop:
      - CAP_MKNOD
$ build/docker stack deploy --compose-file docker-compose.yaml t1
$ docker inspect t1_test.1.m0jmdufuo93fotyyrhm00xx16
        "CapAdd": [
            "CAP_NET_ADMIN"
        ],
        "CapDrop": [
            "CAP_MKNOD"
        ],
docker service create
$ build/docker service create --name test --cap-add NET_ADMIN --cap-drop CAP_MKNOD ollijanatuinen/capsh
$ docker inspect test.1.li7llrgyp8v4mfvo5tvimhzxt
        "CapAdd": [
            "CAP_NET_ADMIN"
        ],
        "CapDrop": [
            "CAP_MKNOD"
        ],
docker service update
$ build/docker service update --cap-add CAP_MKNOD t1_test
$ docker inspect t1_test.1.92sd9omniksbenuv6wm17ft78
        "CapAdd": [
            "CAP_NET_ADMIN",
            "CAP_MKNOD"
        ],
        "CapDrop": null,

$ build/docker service update --cap-drop CAP_MKNOD --cap-drop NET_ADMIN t1_test
        "CapAdd": null,
        "CapDrop": [
            "CAP_MKNOD",
            "CAP_NET_ADMIN"
        ],
docker service inspect
$ build/docker service inspect t1_test
        "CapabilityAdd": [
            "CAP_NET_ADMIN"
        ],
        "CapabilityDrop": [
            "CAP_MKNOD"
        ]
$ build/docker service inspect --pretty t1_test
Capabilities:
 Add: CAP_NET_ADMIN
 Drop: CAP_MKNOD

- Description for the changelog

Add cap_add and cap_drop support to docker stack deploy and --cap-add and --cap-drop flags to docker service create|update.

- A picture of a cute animal (not mandatory but encouraged)

@codecov-commenter
Copy link

codecov-commenter commented Aug 25, 2020

Codecov Report

Merging #2687 into master will increase coverage by 0.11%.
The diff coverage is 88.23%.

@@            Coverage Diff             @@
##           master    #2687      +/-   ##
==========================================
+ Coverage   58.42%   58.54%   +0.11%     
==========================================
  Files         295      296       +1     
  Lines       21201    21286      +85     
==========================================
+ Hits        12387    12462      +75     
- Misses       7906     7915       +9     
- Partials      908      909       +1     

@thaJeztah
Copy link
Member Author

Ok, so I'm a bit in doubt what would be more logical; when updating a service that had previous cap-add/cap-drops, should we do:

A. Update both "previous" and "new" state at once

Given the following service;

CapDrop CapAdd
CAP_SOME_CAP

When updating the service, and applying --cap-add CAP_SOME_CAP, the previously dropped capability is removed, and CAP_SOME_CAP is added:

CapDrop CapAdd
CAP_SOME_CAP

Downside of this is that there's no option to reset the cap-add/cap-drop through docker service update (note that this would be possible through docker stack up as it's "declarative", and doesn't take the previous state into account).

B. Update as a "tri-state" (for better words)

Given the following service;

CapDrop CapAdd
CAP_SOME_CAP

When updating the service, and applying --cap-add CAP_SOME_CAP, the previously dropped capability is removed:

CapDrop CapAdd

When updating the service a second time, applying --cap-add CAP_SOME_CAP, capability is now added:

CapDrop CapAdd
CAP_SOME_CAP

So upside is that it's possible to "reset" previous capabilities without adding new ones. Downside is that it requires multiple updates if that is the desired result (given, probably a rare condition)

C. Introduce a special "RESET" value

Given the following service;

CapDrop CapAdd
CAP_SOME_CAP

When updating the service, and applying --cap-drop RESET:

CapDrop CapAdd

When updating the service, and applying --cap-drop RESET, combined with --cap-add CAP_SOME_CAP and --cap-drop CAP_SOME_OTHER_CAP:

CapDrop CapAdd
CAP_FOO_CAP CAP_SOME_CAP

D. Combine B + C

Apply the diff to the existing list of capabilities first, but also allow using RESET to "start from scratch"

@thaJeztah thaJeztah force-pushed the carry_service_caps branch 2 times, most recently from 31cd380 to e336b77 Compare August 26, 2020 17:36
@thaJeztah

This comment has been minimized.

@thaJeztah thaJeztah force-pushed the carry_service_caps branch 4 times, most recently from ce622d6 to d85589d Compare August 27, 2020 11:06
@thaJeztah thaJeztah marked this pull request as ready for review August 27, 2020 11:07
@thaJeztah thaJeztah requested a review from albers as a code owner August 27, 2020 11:07
@thaJeztah
Copy link
Member Author

As to my comment above, I added two commits that implement B and C

Comment on lines 877 to 878
NET_RAW
RESET
SETFCAP
Copy link
Member Author

Choose a reason for hiding this comment

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

I noticed that our completion scripts use the capabilities without the CAP_ prefix; I'm on the fence what we should use as "normalised" format: with, or without the CAP_. From a UX perspective, possibly without is more friendly (less to type, and less characters to type to use auto-completion)

@tiborvass @silvin-lubecki WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

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

Perhaps it doesn't make a big difference (as the values entered by the user will be normalised anyway, so the only difference will be in what's shown in docker service inspect. Looks like that's currently consistent with (e.g.) what's documented for docker plugin capabilities.

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 totally fine with values without the CAP_ 👍

Copy link
Collaborator

Choose a reason for hiding this comment

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

When completing signals, we offer both SIGXXX and XXX.
So for consistency, we could switch to supporting both variants here as well.
I'll create a PR for that.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Created #2706

@thaJeztah thaJeztah added this to the 20.03.0 milestone Aug 27, 2020
// list of capabilities to "drop").
//
// Capabilities are normalized, sorted, and duplicates are removed to prevent
// service tasks from being updated if no changes are made. If the a list has
Copy link
Contributor

Choose a reason for hiding this comment

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

typo: the/a list

spec: &swarm.ContainerSpec{
CapabilityDrop: []string{"ALL", "CAP_MOUNT", "CAP_NET_ADMIN"},
},
expectedDrop: []string{"ALL"},
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: should we also test ALL in cap-add AND cap-drop?

flagDrop: []string{},
spec: &swarm.ContainerSpec{
CapabilityDrop: []string{"CAP_NET_ADMIN"},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: maybe add explicit empty expectedDrop?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, guess it makes it slightly more understandable; I'll add explicit expectedDrop / expectedAdd lines

},
{
name: "Reset capabilities, and update after",
flagAdd: []string{"RESET", "CAP_ADD_ONE", "CAP_FOO"},
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: test also with "RESET", "ALL" ?

@thaJeztah
Copy link
Member Author

even if I'm a bit on the fence with the UX (RESET looks weird to me, but I can't find a better way), so let's move with that 👍

I can move the last commit to a separate PR; I don't think it's critical to have it, and we can add it after that, so if it requires more discussion, we can do so separately

@thaJeztah
Copy link
Member Author

@silvin-lubecki @albers updated this one, and moved the RESET commit to #2709

Copy link
Contributor

@silvin-lubecki silvin-lubecki left a comment

Choose a reason for hiding this comment

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

LGTM

@thaJeztah
Copy link
Member Author

@tiborvass @cpuguy83 PTAL

Copy link
Collaborator

@cpuguy83 cpuguy83 left a comment

Choose a reason for hiding this comment

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

LGTM

@kaysond
Copy link

kaysond commented Sep 27, 2020

I've been waiting for this! Is it going to be in 19.03 or a newer version? Any idea when it will get released?

@thaJeztah
Copy link
Member Author

this will be in the upcoming 20.xx release

@robertnisipeanu
Copy link

Isn't this in the master branch? I tried installing docker-ce docker-ce-cli and containerd.io from the nightly build, however I still get "Ignoring unsupported options: cap_add"

@thaJeztah
Copy link
Member Author

I think there's an issue with the nightly builds currently not being updated; this should be in the docker v20.10 release candidates in the testing channel (GA should be released soon)

@liangyuanpeng
Copy link

Look forward it!

@georgmay
Copy link

georgmay commented Dec 16, 2020

I'm getting the same "Ignoring unsupported options: cap_add" on 20.10

@trajano
Copy link

trajano commented Dec 17, 2020

It does not work on Docker Desktop for Windows 3.0. I tried

  haveged:
    image: hortonworks/haveged:1.1.0
    deploy:
      restart_policy:
        max_attempts: 3
    cap_add:
      - SYS_ADMIN
      - MKNOD
      - DAC_OVERRIDE
      - NET_ADMIN
      - SYS_MODULE
      - SYS_PACCT

I don't get the data in

docker service inspect api_haveged --pretty

ID:             bcjakjq6i1xfuwdw729eix5sh
Name:           api_haveged
Labels:
 com.docker.stack.image=hortonworks/haveged:1.1.0
 com.docker.stack.namespace=api
Service Mode:   Replicated
 Replicas:      1
Placement:
UpdateConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Update order:      stop-first
RollbackConfig:
 Parallelism:   1
 On failure:    pause
 Monitoring Period: 5s
 Max failure ratio: 0
 Rollback order:    stop-first
ContainerSpec:
 Image:         hortonworks/haveged:1.1.0
Resources:
Networks: api_default
Endpoint Mode:  vip

This is in regards to https://stackoverflow.com/questions/65241151/running-haveged-in-docker-swarm

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.

Missing from Swarmmode --cap-add