conjur-asset-policy 0.8.3 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7d3f421be05da2eced0b95bfa1028a1a3e01695f
4
- data.tar.gz: 73121a9f79529fae31f28c8f7ed08842b8481bd8
3
+ metadata.gz: 64cf9174fc3ed6a86366f2f46c052952c054440e
4
+ data.tar.gz: 1f02801a02ae8d60b28c78faa1d254872778d2ea
5
5
  SHA512:
6
- metadata.gz: 857b7d9be7f6a76d6721b51c8a479fb78ad125efbbf76ade98d10671e6b7cfc561c4b39a5dc5466b0801a482aed09c2feab439cff839532565a89e7d56a2e7f7
7
- data.tar.gz: 1208b5fefe05b10c7d7c7b212f76cbda8344eaaf141b9c3d62181720db172a8056bc18f15b8122b8a7cdbbdd7ec4532afac6faa63678dc5387d52a479c04e7f8
6
+ metadata.gz: 1744445bfee08b4c08f0dc5bbde0931d744559659a348e4158e1863b571b1a699f37c8292942e8171d5156076a07558f59abccf7fd3516dbeed00695a99b5e8d
7
+ data.tar.gz: 29dede5e8aaab32f3fd7ecf4915908da281b15b3896984c388252cd332ba8cc1dad16e45dd8711bd535de8343d11f5c9f722296b5e0721753537c9626302850a
data/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ # 0.11.0
2
+
3
+ * Enable management of user public keys.
4
+ * Properly escape resource ids with spaces in them.
5
+
6
+ # 0.10.0
7
+
8
+ * Granting a layer to a host also gives permissions to the layer managed roles.
9
+ * Revoking a layer from a host also revokes permissions from the layer managed roles.
10
+
11
+ # 0.9.0
12
+
13
+ * Rename `!managed-role` to `!automatic-role`, while maintaining backwards compatibility.
14
+
1
15
  # 0.8.3
2
16
 
3
17
  * When re-loading a policy, properly apply `--as-group` and `--as-role` by changing the ownership of top-level records as needed.
data/Gemfile CHANGED
@@ -7,3 +7,4 @@ source 'https://rubygems.org'
7
7
  gemspec
8
8
 
9
9
  gem 'simplecov', require: false
10
+ gem 'conjur-asset-authn-local', git: 'https://github.com/conjurinc/conjur-asset-authn-local.git', branch: 'master'
data/ci/test.sh CHANGED
@@ -8,6 +8,7 @@ cd /src/conjur-asset-policy
8
8
  bundle
9
9
 
10
10
  export CONJUR_AUTHN_LOGIN=admin
11
- export CONJUR_AUTHN_API_KEY=secret
11
+
12
+ ruby -ryaml -e "conf = YAML.load(File.read('/etc/conjur.conf')); conf['plugins'] = [ 'policy', 'authn-local' ]; File.write('/etc/conjur.conf', YAML.dump(conf))"
12
13
 
13
14
  bundle exec rake jenkins || true
@@ -1,7 +1,7 @@
1
1
  module Conjur
2
2
  module Asset
3
3
  module Policy
4
- VERSION = "0.8.3"
4
+ VERSION = "0.11.0"
5
5
  end
6
6
  end
7
7
  end
@@ -14,6 +14,7 @@ end
14
14
  require 'rest-client'
15
15
 
16
16
  require 'conjur/api/patches/role'
17
+ require 'conjur/api/patches/user'
17
18
 
18
19
  require 'conjur/policy/logger'
19
20
  require 'conjur/policy/invalid'
@@ -0,0 +1,9 @@
1
+ require 'conjur/api'
2
+
3
+ class Conjur::User
4
+ # The attribute synchronization expects a +public_keys+ method on the User, so add one.
5
+ # The expected form is a list, so split the raw pubkeys result on newlines.
6
+ def public_keys
7
+ conjur_api.public_keys(login).split("\n")
8
+ end
9
+ end
@@ -54,7 +54,7 @@ class Conjur::Command::Policy < Conjur::DSLCommand
54
54
  actions = []
55
55
  records.each do |record|
56
56
  executor_class = Conjur::Policy::Executor.class_for(record)
57
- executor = executor_class.new(record, actions)
57
+ executor = executor_class.new(api, record, actions)
58
58
  executor.execute
59
59
  end
60
60
  Conjur::Policy::HTTPExecutor.new(api).execute actions
@@ -155,7 +155,21 @@ command. Therefore, a policy can be loaded in three steps, if desired:
155
155
  end
156
156
 
157
157
  records = Conjur::Policy::Resolver.resolve(records, Conjur.configuration.account, ownerid, options[:namespace])
