# Policy Engine Simulator This tool provides a means to test out security policies. Usage: ``` -commands string path to commands JSON file -data string path to initial data state JSON file (optional) -log string path to output log file -logLevel string None|Info|Results|Metadata (default "Info") -policy string path to policy Rego file ``` ## Getting started From the tool directory run: go run . -policy [samples/simple_framework/policy.rego](samples/simple_framework/policy.rego) -commands [samples/simple_framework/commands.json](samples/simple_framework/commands.json) This will load the authored policy and then simulate the enforcement behavior for the provided commands. This policy uses the framework, however, the simulator also handles completely custom policies: go run . -policy [samples/simple_custom/policy.rego](samples/simple_framework/policy.rego) -commands [samples/simple_custom/commands.json](samples/simple_custom/commands.json) ## Commands Consists of a sequential list of commands that will be issued for enforcement to the policy. Some sample commands can be seen here: - [Framework Example Commands](samples/simple_custom/commands.json) - [Custom Example Commands](samples/simple_framework/commands.json) These commands take the form of JSON objects, *e.g.*: ``` json [ { "name": "load_fragment", "input": { "issuer": "did:web:contoso.github.io", "feed": "contoso.azurecr.io/custom", "namespace": "custom", "local_path": "custom.rego" } }, { "name": "mount_device", "input": { "target": "/mnt/layer0", "deviceHash": "16b514057a06ad665f92c02863aca074fd5976c755d26bff16365299169e8415" } }, { "name": "mount_overlay", "input": { "target": "/mnt/overlay0", "containerID": "container0", "layerPaths": [ "/mnt/layer0" ] } }, { "name": "create_container", "input": { "containerID": "container0", "argList": [ "/pause" ], "envList": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "TERM=xterm" ], "mounts": [], "workingDir": "/", "sandboxDir": "/sandbox", "hugePagesDir": "/hugepages" } } ] ``` Each command has a name (corresponding to the API enforcement point) and then an input which will be passed directly to the policy. The API being tested is defined in [`api.rego`](../../../pkg/securitypolicy/api.rego). ## Data If the authored policy requires certain values in the Rego data structure to function, or if the author wants to test enforcement behavior given a known starting state, they can provide an optional initial data file as an argument to the tool. This should take the form of a single JSON object, *e.g.*: ``` json { "defaultMounts": [/*some mount constraint objects*/], "privilegedMounts": [/*some mount constraint objects*/], "sandboxPrefix": "sandbox://", "hugePagesPrefix": "hugepages://" } ``` ## Log To aid in debugging, the user can specify a log file. This will enable logging at the `Info` level, which consists of the output of any Rego `print()` calls from the policy. ## Log Level There are several log levels that the user can use to gain greater insight into policy enforcement: | Name | Description | | ---------- | --------------------------------------------------------- | | `None` | Used when no log file is provided via the `-log` argument | | `Info` | Outputs the results of Rego `print()` statements. | | `Results` | Outputs the results returned by each policy query | | `Metadata` | Outputs the entire metadata state after each query | ## Policy This can be any Rego with a package name of `policy`, though policies which do not define the required enforcement point rules will result in enforcement failures. We include some straightforward samples below, but see [simple_custom](simple_custom) and [simple_framework](simple_framework) for more detail. ### Framework-based policy ``` rego package policy api_version := "0.7.0" import future.keywords.every import future.keywords.in containers := [ { "command": ["/pause"], "env_rules": [ { "pattern": "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", "strategy": "string", "required": false }, { "pattern": "TERM=xterm", "strategy": "string", "required": false } ], "layers": ["16b514057a06ad665f92c02863aca074fd5976c755d26bff16365299169e8415"], "mounts": [], "exec_processes": [], "signals": [], "allow_elevated": false, "working_dir": "/" } ] mount_device := data.framework.mount_device unmount_device := data.framework.unmount_device mount_overlay := data.framework.mount_overlay unmount_overlay := data.framework.unmount_overlay create_container := data.framework.create_container exec_in_container := data.framework.exec_in_container exec_external := data.framework.exec_external shutdown_container := data.framework.shutdown_container signal_container_process := data.framework.signal_container_process plan9_mount := data.framework.plan9_mount plan9_unmount := data.framework.plan9_unmount load_fragment := data.framework.load_fragment reason := {"errors": data.framework.errors} ``` ### Custom Policy ``` rego package policy api_version := "0.7.0" overlays := { "pause": { "deviceHashes": ["16b514057a06ad665f92c02863aca074fd5976c755d26bff16365299169e8415"], "mounts": [] } } custom_containers := [ { "id": "pause", "command": ["/pause"], "overlayID": "pause", "depends": [] } ] mount_device := data.custom.mount_device mount_overlay := data.custom.mount_overlay create_container := data.custom.create_container unmount_device := {"allowed": true} unmount_overlay := {"allowed": true} exec_in_container := {"allowed": true} exec_external := {"allowed": true} shutdown_container := {"allowed": true} signal_container_process := {"allowed": true} plan9_mount := {"allowed": true} plan9_unmount := {"allowed": true} default load_fragment := {"allowed": false} load_fragment := {"allowed": true, "add_module": true} { input.issuer == "did:web:contoso.github.io" input.feed == "contoso.azurecr.io/custom" } ```