conjur-cli 4.6.1 → 4.7.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
data/Gemfile CHANGED
@@ -4,7 +4,13 @@ source 'https://rubygems.org'
4
4
  gemspec
5
5
 
6
6
  gem 'conjur-api', git: 'https://github.com/inscitiv/api-ruby.git', branch: 'master'
7
-
8
7
  group :test, :development do
9
8
  gem 'pry'
10
9
  end
10
+
11
+ group :development do
12
+ gem 'conjur-asset-environment-api'
13
+ gem 'conjur-asset-key-pair-api'
14
+ gem 'conjur-asset-layer-api'
15
+ # gem 'conjur-asset-ui-api', github: 'conjurinc/conjur-asset-ui', branch: 'new-audit'
16
+ end
@@ -75,7 +75,11 @@ class Conjur::Command::Assets < Conjur::Command
75
75
  command :list do |c|
76
76
  c.action do |global_options,options,args|
77
77
  kind = require_arg(args, "kind").gsub('-', '_')
78
- api.send(kind.pluralize).each do |e|
78
+ if api.respond_to?(kind.pluralize)
79
+ api.send(kind.pluralize)
80
+ else
81
+ api.resources(kind: kind)
82
+ end.each do |e|
79
83
  display(e, options)
80
84
  end
81
85
  end
@@ -0,0 +1,65 @@
1
+ #
2
+ # Copyright (C) 2014 Conjur Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'conjur/command'
22
+
23
+ class Conjur::DSLCommand < Conjur::Command
24
+ class << self
25
+ def file_or_stdin_arg(args)
26
+ end
27
+
28
+ def run_script(args, options, &block)
29
+ filename = nil
30
+ script = if script = args.pop
31
+ filename = script
32
+ script = File.read(script)
33
+ else
34
+ STDIN.read
35
+ end
36
+
37
+ require 'conjur/dsl/runner'
38
+ runner = Conjur::DSL::Runner.new(script, filename)
39
+
40
+ if context = options[:context]
41
+ runner.context = begin
42
+ JSON.parse(File.read(context))
43
+ rescue Errno::ENOENT
44
+ {}
45
+ end
46
+ end
47
+
48
+ if block_given?
49
+ block.call(runner) do
50
+ runner.execute
51
+ end
52
+ else
53
+ runner.execute
54
+ end
55
+
56
+ if context
57
+ File.write(context, JSON.pretty_generate(runner.context))
58
+ File.chmod(0600, context)
59
+ end
60
+
61
+ puts JSON.pretty_generate(runner.context)
62
+ end
63
+ end
64
+
65
+ end
@@ -0,0 +1,83 @@
1
+ #
2
+ # Copyright (C) 2014 Conjur Inc
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
+ # this software and associated documentation files (the "Software"), to deal in
6
+ # the Software without restriction, including without limitation the rights to
7
+ # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8
+ # the Software, and to permit persons to whom the Software is furnished to do so,
9
+ # subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in all
12
+ # copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16
+ # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18
+ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19
+ # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
+ #
21
+ require 'conjur/command/dsl_command'
22
+
23
+ class Conjur::Command::Policy < Conjur::DSLCommand
24
+ self.prefix = :policy
25
+
26
+ class << self
27
+ def default_collection_user
28
+ ( ENV['USER'] ).strip
29
+ end
30
+
31
+ def default_collection_hostname
32
+ ( ENV['HOSTNAME'] || `hostname` ).strip
33
+ end
34
+
35
+ def default_collection_name
36
+ [ default_collection_user, default_collection_hostname ].join('@')
37
+ end
38
+ end
39
+
40
+ desc "Load a policy from Conjur DSL"
41
+ long_desc <<-DESC
42
+ This method is EXPERIMENTAL and subject to change
43
+
44
+ Loads a Conjur policy from DSL, applying particular conventions to the role and resource
45
+ ids.
46
+
47
+ The first path element of each id is the collection. Policies are separated into collections
48
+ according to software development lifecycle. The default collection for a policy is $USER@$HOSTNAME,
49
+ in other words, the username and hostname on which the policy is created. This is approriate for
50
+ policy development and local testing. Once tested, policies can be created in more official
51
+ environments such as ci, stage, and production.
52
+
53
+ The second path element of each id is the policy name and version, following the convention
54
+ policy-x.y.z, where x, y, and z are the semantic version of the policy.
55
+
56
+ Next, each policy creates a policy role and policy resource. The policy resource is used to store
57
+ annotations on the policy. The policy role becomes the owner of the owned policy assets. The
58
+ --as-group and --as-role options can be used to set the owner of the policy role. The default
59
+ owner of the policy role is the logged-in user (you), as always.
60
+ DESC
61
+ arg_name "(policy-file | STDIN)"
62
+ command :load do |c|
63
+ acting_as_option(c)
64
+
65
+ c.desc "Policy collection (default: #{default_collection_user}@#{default_collection_hostname})"
66
+ c.arg_name "collection"
67
+ c.flag [:collection]
68
+
69
+ c.desc "Load context from this config file, and save it when finished. The file permissions will be 0600 by default."
70
+ c.arg_name "context"
71
+ c.flag [:c, :context]
72
+
73
+ c.action do |global_options,options,args|
74
+ collection = options[:collection] || default_collection_name
75
+
76
+ run_script args, options do |runner, &block|
77
+ runner.scope collection do
78
+ block.call
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -51,7 +51,7 @@ class Conjur::Command::Resources < Conjur::Command
51
51
  display api.resource(id).attributes