158
- plan = Conjur::Policy::Planner.plan(records, api)
158
+ plan_api = if api.privilege == "elevate"
159
+ # Check if the user has 'reveal'
160
+ # In order to do this, the 'elevate' privilege must be removed, otherwise the permission
161
+ # check always returns 'true'
162
+ naked_api = api.dup
163
+ naked_api.privilege = nil
164
+ if naked_api.global_privilege_permitted?("reveal")
165
+ api.with_privilege("reveal")
166
+ else
167
+ api
168
+ end
169
+ else
170
+ api
171
+ end
172
+ plan = Conjur::Policy::Planner.plan(records, plan_api)
159
173
 
160
174
  if options[:"dry-run"]
161
175
  case options[:"format"]
@@ -28,8 +28,15 @@ module Conjur
28
28
  Conjur::Policy::Executor::CreateRecord
29
29
  end
30
30
  else
31
- class_name = action.class.name.split("::")[-1]
32
- Conjur::Policy::Executor.const_get(class_name)
31
+ action_name = action.class.name.split("::")[-1]
32
+ if action.respond_to?(:record)
33
+ type_name = action.record.class.short_name
34
+ end
35
+ begin
36
+ Conjur::Policy::Executor.const_get([ action_name, type_name ].compact.join)
37
+ rescue NameError
38
+ Conjur::Policy::Executor.const_get(action_name)
39
+ end
33
40
  end
34
41
  end
35
42
  end
@@ -66,7 +73,7 @@ module Conjur
66
73
 
67
74
  def create path, parameters
68
75
  request = Net::HTTP::Post.new [ @base_path, path ].join('/')
69
- request.set_form_data to_params(parameters)
76
+ set_request_body request, parameters
70
77
  send_request request
71
78
  end
72
79
 
@@ -74,7 +81,7 @@ module Conjur
74
81
 
75
82
  def update path, parameters
76
83
  request = Net::HTTP::Put.new [ @base_path, path ].join('/')
77
- request.set_form_data to_params(parameters)
84
+ set_request_body request, parameters
78
85
  send_request request
79
86
  end
80
87
 
@@ -82,7 +89,9 @@ module Conjur
82
89
 
83
90
  def delete path, parameters
84
91
  uri = URI.parse([ @base_path, path ].join('/'))
85
- uri.query = [uri.query, parameters.to_query].compact.join('&')
92
+ unless parameters.blank?
93
+ uri.query = [uri.query, parameters.to_query(nil)].compact.join('&')
94
+ end
86
95
  request = Net::HTTP::Delete.new [ uri.path, '?', uri.query ].join
87
96
 
88
97
  send_request request
@@ -114,9 +123,17 @@ module Conjur
114
123
  # empty
115
124
  end
116
125
 
126
+ def set_request_body request, params
127
+ if params.is_a?(String)
128
+ request.body = params
129
+ else
130
+ request.set_form_data to_params(params)
131
+ end
132
+ end
133
+
117
134
  # Convert parameter keys to rails []-style keys
118
135
  def to_params params
119
- params.inject({}) do |memo,entry|
136
+ Array(params).inject({}) do |memo,entry|
120
137
  key, value = entry
121
138
  if value.is_a?(Array)
122
139
  key = "#{key}[]"
@@ -1,14 +1,18 @@
1
1
  module Conjur::Policy
2
2
  module Executor
3
+ require 'conjur/escape'
4
+
3
5
  # Builds a list of execution actions for a statement. The statement
4
6
  # is an object from Conjur::Policy::Types. Each execution action is
5
7
  # an HTTP method, a request path, and request parameters.
6
8
  class Base
7
9
  include Conjur::Policy::Logger
10
+ include Conjur::Escape
8
11
 
9
- attr_reader :statement, :actions
12
+ attr_reader :api, :statement, :actions
10
13
 
11
- def initialize statement, actions
14
+ def initialize api, statement, actions
15
+ @api = api
12
16
  @statement = statement
13
17
  @actions = actions
14
18
  end
@@ -23,12 +27,12 @@ module Conjur::Policy
23
27
 
24
28
  def resource_path record = nil
25
29
  record ||= self.statement
26
- [ "authz", record.account, "resources", record.resource_kind, record.id ].join('/')
30
+ [ "authz", record.account, "resources", record.resource_kind, path_escape(record.id) ].join('/')
27
31
  end
28
32
 
29
33
  def role_path record = nil
30
34
  record ||= self.statement
31
- [ "authz", record.account, "roles", record.role_kind, record.id ].join('/')
35
+ [ "authz", record.account, "roles", record.role_kind, path_escape(record.id) ].join('/')
32
36
  end
33
37
  end
34
38
 
@@ -47,7 +51,17 @@ module Conjur::Policy
47
51
  [ "authz", annotate_record.account,
48
52
  "annotations",
49
53
  annotate_record.resource_kind,
50
- CGI.escape(annotate_record.id) ].join('/')
54
+ path_escape(annotate_record.id) ].join('/')
55
+ end
56
+ end
57
+
58
+ module PublicKeys
59
+ def public_key_path
60
+ [ "pubkeys", CGI.escape(record.id) ].join('/')
61
+ end
62
+
63
+ def attribute_names
64
+ super - [ :public_key ]
51
65
  end
