conjur-policy-parser 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.project +18 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +41 -0
- data/Rakefile +10 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/ci/test.sh +6 -0
- data/conjur-policy-parser.gemspec +31 -0
- data/jenkins.sh +27 -0
- data/lib/conjur-policy-parser-version.rb +7 -0
- data/lib/conjur-policy-parser.rb +32 -0
- data/lib/conjur/policy/doc.rb +43 -0
- data/lib/conjur/policy/invalid.rb +12 -0
- data/lib/conjur/policy/logger.rb +12 -0
- data/lib/conjur/policy/resolver.rb +262 -0
- data/lib/conjur/policy/types/base.rb +417 -0
- data/lib/conjur/policy/types/create.rb +40 -0
- data/lib/conjur/policy/types/deny.rb +33 -0
- data/lib/conjur/policy/types/give.rb +28 -0
- data/lib/conjur/policy/types/grant.rb +72 -0
- data/lib/conjur/policy/types/include.rb +46 -0
- data/lib/conjur/policy/types/member.rb +37 -0
- data/lib/conjur/policy/types/permit.rb +59 -0
- data/lib/conjur/policy/types/policy.rb +180 -0
- data/lib/conjur/policy/types/records.rb +518 -0
- data/lib/conjur/policy/types/retire.rb +36 -0
- data/lib/conjur/policy/types/revoke.rb +32 -0
- data/lib/conjur/policy/types/update.rb +36 -0
- data/lib/conjur/policy/yaml/handler.rb +392 -0
- data/lib/conjur/policy/yaml/loader.rb +60 -0
- metadata +205 -0
@@ -0,0 +1,518 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
module Conjur
|
3
|
+
module Policy
|
4
|
+
module Types
|
5
|
+
# A createable record type.
|
6
|
+
class Record < Base
|
7
|
+
def role?
|
8
|
+
false
|
9
|
+
end
|
10
|
+
def resource?
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module ActsAsResource
|
16
|
+
def self.included(base)
|
17
|
+
base.module_eval do
|
18
|
+
attribute :id, kind: :string, singular: true, dsl_accessor: true
|
19
|
+
attribute :account, kind: :string, singular: true
|
20
|
+
attribute :owner, kind: :role, singular: true, dsl_accessor: true
|
21
|
+
|
22
|
+
attribute :annotations, kind: :hash, type: Hash, singular: true
|
23
|
+
|
24
|
+
def description value
|
25
|
+
annotation 'description', value
|
26
|
+
end
|
27
|
+
|
28
|
+
def annotation name, value
|
29
|
+
self.annotations ||= {}
|
30
|
+
self.annotations[name] = value
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def initialize id = nil
|
36
|
+
self.id = id if id
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
"#{resource_kind.gsub('_', ' ')} '#{id}'#{account && account != Conjur.configuration.account ? ' in account \'' + account + '\'': ''}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def resourceid default_account = nil
|
44
|
+
[ account || default_account, resource_kind, id ].join(":")
|
45
|
+
end
|
46
|
+
|
47
|
+
def resource_kind
|
48
|
+
self.class.name.split("::")[-1].underscore
|
49
|
+
end
|
50
|
+
|
51
|
+
def resource_id
|
52
|
+
id
|
53
|
+
end
|
54
|
+
|
55
|
+
def action
|
56
|
+
:create
|
57
|
+
end
|
58
|
+
|
59
|
+
def resource?
|
60
|
+
true
|
61
|
+
end
|
62
|
+
|
63
|
+
def immutable_attribute_names
|
64
|
+
[]
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
module ActsAsRole
|
70
|
+
def roleid default_account = nil
|
71
|
+
[ account || default_account, role_kind, id ].join(":")
|
72
|
+
end
|
73
|
+
|
74
|
+
def role?
|
75
|
+
true
|
76
|
+
end
|
77
|
+
|
78
|
+
def role_kind
|
79
|
+
self.class.name.split("::")[-1].underscore
|
80
|
+
end
|
81
|
+
|
82
|
+
def role_id
|
83
|
+
id
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
module ActsAsCompoundId
|
88
|
+
def initialize kind_or_id = nil, id_or_options = nil
|
89
|
+
if kind_or_id && id_or_options && id_or_options.is_a?(String)
|
90
|
+
self.kind = kind_or_id
|
91
|
+
self.id = id_or_options
|
92
|
+
elsif kind_or_id && kind_or_id.index(":")
|
93
|
+
id_or_options ||= {}
|
94
|
+
account, self.kind, self.id = kind_or_id.split(':', 3)
|
95
|
+
self.account = account if account != id_or_options[:default_account]
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def == other
|
100
|
+
other.kind_of?(ActsAsCompoundId) && kind == other.kind && id == other.id && account == other.account
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_s
|
104
|
+
"#{kind} #{self.class.short_name.underscore} '#{id}'#{account && account != Conjur.configuration.account ? ' in account \'' + account + '\'': ''}"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
class Role < Record
|
109
|
+
include ActsAsRole
|
110
|
+
include ActsAsCompoundId
|
111
|
+
|
112
|
+
attribute :id, kind: :string, singular: true, dsl_accessor: true
|
113
|
+
attribute :kind, kind: :string, singular: true, dsl_accessor: true
|
114
|
+
attribute :account, kind: :string, singular: true
|
115
|
+
attribute :owner, kind: :role, singular: true, dsl_accessor: true
|
116
|
+
|
117
|
+
self.description = %(
|
118
|
+
Create a custom role.
|
119
|
+
|
120
|
+
The purpose of a role is to have privileges and to initiate
|
121
|
+
transactions.
|
122
|
+
|
123
|
+
A role may represent a person, a group, a non-human user (“robot”)
|
124
|
+
such as a virtual machine or process, or a group of other roles.
|
125
|
+
|
126
|
+
In addition to having privileges, a role can be granted to another
|
127
|
+
role.
|
128
|
+
|
129
|
+
When a role is granted, the receiving role gains all the privileges
|
130
|
+
of the granted role. In addition, it gains all the roles which are
|
131
|
+
held by the granted role; role grants are fully inherited.
|
132
|
+
|
133
|
+
Typically, roles are not defined directly.
|
134
|
+
Rather, records that behave as roles, such as Users, Groups,
|
135
|
+
Hosts and Layers are used instead.
|
136
|
+
|
137
|
+
See also: [role-based access control guide](/key_concepts/rbac.html)
|
138
|
+
)
|
139
|
+
|
140
|
+
self.example = %(
|
141
|
+
- !user Beowulf
|
142
|
+
|
143
|
+
- !role tragic_end
|
144
|
+
kind: destiny
|
145
|
+
owner: !user Beowulf
|
146
|
+
)
|
147
|
+
|
148
|
+
def roleid default_account = nil
|
149
|
+
raise "account is required" unless account || default_account
|
150
|
+
[ account || default_account, kind, id ].join(":")
|
151
|
+
end
|
152
|
+
|
153
|
+
def role_id; id; end
|
154
|
+
def role_kind; kind; end
|
155
|
+
|
156
|
+
def immutable_attribute_names
|
157
|
+
[]
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class Resource < Record
|
162
|
+
include ActsAsResource
|
163
|
+
include ActsAsCompoundId
|
164
|
+
|
165
|
+
attribute :kind, kind: :string, singular: true, dsl_accessor: true
|
166
|
+
|
167
|
+
self.description = %(
|
168
|
+
Create a custom Resource.
|
169
|
+
|
170
|
+
Resources are the entities on which permissions are defined. A
|
171
|
+
resource id is an arbitrary, unique string which identifies the
|
172
|
+
protected asset.
|
173
|
+
|
174
|
+
Examples: database password, virtual machine or
|
175
|
+
server (for SSH access management), web service endpoint
|
176
|
+
|
177
|
+
Any Conjur resource can be annotated with a key-value pair. This
|
178
|
+
makes organization and discovery easier since annotations can be
|
179
|
+
searched on and are shown in the Conjur UI. Automation workflows
|
180
|
+
like rotation and expiration are based on annotations.
|
181
|
+
|
182
|
+
Typically, resources are not defined directly.
|
183
|
+
Rather, records that behave as resources, such as Users, Groups,
|
184
|
+
Hosts, Layers, Variables and Webservices are used instead.
|
185
|
+
|
186
|
+
See also: [role-based access control guide](/key_concepts/rbac.html)
|
187
|
+
)
|
188
|
+
|
189
|
+
self.example = %(
|
190
|
+
- !user nobody
|
191
|
+
|
192
|
+
- !resource unicorn
|
193
|
+
kind: magical_beast
|
194
|
+
annotations:
|
195
|
+
has_deadly_horn: true
|
196
|
+
has_mercy: false
|
197
|
+
owner: !user nobody
|
198
|
+
)
|
199
|
+
|
200
|
+
def resource_kind
|
201
|
+
kind
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
class User < Record
|
206
|
+
include ActsAsResource
|
207
|
+
include ActsAsRole
|
208
|
+
|
209
|
+
self.description = %(
|
210
|
+
Create a [Role](#reference/role) representing a human user.
|
211
|
+
|
212
|
+
Users have several specific attributes:
|
213
|
+
|
214
|
+
* **uidnumber** An integer which is the user's uid number for SSH access to Hosts. The `uidnumber` must
|
215
|
+
be unique across the Conjur system.
|
216
|
+
* **public_keys** Stores public keys for the user, which can be retrieved through the
|
217
|
+
[PubKeys API](http://docs.conjur.apiary.io/#reference/pubkeys/show/show-keys-for-a-user).
|
218
|
+
Public keys loaded through the Policy markup are strictly additive. To remove public keys, use the
|
219
|
+
API or the CLI.
|
220
|
+
|
221
|
+
For virtual machines, scripts, and other infrastructure, create [Host](#reference/host) identities instead.
|
222
|
+
)
|
223
|
+
|
224
|
+
self.example = %(
|
225
|
+
- !user robert
|
226
|
+
uidnumber: 1208
|
227
|
+
public_keys:
|
228
|
+
- ssh-rsa AAAAB3NzaC1yc2EAAAAD...+10trhK5Pt robert@home
|
229
|
+
- ssh-rsa AAAAB3NzaC1yc2EAAAAD...+10trhK5Pt robert@work
|
230
|
+
annotations:
|
231
|
+
public: true
|
232
|
+
can_predict_movement: false
|
233
|
+
)
|
234
|
+
|
235
|
+
attribute :uidnumber, kind: :integer, singular: true, dsl_accessor: true
|
236
|
+
attribute :public_key, kind: :string, dsl_accessor: true
|
237
|
+
|
238
|
+
def id_attribute; 'login'; end
|
239
|
+
|
240
|
+
def custom_attribute_names
|
241
|
+
[ :uidnumber, :public_key ]
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
class Group < Record
|
246
|
+
include ActsAsResource
|
247
|
+
include ActsAsRole
|
248
|
+
|
249
|
+
attribute :gidnumber, kind: :integer, singular: true, dsl_accessor: true
|
250
|
+
|
251
|
+
self.description = %(
|
252
|
+
Create a Group record.
|
253
|
+
|
254
|
+
Users are organized into groups in Conjur. Every user other than
|
255
|
+
'admin' should be in a group. When a user becomes a member of a
|
256
|
+
group they inherit the group's privileges. You can delegate members
|
257
|
+
of the group to be admins. This means that they can add and remove
|
258
|
+
other members of the group. The owner of a group is automatically an
|
259
|
+
admin.
|
260
|
+
)
|
261
|
+
|
262
|
+
self.example = %(
|
263
|
+
- !user alice
|
264
|
+
- !user bob
|
265
|
+
|
266
|
+
- !group ops
|
267
|
+
gidnumber: 110
|
268
|
+
|
269
|
+
- !grant
|
270
|
+
role: !group ops
|
271
|
+
members:
|
272
|
+
- !user alice
|
273
|
+
- !member
|
274
|
+
role: !user bob
|
275
|
+
admin: true
|
276
|
+
)
|
277
|
+
def custom_attribute_names
|
278
|
+
[ :gidnumber ]
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
class Host < Record
|
283
|
+
include ActsAsResource
|
284
|
+
include ActsAsRole
|
285
|
+
|
286
|
+
self.description = %(
|
287
|
+
Create a Host record.
|
288
|
+
|
289
|
+
A Host is an identity which represents a machine or code; for example, a
|
290
|
+
Server, VM, job or container.
|
291
|
+
|
292
|
+
Hosts can be long-lasting, and managed through the Conjur host factory, or
|
293
|
+
ephemeral, and managed through Conjur oAuth (aka authn-tv).
|
294
|
+
)
|
295
|
+
|
296
|
+
self.example = %(
|
297
|
+
- !group CERN
|
298
|
+
|
299
|
+
- !host httpd
|
300
|
+
annotations:
|
301
|
+
descripton: hypertext web server
|
302
|
+
started: 1990-12-25
|
303
|
+
owner: !group CERN
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
307
|
+
class Layer < Record
|
308
|
+
include ActsAsResource
|
309
|
+
include ActsAsRole
|
310
|
+
|
311
|
+
self.description = %(
|
312
|
+
Create a Layer record.
|
313
|
+
|
314
|
+
Host are organized into layers in Conjur. Hosts can be added and
|
315
|
+
removed from layers, and map logically to your infrastructure. A
|
316
|
+
host can be a single machine, but it could also be an application or
|
317
|
+
Docker container - where several different applications are running
|
318
|
+
on the same machine or VM.
|
319
|
+
)
|
320
|
+
|
321
|
+
self.example = %(
|
322
|
+
- !host ProteusIV
|
323
|
+
- !host AM
|
324
|
+
- !host GLaDOS
|
325
|
+
|
326
|
+
- !layer evil-hosts
|
327
|
+
|
328
|
+
- !grant
|
329
|
+
role: !layer evil-hosts
|
330
|
+
members:
|
331
|
+
- !host ProteusIV
|
332
|
+
- !host AM
|
333
|
+
- !host GLaDOS
|
334
|
+
)
|
335
|
+
end
|
336
|
+
|
337
|
+
class Variable < Record
|
338
|
+
include ActsAsResource
|
339
|
+
|
340
|
+
attribute :kind, kind: :string, singular: true, dsl_accessor: true
|
341
|
+
attribute :mime_type, kind: :string, singular: true, dsl_accessor: true
|
342
|
+
|
343
|
+
self.description = %(
|
344
|
+
Create a Variable resource to hold a secret value.
|
345
|
+
|
346
|
+
Variables are containers for secrets in Conjur. They can hold any
|
347
|
+
ascii-armored value. You can annotate resources and also assign them a kind, a
|
348
|
+
signifier as to what type of value they hold. Variable values are
|
349
|
+
versioned and assigning a value during variable creation is
|
350
|
+
optional. When fetching a value, the latest version is returned by
|
351
|
+
default.
|
352
|
+
|
353
|
+
Variables are resources; you assign roles privileges to them as
|
354
|
+
desired.
|
355
|
+
)
|
356
|
+
|
357
|
+
self.example = %(
|
358
|
+
- !variable spoiler
|
359
|
+
kind: utf-8
|
360
|
+
mime-type: x/json
|
361
|
+
)
|
362
|
+
|
363
|
+
def custom_attribute_names
|
364
|
+
[ :kind, :mime_type ]
|
365
|
+
end
|
366
|
+
|
367
|
+
def immutable_attribute_names
|
368
|
+
[ :kind, :mime_type ]
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
class Webservice < Record
|
373
|
+
include ActsAsResource
|
374
|
+
|
375
|
+
self.description = %(
|
376
|
+
Create a [Resource](#reference/resource) representing a web service endpoint.
|
377
|
+
|
378
|
+
Web services endpoints are represented in Conjur as a webservice
|
379
|
+
resource. Permission grants are straightforward: an input
|
380
|
+
HTTP request path is mapped to a webservice resource. The HTTP
|
381
|
+
method is mapped to an RBAC privilege. A permission check is
|
382
|
+
performed, according to the following transaction:
|
383
|
+
|
384
|
+
* `role` incoming role on the HTTP (typically, Conjur access token on the request Authorization header)
|
385
|
+
* `privilege` read, update, or delete according to HTTP verb
|
386
|
+
* `resource` web service resource id
|
387
|
+
)
|
388
|
+
|
389
|
+
self.example = %(
|
390
|
+
- !group analysts
|
391
|
+
- !webservice xkeyscore
|
392
|
+
annotations:
|
393
|
+
description: API endpoint for surveillance apparatus
|
394
|
+
|
395
|
+
- !permit
|
396
|
+
role: !group analysts
|
397
|
+
privilege: read
|
398
|
+
resource: !webservice xkeyscore
|
399
|
+
)
|
400
|
+
end
|
401
|
+
|
402
|
+
class HostFactory < Record
|
403
|
+
include ActsAsResource
|
404
|
+
|
405
|
+
self.description = %(
|
406
|
+
Create a host-factory service for automatically creating [Hosts](#reference/host)
|
407
|
+
and enrolling them into one or more [Layer](#reference/layer)s.
|
408
|
+
)
|
409
|
+
|
410
|
+
self.example = %(
|
411
|
+
- !layer nest
|
412
|
+
|
413
|
+
- !host-factory
|
414
|
+
annotations:
|
415
|
+
description: Factory to create new bird hosts
|
416
|
+
layers: [ !layer nest ]
|
417
|
+
)
|
418
|
+
|
419
|
+
attribute :role, kind: :role, dsl_accessor: true, singular: true
|
420
|
+
attribute :layer, kind: :layer, dsl_accessor: true
|
421
|
+
|
422
|
+
alias role_accessor role
|
423
|
+
|
424
|
+
def role *args
|
425
|
+
if args.empty?
|
426
|
+
role_accessor || self.owner
|
427
|
+
else
|
428
|
+
role_accessor(*args)
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
class AutomaticRole < Base
|
434
|
+
include ActsAsRole
|
435
|
+
|
436
|
+
def initialize record = nil, role_name = nil
|
437
|
+
self.record = record if record
|
438
|
+
self.role_name = role_name if role_name
|
439
|
+
end
|
440
|
+
|
441
|
+
attribute :record, kind: :role, singular: true
|
442
|
+
attribute :role_name, kind: :string, singular: true
|
443
|
+
|
444
|
+
self.description = %(
|
445
|
+
Some [Roles](#reference/role) are created automatically by a containing record.
|
446
|
+
|
447
|
+
These roles are accessed by using the `automatic-role`
|
448
|
+
type, which identifies the containing record (e.g. a Layer), and the name of the automatic role (e.g. `use_host`).
|
449
|
+
|
450
|
+
The automatic roles of a Layer are:
|
451
|
+
|
452
|
+
* `use_host`, for allowing SSH access to each host as the `users` primary group.
|
453
|
+
* `admin_host`, for allowing SSH access to each host as the `conjurers` primary group.
|
454
|
+
* `observe`, for `read` privileges on the hosts.
|
455
|
+
)
|
456
|
+
|
457
|
+
self.example = %(
|
458
|
+
- !user chef
|
459
|
+
- !user owner
|
460
|
+
- !group line-cooks
|
461
|
+
- !layer kitchen
|
462
|
+
|
463
|
+
# There's no need to create automatic roles explicitly
|
464
|
+
|
465
|
+
- !grant
|
466
|
+
role: !automatic-role
|
467
|
+
record: !layer kitchen
|
468
|
+
role_name: use_host
|
469
|
+
member: !group line-cooks
|
470
|
+
|
471
|
+
- !grant
|
472
|
+
role: !automatic-role
|
473
|
+
record: !layer kitchen
|
474
|
+
role_name: admin_host
|
475
|
+
member: !user chef
|
476
|
+
|
477
|
+
- !grant
|
478
|
+
role: !automatic-role
|
479
|
+
record: !layer kitchen
|
480
|
+
role_name: observe
|
481
|
+
member: !user owner
|
482
|
+
)
|
483
|
+
|
484
|
+
class << self
|
485
|
+
def build fullid
|
486
|
+
account, kind, id = fullid.split(':', 3)
|
487
|
+
raise "Expecting @ for kind, got #{kind}" unless kind == "@"
|
488
|
+
id_tokens = id.split('/')
|
489
|
+
record_kind = id_tokens.shift
|
490
|
+
role_name = id_tokens.pop
|
491
|
+
record = Conjur::Policy::Types.const_get(record_kind.classify).new.tap do |record|
|
492
|
+
record.id = id_tokens.join('/')
|
493
|
+
record.account = account
|
494
|
+
end
|
495
|
+
self.new record, role_name
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
def to_s
|
500
|
+
role_name = self.id.split('/')[-1]
|
501
|
+
"'#{role_name}' on #{record}"
|
502
|
+
end
|
503
|
+
|
504
|
+
def account
|
505
|
+
record.account
|
506
|
+
end
|
507
|
+
|
508
|
+
def role_kind
|
509
|
+
"@"
|
510
|
+
end
|
511
|
+
|
512
|
+
def id
|
513
|
+
[ record.role_kind, record.id, role_name ].join('/')
|
514
|
+
end
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
end
|