Policy Simulation

This section describes how to use the Apcera Policy Simulator to test and troubleshoot policy.

The Apcera Policy Simulator is available starting with the initial Long Term Support (LTS) release of the Apcera Platform.

Introduction

Apcera provides you with a policy simulator to audit and test policy behavior in the system.

To invoke the policy simulator, you run the apc policy sim <realm(s)> [args] command.

The simulator returns results based on the simulation parameters you provide:

  ╭───────────────────┬───────────┬───────────────────────────────────────────────────────────────────╮
  │ Context           │ Type      │ Claim / Condition / FQN / Input Value                             │
  ├───────────────────┼───────────┼───────────────────────────────────────────────────────────────────┤
  │ authPolicy.pol:41 │ Claim     │ permit update                                                     │
  │ authPolicy.pol:39 │ FQN       │   policy::/sandbox/[name]                                         │
  │ authPolicy.pol:40 │ Condition │   (auth_server@apcera.me->name == [name] && ResType == "gateway") │
  │ INPUT             │ Input     │     name fred                                                     │
  │ ADD INPUT         │ Input     │     ResType "gateway"                                             │
  ╰───────────────────┴───────────┴───────────────────────────────────────────────────────────────────╯

Use cases

There are two main use cases for the Apcera Policy Simulator:

Use Case Description
Audit and troubleshoot existing policy. Run policy simulations to determine why existing policy does not permit a user to act on a resource by providing the realm (FQN), user name, and permissions you want to check.
Test new policy. Upload a policy document containing policy you want to add and see if you get the results you expect.

See Examples section below.

Command syntax

You run the Policy Simulator using APC commands.

apc policy sim <filter> [<filter>...] [-i <input_claims> [-i ...]] [-c <claimtype>[=value] [-c ...]] [-f <file> [-f ...]] [-y]
apc help policy sim

Or:

apc policy sim --help

Filter parameters

Use the filter parameter to specify one or more FQNs (realms) for the simulation. For example: apc policy sim "job::/" [args] or apc policy sim "job::/" "service::/" [args].

You can process all FQNs using the "*" wildcard character. For example: apc policy sim "*" [args]. Note that processing all FQNs may return a lot of information.

Simulation permissions

The simulation requestor must have permit read on all realms specified in the simulation command as well as on any additional realms to be returned. The simulation returns an "access denied" error if the requestor does not have such policy.

Command options

Command options include the following:

Command Usage Description
-i, --input Establish the user identity and other input claims for the simulation. This option may be specified more than once if multiple input claims are required. Example inputs: name=bob, "Google->email=bob@gmail.com", ResType=gateway. Use "name=*" to run the simulation against all user IDs.
-c, --claimtype Claim types and optional values to return. This option may be specified more than once if multiple claim types and/or specific values are to be returned. Example claim types: permit=read, role=<value>, max.package.size. If not specified then all claim types and their values are returned.
-r, --replace Policy files to replace or add to the simulation. The file(s) will replace existing policies in the system for this simulation only. They are not be saved in the system. If the filename does not match an existing policy document, then it is simply added to the list of policy documents for the simulation. This option may be specified more than once if multiple policy files are to be part of the simulation. The document name reported will be the filename specified with the .pol suffix stripped from the name. The file must be a standard policy text file such as one downloaded using the "apc policy export" command.
-y, --hypothetical Request a hypothetical analysis. During a hypothetical analysis, the simulation first determines any missing claims that are required to satisfy all the policy output claims for the realm. The simulation then uses the original input claims and the missing claims as the total set of input claims for the simulation.

Use of quotes

If a command argument contains a reserved character, you must use quotes so that the shell does not perform special processing.

Unix recognizes single or double quotes. Windows requires double quotes.

Characters that have special meaning include: *, @, #, $, [, and ].

If any of these characters are in the command argument, it must be properly quoted.

Output fields

Policy simulation returns the following output fields:

