Notes on Open Policy Agent and Docker Security

Notes on Open Policy Agent and Docker Security

I am starting to work with Open Policy Agent (OPA) for Kubernetes. OPA is largely known for its ability to behave as a powerful Admission Controller for Kubernetes.

However, I find that Open Policy Agent is a great Admission Controller/Policy Enforcement tool for Docker, HTTP REST API and other technologies as well.

This is a public note on some possible options to enforce security policy for Docker deployments, with Open Policy Agent (OPA)

>> tested on Ubuntu 18.04

Installation

Install the Policy Agent with docker plugin

  • Create a Policy directory under /etc/docker
mkdir -p /etc/docker/policies # to load policies
vim /etc/docker/policies/authz.rego #to create a policy
  • Install the plugin with docker plugin
docker plugin install openpolicyagent/opa-docker-authz-v2:0.4 opa-args="-policy-file /opa/policies/authz.rego"
# link policy file to the plugin
Plugin "openpolicyagent/opa-docker-authz-v2:0.4" is requesting the following privileges:
 - mount: [/etc/docker]
Do you grant the above permissions? [y/N] y
0.4: Pulling from openpolicyagent/opa-docker-authz-v2
d93242d88c4c: Download complete 
Digest: sha256:03ee6dfeda0ffe561980ef43fe91f9fd05b093757623887da724bb42b02f3113
Status: Downloaded newer image for openpolicyagent/opa-docker-authz-v2:0.4
Installed plugin openpolicyagent/opa-docker-authz-v2:0.4
  • Add Plugin to the Docker Daemon
root@container-dummy-os:/# cat > /etc/docker/daemon.json <<EOF
> {
>     "authorization-plugins": ["openpolicyagent/opa-docker-authz-v2:0.4"]
> }
> EOF

As you can see, you are adding an additional Authorization Layer to running the docker daemon based on what's specified in the policy file

Let's create a security policy

I am going to create a simple authorization policy to disallow containers to be run with the --privileged flag (which disables all SYSCALL limits on the container)

I add this to the /etc/docker/policies/authz.rego file

package docker.authz
  
default allow = false

allow {
    not deny
}

deny {
    priv_containers
}

priv_containers {
    input.Body.HostConfig.Privileged == true
}

As you can see, I can specify multiple deny policies by naming them. I set the parameters for the --privileged flag by the params passed by Docker API when attributes are passed from the API to the Daemon.

This should now enforce system-wide, with a deny everytime when someone attempts to run a privileged container

This works!

docker run -p 5000:5000 some_app:latest

But this should be blocked!

docker run --privileged alpine sh
docker: Error response from daemon: authorization denied by plugin openpolicyagent/opa-docker-authz-v2:0.4: request rejected by administrative policy.
See 'docker run --help'.

I find that this is a great way to setup preventative controls on Docker Runtimes, especially to block low-hanging insecure settings like:

  1. Privileged containers
  2. seccomp:unconfined or lack of --security-opts flag
  3. Resource limits on CPU, memory, etc
  4. Restricted port bindings
  5. Block run as user uid0
  6. Sensitive Environment Variables with keywords like password