1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
====================
The policy.json file
====================
.. warning::
While the old json format policy file is still supported, we
recommend using the :doc:`newer YAML format <policy-yaml-file>`.
Each OpenStack service, Identity, Compute, Networking, and so on, has its
own role-based access policies. They determine which user can access
which objects in which way, and are defined in the service's
``policy.json`` file.
Whenever an API call to an OpenStack service is made, the service's
policy engine uses the appropriate policy definitions to determine if
the call can be accepted. Any changes to ``policy.json`` are effective
immediately, which allows new policies to be implemented while the
service is running.
A ``policy.json`` file is a text file in JSON (Javascript Object
Notation) format. Each policy is defined by a one-line statement in the
form ``"<target>" : "<rule>"``.
The policy target, also named "action", represents an API call like
"start an instance" or "attach a volume".
Action names are usually qualified. For example, the Compute service features
API calls to list instances, volumes, and networks. In
``/etc/nova/policy.json``, these APIs are represented by
``compute:get_all``, ``volume:get_all``, and ``network:get_all``,
respectively.
The mapping between API calls and actions is not generally documented.
The policy rule determines under which circumstances the API call is
permitted. Usually this involves the user who makes the call (hereafter
named the "API user") and often the object on which the API call
operates. A typical rule checks if the API user is the object's owner.
.. warning::
**Modifying the policy**
While recipes for editing ``policy.json`` files are found on blogs,
modifying the policy can have unexpected side effects and is not
encouraged.
Examples
~~~~~~~~
A simple rule might look like this:
.. code-block:: none
"compute:get_all" : ""
The target is ``"compute:get_all"``, the "list all instances" API of the
Compute service. The rule is an empty string meaning "always". This
policy allows anybody to list instances.
You can also decline permission to use an API:
.. code-block:: none
"compute:shelve": "!"
The exclamation mark stands for "never" or "nobody", which effectively
disables the Compute API "shelve an instance".
Many APIs can only be called by administrators. This can be expressed by
the rule ``"role:admin"``. The following policy ensures that only
administrators can create new users in the Identity database:
.. code-block:: none
"identity:create_user" : "role:admin"
You can limit APIs to any role. For example, the Orchestration service
defines a role named ``heat_stack_user``. Whoever has this role is not
allowed to create stacks:
.. code-block:: none
"stacks:create": "not role:heat_stack_user"
This rule makes use of the boolean operator ``not``. More complex rules
can be built using operators ``and``, ``or``, and parentheses.
You can define aliases for rules:
.. code-block:: none
"deny_stack_user": "not role:heat_stack_user"
The policy engine understands that ``"deny_stack_user"`` is not an API
and consequently interprets it as an alias. The stack creation policy
above can then be written as:
.. code-block:: none
"stacks:create": "rule:deny_stack_user"
This is taken verbatim from ``/etc/heat/policy.json``.
Rules can compare API attributes to object attributes. For example:
.. code-block:: none
"os_compute_api:servers:start" : "project_id:%(project_id)s"
states that only the owner of an instance can start it up. The
``project_id`` string before the colon is an API attribute, namely the project
ID of the API user. It is compared with the project ID of the object (in
this case, an instance). More precisely, it is compared with the
``project_id`` field of that object in the database. If the two values are
equal, permission is granted.
An administrator always has permission to call APIs. This is how
``/etc/keystone/policy.json`` makes this policy explicit:
.. code-block:: none
"admin_required": "role:admin or is_admin:1",
"owner" : "user_id:%(user_id)s",
"admin_or_owner": "rule:admin_required or rule:owner",
"identity:change_password": "rule:admin_or_owner"
The first line defines an alias for "user is an admin user". The
``is_admin`` flag is only used when setting up the Identity service for
the first time. It indicates that the user has admin privileges granted
by the service token (``--os-token`` parameter of the ``keystone``
command line client).
The second line creates an alias for "user owns the object" by comparing
the API's user ID with the object's user ID.
Line 3 defines a third alias ``admin_or_owner``, combining the two first
aliases with the Boolean operator ``or``.
Line 4 sets up the policy that a password can only be modified by its
owner or an admin user.
As a final example, let's examine a more complex rule:
.. code-block:: none
"identity:ec2_delete_credential": "rule:admin_required or
(rule:owner and user_id:%(target.credential.user_id)s)"
This rule determines who can use the Identity API "delete EC2
credential". Here, boolean operators and parentheses combine three
simpler rules. ``admin_required`` and ``owner`` are the same aliases as
in the previous example. ``user_id:%(target.credential.user_id)s``
compares the API user with the user ID of the credential object
associated with the target.
Syntax
~~~~~~
A ``policy.json`` file consists of policies and aliases of the form
``target:rule`` or ``alias:definition``, separated by commas and
enclosed in curly braces:
.. code-block:: none
{
"alias 1" : "definition 1",
"alias 2" : "definition 2",
...
"target 1" : "rule 1",
"target 2" : "rule 2",
....
}
Targets are APIs and are written ``"service:API"`` or simply ``"API"``.
For example, ``"compute:create"`` or ``"add_image"``.
Rules determine whether the API call is allowed.
Rules can be:
- always true. The action is always permitted. This can be written as
``""`` (empty string), ``[]``, or ``"@"``.
- always false. The action is never permitted. Written as ``"!"``.
- a special check
- a comparison of two values
- boolean expressions based on simpler rules
Special checks are:
- ``<role>:<role name>``, a test whether the API credentials contain
this role.
- ``<rule>:<rule name>``, the definition of an alias.
- ``http:<target URL>``, which delegates the check to a remote server.
The API is authorized when the server returns True.
Developers can define additional special checks.
Two values are compared in the following way:
.. code-block:: none
"value1 : value2"
Possible values are:
- constants: Strings, numbers, ``true``, ``false``
- API attributes
- target object attributes
- the flag ``is_admin``
API attributes can be ``project_id``, ``user_id`` or ``domain_id``.
Target object attributes are fields from the object description in the
database. For example in the case of the ``"compute:start"`` API, the
object is the instance to be started. The policy for starting instances
could use the ``%(project_id)s`` attribute, that is the project that
owns the instance. The trailing ``s`` indicates this is a string.
``is_admin`` indicates that administrative privileges are granted via
the admin token mechanism (the ``--os-token`` option of the ``keystone``
command). The admin token allows initialisation of the Identity database
before the admin role exists.
The alias construct exists for convenience. An alias is short name for a
complex or hard to understand rule. It is defined in the same way as a
policy:
.. code-block:: none
alias name : alias definition
Once an alias is defined, use the ``rule`` keyword to use it in a policy
rule.
Older syntax
~~~~~~~~~~~~
You may encounter older ``policy.json`` files that feature a different
syntax, where JavaScript arrays are used instead of boolean operators.
For example, the EC2 credentials rule above would have been written as
follows:
.. code-block:: none
"identity:ec2_delete_credential": [ [ "rule:admin_required ],
[ "rule:owner", "user_id:%(target.credential.user_id)s)" ] ]
The rule is an array of arrays. The innermost arrays are or'ed together,
whereas elements inside the innermost arrays are and'ed.
While the old syntax is still supported, we recommend using the newer,
more intuitive syntax.
|