Command Usage Description
Context Indicates the source of the claim, condition, FQN, or input value. The majority of the lines contain the policy file and line number of the claim, condition or FQN in the format: (s) filename:nn where (s) indicates that the document is one stored in the system, filename is the name of the policy document, and nn is the line number. When a policy document is specified on the command line using the -r option, the indicator (a), added policy document, or (r), replaces an existing policy document, will precede the policy document name. Context contains "access_denied" if the requestor has access to the realm, but does not have access to the policy file. Context contains INPUT when the source of the field is one of the input parameters or implied from an input parameter. For example: Google->name=bob@gmail.com implies an input claim of AUTHTYPE Google. Context contains "ADD INPUT" when you have requested a hypothetical analysis (the -y option) and the required input claim was added to the simulation in order to determine why a user may not have access to a resource.  
Type Indicates the value field type: Claim, FQN, Condition, or Input.  
Claim / Cond... Contains the value of the Claim, Condition, FQN, or Input field.  

Note that when a policy document is listed in the Context column, the row is prefaced by one of the following indicators:

  • (s) indicating system stored document
  • (r) indicating replaced system stored document
  • (a) indicating added to the system documents by simulation

For example, the following simulation result is based on 3 existing system stored policy documents:

| (s) authPolicy.pol:41 │ Claim     │ permit update
│ (s) authPolicy.pol:39 │ FQN       │ policy::/sandbox/[name]
│ (s) authPolicy.pol:40 │ Condition │ (auth_server@apcera.me->name == [name] && ResType == "gateway")
│ INPUT                 │ Input     │ name fred
│ ADD INPUT

Examples

This section provides some example simulations.

Basic example

The following simulation returns the policy tree on the stagpipe::/ realm where the claim is "role admin" and the name (userid) is "fred@apcera.com":

apc policy sim "stagpipe::/" -c role=admin -i "name=fred@apcera.com"

Compound example

The following simulation returns the policy tree for all resources where the claim type is either "permit" or "role dev" when the Google email and name are "fred@apcera.com":

apc policy sim "*" -i "Google->email=fred@apcera.com" -i "Google->name=fred@apcera.com" -c permit -c role=dev

Hypothetical example

This example demonstrates how to use the policy simulator hypothetical flag (-y) to troubleshoot existing policy. In this case, we want the simulation to tell us why user Fred doesn't have permit update on the realm policy::/sandbox/fred.

First, consider the following policy that grants permit update if name=fred and ResType is equal to gateway.

policy::/sandbox/[name] {
  if (auth_server@apcera.me->name==[name] && ResType == "gateway") {
    permit update
  }
}

If you run the following simulation:

apc policy sim "policy::/sandbox/fred" -i name=fred -c permit=update

The simulation returns the message "No claims meet your criteria" because the only input claim provided is name=fred. Since the policy grants permit update only if both name=fred and ResType is equal to gateway are true, the input claims do not meet the policy criteria.

Now, if you use the -y parameter and run a hypothetical simulation, the results show why Fred doesn't have permit update on policy::/sandbox/fred:

apc policy sim "policy::/sandbox/fred" -i name=fred -c permit=update -y

  ╭───────────────────┬───────────┬───────────────────────────────────────────────────────────────────╮
  │ Context           │ Type      │ Claim / Condition / FQN / Input Value                             │
  ├───────────────────┼───────────┼───────────────────────────────────────────────────────────────────┤
  │ authPolicy.pol:41 │ Claim     │ permit update                                                     │
  │ authPolicy.pol:39 │ FQN       │   policy::/sandbox/[name]                                         │
  │ authPolicy.pol:40 │ Condition │   (auth_server@apcera.me->name == [name] && ResType == "gateway") │
  │ INPUT             │ Input     │     name fred                                                     │
  │ ADD INPUT         │ Input     │     ResType "gateway"                                             │
  ╰───────────────────┴───────────┴───────────────────────────────────────────────────────────────────╯

In this case the simulation takes two passes. During the first pass the simulation records all the failures and the additional claims needed to turn those failures into successes. Then the simulation adds those additional claims and takes a second pass. The "ADD INPUT" value in the context column indicates that permit update on that target realm (FQN) is only allowed when the input claims also provide restype=gateway to the policy engine. Otherwise Fred isn't permitted update to that target FQN.