52
52
  end
53
53
  end
54
-
54
+
55
55
  desc "Determines whether a resource exists"
56
56
  arg_name "resource-id"
57
57
  command :exists do |c|
@@ -129,4 +129,82 @@ class Conjur::Command::Resources < Conjur::Command
129
129
  display api.resource(id).permitted_roles(permission)
130
130
  end
131
131
  end
132
+
133
+ desc "Set an annotation on a resource"
134
+ arg_name "resource-id name value"
135
+ command :annotate do |c|
136
+ c.action do |global_options, options, args|
137
+ id = full_resource_id require_arg(args, 'resource-id')
138
+ name = require_arg args, 'name'
139
+ value = require_arg args, 'value'
140
+ api.resource(id).annotations[name] = value
141
+ puts "Set annotation '#{name}' to '#{value}' for resource '#{id}'"
142
+ end
143
+ end
144
+
145
+ desc "Show an annotation for a resource"
146
+ arg_name "resource-id name"
147
+ command :annotation do |c|
148
+ c.action do |global_options, options, args|
149
+ id = full_resource_id require_arg args, 'resource-id'
150
+ name = require_arg args, 'name'
151
+ value = api.resource(id).annotations[name]
152
+ puts value unless value.nil?
153
+ end
154
+ end
155
+
156
+ desc "Print annotations as JSON"
157
+ arg_name 'resource-id'
158
+ command :annotations do |c|
159
+ c.action do |go, o, args|
160
+ id = full_resource_id require_arg args, 'resource-id'
161
+ annots = api.resource(id).annotations.to_h
162
+ puts annots.to_json
163
+ end
164
+ end
165
+
166
+ desc "List all resources"
167
+ command :list do |c|
168
+ c.desc "Role to act as. By default, the current logged-in role is used."
169
+ c.flag [:role]
170
+
171
+ c.desc "Filter by kind"
172
+ c.flag [:k, :kind]
173
+
174
+ c.desc "Full-text search on resource id and annotation values"
175
+ c.flag [:s, :search]
176
+
177
+ c.desc "Maximum number of records to return"
178
+ c.flag [:l, :limit]
179
+
180
+ c.desc "Offset to start from"
181
+ c.flag [:o, :offset]
182
+
183
+ c.desc "Show only ids"
184
+ c.switch [:i, :ids]
185
+
186
+ c.desc "Show annotations in 'raw' format"
187
+ c.switch [:r, :"raw-annotations"]
188
+
189
+ c.action do |global_options, options, args|
190
+ opts = options.slice(:search, :limit, :options, :kind)
191
+ opts[:acting_as] = options[:role] if options[:role]
192
+ resources = api.resources(opts)
193
+ if options[:ids]
194
+ puts resources.map(&:resourceid)
195
+ else
196
+ resources = resources.map &:attributes
197
+ unless options[:'raw-annotations']
198
+ resources = resources.map do |r|
199
+ r['annotations'] = (r['annotations'] || []).inject({}) do |hash, annot|
200
+ hash[annot['name']] = annot['value']
201
+ hash
202
+ end
203
+ r
204
+ end
205
+ end
206
+ puts JSON.pretty_generate resources
207
+ end
208
+ end
209
+ end
132
210
  end
@@ -19,9 +19,9 @@
19
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
20
  #
21
21
  require 'conjur/authn'
22
- require 'conjur/command'
22
+ require 'conjur/command/dsl_command'
23
23
 
24
- class Conjur::Command::Authn < Conjur::Command
24
+ class Conjur::Command::Script < Conjur::DSLCommand
25
25
  self.prefix = :script
26
26
 
27
27
  desc "Run a Conjur DSL script"
@@ -34,31 +34,7 @@ class Conjur::Command::Authn < Conjur::Command
34
34
  c.flag [:c, :context]
35
35
 
36
36
  c.action do |global_options,options,args|
37
- filename = nil
38
- if script = args.pop
39
- filename = script
40
- script = File.read(script)
41
- else
42
- script = STDIN.read
43
- end
44
- require 'conjur/dsl/runner'
45
- runner = Conjur::DSL::Runner.new(script, filename)
46
- if options[:context]
47
- runner.context = begin
48
- JSON.parse(File.read(options[:context]))
49
- rescue Errno::ENOENT
50
- {}
51
- end
52
- end
53
-
54
- result = runner.execute
55
-
56
- if options[:context]
57
- File.write(options[:context], JSON.pretty_generate(runner.context))
58
- File.chmod(0600, options[:context])
59
- end
60
-
61
- puts JSON.pretty_generate(result)
37
+ run_script args, options
62
38
  end
63
39
  end
64
40
  end
@@ -20,6 +20,7 @@
20
20
  #
21
21
  require 'active_support/core_ext/hash/deep_merge'
22
22
  require 'active_support/core_ext/hash/indifferent_access'
23
+
23
24
  module Conjur
24
25
  class Config
25
26
  @@attributes = {}
@@ -62,7 +63,6 @@ module Conjur
62
63
  end
63
64
  if Config[:cert_file]
64
65
  OpenSSL::SSL::SSLContext::DEFAULT_CERT_STORE.add_file Config[:cert_file]
65
- #OpenSSL::X509::Store.add_file Config[:cert_file]
66
66
  end
67
67
  end
68
68
 
@@ -47,10 +47,16 @@ module Conjur
47
47
  !@objects.empty? ? @objects.last : nil
48
48
  end
49
49
 
50
+ # Current scope, used as a path/delimited/prefix to a role or resource id.
50
51
  def current_scope
51
52
  !@scopes.empty? ? @scopes.join('/') : nil
52
53
  end
53
54
 
55
+ # Current scope, used for user@scope.
56
+ def current_user_scope
57
+ current_scope ? current_scope.gsub(/[^\w]/, '-') : nil
58
+ end
59
+
54
60
  def scope name = nil, &block
55
61
  if name != nil
56
62
  do_scope name, &block
@@ -73,6 +79,19 @@ module Conjur
73
79
  end
74
80
  end
75
81
 
82
+ def policy id, &block
83
+ self.role "policy", id do |role|
84
+ context["policy"] = role.identifier
85
+ self.owns do
86
+ self.resource "policy", id do
87
+ scope id do
88
+ block.call if block_given?
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+
76
95
  alias model namespace
77
96
 
78
97
  def execute
@@ -82,15 +101,19 @@ module Conjur
82
101
  end
83
102
 
84
103
  def resource kind, id, options = {}, &block
85
- id = full_resource_id([kind, qualify_id(id) ].join(':'))
104
+ id = full_resource_id([kind, qualify_id(id, kind) ].join(':'))
86
105
  find_or_create :resource, id, options, &block
87
106
  end
88
107
 
89
108
  def role kind, id, options = {}, &block
90
- id = full_resource_id([ kind, qualify_id(id) ].join(':'))
109
+ id = full_resource_id([ kind, qualify_id(id, kind) ].join(':'))
91
110
  find_or_create :role, id, options, &block
92
111
  end
93
112
 
