conjur-policy-parser 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- 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,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
|