Note: This repository is in prototype phase and under active development with subject to breaking changes.
Ansible Policy is a prototype implementation which allows us to define and set constraints to the Ansible project in OPA Rego language. The key features of Ansible Policy are
opa
commandrefer to OPA document
clone this repository
ansbile-policy
commandAnsible Policy requires Python 3.11 or later
. Please install it before this step.
The following command installs ansible-policy
command and dependency packages.
$ cd ansible-policy
$ pip install -e .
As examples, the following policybooks can be found in the examples/check_project/policies
directory.
check_package_policy
yml: Check if only authorized packages are installed.check_collection_policy
yml: Check if only authorized collections are usedcheck_become_policy
yml: check if become: true
is used and check if only trusted user
is usedansible-policy transpile these policybooks into OPA policy automatically and evaluate the policies.
See this doc about Policybook specification.
The example playbook has some tasks that violate the 3 policies above.
ansible-policy can report these violations like the following.
$ ansible-policy -p examples/check_project/playbook.yml --policy-dir examples/check_project/policies
From the result, you can see the details on violations.
The task "Install Unauthorized App" is installing a package unauthorized-app
with a root permission by using become: true
. This is not listed in the allowed packages defined in the policybook check_package_policy. Also the privilege escalation is detected by the policybook check_become_policy.
The task "Set MySQL root password" is using a collection community.mysql
which is not in the allowed list, and this is detected by the policybook check_collection_policy.
Alternatively, you can output the evaluation result in a JSON format.
$ ansible-policy -p examples/check_project/playbook.yml --policy-dir examples/check_project/policies --format json > agk-result.json
Then you would get the JSON file like the following.
The summary
section in the JSON is a summary of the evaluation results such as the number of total policies, the number of policies with one or more violations, total files and OK/NG for each of them.
For example, you can get a summary about files by jq
command like this.
$ cat agk-result.json | jq .summary.files
{
"total": 1,
"validated": 0,
"not_validated": 1,
"list": [
"examples/check_project/playbook.yml"
]
}
The files
section contains the details for each file evaluation result.
Each file result has results per policy, and a policy result contains multiple results for policy evaluation targets like tasks or plays.
For example, you can use this detailed data by the following commands.
# get overall result for a file
$ cat /tmp/agk-result.json | jq .files[0].violation
true
# get overall result for the second policy for the file
$ cat /tmp/agk-result.json | jq .files[0].policies[1].violation
true
# get an policy result for the second task in the file for the second policy
cat /tmp/agk-result.json | jq .files[0].policies[1].targets[1]
{
"name": "Install nginx [installing unauthorized pkg]",
"lines": {
"begin": 31,
"end": 36
},
"validated": false,
"message": "privilage escalation is detected. allowed users are one of [\"trusted_user\"]\n"
}
Instead of specifying the policy directory, you can define a configuration for ansible-policy like the following.
[policy]
default disabled
policies.org.compliance tag=compliance enabled
[source]
policies.org.compliance = examples/check_project # org-wide compliance policy
policy
field is a configuration like iptable to enable/disable installed policies. Users can use tag for configuring this in detail.
source
field is a list of module packages and their source like ansible-galaxy or local directory. ansible-policy installs policies based on this configuration.
The example above is configured to enable the 3 policies in step 4.
You can check the example config file as reference.
Ansible Policy supports policy checks for runtime events output from ansible-runner
.
ansible-runner generates the events while playbook execution. For example, "playbook_on_start" is an event at the start of the playbook execution, and "runner_on_ok" is the one for a task that is completed successfully.
event_handler.py is a reference implementation to handle these runner events that are input by standard input and it outputs policy evaluation results to standard output like the following image.
In the example above, a policybook here is used.
An event JSON data and its attributes are accessible by input.xxxx
in the policybook condition field.
For example, the changed
status of a task is input.event_data.changed
, so the example policy is checking if input.event_data.changed
as one of the conditions.
You can implement your policy conditions by using input.xxxx
.
Also, you can use event_handler.py
, in particular, the code block below to implement your event handler depending on the way to receive events.
evaluator = PolicyEvaluator(policy_dir="/path/to/your_policy_dir")
formatter = ResultFormatter(format_type="event_stream")
# `load_event()` here should be replaced with your generator to read a single event
for event in load_event():
result = evaluator.run(
eval_type="event",
event=event,
)
formatter.print(result)