mirror of
https://github.com/open-policy-agent/opa.git
synced 2026-08-24 17:25:16 -06:00
230fae190d
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>
269 lines
6.6 KiB
Markdown
269 lines
6.6 KiB
Markdown
---
|
||
title: Docker Authorization
|
||
kind: tutorial
|
||
weight: 2
|
||
---
|
||
|
||
Docker’s out-of-the-box authorization model is all or nothing. But many users
|
||
require finer-grained access control and Docker’s 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.
|
||
|
||
Let’s 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!
|