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,33 @@
1
+ module Conjur::Policy::Types
2
+ class Deny < Base
3
+
4
+ self.description = %(
5
+ Deny privilege(s) on a [Resource](#reference/resource) to a role.
6
+ Once a privilege is denied, permission checks performed by the role
7
+ will return `false`.
8
+
9
+ If the role does not hold the privilege, this statement is a nop.
10
+
11
+ See also: [Revoke](#reference/revoke) for [Roles](#reference/role)
12
+ )
13
+
14
+ self.example = %(
15
+ - !variable secret
16
+ - !user rando
17
+ - !deny
18
+ role: !user rando
19
+ privilege: read
20
+ resource: !variable secret
21
+ )
22
+
23
+ attribute :role, kind: :role, dsl_accessor: true
24
+ attribute :privilege, kind: :string, dsl_accessor: true
25
+ attribute :resource, dsl_accessor: true
26
+
27
+ include ResourceMemberDSL
28
+
29
+ def to_s
30
+ "Deny #{role} to '#{privilege}' #{resource}"
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ module Conjur::Policy::Types
2
+ class Give < Base
3
+ attribute :resource, kind: :resource
4
+ attribute :owner, kind: :role
5
+
6
+ self.description = %(
7
+ Give ownership of a resource to a [Role](#reference/role).
8
+
9
+ When the owner role performs a permission check on an owned resource, the
10
+ result is always `true`.
11
+
12
+ [More](/key_concepts/rbac.html) on role-based access control in Conjur.
13
+ )
14
+
15
+ self.example = %(
16
+ - !user Link
17
+ - !secret song-of-storms
18
+
19
+ - !give
20
+ resource: !secret song-of-storms
21
+ owner: !user Link
22
+ )
23
+
24
+ def to_s
25
+ "Give #{resource} to #{owner}"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,72 @@
1
+ module Conjur::Policy::Types
2
+ class Grant < Base
3
+ attribute :role, dsl_accessor: true
4
+ attribute :member
5
+ attribute :replace, kind: :boolean, singular: true, dsl_accessor: true
6
+
7
+ include RoleMemberDSL
8
+ include AutomaticRoleDSL
9
+
10
+ self.description = %(
11
+ Grant one [Role](#reference/role) to another. When role A is granted to role B,
12
+ then role B is said to "have" role A. The set of all memberships of role B
13
+ will include A. The set of direct members of role A will include role B.
14
+
15
+ If the role is granted with `admin` option, then the grantee (role B),
16
+ in addition to having the role, can also grant and revoke the role
17
+ to other roles.
18
+
19
+ The only limitation on role grants is that there may never be a cycle
20
+ in the role graph. For example, if role A is granted to role B, then role B
21
+ cannot be granted to role A.
22
+
23
+ Several types of Conjur records are roles. For example, Users, Groups,
24
+ Hosts and Layers are all roles. This means they can be granted to and
25
+ revoked from each other. For example, when a Group is granted to a User,
26
+ the User gains all the privileges of the Group. (Note: "Adding" a User to
27
+ a Group is just another way to say that the Group role is granted to the User).
28
+
29
+ Some `grant` operations have additional semantics beyond the role grant:
30
+
31
+ * When a Layer is granted to a Host, the automatic roles on the Layer are granted
32
+ privileges on the Host. Specifically, the `observe` role is given `read` privilege,
33
+ `use_host` is given `execute`, and `admin_host` is given `update`. The `admin`
34
+ option is ignored.
35
+
36
+ [More](/key_concepts/rbac.html) on role-based access control in Conjur.
37
+
38
+ See also: [Permit](#reference/permit) for [Resources](#reference/resource)
39
+ )
40
+
41
+ self.example = %(
42
+ - !user Link
43
+ - !user Navi
44
+
45
+ - !grant
46
+ role: !user Navi
47
+ member: !user Link
48
+ )
49
+
50
+ def to_s
51
+ role_str = if role.kind_of?(Array)
52
+ role.join(', ')
53
+ else
54
+ role
55
+ end
56
+ member_str = if member.kind_of?(Array)
57
+ member.map(&:role).join(', ')
58
+ elsif member
59
+ member.role
60
+ end
61
+ admin = Array(member).map do |member|
62
+ member && member.admin
63
+ end
64
+ admin_str = if Array(member).count == admin.select{|admin| admin}.count
65
+ " with admin option"
66
+ elsif admin.any?
67
+ " with admin options: #{admin.join(', ')}"
68
+ end
69
+ %Q(Grant #{role_str} to #{member_str}#{replace ? ' with replacement ' : ''}#{admin_str})
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,46 @@
1
+ module Conjur::Policy::Types
2
+ # Include another policy into the policy.
3
+ class Include < Base
4
+ attribute :file, kind: :string, type: String, singular: true, dsl_accessor: true
5
+
6
+ self.description = %(
7
+ Includes the contents of another policy file.
8
+
9
+ By using this feature, policies for an entire organization can be
10
+ defined in one source repository, and then unified by a top-level
11
+ "Conjurfile".
12
+
13
+ Attributes:
14
+
15
+ * **file** path to the included policy file, relative to the including policy file.
16
+ This is the default attribute, so it can be specified in shorthand form as:
17
+ `- !include the-policy.yml`
18
+
19
+ Included policies inherit the namespace and owner of the enclosing
20
+ context. To include a policy with a different namespace and owner,
21
+ first define an enclosing policy record with the following attributes:
22
+
23
+ * **id** the name which is appended to the current namespace
24
+ * **owner** the desired owner
25
+
26
+ Then, within the body of that policy, include the additional
27
+ policy files.
28
+ )
29
+
30
+ self.example = %(
31
+ - !include groups.yml
32
+
33
+ - !policy
34
+ id: ops
35
+ owner: !group operations
36
+ body:
37
+ - !include jenkins-master.yml
38
+ - !include ansible.yml
39
+ - !include openvpn.yml
40
+ )
41
+
42
+ def id= value
43
+ self.file = value
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,37 @@
1
+ module Conjur::Policy::Types
2
+ class Member < Base
3
+ def initialize role = nil
4
+ self.role = role
5
+ end
6
+
7
+ attribute :role
8
+ attribute :admin, kind: :boolean, singular: true
9
+
10
+ self.description = %(
11
+ Designate the members of a [Role](#reference/role) such as a [Group](#reference/group).
12
+
13
+ The member indicates the "grantee" (which role will gain the role grant), as well as the
14
+ `admin` option which determines whether the grantee can grant/revoke the role to other roles.
15
+
16
+ The default value for `admin` is `false`.
17
+ )
18
+
19
+ self.example = %(
20
+ - !user dee
21
+ - !user dum
22
+ - !group brothers
23
+
24
+ - !grant
25
+ role: !group brothers
26
+ members:
27
+ - !user dee
28
+ - !member dum
29
+ role: !user dum
30
+ admin: true
31
+ )
32
+
33
+ def to_s
34
+ "#{role} #{admin ? 'with' : 'without'} admin option"
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,59 @@
1
+ module Conjur
2
+ module Policy
3
+ module Types
4
+ class Permit < Base
5
+ attribute :role, kind: :member
6
+ attribute :privilege, kind: :string, dsl_accessor: true
7
+ attribute :resource, dsl_accessor: true
8
+ attribute :replace, kind: :boolean, singular: true, dsl_accessor: true
9
+
10
+ self.description = %(
11
+ Give permissions on a [Resource](#reference/resource) to a [Role](#reference/role).
12
+
13
+ Once a privilege is given, permission checks performed by the role
14
+ will return `true`.
15
+
16
+ Note that permissions are not "inherited" in the same way that roles are.
17
+ If role A is granted to role B, then role B "inherits" all the privileges held
18
+ by role A. If role A can `execute` a variable, then role B can as well.
19
+ The privileges on each resource are distinct, regardless of how they are named.
20
+ If role A has `execute` privilege on a resource called `dev`, the role does **not**
21
+ gain any privileges on a resource called `dev/password`. Role-based access control
22
+ is explicit in this way to avoid unintendend side-effects from the way that
23
+ resources are named.
24
+
25
+ [More](/key_concepts/rbac.html) on role-based access control in Conjur.
26
+
27
+ See also: [Deny](#reference/deny)
28
+ )
29
+
30
+ self.example = %(
31
+ - !variable answer
32
+ - !user deep_thought
33
+
34
+ - !permit
35
+ role: !user deep_thought
36
+ privileges: [ read, execute, update ]
37
+ resource: !variable answer
38
+ )
39
+
40
+ include ResourceMemberDSL
41
+
42
+ def initialize privilege = nil
43
+ self.privilege = privilege
44
+ end
45
+
46
+ def to_s
47
+ if Array === role
48
+ role_string = role.map &:role
49
+ admin = false
50
+ else
51
+ role_string = role.role
52
+ admin = role.admin
53
+ end
54
+ "Permit #{role_string} to [#{Array(privilege).join(', ')}] on #{Array(resource).join(', ')}#{admin ? ' with grant option' : ''}"
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,180 @@
1
+ module Conjur
2
+ module Policy
3
+ module Types
4
+ class YAMLList < Array
5
+ def tag
6
+ [ "!", self.class.name.split("::")[-1].underscore ].join
7
+ end
8
+
9
+ def encode_with coder
10
+ coder.represent_seq tag, self
11
+ end
12
+ end
13
+
14
+ module Tagless
15
+ def tag; nil; end
16
+ end
17
+
18
+ module CustomStatement
19
+ def custom_statement handler, &block
20
+ record = yield
21
+ class << record
22
+ include RecordReferenceFactory
23
+ end
24
+ push record
25
+ do_scope record, &handler
26
+ end
27
+ end
28
+
29
+ module Grants
30
+ include CustomStatement
31
+
32
+ def grant &block
33
+ custom_statement(block) do
34
+ Conjur::Policy::Types::Grant.new
35
+ end
36
+ end
37
+
38
+ def revoke &block
39
+ custom_statement(block) do
40
+ Conjur::Policy::Types::Revoke.new
41
+ end
42
+ end
43
+ end
44
+
45
+ module Permissions
46
+ include CustomStatement
47
+
48
+ def permit privilege, &block
49
+ custom_statement(block) do
50
+ Conjur::Policy::Types::Permit.new(privilege)
51
+ end
52
+ end
53
+
54
+ def give &block
55
+ custom_statement(block) do
56
+ Conjur::Policy::Types::Give.new
57
+ end
58
+ end
59
+
60
+ def retire &block
61
+ custom_statement(block) do
62
+ Conjur::Policy::Types::Retire.new
63
+ end
64
+ end
65
+ end
66
+
67
+ # Entitlements will allow creation of any record, as well as declaration
68
+ # of permit, deny, grant and revoke.
69
+ class Entitlements < YAMLList
70
+ include Tagless
71
+ include Grants
72
+ include Permissions
73
+
74
+ def policy id=nil, &block
75
+ policy = Policy.new
76
+ policy.id(id) unless id.nil?
77
+ push policy
78
+
79
+ do_scope policy, &block
80
+ end
81
+ end
82
+
83
+ class Body < YAMLList
84
+ include Grants
85
+ include Permissions
86
+ end
87
+
88
+ # Policy includes the functionality of Entitlements, wrapped in a
89
+ # policy role, policy resource, policy id and policy version.
90
+ class Policy < Record
91
+ include ActsAsResource
92
+ include ActsAsRole
93
+
94
+ self.description = %(
95
+ Create a policy. A policy is composed of the following:
96
+
97
+ * **id** A unique id, which can be prefixed by a `namespace`.
98
+ * **body** A set of records such as variables, groups and layers which are "owned" by the policy.
99
+
100
+ Under the hood, a Policy is actually a role *and* a resource.
101
+ The role is a role whose kind is "policy", and it has the specified `id`. By default
102
+ the policy role is granted, with `admin` option, to the `--as-group` or `--as-role` option which is specified
103
+ when the policy is loaded. The policy resource is a resource whose kind is "policy", and
104
+ whose owner is the policy role.
105
+
106
+ All the records declared in the `body` of the policy are also owned by the policy role
107
+ by default. As a result, the role specified by `--as-group` or `--as-role` has full
108
+ ownership and management of everything defined in the policy.
109
+
110
+ Policies should be self-contained; they should not generally make any reference to
111
+ records from outside the policy. This way, the policy can be loaded with different
112
+ `--as-group`, `--as-role`, and `--namespace` options to serve different functions in the workflow.
113
+ For example, if a policy is loaded into the `dev` namespace with `--as-group dev-admin`,
114
+ then a "dev" version of the policy is created with full management assigned to the `dev-admin` group.
115
+
116
+ [See above](#example) for an example of a complete policy.
117
+ )
118
+
119
+ self.example = %(
120
+ - !policy
121
+ id: example/v1
122
+ body:
123
+ - &secrets
124
+ - !variable secret
125
+
126
+ - !layer
127
+
128
+ - !grant
129
+ role: !layer
130
+ permissions: [ read, execute ]
131
+ resources: *secrets
132
+ )
133
+
134
+ def role
135
+ raise "account is nil" unless account
136
+ @role ||= Role.new("#{account}:policy:#{id}").tap do |role|
137
+ role.owner = Role.new(owner.roleid)
138
+ end
139
+ end
140
+
141
+ def resource
142
+ raise "account is nil" unless account
143
+ @resource ||= Resource.new("#{account}:policy:#{id}").tap do |resource|
144
+ resource.owner = Role.new(role.roleid)
145
+ end
146
+ end
147
+
148
+ # Body is handled specially.
149
+ def referenced_records
150
+ super - Array(@body)
151
+ end
152
+
153
+ def body &block
154
+ if block_given?
155
+ singleton :body, lambda { Body.new }, &block
156
+ end
157
+ @body
158
+ end
159
+
160
+ def body= body
161
+ @body = body
162
+ end
163
+
164
+ protected
165
+
166
+ def singleton id, factory, &block
167
+ object = instance_variable_get("@#{id}")
168
+ unless object
169
+ object = factory.call
170
+ class << object
171
+ include Tagless
172
+ end
173
+ instance_variable_set("@#{id}", object)
174
+ end
175
+ do_scope object, &block
176
+ end
177
+ end
178
+ end
179
+ end
180
+ end