Now that we know what is wrong we can update policy for Fred or write a new rule.

Test new policy example

This example demonstrates how to use the policy simulator to test policy you want to add to the system. You do this by referencing the policy file you want to add. Note that the policy document is considered only for the simulation; it is not uploaded to the system.

For this example, consider the following policy that authorizes a user based on the Gmail address, generates a user ID, assigns this user to the "dev" role and defines the permissions for the "dev" role:

// Policy document dev-policy.pol

// Policy for dev auth

auth::/oauth2/http {
  if (Google->email == "apcera.hcos@gmail.com") {
      permit issue
      name dev01
  }
}

// Policy for dev role assignment

audit::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

cluster::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

gateway::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

job::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

network::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

package::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

policy::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

policydoc::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

principal::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

provider::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

route::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

sempiperule::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

service::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

stagpipe::/ {
  if (auth_server@apcera.me->name == apcdev) { role dev }
}

// Policy for permission grants to dev role

audit::/ {
  if (role == "dev") { permit read }
}

cluster::/ {
  if (role == "dev") { permit read }
}

gateway::/ {
  if (role == "dev") { permit use }
}

job::/ {
  if (role == "dev") { permit all }
}

network::/ {
  if (role == "dev") { permit all }
}

package::/ {
  if (role == "dev") { permit all }
}

policy::/ {
  if (role == "dev") { permit read }
}

policydoc::/ {
  if (role == "dev") { permit read }
}

principal::/ {
  if (role == "dev") { permit all }
}

provider::/ {
  if (role == "dev") { permit all }
}

route::/ {
  if (role == "dev") { permit map }
}

sempiperule::/ {
  if (role == "dev") { permit all }
}

service::/ {
  if (role == "dev") { permit all }
}

stagpipe::/ {
  if (role == "dev") { permit all }
}

Running a simulation aginst the dev-policy.pol policy document returns the following results that let you verify that the policy only grants the permissions you want:

apc policy sim "*" -c role=dev -i name=apcdev -r dev-policy.pol
╭───────────────────────┬───────────┬───────────────────────────────────────────╮
│ Context               │ Type      │ Claim / Condition / FQN / Input Value     │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:21 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:20 │ FQN       │   gateway::/                              │
│ (a) dev-policy.pol:21 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:13 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:12 │ FQN       │   audit::/                                │
│ (a) dev-policy.pol:13 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:61 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:60 │ FQN       │   service::/                              │
│ (a) dev-policy.pol:61 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:41 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:40 │ FQN       │   policydoc::/                            │
│ (a) dev-policy.pol:41 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:65 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:64 │ FQN       │   stagpipe::/                             │
│ (a) dev-policy.pol:65 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:25 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:24 │ FQN       │   job::/                                  │
│ (a) dev-policy.pol:25 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:45 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:44 │ FQN       │   principal::/                            │
│ (a) dev-policy.pol:45 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:49 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:48 │ FQN       │   provider::/                             │
│ (a) dev-policy.pol:49 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:17 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:16 │ FQN       │   cluster::/                              │
│ (a) dev-policy.pol:17 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:53 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:52 │ FQN       │   route::/                                │
│ (a) dev-policy.pol:53 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:57 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:56 │ FQN       │   sempiperule::/                          │
│ (a) dev-policy.pol:57 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:33 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:32 │ FQN       │   package::/                              │
│ (a) dev-policy.pol:33 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:37 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:36 │ FQN       │   policy::/                               │
│ (a) dev-policy.pol:37 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
│                       │           │                                           │
├───────────────────────┼───────────┼───────────────────────────────────────────┤
│ (a) dev-policy.pol:29 │ Claim     │ role dev                                  │
│ (a) dev-policy.pol:28 │ FQN       │   network::/                              │
│ (a) dev-policy.pol:29 │ Condition │   (auth_server@apcera.me->name == apcdev) │
│ INPUT                 │ Input     │     name apcdev                           │
╰───────────────────────┴───────────┴───────────────────────────────────────────╯