[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [atomic-devel] We are working on Roles Based Access Control for docker.



On Tue, 2015-04-07 at 06:52 -0400, Daniel J Walsh wrote:
> On 04/07/2015 05:57 AM, Pavel Odvody wrote:
> > On Mon, 2015-04-06 at 11:34 -0400, Daniel J Walsh wrote:
> >> On 04/02/2015 11:50 AM, Pavel Odvody wrote:
> >>> On Wed, 2015-04-01 at 10:34 +0200, Pavel Odvody wrote:
> >>>> On Tue, 2015-03-31 at 17:02 -0400, Colin Walters wrote:
> >>>>> On Tue, Mar 31, 2015, at 04:35 AM, Pavel Odvody wrote:
> >>>>>
> >>>>>> It's supposed to work in the following way:
> >>>>>> - docker daemon is started with the --trusted flag, this labels the
> >>>>>> process as SELinux type 'docker_daemon_t', daemon also labels the
> >>>>>> created Unix socket as 'docker_socket_t'. Define a policy that allows
> >>>>>> only docker_daemon_t to talk to docker_socket_t. This ensures that the
> >>>>>> daemon communicates only with compatible binary; other methods of
> >>>>>> communication with the daemon have to be disabled (TCP).
> >>>>> But what domains can transition to docker_daemon_t ? Is e.g. unconfined_t -> docker_daemon_t a valid transition?  If so, we aren't gaining anything AFAICS.  If it's not, what domains can?
> >>>>>
> >>>> The docker binary is originally labeled as docker_client_t, which is
> >>>> also capable of talking to docker_socket_t.
> >>>>
> >>>>> On Tue, Mar 31, 2015, at 04:35 AM, Pavel Odvody wrote:
> >>>>>> - each request that is sent from Docker Cli to the daemon is decorated
> >>>>>> with 2 additional HTTP headers, UID/EUID of the user.
> >>>>> You really want instead to have docker use `getsockopt` with `SO_PEERCRED` when the socket connection is first set up.  Anything else is subject to forgery.
> >>>>>
> >>>> That's nice! Didn't know about that one, sounds much better than pushing
> >>>> HTTP headers around :)
> >>>> Btw. the headers could not be forged, due to the policy constraints put
> >>>> on the socket, but this one should also work with docker-py and similar
> >>>> tools talking to the socket directly out of the box.
> >>>>
> >>>>
> >>> I created a fresh branch which uses `SO_PEERCRED`, the road was bumpy
> >>> as none of the structs actually expose the file descriptor of the
> >>> connection or the connection object itself (reflection to the rescue!).
> >>> Example output:
> >>>
> >>> # docker version
> >>> vars: {"rgid":"0","rpid":"21855","ruid":"0","version":"1.19"}
> >>>
> >>> # sudo -u nginx docker version 
> >>> vars: {"rgid":"986","rpid":"21881","ruid":"990","version":"1.19"}
> >>>
> >>> https://github.com/shaded-enmity/docker/compare/trusteddocker
> >>>
> >> You should be looking to get the loginuid not the UID or gid.  We also
> >> have SO_PEERCON
> >>
> >> man getpeercon() in libselinux returns the type of the remote connection
> >> on the socket.
> >>
> >> But I think we want to do this in two different steps.  First look at
> >> the communications with the docker
> >> socket purely from a DAC perspective.  Once we have something in place
> >> for this, we can start looking
> >> at the SELinux/MAC issues.
> >>
> >>
> >>
> >>
> > I've pushed an update that also grabs the `loginuid` from 
> > /proc/${pid}/loginuid and stores it in the `rlid` variable per each
> > request:
> >
> > # docker version
> > {"rgid":"0","rlid":"0","rpid":"2260","ruid":"0","version":"1.19"}
> >
> > # sudo -u nginx docker version
> > {"rgid":"986","rlid":"0","rpid":"2267","ruid":"990","version":"1.19"}
> >
> > (fedora)$ sudo docker version
> > {"rgid":"0","rlid":"1000","rpid":"2415","ruid":"0","version":"1.19"}
> >
> > (fedora)$ docker version
> > {"rgid":"1000","rlid":"1000","rpid":"2382","ruid":"1000","version":"1.19"} 
> >
> >
> > Now figure out what to actually do with all the IDs and how to label
> > stuff inside docker.
> > Do you have a Docker branch for this project or is this the only
> > prototype?
> >
> Matt Heon has been looking into this.  He is doing Authentication
> patches right now, basically we want
> docker to confirm the other end of the connection using PAM controls. 
> We want to support User/Password,
> Kerberos and potentially others in the future.  We want to support not
> only talking to the unix domain socket but
> to a network connection.
> 
So if socket_type == TCP then the first message received should contain
auth info otherwise the connection is dropped? How are you sending the
credentials? I wonder how the session is tracked since HTTP is
stateless, so either you validate first then pass around a token, or
validate on a per-request basis (as with the headers in my original
solution).
How is this going to work with with other tools expecting the current
remote API sitting at the other end of the socket (docker-py)?

> The first step I would like to see is to get proper logging/auditing.  I
> want to see a syslog/journald/audit message
> saying dwalsh created a privileged container named foobar with the
> following options.
> 

Agreed. I'll update here when I push this.

> After we have logging, we could look into grouping users and machines
> and that adding relationships/access control between them.
> 
> Finally we would get the docker daemon to start enforcing the access
> control.

Is it possible to set selinux labels per-thread? If so, do these survive
Goroutines?
I was thinking about spawning a thread with per-user specific label to
handle each request, but since the code is rather goroutine happy, and
goroutines spawn threads or maybe even reuse existing ones to execute
the workload I'm little worried that if the labels are not inherited
that the only reasonable thing is to fork + set uid per each request.


-- 
Pavel Odvody <podvody redhat com>
Software Engineer - EMEA ENG Developer Experience
5EC1 95C1 8E08 5BD9 9BBF 9241 3AFA 3A66 024F F68D
Red Hat Czech s.r.o., Purkyňova 99/71, 612 45, Brno

Attachment: signature.asc
Description: This is a digitally signed message part


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]