52
66
  end
53
67
  end
@@ -38,7 +38,7 @@ module Conjur::Policy::Executor
38
38
  {
39
39
  record.id_attribute => record.id
40
40
  }.tap do |params|
41
- custom_attrs = record.custom_attribute_names.inject({}) do |memo, attr|
41
+ custom_attrs = attribute_names.inject({}) do |memo, attr|
42
42
  value = record.send(attr)
43
43
  memo[attr.to_s] = value if value
44
44
  memo
@@ -47,6 +47,28 @@ module Conjur::Policy::Executor
47
47
  params["ownerid"] = record.owner.roleid if record.owner
48
48
  end
49
49
  end
50
+
51
+ def attribute_names
52
+ record.custom_attribute_names
53
+ end
54
+ end
55
+
56
+ # Sync the user's public keys using the Pubkeys service. POSTing the
57
+ # public keys to the User service won't have any effect.
58
+ class CreateUser < CreateRecord
59
+ include PublicKeys
60
+
61
+ def execute
62
+ super
63
+
64
+ Array(record.public_keys).each do |key|
65
+ action({
66
+ 'method' => 'post',
67
+ 'path' => public_key_path,
68
+ 'parameters' => key
69
+ })
70
+ end
71
+ end
50
72
  end
51
73
 
52
74
  # When creating a host factory, the +roleid+ and +layer+ are required.
@@ -1,6 +1,23 @@
1
1
  module Conjur::Policy::Executor
2
2
  class Grant < Base
3
3
  def execute
4
+ if statement.role.is_a?(Conjur::Policy::Types::Layer) && statement.member.role.is_a?(Conjur::Policy::Types::Host)
5
+ add_host_to_layer
6
+ else
7
+ grant_role_to_member
8
+ end
9
+ end
10
+
11
+ def add_host_to_layer
12
+ parameters = { "hostid" => statement.member.role.roleid }
13
+ action({
14
+ 'method' => 'post',
15
+ 'path' => "layers/#{fully_escape statement.role.id}/hosts",
16
+ 'parameters' => parameters
17
+ })
18
+ end
19
+
20
+ def grant_role_to_member
4
21
  parameters = { "member" => statement.member.role.roleid }
5
22
  parameters['admin_option'] = statement.member.admin unless statement.member.admin.nil?
6
23
  action({
@@ -10,4 +27,4 @@ module Conjur::Policy::Executor
10
27
  })
11
28
  end
12
29
  end
13
- end
30
+ end
@@ -1,6 +1,22 @@
1
1
  module Conjur::Policy::Executor
2
2
  class Revoke < Base
3
3
  def execute
