conjur-policy-parser 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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