113
+ # purpose and existence of this method are unobvious for model designer
114
+ # just "variable" in DSL works fine through method_missing
115
+ # is this method OBSOLETED ?
116
+ # https://basecamp.com/1949725/projects/4268938-api-version-4-x/todos/84972543-low-variable
94
117
  def create_variable id = nil, options = {}, &block
95
118
  options[:id] = id if id
96
119
  mime_type = options.delete(:mime_type) || 'text/plain'
@@ -110,18 +133,23 @@ module Conjur
110
133
 
111
134
  protected
112
135
 
113
- def qualify_id id
136
+ def qualify_id id, kind
114
137
  if id[0] == "/"
115
138
  id[1..-1]
116
139
  else
117
- [ current_scope, id ].compact.join('/')
140
+ case kind.to_sym
141
+ when :user
142
+ [ id, current_user_scope ].compact.join('@')
143
+ else
144
+ [ current_scope, id ].compact.join('/')
145
+ end
118
146
  end
119
147
  end
120
148
 
121
149
  def method_missing(sym, *args, &block)
122
150
  if create_compatible_args?(args) && api.respond_to?(sym)
123
151
  id = args[0]
124
- id = qualify_id(id) unless sym == :user
152
+ id = qualify_id(id, sym)
125
153
  find_or_create sym, id, args[1] || {}, &block
126
154
  elsif current_object && current_object.respond_to?(sym)
127
155
  current_object.send(sym, *args, &block)
@@ -141,11 +169,20 @@ module Conjur
141
169
  def find_or_create(type, id, options, &block)
142
170
  find_method = type.to_sym
143
171
  create_method = "create_#{type}".to_sym
172
+
173
+ # TODO: find a way to pass annotations as part of top-level options hash
174
+ # https://basecamp.com/1949725/projects/4268938-api-version-4-x/todos/84965324-low-dsl-design
175
+ annotations = options.delete(:annotations)
176
+
144
177
  unless (obj = api.send(find_method, id)) && obj.exists?
145
178
  options = expand_options(options)
146
179
  obj = if create_method == :create_variable
180
+ #NOTE: it duplicates logic of "create_variable" method above
181
+ # https://basecamp.com/1949725/projects/4268938-api-version-4-x/todos/84972543-low-variable
147
182
  options[:id] = id
148
- api.send(create_method, options.delete(:mime_type), options.delete(:kind), options)
183
+ mime_type = options.delete(:mime_type) || annotations[:mime_type] || 'text/plain'
184
+ kind = options.delete(:kind) || annotations[:kind] || 'secret'
185
+ api.send(create_method, mime_type, kind, options)
149
186
  elsif [ 2, -2 ].member?(api.method(create_method).arity)
150
187
  api.send(create_method, id, options)
151
188
  else
@@ -153,6 +190,12 @@ module Conjur
153
190
  api.send(create_method, options)
154
191
  end
155
192
  end
193
+ if annotations.kind_of? Hash
194
+ # TODO: fix API to make 'annotations' available directly on objects
195
+ # https://basecamp.com/1949725/projects/4268938-api-version-4-x/todos/84970444-high-support
196
+ obj_as_resource = obj.resource
197
+ annotations.each { |k,v| obj_as_resource.annotations[k]=v }
198
+ end
156
199
  do_object obj, &block
157
200
  end
158
201
 
@@ -202,4 +245,4 @@ module Conjur
202
245
  end
203
246
  end
204
247
  end
205
- end
248
+ end
@@ -19,5 +19,6 @@
19
19
  # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
20
  #
21
21
  module Conjur
22
- VERSION = "4.6.1"
22
+ VERSION = "4.7.0"
23
+ ::Version=VERSION
23
24
  end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'conjur/dsl/runner'
