Skip to content

ENH,SEC: Create additional sockets with limited permissions #38879

Open

Description

@westurner

It's unfortunately common for projects to mount the docker socket into (privileged) containers. A configuration option for specifying additional sockets with limited privileges would be fairly simple and would make it easier to do it easily without doing it wrong.

Essentially, in the docker configuration, users would be able to specify the path of an additional socket with a limited set of permissions:

[(socket_path, [permissions,]),]

Or maybe also able to specify read-only access:

[(socket_path, {principal: 'rw', principal2: 'r'},]

I am aware that there are a number of far more complete RBAC solutions to limiting privileges; but I think creating said additional socket(s) with limited docker API privileges would be a fairly simple improvement that could help avoid granting unnecessarily broad privileges (e.g for easy ACME cert reloads and load balancing).

An example use case: securing the Traefik docker driver:

With such a proposed configuration option for additional docker sockets with limited privileges, such an additional docker socket proxy container would be unnecessary.

Activity

  1. westurner commented on Mar 14, 2019

    @westurner
    Author

    https://docs.docker.com/glossary/?term=authorization

    "Access authorization plugin"
    https://docs.docker.com/engine/extend/plugins_authorization/

    • This requires managing certs, installing them into containers, and managing DNS/IPs.
  2. added
    kind/featureFunctionality or other elements that the project doesn't currently have. Features are new and shiny
    on Mar 14, 2019
  3. thaJeztah commented on Mar 14, 2019

    @thaJeztah
    Member

    Thanks for opening; there's been quite some discussions around this (I'll link to some of them), and some attempts on possible implementations, but unfortunately, there was never a consensus on the right approach.

    I definitely agree that this is still a desirable feature though (my personal 0.02c).

    Some earlier discussions;

  4. westurner commented on Mar 14, 2019

    @westurner
    Author

    Thank you for the references to earlier discussions.

    #27261 (comment) suggests three cap names: (DOCKER_CAP_FORK, DOCKER_CAP_INSPECT, DOCKER_CAP_ADMIN), which may be sufficiently granular.

    docker-socket-proxy [1] has:

    Access granted by default

    These API sections are mostly harmless and almost required for any service that
    uses the API, so they are granted by default.

    • EVENTS
    • PING
    • VERSION

    Access revoked by default

    Security-critical

    These API sections are considered security-critical, and thus access is revoked
    by default. Maximum caution when enabling these.

    • AUTH
    • SECRETS
    • POST: When disabled, only GET and HEAD operations are allowed, meaning
      any section of the API is read-only.

    Not always needed

    You will possibly need to grant access to some of these API sections, which are
    not so extremely critical but can expose some information that your service
    does not need.

    • BUILD
    • COMMIT
    • CONFIGS
    • CONTAINERS
    • DISTRIBUTION
    • EXEC
    • IMAGES
    • INFO
    • NETWORKS
    • NODES
    • PLUGINS
    • SERVICES
    • SESSION
    • SWARM
    • SYSTEM
    • TASKS
    • VOLUMES

    With the following from haproxy.cfg https://github.com/Tecnativa/docker-socket-proxy/blob/master/haproxy.cfg:

    frontend dockerfrontend
        bind :2375
        http-request deny unless METH_GET || { env(POST) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers/[a-zA-Z0-9_.-]+/((stop)|(restart)|(kill)) } { env(ALLOW_RESTARTS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/auth } { env(AUTH) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/build } { env(BUILD) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/commit } { env(COMMIT) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/configs } { env(CONFIGS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/containers } { env(CONTAINERS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/distribution } { env(DISTRIBUTION) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/events } { env(EVENTS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/exec } { env(EXEC) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/images } { env(IMAGES) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/info } { env(INFO) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/networks } { env(NETWORKS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/nodes } { env(NODES) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/_ping } { env(PING) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/plugins } { env(PLUGINS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/post } { env(POST) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/secrets } { env(SECRETS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/services } { env(SERVICES) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/session } { env(SESSION) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/swarm } { env(SWARM) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/system } { env(SYSTEM) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/tasks } { env(TASKS) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/version } { env(VERSION) -m bool }
        http-request allow if { path,url_dec -m reg -i ^(/v[\d\.]+)?/volumes } { env(VOLUMES) -m bool }

    [1] https://github.com/Tecnativa/docker-socket-proxy

  5. westurner commented on Mar 14, 2019

    @westurner
    Author

    It appears that #32801 has the longest list; but the only API permission listed is api.access in https://github.com/moby/libentitlement as well. moby/libentitlement#67 may also be relevant.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiAPIarea/daemonCore Enginekind/featureFunctionality or other elements that the project doesn't currently have. Features are new and shiny

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions