Jump to: navigation, search

PolicyDatabase

Revision as of 11:48, 3 March 2015 by David Chadwick (talk | contribs) (Policy)

Policy Relational Database Schema for Openstack

Overview

This document describes a relational database schema that stores security policies for Openstack.

An OpenStack Policy file comprises a set of policy rules. For example, "identity:create_region": "role:admin or is_admin:1" may be a policy rule from Keystone's policy file. This says that the principal must either be the administrator or have the role of admin in order to create a region with the identity API. A policy rule logically comprises a set of conditions. The example policy rule comprises the following conditions: service equals the identity API AND action equals create_region AND (role equals admin OR is_admin equals TRUE).

OpenStack policies are stored in the database in Disjunctive Normal Form (DNF). The DNF stores sets of simple conditions combined by the AND logical operator, and each set is combined by the OR logical operator. Each policy rule will form one or more sets of simple conditions.

The DNF policy structure can be represented by the tree structure below.

                    OR  
                /    |    \
             AND    AND    AND .......
           /  | \    |    /   \
          C1 C2 C3  C4   C5   C6

Using the example policy rule from above, this converts into the following simple conditions:

  • C1: role = "admin"
  • C2: is_admin = TRUE
  • C3: service = "identity"
  • C4: action = "create_region"


The policy rule in DNF forms two sets of simple conditions, namely:

(C3 and C4 and C1) or (C3 and C4 and C2)

Database Schema

The following figure presents the database schema to store security policies in Openstack.

Policy Database Schema

Each of these tables are detailed below.

Policy

Represents the Openstack Policy.

The id is the unique key for this policy.

The description field is optional, and describes the meaning of the Policy.

OR Rule

Each Openstack Policy is composed by one "OR structure". This structure is formed by multiple "AND structures".

When an OR expression is evaluated:

  • If the result of one "AND condition" is "TRUE", the access is granted.
  • Otherwise, the "AND conditions" continue to be verified.
  • If all "AND conditions" are "FALSE", the access is denied.

The OR Rule can have a label, that should be a simple description of its purpose. Usually, it represents the "OR structure of Policy x".

Just like the Policy, the version represents the date and time of it's last change (or creation, if no changes are done). When a OR condition is modified, this field is updated. A copy of the old version should be kept in another table/database in order to make it possible to roll back to a previous version. This mechanism is not detailed in this document.

The enabled field must be set to "TRUE" in order to the OR rule be verified.

AND Rule

Each "OR Rule" is composed by multiple "AND structures". An "AND structure" is formed by multiple conditions.

When an AND expression is evaluated:

  • If the result of one "condition" is "FALSE", the result is "FALSE".
  • Otherwise, the "conditions" continue to be verified.
  • If all "AND conditions" are "TRUE", the result is "TRUE".

The AND Rule can have a label, that should be a simple description of its purpose.

Just like the Policy and the OR Rule, the version represents the date and time of it's last change (or creation, if no changes are done). When a AND condition is modified, this field is updated. A copy of the old version should be kept in another table/database in order to make it possible to roll back to a previous version. This mechanism is not detailed in this document.

The enabled field must be set to "TRUE" in order to the AND rule be verified.

Condition

A condition represents the basic element of a policy. The policy engine will verify if the content of the "attribute" field matches with the "value" one. No operator is provided, since it is always, implicitly, the equals (==) operator. A value can be a literal (eg. a string or a number) or a variable, which will be interpreted by the Policy Engine.

Attributes can be of different types, for instance:

  • Action

Policies in Openstack are assigned to Actions. Actions are represented in the policy.json file by "service:action" entries. They serve as triggers for the Policy Engines to know which rule will be verified. In this database model, they are stored as conditions.

  • Role

Roles in Openstack represent Subjects. A user in a domain or project can be directly assigned to roles, or can be part of a group which is assigned to a role. A Role condition will make Policy Engines to verify if the user has a specific role.

  • Other types

Despite Openstack uses an RBAC engine, it allows other types of attribute checking in their policies. For instance, the entry below verifies if the user's id matches with the content of the variable user_id. user_id:%(user_id)s The "user_id" is also considered as an Attribute type in this database model.

Labels are descriptions to the Condition. For instance, the condition "user_id:%(user_id)s" has the label "owner". Conditions are not mandatory (can be NULL).

Attribute

Each type of attribute must have an entry in this table. An attribute has an id and a label. Eg. 1 - Action, 2 - Role, 3 - User_id, ...

Or_Rule_has_And_Rule | And_Rule_has_Condition

OR rules and AND rules are combined in the Or_Rule_has_And_Rule table. Similarly, AND rules and conditions are combined in the And_Rule_has_Condition table. These tables represent a many to many relationship of their components.

This allows a single "AND" entry to be part of multiple "OR Rules", or a single condition to be part of multiple "AND Rules". Therefore, when a "AND" entry or condition is modified, it affects all the "OR Rules" or "AND Rules" (respectively) which reffers to it.

Supported Operations

Policies stored in the database will support CRUD operations on policies, and also complex SQL queries, for instance, to find out which are the necessary conditions to perform a given action.

Besides these, two operations will also be supported:

  • Import policy.json file into the database: In this operation, policies conflicts will be eliminated. Duplicate rules will also be removed.
  • Export policies from database to new policy.json files. These new files will reflect the managed set of rules. It's important to say that, since rules are decomposed to DNF and not stored in it's original syntax, the new generated policy files will be semantically equivalent to their original, but can be syntactically different.

Importing a policy file to the Database Schema

Introduction

In order to show how the Database Scheme is applicable, we present a database representation for the following lines from Keystone's policy.json.

   "admin_required": "role:admin or is_admin:1",
   "service_role": "role:service",
   "service_or_admin": "rule:admin_required or rule:service_role",
   "owner" : "user_id:%(user_id)s",
   "admin_or_owner": "rule:admin_required or rule:owner",
   "identity:list_regions": "",
   "identity:create_region": "rule:admin_required",
   "identity:ec2_create_credential": "rule:admin_or_owner",
   "identity:create_trust": "user_id:%(trust.trustor_user_id)s",
   "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",

Labels

The 5 first lines constitute a set of conditions combined with AND or OR operators, which are assigned to a "label" in the syntax below.

"<label>" : "<conditions>"

Labels act as macros, in order to simplify the policies to be read by humans. Labels are not singly evaluated, since they are not assigned to any service/action. Because of that, they are stored as one or more conditions, which are not necessarily attached to the DNF structure or to a Policy.

Rules

The last 5 lines constitute of rules which are evaluated when an action (API entry) is called in a Service. Rules are represented by the following syntax:

"<service>:<action>" : "<conditions>"

Services are attached to the DNF structure, which is attached to a Policy.

Converting entries in Conditions

Each line of the example will be converted in one or more condition. A condition is composed by an attribute and a value.

Conditions are represented in this example as:

C<id>: <attr> = <value>
Labels

   "admin_required": "role:admin or is_admin:1",

  • C1: role = "admin"
  • C2: is_admin = 1
    • L("admin_required"): C1 or C2

   "service_role": "role:service",

  • C3: role = "service"
    • L("service_role"): C3

   "service_or_admin": "rule:admin_required or rule:service_role",

Rules elements points to labels.

    • L("service_or_admin"): L("admin_required") or L("service_role")
    • L("service_or_admin"): (C1 or C2) or C3

   "owner" : "user_id:%(user_id)s",

  • C4: user_id = "%(user_id)s"
    • L("owner"): C4

   "admin_or_owner": "rule:admin_required or rule:owner",

    • L("admin_or_owner"): L("admin_required") or L("owner")
    • L("admin_or_owner"): (C1 or C2) or C4
Rules

   "identity:list_regions": "",

  • C5: service = "identity"
  • C6: action = "list_regions"
    • R("identity:list_regions"): C5 and C6

   "identity:create_region": "rule:admin_required",

  • C7: action = "create_region"
    • R("identity:create_region"): C5 and C7 and L("admin_required")
    • R("identity:create_region"): C5 and C7 and (C1 or C2)
    • R("identity:create_region"): (C5 and C7 and C1) or (C5 and C7 and C2) in DNF

   "identity:ec2_create_credential": "rule:admin_or_owner",

  • C8: action = "ec2_create_credential"
    • R("identity:ec2_create_credential"): C5 and C8 and L("rule:admin_or_owner")
    • R("identity:ec2_create_credential"): C5 and C8 and (C1 or C2 or C4)
    • R("identity:ec2_create_credential"): (C5 and C8 and C1) or (C5 and C8 and C2) or (C5 and C8 and C4) in DNF

   "identity:create_trust": "user_id:%(trust.trustor_user_id)s",

  • C9: action = "create_trust"
  • Ca: user_id = "%(trust.trustor_user_id)s"
    • R("identity:create_trust"): C5 and C9 and CA

   "identity:ec2_delete_credential": "rule:admin_required or (rule:owner and user_id:%(target.credential.user_id)s)",

  • Cb: action = "ec2_delete_credential"
  • Cc: user_id = "%(target.credential.user_id)s"
    • R("identity:ec2_delete_credential"): C5 and Cb and (L("admin_required") or (L("owner") and Cc))
    • R("identity:ec2_delete_credential"): C5 and Cb and ((C1 or C2) or (C4 and Cc))
    • R("identity:ec2_delete_credential"): C5 and Cb and ((C1 or C2) or (C4 and Cc))
    • R("identity:ec2_delete_credential"): C5 and Cb and (C1 or C2 or (C4 and Cc))
    • R("identity:ec2_delete_credential"): (C5 and Cb and C1) or (C5 and Cb and C2) or (C5 and Cb and C4 and Cc) in DNF

Conditions C1 to Cc are candidate to be stored in the "condition" table.

Building the AND_Rule and And_Rule_has_Condition tables

Each "AND" block from the rules above represents an entry in the AND table. We will illustrate them below. The association of And Rules and Conditions are stored in the "and_rule_has_condition" table.

  • R("identity:list_regions"): C5 and C6
    • A1: C5 and C6
  • R("identity:list_regions"): A1


  • R("identity:create_region"): (C5 and C7 and C1) or (C5 and C7 and C2)
    • A2: C5 and C7 and C1
    • A3: C5 and C7 and C2
  • R("identity:create_region"): A2 or A3


  • R("identity:ec2_create_credential"): (C5 and C8 and C1) or (C5 and C8 and C2) or (C5 and C8 and C4)
    • A4: C5 and C8 and C1
    • A5: C5 and C8 and C2
    • A6: C5 and C8 and C4
  • R("identity:ec2_create_credential"): A4 or A5 or A6


  • R("identity:create_trust"): C5 and C9 and CA
    • A7: C5 and C9 and CA
  • R("identity:create_trust"): A7


  • R("identity:ec2_delete_credential"): (C5 and Cb and C1) or (C5 and Cb and C2) or (C5 and Cb and C4 and Cc)
    • A8: C5 and Cb and C1
    • A9: C5 and Cb and C2
    • Aa: C5 and Cb and C4 and Cc
  • R("identity:ec2_delete_credential"): A8 or A9 or Aa

Since all Roles are combined in a unique "Or" entry, roles are not directly represented in the Database schema. Nevertheless, they can be easily recovered by searching for entries of the same "service"+"action" from the "AND_Rule" table.

Tables

All tables in this section are populated according to the example above.

policy
id description or_rule_id version enabled scope_id
"a2f57b" "Openstack Security Policy" "5e98b2" "2015-02-26 14:00:00" TRUE NULL
or_rule
id label version enabled
"5e98b2" "OR Rule for Openstack Security Policy" "2015-02-26 14:00:01" TRUE
and_rule
id label version enabled
"000001" "identity:list_regions" "2015-02-26 14:01:01" TRUE
"000002" "identity:create_region_001" "2015-02-26 14:01:02" TRUE
"000003" "identity:create_region_002" "2015-02-26 14:01:03" TRUE
"000004" "identity:ec2_create_credential_001" "2015-02-26 14:01:04" TRUE
"000005" "identity:ec2_create_credential_002" "2015-02-26 14:01:05" TRUE
"000006" "identity:ec2_create_credential_003" "2015-02-26 14:01:06" TRUE
"000007" "identity:create_trust" "2015-02-26 14:01:07" TRUE
"000008" "identity:ec2_delete_credential_001" "2015-02-26 14:01:08" TRUE
"000009" "identity:ec2_delete_credential_002" "2015-02-26 14:01:09" TRUE
"00000A" "identity:ec2_delete_credential_003" "2015-02-26 14:01:10" TRUE
or_rule_has_and_rule
or_rule_id and_rule_id
"5e98b2" "000001"
"5e98b2" "000002"
"5e98b2" "000003"
"5e98b2" "000004"
"5e98b2" "000005"
"5e98b2" "000006"
"5e98b2" "000007"
"5e98b2" "000008"
"5e98b2" "000009"
"5e98b2" "00000A"
"5e98b2" "00000B"
"5e98b2" "00000C"
"5e98b2" "00000D"
"5e98b2" "00000E"
"5e98b2" "00000F"
attribute
id description
"A00001" "service"
"A00002" "action"
"A00003" "role"
"A00004" "is_admin"
"A00005" "user_id"
condition
id label attribute_id value version enabled
"C00001" "role:admin" "A00003" "admin" "2015-02-26 14:02:01" TRUE
"C00002" "is_admin:1" "A00004" "1" "2015-02-26 14:02:02" TRUE
"C00003" "role:service" "A00003" "service" "2015-02-26 14:02:03" TRUE
"C00004" "user_id:%(user_id)s" "A00005" "%(user_id)s" "2015-02-26 14:02:04" TRUE
"C00005" "service_identity" "A00001" "identity" "2015-02-26 14:02:05" TRUE
"C00006" "action_list_regions" "A00002" "list_regions" "2015-02-26 14:02:06" TRUE
"C00007" "action_create_region" "A00002" "create_region" "2015-02-26 14:02:07" TRUE
"C00008" "action_ec2_create_credential" "A00002" "ec2_create_credential" "2015-02-26 14:02:08" TRUE
"C00009" "action_create_trust" "A00002" "create_trust" "2015-02-26 14:02:09" TRUE
"C0000A" "user_id:%(trust.trustor_user_id)s" "A00005" "%(trust.trustor_user_id)s" "2015-02-26 14:02:10" TRUE
"C0000B" "action_ec2_delete_credential" "A00002" "ec2_delete_credential" "2015-02-26 14:02:11" TRUE
"C0000C" "user_id:%(target.credential.user_id)s" "A00005" "%(target.credential.user_id)s" "2015-02-26 14:02:12" TRUE
and_rule_has_condition
and_rule_id condition_id
"000001" "C00005"
"000001" "C00006"
"000002" "C00005"
"000002" "C00007"
"000002" "C00001"
"000003" "C00005"
"000003" "C00007"
"000003" "C00002"
"000004" "C00005"
"000004" "C00008"
"000004" "C00001"
"000005" "C00005"
"000005" "C00008"
"000005" "C00002"
"000006" "C00005"
"000006" "C00008"
"000006" "C00004"
"000007" "C00005"
"000007" "C00009"
"000007" "C0000A"
"000008" "C00005"
"000008" "C0000B"
"000008" "C00001"
"000009" "C00005"
"000009" "C0000B"
"000009" "C00002"
"00000A" "C00005"
"00000A" "C0000B"
"00000A" "C00004"
"00000A" "C0000C"