3
+
4
+ describe Conjur::Command::Policy do
5
+ context logged_in: true do
6
+ let(:role) do
7
+ double("role", exists?: true, api_key: "the-api-key", roleid: "the-role")
8
+ end
9
+ let(:resource) do
10
+ double("resource", exists?: true).as_null_object
11
+ end
12
+ let(:name) { nil }
13
+ before {
14
+ File.stub(:read).with("policy-body").and_return "{}"
15
+ Conjur::DSL::Runner.any_instance.stub(:api).and_return api
16
+ }
17
+ before {
18
+ api.stub(:role).with("the-account:policy:#{collection}/the-policy-1.0.0").and_return role
19
+ api.stub(:resource).with("the-account:policy:#{collection}/the-policy-1.0.0").and_return resource
20
+ if name
21
+ resource.should_receive(:[]).with(:name, name)
22
+ end
23
+ }
24
+
25
+ describe_command 'policy:load --collection the-collection policy-body' do
26
+ let(:collection) { "the-collection" }
27
+ it "creates the policy" do
28
+ invoke.should == 0
29
+ end
30
+ end
31
+ context "default collection" do
32
+ let(:collection) { "alice@localhost" }
33
+ before {
34
+ stub_const("ENV", "USER" => "alice", "HOSTNAME" => "localhost")
35
+ }
36
+ describe_command 'policy:load policy-body' do
37
+ it "creates the policy with default collection" do
38
+ invoke.should == 0
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
data/tamr.rb ADDED
@@ -0,0 +1,15 @@
1
+ policy "tamr-1.0.0" do
2
+ group "admin" do
3
+ owns do
4
+ ops, developers, build = [
5
+ group("ops"),
6
+ group("developers"),
7
+ group("build")
8
+ ]
9
+
10
+ layer "sandbox" do
11
+ add_member "admin_host", developers
12
+ end
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: conjur-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.6.1
4
+ version: 4.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-03-03 00:00:00.000000000 Z
13
+ date: 2014-03-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: conjur-api
@@ -218,6 +218,7 @@ files:
218
218
  - .gitignore
219
219
  - .kateproject
220
220
  - .project
221
+ - .tamr.rb.swp
221
222
  - Gemfile
222
223
  - LICENSE
223
224
  - README.md
@@ -244,11 +245,13 @@ files:
244
245
  - lib/conjur/command/assets.rb
245
246
  - lib/conjur/command/audit.rb
246
247
  - lib/conjur/command/authn.rb
248
+ - lib/conjur/command/dsl_command.rb
247
249
  - lib/conjur/command/field.rb
248
250
  - lib/conjur/command/groups.rb
249
251
  - lib/conjur/command/hosts.rb
250
252
  - lib/conjur/command/ids.rb
251
253
  - lib/conjur/command/init.rb
254
+ - lib/conjur/command/policy.rb
252
255
  - lib/conjur/command/resources.rb
253
256
  - lib/conjur/command/roles.rb
254
257
  - lib/conjur/command/rspec/describe_command.rb
@@ -271,6 +274,7 @@ files:
271
274
  - spec/command/groups_spec.rb
272
275
  - spec/command/hosts_spec.rb
273
276
  - spec/command/init_spec.rb
277
+ - spec/command/policy_spec.rb
274
278
  - spec/command/resources_spec.rb
275
279
  - spec/command/roles_spec.rb
276
280
  - spec/command/users_spec.rb
@@ -280,6 +284,7 @@ files:
280
284
  - spec/conjurrc
281
285
  - spec/dsl/runner_spec.rb
282
286
  - spec/spec_helper.rb
287
+ - tamr.rb
283
288
  - update_ci.sh
284
289
  homepage: https://github.com/conjurinc/cli-ruby
285
290
  licenses:
@@ -294,12 +299,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
294
299
  - - ! '>='
295
300
  - !ruby/object:Gem::Version
296
301
  version: '0'
302
+ segments:
303
+ - 0
304
+ hash: -1938562320841533221
297
305
  required_rubygems_version: !ruby/object:Gem::Requirement
298
306
  none: false
299
307
  requirements:
300
308
  - - ! '>='
301
309
  - !ruby/object:Gem::Version
302
310
  version: '0'
311
+ segments:
312
+ - 0
313
+ hash: -1938562320841533221
303
314
  requirements: []
304
315
  rubyforge_project:
305
316
  rubygems_version: 1.8.25
@@ -326,6 +337,7 @@ test_files:
326
337
  - spec/command/groups_spec.rb
327
338
  - spec/command/hosts_spec.rb
328
339
  - spec/command/init_spec.rb
340
+ - spec/command/policy_spec.rb
329
341
  - spec/command/resources_spec.rb
330
342
  - spec/command/roles_spec.rb
331
343
  - spec/command/users_spec.rb