4
+ if statement.role.is_a?(Conjur::Policy::Types::Layer) && statement.member.is_a?(Conjur::Policy::Types::Host)
5
+ remove_host_from_layer
6
+ else
7
+ revoke_role_from_member
8
+ end
9
+ end
10
+
11
+ def remove_host_from_layer
12
+ action({
13
+ 'method' => 'delete',
14
+ 'path' => "layers/#{fully_escape statement.role.id}/hosts/#{fully_escape statement.member.roleid}",
15
+ 'parameters' => {}
16
+ })
17
+ end
18
+
19
+ def revoke_role_from_member
4
20
  action({
5
21
  'method' => 'delete',
6
22
  'path' => "#{role_path(statement.role)}?members",
@@ -3,29 +3,70 @@ module Conjur::Policy::Executor
3
3
  include Annotate
4
4
 
5
5
  def execute
6
- statement.record.custom_attribute_names.each do |attr|
7
- value = statement.record.send(attr)
8
- action({
9
- 'method' => 'put',
10
- 'path' => update_path,
11
- 'parameters' => { attr.to_s => value }
12
- })
6
+ attribute_names.each do |attr|
7
+ value = record.send(attr)
8
+ if value
9
+ action({
10
+ 'method' => 'put',
11
+ 'path' => update_path,
12
+ 'parameters' => { attr.to_s => value }
13
+ })
14
+ end
13
15
  end
14
16
 
15
17
  annotate
16
18
  end
17
19
 
18
20
  def kind_path
19
- statement.record.resource_kind.pluralize
21
+ record.resource_kind.pluralize
20
22
  end
21
23
 
22
24
  def update_path
23
- require 'cgi'
24
- [ kind_path, CGI.escape(statement.record.id) ].join('/')
25
+ [ kind_path, fully_escape(statement.record.id) ].join('/')
25
26
  end
26
27
 
27
28
  def annotate_record
29
+ record
30
+ end
31
+
32
+ def record
28
33
  statement.record
29
34
  end
35
+
36
+ def attribute_names
37
+ record.custom_attribute_names
38
+ end
39
+ end
40
+
41
+ class UpdateUser < Update
42
+ include PublicKeys
43
+
44
+ def execute
45
+ super
46
+
47
+ if record.public_keys
48
+ (Array(record.public_keys) - user.public_keys).each do |key|
49
+ action({
50
+ 'method' => 'post',
51
+ 'path' => public_key_path,
52
+ 'parameters' => key
53
+ })
54
+ end
55
+ (user.public_keys - Array(record.public_keys)).each do |key|
56
+ action({
57
+ 'method' => 'delete',
58
+ 'path' => [ public_key_path, CGI.escape(key_name(key)) ].join('/')
59
+ })
60
+ end
61
+ end
62
+ end
63
+
64
+ def user
65
+ api.user record.id
66
+ end
67
+
68
+ def key_name key
69
+ key.split(' ')[-1]
70
+ end
30
71
  end
31
72
  end
@@ -6,7 +6,7 @@ module Conjur::Policy::Logger
6
6
 
7
7
  require 'logger'
8
8
  self.logger = Logger.new(STDERR)
9
- self.logger.level = Logger::INFO
9
+ self.logger.level = (ENV['DEBUG'] == "true" ? Logger::DEBUG : Logger::INFO)
10
10
  end
11
11
  end
12
12
  end
@@ -19,7 +19,7 @@ module Conjur
19
19
  ensure
20
20
  planner.plan = nil
21
21
  end
22
- end
22
+ end
23
23
  end
24
24
  end
25
25
 
@@ -22,34 +22,13 @@ module Conjur
22
22
  end
23
23
 
24
24
  def role_record fullid
25
- account, kind, id = fullid.split(':', 3)
26
- if kind == '@'
27
- Conjur::Policy::Types::ManagedRole.build fullid
28
- else
29
- if record_class = record_type(kind)
30
- record_class.new.tap do |record|
31
- record.account = account
32
- unless record.is_a?(Conjur::Policy::Types::Variable)
33
- record.kind = kind if record.respond_to?(:kind=)
34
- end
35
- record.id = id
36
- end
37
- else
38
- Conjur::Policy::Types::Role.new(fullid)
39
- end
40
- end
25
+ detect_record fullid, Conjur::Policy::Types::Role
41
26
  end
42
27
 
43
- def record_type kind
44
- begin
45
- Conjur::Policy::Types.const_get(kind.classify)
46
- rescue NameError
47
- nil
48
- end
28
+ def resource_record fullid
29
+ detect_record fullid, Conjur::Policy::Types::Resource
49
30
  end
50
-
51
- alias resource_record role_record
52
-
31
+
53
32
  def resource
54
33
  api.resource(record.resourceid)
55
34
  end
@@ -158,7 +137,7 @@ module Conjur
158
137
 
159
138
  def create_record
160
139
  log { "Creating #{record}" }
161
-
140
+
162
141
  create = Conjur::Policy::Types::Create.new
163
142
  create.record = record
164
143
 
@@ -179,6 +158,36 @@ module Conjur
179
158
  plan.resources_created.add(record.resourceid) if record.resource?
180
159
  action create
181
160
  end
161
+
162
+ protected
163
+
164
+ def detect_record fullid, raw_type
165
+ account, kind, id = fullid.split(':', 3)
166
+ if kind == '@'
167
+ Conjur::Policy::Types::AutomaticRole.build fullid
168
+ else
169
+ if record_class = record_type(kind, raw_type)
170
+ record_class.new.tap do |record|
171
+ record.account = account
172
+ unless record.is_a?(Conjur::Policy::Types::Variable)
173
+ record.kind = kind if record.respond_to?(:kind=)
174
+ end
175
+ record.id = id
176
+ end
177
+ else
178
+ Conjur::Policy::Types::Role.new(fullid)
179
+ end
180
+ end
181
+ end
182
+
183
+ def record_type kind, raw_type
184
+ return raw_type if kind == '!'
185
+ begin
186
+ Conjur::Policy::Types.const_get(kind.classify)
187
+ rescue NameError
188
+ nil
189
+ end
190
+ end
182
191
  end
183
192
  end
184
193
  end
@@ -121,7 +121,13 @@ module Conjur
121
121
  # Each permission is yielded to the block.
122
122
  def resource_permissions resource, privileges, &block
123
123
  permissions = begin
124
- JSON.parse(api.resource(resource.resourceid).get)['permissions']
124
+ resource = JSON.parse(api.resource(resource.resourceid).get)
125
+ # Malformed resource ids can be interpreted as a resource search
126
+ if resource.is_a?(Array)
127
+ []
128
+ else
129
+ resource['permissions']
130
+ end
125
131
  rescue RestClient::ResourceNotFound
126
132
  if api.resource(resource.resourceid).exists?
127
133
  $stderr.puts "WARNING: Unable to fetch permissions of resource #{resource.resourceid}. Use 'elevate' mode, or at least 'reveal' mode, for policy management."
@@ -85,7 +85,7 @@ module Conjur
85
85
  id = id[1..-1]
86
86
  else
87
87
  if record.respond_to?(:resource_kind) && record.resource_kind == "user"
88
- id = [ id, namespace ].compact.join('@')
88
+ id = [ id, user_namespace ].compact.join('@')
89
89
  else
90
90
  id = [ namespace, id ].compact.join('/')
91
91
  end
@@ -109,6 +109,10 @@ module Conjur
109
109
 
110
110
  protected
111
111
 
112
+ def user_namespace
113
+ namespace.gsub('/', '-') if namespace
114
+ end
115
+
112
116
  def substitute! id
113
117
  SUBSTITUTIONS.each do |k,v|
114
118
  next unless value = send(v)
@@ -400,9 +400,9 @@ module Conjur
400
400
  end
401
401
  end
402
402
 
403
- module ManagedRoleDSL
404
- def managed_role record, role_name
405
- ManagedRole.new(record, role_name)
403
+ module AutomaticRoleDSL
404
+ def automatic_role record, role_name
405
+ AutomaticRole.new(record, role_name)
406
406
  end
407
407
  end
408
408
  end
@@ -8,7 +8,11 @@ Create a record of any type.
8
8
  A record can be a [Role](#reference/role) or a [Resource](#reference/resource).
9
9
 
10
10
  Creating records can be done explicitly using this node type, or
11
- implicitly. Examples of both are given immeditely below.
11
+ implicitly. Examples of both are given immediately below.
12
+
13
+ When a record is created explicitly, it's an error if the record already exists.
14
+ When a record is created implicitly, the record will be found-or-created, and its
15
+ state (owner, fields and annotations) will be updated to match the policy declaration.
12
16
  )
13
17
 
14
18
  self.example = %(
@@ -2,8 +2,13 @@ module Conjur::Policy::Types
2
2
  class Deny < Base
3
3
 
4
4
  self.description = %(
5
- Deny privileges on a [Resource](#reference/resource). (compare:
6
- [Revoke](#reference/revoke) for [Roles](#reference/role))
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)
7
12
  )
8
13
 
9
14
  self.example = %(
@@ -5,7 +5,9 @@ module Conjur::Policy::Types
5
5
 
6
6
  self.description = %(
7
7
  Give ownership of a resource to a [Role](#reference/role).
8
- (compare: [Grant](#reference/grant))
8
+
9
+ When the owner role performs a permission check on an owned resource, the
10
+ result is always `true`.
9
11
 
10
12
  [More](/key_concepts/rbac.html) on role-based access control in Conjur.
11
13
  )
@@ -5,13 +5,37 @@ module Conjur::Policy::Types
5
5
  attribute :replace, kind: :boolean, singular: true, dsl_accessor: true
6
6
 
7
7
  include RoleMemberDSL
8
- include ManagedRoleDSL
8
+ include AutomaticRoleDSL
9
9
 
10
10
  self.description = %(
11
- Grant one [Role](#reference/role) to another.
12
- (compare: [Give](#reference/give) for [Resources](#reference/resource))
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.
13
35
 
14
36
  [More](/key_concepts/rbac.html) on role-based access control in Conjur.
37
+
38
+ See also: [Permit](#reference/permit) for [Resources](#reference/resource)
15
39
  )
16
40
 
17
41
  self.example = %(
@@ -9,6 +9,11 @@ module Conjur::Policy::Types
9
9
 
10
10
  self.description = %(
11
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`.
12
17
  )
13
18
 
14
19
  self.example = %(
@@ -8,14 +8,23 @@ module Conjur
8
8
  attribute :replace, kind: :boolean, singular: true, dsl_accessor: true
9
9
 
10
10
  self.description = %(
11
- Give permissions on a [Resource](#reference/resource) to a [Role](#reference/role). (contrast: [Deny](#reference/deny))
11
+ Give permissions on a [Resource](#reference/resource) to a [Role](#reference/role).
12
12
 
13
- The permissions are:
14
- 1. read (see the resource)
15
- 2. execute (use the resource)
16
- 3. update (make changes to the resource)
13
+ Once a privilege is given, permission checks performed by the role
14
+ will return `true`.
17
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
+
18
25
  [More](/key_concepts/rbac.html) on role-based access control in Conjur.
26
+
27
+ See also: [Deny](#reference/deny)
19
28
  )
20
29
 
21
30
  self.example = %(
@@ -92,23 +92,43 @@ module Conjur
92
92
  include ActsAsRole
93
93
 
94
94
  self.description = %(
95
- Create a versioned policy.
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.
96
115
 
97
116
  [See above](#example) for an example of a complete policy.
98
117
  )
99
118
 
100
119
  self.example = %(
101
- - !user operator
102
-
103
120
  - !policy
104
121
  id: example/v1
105
- owner: !user operator
106
122
  body:
107
- - !variable secret
123
+ - &secrets
124
+ - !variable secret
125
+
126
+ - !layer
127
+
108
128
  - !grant
109
- role: !user operator
110
- permissions: [ read, execute, update ]
111
- resource: !variable secret
129
+ role: !layer
130
+ permissions: [ read, execute ]
131
+ resources: *secrets
112
132
  )
113
133
 
114
134
  def role
@@ -115,23 +115,26 @@ module Conjur
115
115
  attribute :owner, kind: :role, singular: true, dsl_accessor: true
116
116
 
117
117
  self.description = %(
118
- Create a custom role.
119
-
120
- From our [role-based access control guide](/key_concepts/rbac.html):
121
-
122
- > The purpose of a role is to have privileges and to initiate
123
- > transactions.
124
- >
125
- > A role may represent a person, a group, a non-human user (“robot”)
126
- > such as a virtual machine or process, or a group of other roles.
127
- >
128
- > In addition to having privileges, a role can be granted to another
129
- > role.
130
- >
131
- > When a role is granted, the receiving role gains all the privileges
132
- > of the granted role. In addition, it gains all the roles which are
133
- > held by the granted role; role grants are fully inherited.
118
+ Create a custom role.
134
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)
135
138
  )
136
139
 
137
140
  self.example = %(
@@ -164,22 +167,23 @@ From our [role-based access control guide](/key_concepts/rbac.html):
164
167
  self.description = %(
165
168
  Create a custom Resource.
166
169
 
167
- From our [role-based access control guide](/key_concepts/rbac.html):
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.
168
173
 
169
- > Resources are the entities on which permissions are defined. A
170
- > resource id is an arbitrary, unique string which identifies the
171
- > protected asset.
172
- >
173
- > Examples: database password, virtual machine or
174
- > server (for SSH access management), web service endpoint
174
+ Examples: database password, virtual machine or
175
+ server (for SSH access management), web service endpoint
175
176
 
176
- From our [CLI reference](/cli#annotating-resources):
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.
177
181
 
178
- > Any Conjur resource can be annotated with a key-value pair. This
179
- makes organization and discovery easier since annotations can be
180
- searched on and are shown in the Conjur UI. Automation workflows
181
- like rotation and expiration are based on annotations.
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.
182
185
 
186
+ See also: [role-based access control guide](/key_concepts/rbac.html)
183
187
  )
184
188
 
185
189
  self.example = %(
@@ -203,25 +207,38 @@ From our [CLI reference](/cli#annotating-resources):
203
207
  include ActsAsRole
204
208
 
205
209
  self.description = %(
206
- Create a [Role](#reference/role) representing a human user. (For virtual machines, scripts, and other infrastructure, [Host](#reference/host) is a more appropriate role.)
210
+ Create a [Role](#reference/role) representing a human user.
211
+
212
+ Users have several specific attributes:
207
213
 
208
- See also: [Users](/reference/services/directory/user) in our service reference.
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.
209
222
  )
210
223
 
211
224
  self.example = %(
212
225
  - !user robert
213
226
  uidnumber: 1208
227
+ public_keys:
228
+ - ssh-rsa AAAAB3NzaC1yc2EAAAAD...+10trhK5Pt robert@home
229
+ - ssh-rsa AAAAB3NzaC1yc2EAAAAD...+10trhK5Pt robert@work
214
230
  annotations:
215
231
  public: true
216
232
  can_predict_movement: false
217
233
  )
218
-
234
+
219
235
  attribute :uidnumber, kind: :integer, singular: true, dsl_accessor: true
220
-
236
+ attribute :public_key, kind: :string, dsl_accessor: true
237
+
221
238
  def id_attribute; 'login'; end
222
239
 
223
240
  def custom_attribute_names
224
- [ :uidnumber ]
241
+ [ :uidnumber, :public_key ]
225
242
  end
226
243
  end
227
244
 
@@ -234,21 +251,17 @@ See also: [Users](/reference/services/directory/user) in our service reference.
234
251
  self.description = %(
235
252
  Create a Group record.
236
253
 
237
- From our [CLI reference](/cli#users-groups):
238
-
239
- > Users are organized into groups in Conjur. Every user other than
240
- 'admin' should be in a group. When a user becomes a member of a
241
- group they inherit the group's privileges. You can delegate members
242
- of the group to be admins. This means that they can add and remove
243
- other members of the group. The owner of a group is automatically an
244
- admin.
245
-
246
- See also: [User](#reference/user) type, [Groups](/reference/services/directory/group) in our service reference.
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.
247
260
  )
248
261
 
249
262
  self.example = %(
250
- - !user sysop
251
- - !user db-admin
263
+ - !user alice
264
+ - !user bob
252
265
 
253
266
  - !group ops
254
267
  gidnumber: 110
@@ -256,9 +269,9 @@ See also: [User](#reference/user) type, [Groups](/reference/services/directory/g
256
269
  - !grant
257
270
  role: !group ops
258
271
  members:
259
- - !user sysop
272
+ - !user alice
260
273
  - !member
261
- role: !user db-admin
274
+ role: !user bob
262
275
  admin: true
263
276
  )
264
277
  def custom_attribute_names
@@ -271,9 +284,13 @@ See also: [User](#reference/user) type, [Groups](/reference/services/directory/g
271
284
  include ActsAsRole
272
285
 
273
286
  self.description = %(
274
- Create a Host record and resource.
275
-
276
- See also: [Layer](#reference/layer) type, [machine identity](/key_concepts/machine_identity.html), [Host](/reference/services/directory/host) in our service reference.
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).
277
294
  )
278
295
 
279
296
  self.example = %(
@@ -294,15 +311,11 @@ See also: [Layer](#reference/layer) type, [machine identity](/key_concepts/machi
294
311
  self.description = %(
295
312
  Create a Layer record.
296
313
 
297
- From our [CLI reference](/cli#hosts-layers):
298
-
299
- > Host are organized into layers in Conjur. Hosts can be added and
300
- removed from layers, and map logically to your infrastructure. A
301
- host can be a single machine, but it could also be an application or
302
- Docker container - where several different applications are running
303
- on the same machine or VM.
304
-
305
- See also: [Host](#reference/host) type, [Layers](/reference/services/directory/layer) in our service reference.
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.
306
319
  )
307
320
 
308
321
  self.example = %(
@@ -310,10 +323,10 @@ See also: [Host](#reference/host) type, [Layers](/reference/services/directory/l
310
323
  - !host AM
311
324
  - !host GLaDOS
312
325
 
313
- - !layer bad_hosts
326
+ - !layer evil-hosts
314
327
 
315
328
  - !grant
316
- role: !layer bad_hosts
329
+ role: !layer evil-hosts
317
330
  members:
318
331
  - !host ProteusIV
319
332
  - !host AM
@@ -330,19 +343,15 @@ See also: [Host](#reference/host) type, [Layers](/reference/services/directory/l
330
343
  self.description = %(
331
344
  Create a Variable resource to hold a secret value.
332
345
 
333
- From our [CLI reference](/cli#variables):
334
-
335
- > Variables are containers for secrets in Conjur. They can hold any
336
- > value. You can annotate resources and also assign them a kind, a
337
- > signifier as to what type of value they hold. Variable values are
338
- > versioned and assigning a value during variable creation is
339
- > optional. When fetching a value, the latest version is returned by
340
- > default.
341
- >
342
- > Variables are resources; you assign roles privileges to them as
343
- > desired.
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.
344
352
 
345
- See also: [Variables](https://developer.conjur.net/reference/services/directory/variable) in the service reference.
353
+ Variables are resources; you assign roles privileges to them as
354
+ desired.
346
355
  )
347
356
 
348
357
  self.example = %(
@@ -366,18 +375,15 @@ See also: [Variables](https://developer.conjur.net/reference/services/directory/
366
375
  self.description = %(
367
376
  Create a [Resource](#reference/resource) representing a web service endpoint.
368
377
 
369
- From our [role-based access control guide](/key_concepts/rbac.html):
370
-
371
- > Web services endpoints are represented in Conjur as a webservice
372
- > resource. Permission grants are pretty straightforward: an input
373
- > HTTP request path is mapped to a webservice resource. The HTTP
374
- > method is mapped to an RBAC privilege. A permission check is
375
- > performed, according to the following transaction:
376
- >
377
- > * `role` incoming role on the HTTP request
378
- > * `privilege` read, update, or delete according to HTTP verb
379
- > * `resource` web service resource id
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:
380
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
381
387
  )
382
388
 
383
389
  self.example = %(
@@ -397,9 +403,8 @@ From our [role-based access control guide](/key_concepts/rbac.html):
397
403
  include ActsAsResource
398
404
 
399
405
  self.description = %(
400
- Create a host-factory service for bootstrapping [Hosts](#reference/host) into a [Layer](#reference/layer).
401
-
402
- See also: [Host Factory](/reference/services/host_factory) in our service reference.
406
+ Create a host-factory service for automatically creating [Hosts](#reference/host)
407
+ and enrolling them into one or more [Layer](#reference/layer)s.
403
408
  )
404
409
 
405
410
  self.example = %(
@@ -425,7 +430,7 @@ See also: [Host Factory](/reference/services/host_factory) in our service refere
425
430
  end
426
431
  end
427
432
 
428
- class ManagedRole < Base
433
+ class AutomaticRole < Base
429
434
  include ActsAsRole
430
435
 
431
436
  def initialize record = nil, role_name = nil
@@ -437,13 +442,16 @@ See also: [Host Factory](/reference/services/host_factory) in our service refere
437
442
  attribute :role_name, kind: :string, singular: true
438
443
 
439
444
  self.description = %(
440
- Some [Roles](#reference/role) are created automatically. For historical reasons, these are given the type `managed-role`.
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`).
441
449
 
442
- These roles are:
450
+ The automatic roles of a Layer are:
443
451
 
444
- * `use_host`, for allowing SSH access
445
- * `admin_host`, for allowing admin (root) login.
446
- * `observe`
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.
447
455
  )
448
456
 
449
457
  self.example = %(
@@ -452,22 +460,22 @@ These roles are:
452
460
  - !group line-cooks
453
461
  - !layer kitchen
454
462
 
455
- # no need to create MangedRoles; they are automatic.
463
+ # There's no need to create automatic roles explicitly
456
464
 
457
465
  - !grant
458
- role: !managed-role
466
+ role: !automatic-role
459
467
  record: !layer kitchen
460
468
  role_name: use_host
461
469
  member: !group line-cooks
462
470
 
463
471
  - !grant
464
- role: !managed-role
472
+ role: !automatic-role
465
473
  record: !layer kitchen
466
474
  role_name: admin_host
467
475
  member: !user chef
468
476
 
469
477
  - !grant
470
- role: !managed-role
478
+ role: !automatic-role
471
479
  record: !layer kitchen
472
480
  role_name: observe
473
481
  member: !user owner
@@ -7,21 +7,19 @@ module Conjur
7
7
  self.description = %(
8
8
  Move a Role or Resource to the attic.
9
9
 
10
- From our [CLI reference](/cli#retiring):
10
+ When you no longer need a role or resource in Conjur, you `retire` it.
11
+ This is different than deleting it. When you retire an item, all of
12
+ its memberships and privileges are revoked and its ownership is
13
+ transferred to the `attic` user. This is a special user in Conjur that
14
+ is created when you first bootstrap your Conjur endpoint. By
15
+ retiring rather than deleting items, the integrity of the immutable
16
+ audit log is preserved.
11
17
 
12
- > When you no longer need a role or resource in Conjur, you `retire` it.
13
- > This is different than deleting it. When you retire an item, all of
14
- > its memberships and privileges are revoked and its ownership is
15
- > transferred to the `attic` user. This is a special user in Conjur that
16
- > is created when you first bootstrap your Conjur endpoint. By
17
- > retiring rather than deleting items, the integrity of the immutable
18
- > audit log is preserved.
19
- >
20
- > You can unretire items by logging in as the
21
- > 'attic' user and transferring their ownership to another role. The
22
- > 'attic' user's API key is stored as a variable in Conjur at
23
- > `conjur/users/attic/api-key`. It is owned by the 'security_admin'
24
- > group. )
18
+ You can unretire items by logging in as the
19
+ 'attic' user and transferring their ownership to another role. The
20
+ 'attic' user's API key is stored as a variable in Conjur at
21
+ `conjur/users/attic/api-key`. It is owned by the 'security_admin'
22
+ group. )
25
23
 
26
24
  self.example = %(
27
25
  - !retire
@@ -8,6 +8,12 @@ module Conjur
8
8
  self.description = %(
9
9
  Remove a [Role](#reference/role) grant. (contrast: [Grant](#reference/grant))
10
10
 
11
+ Some `revoke` operations have additional semantics beyond the role revocation:
12
+
13
+ * When a Layer is revoked from a Host, the automatic roles on the Layer are denied their
14
+ privileges on the Host. Specifically, the `observe` role is denied `read` privilege,
15
+ `use_host` is denied `execute`, and `admin_host` is denied `update`.
16
+
11
17
  See also: [role-based access control guide](/key_concepts/rbac.html).
12
18
  )
13
19
 
@@ -3,9 +3,12 @@ module Conjur::Policy::Types
3
3
  attribute :record
4
4
 
5
5
  self.description = %(
6
- Make changes to an existing record's attributes.
6
+ Make explicit changes to an existing record's attributes and/or annotations.
7
7
 
8
- For example, you can change annotations on a [Resource](#reference/resource), the `uidnumber` of a [User](#reference/user), etc.
8
+ For example, you can change annotations on a [Resource](#reference/resource), or the `uidnumber` of a [User](#reference/user).
9
+
10
+ Generally, Update is not used explicitly. Instead, an update is performed by the create-or-replace behavior of
11
+ statements such as User, Group, Host, Layer, etc.
9
12
  )
10
13
 
11
14
  self.example = %(
@@ -350,6 +350,7 @@ module Conjur
350
350
  def start_mapping *args
351
351
  log {"#{indent}start mapping #{args}"}
352
352
  anchor, tag, _ = args
353
+ tag = "!automatic-role" if %w(!managed-role !managed_role).include?(tag)
353
354
  value = handler.start_mapping tag
354
355
  anchor anchor, value
355
356
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conjur-asset-policy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.3
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Gilpin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-04-22 00:00:00.000000000 Z
11
+ date: 2016-04-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -189,6 +189,7 @@ files:
189
189
  - lib/conjur-asset-policy-version.rb
190
190
  - lib/conjur-asset-policy.rb
191
191
  - lib/conjur/api/patches/role.rb
192
+ - lib/conjur/api/patches/user.rb
192
193
  - lib/conjur/command/policy.rb
193
194
  - lib/conjur/policy/doc.rb
194
195
  - lib/conjur/policy/executor.rb