Skip to main content

Spin up Hosts Integrated with OPA

Create a .yaml file named docker-compose.yaml that runs OPA and the containers that represent the backend and frontend hosts.

Create the docker-compose.yaml file, and copy the following YAML into it.


version: '2'
image: openpolicyagent/opa:latest
- 8181:8181
# WARNING: OPA is NOT running with an authorization policy configured. This
# means that clients can read and write policies in OPA. If you are
# deploying OPA in an insecure environment, be sure to configure
# authentication and authorization on the daemon. See the Security page for
# details:
- OPA_LOG_TIMESTAMP_FORMAT="2006-01-02T15:04:05.999999999Z07:00"
- "run"
- "--server"
- "--config-file=/opa-conf.yaml"
- ./opa-conf.yaml:/opa-conf.yaml
image: openpolicyagent/demo-pam
- "2222:22"
- ./frontend_host_id.json:/etc/host_identity.json
- ./sshd:/etc/pam.d/sshd
image: openpolicyagent/demo-pam
- "2223:22"
- ./backend_host_id.json:/etc/host_identity.json
- ./sshd:/etc/pam.d/sshd

The docker-compose.yaml file relies on a configuration file for OPA, so you must create a configuration file named opa-config.yaml.

Create the opa-config.yaml file, and copy the following YAML into it.

Specify the SYSTEMID and the TOKEN, and replace the URL path.

  • The SYSTEMID is the numeric ID for the Custom System you created in Styra DAS.
  • For the TOKEN, you can generate an API token by referring to the Create an API Token page.


name: discovery
prefix: /systems/SYSTEMID
policy-type: custom/rules
system-id: SYSTEMID
system-type: custom
- credentials:
token: TOKEN
name: styra
url: https://<das-id>

To control the policy-paths the PAM module uses to interact with OPA, the docker-compose.yaml file overwrites the pam.d/sshd file in the demo-pam containers.

Create a file named sshd.


There is no file extension for sshd.

Copy the following SSHD configuration and paste it into the sshd file.

SSHD Configuration

# PAM configuration for the Secure Shell service

# Enable the Authz PAM module
# At image build time, the value of HOST_UUID is replaced with the role of the image (for example, webapp)
auth required /lib/security/ url=http://opa:8181 authz_endpoint=/v1/data/rules/authz display_endpoint=/v1/data/rules/display pull_endpoint=/v1/data/rules/pull log_level=debug

# SELinux needs to be the first session rule. This ensures that any
# lingering context has been cleared. Without this it is possible that a
# module could execute code in the wrong domain.
session [success=ok ignore=ignore module_unknown=ignore default=bad] close

# Set the loginuid process attribute.
session required

# Create a new session keyring.
session optional force revoke

# Standard Un*x session setup and teardown.
@include common-session

# Print the message of the day upon successful login.
# This includes a dynamically generated part from /run/motd.dynamic
# and a static (admin-editable) part from /etc/motd.
session optional motd=/run/motd.dynamic
session optional noupdate

# Print the status of the user's mailbox upon successful login.
session optional standard noenv # [1]

# Set up user limits from /etc/security/limits.conf.
session required

# Read environment variables from /etc/environment and
# /etc/security/pam_env.conf.
session required # [1]
# In Debian 4.0 (etch), locale-related environment variables were moved to
# /etc/default/locale, so read that as well.
session required user_readenv=1 envfile=/etc/default/locale

# SELinux needs to intervene at login time to ensure that the process starts
# in the proper default security context. Only sessions which are intended
# to run in the user's context should be run after this.
session [success=ok ignore=ignore module_unknown=ignore default=bad] open

# Standard Un*x password updating.
@include common-password

Each host can have metadata associated with it by creating JSON files in the file system. The content of the file provides context that the PAM module provides as input when executing queries against OPA.

In this tutorial, you can mount the metadata files frontend_host_id.json and backend_host_id.json into Styra's two different hosts, as follows.

echo '{"host_type": "frontend", "host_id": "1234"}' > frontend_host_id.json
echo '{"host_type": "backend", "host_id": "7890"}' > backend_host_id.json

In real-world scenarios, these files could contain arbitrary information that Styra wants to expose to the policy.

Run docker-compose to pull and run the containers.

docker-compose up