Files
releases/docs/content/docker-authorization.md
T
Patrick East 230fae190d Move code snippets into docs content and version them
Previously the code content was only kept in master and was
Subsequently referenced by the versioned doc contents. This causes
A few problems.. so we will version it along with the doc content.

To get this to work we make a handful of changes:

* Move the docs up into just opa/docs/content/*, we’re going to remove
  The difference between local/dev and production builds soon.
* Move the “code” directory into the content dir, it is content tied
  To the markdown files already there.
* Change the Hugo config to ignore the code directories
* Change the “code” shortcode to load the versioned code snippet
* Change load-docs to copy the code directory in addition to the other
  markdown content.

Signed-off-by: Patrick East <east.patrick@gmail.com>
2019-04-26 17:12:15 -07:00

269 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: Docker Authorization
kind: tutorial
weight: 2
---
Dockers out-of-the-box authorization model is all or nothing. But many users
require finer-grained access control and Dockers plugin infrastructure allows
us to do so.
This is an excellent opportunity to see how to policy enable an existing
service.
## Goals
This tutorial helps you get started with OPA and introduces you to core concepts
in OPA.
> Policy enabling an application decouples the policy implementation from the
> business logic so that administrators can define policy without changing the
> application while still keeping up with the size, complexity, and dynamic
> nature of modern applications.
For the purpose of this tutorial, we want to use OPA to enforce a policy that
prevents users from running insecure containers.
This tutorial illustrates two key concepts:
1. OPA policy definition is decoupled from the implementation of the service
(in this case Docker). The administrator is empowered to define and manage
policies without requiring changes to any of the apps.
2. Both the data relevant to policy and the policy definitions themselves can
change rapidly.
## Prerequisites
This tutorial requires:
* Docker Engine 18.06.0-ce or newer
* Docker API version 1.38 or newer
* `root` or `sudo` access
The tutorial has been tested on the following platforms:
* Ubuntu 18.04 (64-bit)
If you are using a different distro, OS, or architecture, the steps will be the
same. However, there may be slight differences in the commands you need to run.
## Steps
Several of the steps below require `root` or `sudo` access. When you are
modifying files under `/etc/docker` or signalling the Docker daemon to
restart, you will need root access.
### 1. Create an empty policy definition that will allow all requests.
```shell
mkdir -p /etc/docker/policies
cat >/etc/docker/policies/authz.rego <<EOF
package docker.authz
allow = true
EOF
```
This policy defines a single rule named `allow` that always produces the
decision `true`. Once all of the components are running, we will come back to
the policy.
### 2. Install the opa-docker-authz plugin.
```shell
docker plugin install openpolicyagent/opa-docker-authz-v2:0.4 opa-args="-policy-file /opa/policies/authz.rego"
```
You need to configure the Docker daemon to use the plugin for authorization.
```shell
cat > /etc/docker/daemon.json <<EOF
{
"authorization-plugins": ["openpolicyagent/opa-docker-authz-v2:0.4"]
}
EOF
```
Signal the Docker daemon to reload the configuration file.
```shell
kill -HUP $(pidof dockerd)
```
### 4. Run a simple Docker command to make sure everything is still working.
```shell
docker ps
```
If everything is setup correctly, the command should exit successfully. You can
expect to see log messages from OPA and the plugin.
### 5. Test that the policy definition is working.
Lets modify our policy to **deny** all requests:
```shell
cat >/etc/docker/policies/authz.rego <<EOF
package docker.authz
allow = false
EOF
```
In OPA, rules defines the content of documents. Documents be boolean values
(true/false) or they can represent more complex structures using arrays,
objects, strings, etc.
In the example above we modified the policy to always return `false` so that
requests will be rejected.
```shell
docker ps
```
The output should be:
```shell
Error response from daemon: authorization denied by plugin opa-docker-authz: request rejected by administrative policy
```
To learn more about how rules define the content of documents, see: [How Does OPA Work?](../how-does-opa-work)
With this policy in place, users will not be able to run any Docker commands. Go
ahead and try other commands such as `docker run` or `docker pull`. They will
all be rejected.
Now let's change the policy so that it's a bit more useful.
### 6. Update the policy to reject requests with the unconfined [seccomp](https://en.wikipedia.org/wiki/Seccomp) profile:
```shell
cat >/etc/docker/policies/authz.rego <<EOF
package docker.authz
default allow = false
allow {
not deny
}
deny {
seccomp_unconfined
}
seccomp_unconfined {
# This expression asserts that the string on the right-hand side is equal
# to an element in the array SecurityOpt referenced on the left-hand side.
input.Body.HostConfig.SecurityOpt[_] == "seccomp:unconfined"
}
EOF
```
### 7. Test the policy is working by running a simple container:
```shell
docker run hello-world
```
Now try running the same container but disable seccomp (which should be
prevented by the policy):
```shell
docker run --security-opt seccomp:unconfined hello-world
```
Congratulations! You have successfully prevented containers from running without
seccomp!
The rest of the tutorial shows how you can grant fine grained access to specific
clients.
### <a name="identify-user"></a> 8. Identify the user in Docker requests.
> Back up your existing Docker configuration, just in case. You can replace your
> original configuration after you are done with the tutorial.
```shell
mkdir -p ~/.docker
cp ~/.docker/config.json ~/.docker/config.json~
```
To identify the user, include an HTTP header in all of the requests sent to the
Docker daemon:
```shell
cat >~/.docker/config.json <<EOF
{
"HttpHeaders": {
"Authz-User": "bob"
}
}
EOF
```
> Docker does not currently provide a way to authenticate clients. But in Docker
> 1.12, clients can be authenticated using TLS and there are plans to include
> other means of authentication. For the purpose of this tutorial, we assume that
> an authentication system is place.
### 9. Update the policy to include basic user access controls.
```shell
cat >/etc/docker/policies/authz.rego <<EOF
package docker.authz
default allow = false
# allow if the user is granted read/write access.
allow {
user_id := input.Headers["Authz-User"]
user := users[user_id]
not user.readOnly
}
# allow if the user is granted read-only access and the request is a GET.
allow {
user_id := input.Headers["Authz-User"]
users[user_id].readOnly
input.Method == "GET"
}
# users defines permissions for the user. In this case, we define a single
# attribute 'readOnly' that controls the kinds of commands the user can run.
users = {
"bob": {"readOnly": true},
"alice": {"readOnly": false},
}
EOF
```
### 10. Attempt to run a container.
Because the configured user is `"bob"`, the request is rejected:
```shell
docker run hello-world
```
### 11. Change the user to "alice" and re-run the container.
```shell
cat > ~/.docker/config.json <<EOF
{
"HttpHeaders": {
"Authz-User": "alice"
}
}
EOF
```
Because the configured user is `"alice"`, the request will succeed:
```shell
docker run hello-world
```
That's it!