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.
@@ -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