conjur-cli 4.29.0 → 4.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 974b0f72a352691fba5f49e01849a56518cf3afe
4
- data.tar.gz: 1ae44b2cbaca17695bfeec8192bba636a43ca6bc
3
+ metadata.gz: 7a8e5171dfa3fb930e4d09c7b48c70f6b572d66a
4
+ data.tar.gz: 38aeb8c329f096825dc1b6273e84d863f3e0a24d
5
5
  SHA512:
6
- metadata.gz: 01f136c95c3467917990b66611bc71f0f3684d0c371e481c3700fdb3532975b9b52f530423da96c6980dbd06518d66571123cc3b5caba10d75de56e6a36819d8
7
- data.tar.gz: 8492137a6c4bc4852dcc85ddec8e826d80ce1d1675a7d198c71680f3fd2fa1d45f3fb15c90f01892153b258dd6f79230008543327ae9da7eb37e1d42ca6d99c3
6
+ metadata.gz: a98b539b66a03f4949372a8d056dde90564d2637d84bc46ada647363cb8aef662cdd85fe852d1adad6364fc211ff7e6e1d75df3edee3a0b91fc9de5bb28aab93
7
+ data.tar.gz: 3bb5257cebd5c670d22f290fea687c0b8a5c9f37669abb87128c39d4a8679f6f247850123825ee37a3aba812d10840df6f754cc9b4f487358da2b21fc6ff6b21
data/.gitignore CHANGED
@@ -23,6 +23,7 @@ pkg
23
23
  rdoc
24
24
  spec/reports
25
25
  features/reports
26
+ acceptance-features/reports
26
27
  test/tmp
27
28
  test/version_tmp
28
29
  tmp
data/CHANGELOG.md CHANGED
@@ -1,4 +1,8 @@
1
- # Unreleased
1
+ # 4.30.0
2
+
3
+ * Implementation of `conjur bootstrap` is moved to the API gem, and made extensible.
4
+ * Added new steps to `conjur bootstrap`, including the creation of service identities, and giving `elevate` and `reveal` to the `security_admin` group.
5
+ * `hostfactory create` verifies that the current role is able to admin the host factory group; otherwise, host factory creation will fail.
2
6
 
3
7
  # 4.29.0
4
8
  * Add `conjur host rotate_api_key` command.
data/Rakefile CHANGED
@@ -9,11 +9,13 @@ require 'rspec/core/rake_task'
9
9
  RSpec::Core::RakeTask.new :spec
10
10
  Cucumber::Rake::Task.new :features
11
11
 
12
- task :jenkins => ['ci:setup:rspec', :spec, 'ci:setup:cucumber_report_cleanup'] do
12
+ task :jenkins => ['ci:setup:rspec', :spec] do
13
+ File.write('build_number', ENV['BUILD_NUMBER']) if ENV['BUILD_NUMBER']
14
+ require 'fileutils'
15
+ FileUtils.rm_rf 'features/reports'
13
16
  Cucumber::Rake::Task.new do |t|
14
- t.cucumber_opts = "--tags ~@real-api --format pretty --format CI::Reporter::Cucumber --out features/reports"
17
+ t.cucumber_opts = "--tags ~@real-api --format pretty --format junit --out features/reports"
15
18
  end.runner.run
16
- File.write('build_number', ENV['BUILD_NUMBER']) if ENV['BUILD_NUMBER']
17
19
  end
18
20
 
19
21
  task default: [:spec, :features]
@@ -0,0 +1,13 @@
1
+ Feature: "conjur bootstrap" creates default resources, privileges and roles
2
+
3
+ Background:
4
+ Given I successfully run `conjur bootstrap -q`
5
+
6
+ Scenario: A new security admin can use 'elevate'
7
+ When I successfully run `conjur resource permitted_roles '!:!:conjur' elevate`
8
+ Then the stdout should contain "cucumber:group:security_admin"
9
+
10
+ Scenario: Run bootstrap and test for the existence of things
11
+ Then I successfully run `conjur elevate group show security_admin`
12
+ And I successfully run `conjur elevate host show conjur/secrets-rotator`
13
+ And I successfully run `conjur elevate resource show webservice:conjur/authn-tv`
@@ -1,13 +1,29 @@
1
1
  Feature: Create a Host Factory
2
+
2
3
  Background:
3
- Given I successfully run `conjur layer create --as-group $ns/security_admin $ns/layer`
4
4
 
5
5
  Scenario: Create a host factory successfully
6
- When I successfully run `conjur hostfactory create --as-group $ns/security_admin --layer $ns/layer $ns/hostfactory`
7
- Then the JSON should have "deputy_api_key"
6
+ Given I successfully run `conjur layer create --as-group $ns/security_admin $ns/layer`
7
+ Then I successfully run `conjur hostfactory create --as-group $ns/security_admin --layer $ns/layer $ns/hostfactory`
8
+ And the JSON should have "deputy_api_key"
8
9
 
9
- Scenario: Host factory owner must have admin on layer
10
+ Scenario: The client role can use itself as the hostfactory role
10
11
  Given I successfully run `conjur user create unprivileged@$ns`
12
+ And I successfully run `conjur layer create $ns/layer`
11
13
  When I run `conjur hostfactory create --as-role user:unprivileged@$ns --layer $ns/layer $ns/hostfactory`
12
- Then the stderr should contain "must be an admin of layer"
13
- And the stdout should not contain anything
14
+
15
+ Scenario: If current role cannot admin the layer, the error is reported
16
+ Given I successfully run `conjur layer create $ns/the-layer`
17
+ And I login as a new user
18
+ Given I successfully run `conjur group create $ns/the-group`
19
+ And I run `conjur hostfactory create --as-group $ns/the-group -l $ns/the-layer $ns/the-factory`
20
+ Then the exit status should not be 0
21
+ And the output should contain "must be an admin of layer"
22
+
23
+ Scenario: If current role cannot admin the HF role, the error is reported
24
+ Given I successfully run `conjur group create $ns/the-group`
25
+ And I login as a new user
26
+ Given I successfully run `conjur layer create $ns/the-layer`
27
+ And I run `conjur hostfactory create --as-group $ns/the-group -l $ns/the-layer $ns/the-factory`
28
+ Then the exit status should not be 0
29
+ And the output should contain "must be an admin of role"
data/lib/conjur-cli.rb ADDED
@@ -0,0 +1,21 @@
1
+ #
2
+ # Copyright (C) 2016 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/cli"
@@ -449,7 +449,17 @@ an alternative destination role.)
449
449
  password
450
450
  end
451
451
 
452
+ def current_role
453
+ kind, id = api.username.split('/', 2)
454
+ if id.nil?
455
+ id = kind
456
+ kind = 'user'
457
+ end
458
+ api.role([ kind, id ].join(":"))
459
+ end
460
+
452
461
  def has_admin?(role, other_role)
462
+ return true if role.roleid == other_role.roleid
453
463
  memberships = role.memberships.map(&:roleid)
454
464
  other_role.members.any? { |m| memberships.member?(m.member.roleid) && m.admin_option }
455
465
  rescue RestClient::Forbidden
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2014 Conjur Inc
2
+ # Copyright (C) 2014-2016 Conjur Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
5
  # this software and associated documentation files (the "Software"), to deal in
@@ -20,7 +20,7 @@
20
20
  #
21
21
 
22
22
  class Conjur::Command::Bootstrap < Conjur::Command
23
- desc "Create initial users, groups, and permissions"
23
+ desc "Create initial users, groups, permissions, and service identities."
24
24
  long_desc %Q(When you launch a new Conjur master server, it contains only one login: the "admin" user.
25
25
  The bootstrap command will finish the setup of a new Conjur system by creating other essential records.
26
26
 
@@ -28,111 +28,101 @@ class Conjur::Command::Bootstrap < Conjur::Command
28
28
 
29
29
  * Creation of a group called "security_admin".
30
30
 
31
- * Giving the "security_admin" the power to manage public keys.
31
+ * Giving the "security_admin" the power to manage public keys.
32
32
 
33
- * Creation of a user called "attic", which will be the owner of retired records.
33
+ * Creation of a user called "attic", which will be the owner of retired records.
34
34
 
35
- * Storing the "attic" user's API key in a variable called "conjur/users/attic/api-key".
35
+ * Create system identities for use services such as pubkeys, rotator, and ldap-sync.
36
36
 
37
- * (optional) Create a new user who will be made a member and admin of the "security_admin" group.
37
+ * (optional) Create a new user who will be made a member and admin of the "security_admin" group.
38
38
 
39
- * (optional) If a new user was created, login as that user.
39
+ * (optional) If a new user was created, login as that user.
40
+
41
+ The Bootstrap command can be extended to perform additional actions by CLI plugins. The plugin just
42
+ needs to define a new class in Conjur::Bootstrap::Command. Its "perform" method will be run automatically.
40
43
  )
41
44
 
42
- # Determines whether the current logged-in user is sufficiently powerful to perform bootstrap.
43
- # This is currently determined by detecting whether the logged-in role:
44
- #
45
- # * Is a user
46
- # * Has admin privilege on the security_admin group role
47
- # * Is an owner of the security_admin group resource
48
- #
49
- # The admin user will always satisfy these conditions, unless they are revoked for some reason.
50
- # Other users created by the bootstrap command will (typically) also have these powers.
51
- def self.security_admin_manager? api
52
- return true if elevated?
53
-
54
- username = api.username
55
- user = if username.index('/')
56
- nil
57
- else
58
- api.user(username)
45
+ class BootstrapListener
46
+ def echo msg
47
+ $stderr.puts msg
59
48
  end
60
- security_admin = api.group("security_admin")
61
-
62
- if user
63
- memberships = user.role.memberships.map(&:roleid)
64
- if security_admin.exists?
65
- # The user has a role which is admin of the security_admin role
66
- # The user has the role which owns the security_admin resource
67
- has_admin?(user.role, security_admin.role) &&
68
- memberships.member?(security_admin.resource.ownerid)
69
- else
70
- user.login == "admin"
71
- end
72
- else
73
- false
49
+ end
50
+
51
+ class << self
52
+ def quiet? options
53
+ !$stdin.tty? || options[:quiet]
74
54
  end
75
55
  end
76
56
 
77
57
  Conjur::CLI.command :bootstrap do |c|
78
- c.desc "Don't perform up-front checks to see if you are sufficiently privileged to run this command."
79
- c.switch [:f, :force]
80
-
58
+ c.desc "Print out all the commands to stderr as they run."
59
+ c.default_value true
60
+ c.switch [:v, :verbose]
61
+
62
+ c.desc "Don't prompt for any user input, even if there's a TTY."
63
+ c.long_desc %Q(By default, 'bootstrap' may issue prompts on the TTY. For example, it will prompt you
64
+ to login if you aren't currently logged in as any user. It will also ask you if you want to create a new
65
+ 'security_admin' user. This switch can be used to disable all such prompts, making it safe to run
66
+ 'bootstrap' even when requests for user input cannot be handled. Prompts are also disabled if STDIN
67
+ is not a tty.)
68
+ c.default_value false
69
+ c.switch [:q, :quiet]
70
+
81
71
  c.action do |global_options,options,args|
82
72
  require 'highline/import'
83
73
 
84
74
  # Ensure there's a logged in user
85
- Conjur::Authn.connect
75
+ connect_options = {}
76
+ connect_options[:noask] = true if quiet?(options)
77
+ Conjur::Authn.connect nil, connect_options
86
78
 
87
- force = options[:force]
88
- exit_now! "You must be an administrator to bootstrap Conjur" unless force || security_admin_manager?(api)
89
-
90
- if (security_admin = api.group("security_admin")).exists?
91
- puts "Group 'security_admin' exists"
92
- else
93
- puts "Creating group 'security_admin'"
94
- security_admin = api.create_group("security_admin")
95
- end
96
-
97
- security_admin.resource.give_to(security_admin) unless security_admin.resource.ownerid == security_admin.role.roleid
98
-
99
- key_managers = api.group("pubkeys-1.0/key-managers")
100
- unless security_admin.role.memberships.map(&:roleid).member?(key_managers.role.roleid)
101
- puts "Permitting group 'security_admin' to manage public keys"
102
- key_managers.add_member security_admin, admin_option: true
103
- end
104
-
105
- security_administrators = security_admin.role.members.select{|m| m.member.roleid.split(':')[1..-1] != [ 'user', 'admin'] }
106
- puts "Current 'security_admin' members are : #{security_administrators.map{|m| m.member.roleid.split(':')[-1]}.join(', ')}" unless security_administrators.blank?
107
- created_user = nil
108
- if security_administrators.empty? || agree("Create a new security_admin? (answer 'y' or 'yes'):")
109
- username = ask("Enter #{security_administrators.empty? ? 'your' : 'the'} username:")
110
- password = prompt_for_password
111
- puts "Creating user '#{username}'"
112
- created_user = user = api.create_user(username, password: password)
113
- Conjur::API.new_from_key(user.login, password).user(user.login).resource.give_to security_admin
114
- puts "User created"
115
- puts "Making '#{username}' a member and admin of group 'security_admin'"
116
- security_admin.add_member user, admin_option: true
117
- puts "Adminship granted"
79
+ unless api.global_privilege_permitted?('elevate')
80
+ $stderr.puts [
81
+ "You must have 'elevate' privilege to bootstrap Conjur.",
82
+ "If are performing a first-time bootstrap of Conjur, you should login as the 'admin' user",
83
+ "using the admin password you selected when you ran 'evoke configure master'.",
84
+ "",
85
+ "If you have run 'conjur bootstrap' before, using CLI version 4.30.0 or later, the 'elevate'",
86
+ "privilege is available to all members of the security_admin group."
87
+ ].join("\n")
88
+ exit_now! "Insufficient privileges to run 'bootstrap'."
118
89
  end
90
+
91
+ saved_log = Conjur.log
92
+ Conjur.log = $stderr if options[:verbose]
93
+
94
+ api = self.api.with_privilege('elevate')
95
+ self.api = api
119
96
 
120
- attic_user_name = "attic"
121
- if (attic = api.user(attic_user_name)).exists?
122
- puts "User '#{attic_user_name}' already exists"
123
- else
124
- puts "Creating user '#{attic_user_name}' to own retired records"
125
- attic = api.create_user(attic_user_name)
126
- api.create_variable "text/plain",
127
- "conjur-api-key",
128
- id: "conjur/users/#{attic_user_name}/api-key",
129
- value: attic.api_key,
130
- ownerid: security_admin.role.roleid
131
- end
97
+ api.bootstrap BootstrapListener.new
132
98
 
133
- if created_user && agree("Login as user '#{created_user.login}'? (answer 'y' or 'yes'):")
134
- Conjur::Authn.fetch_credentials(username: created_user.login, password: created_user.api_key)
135
- puts "Logged in as '#{created_user.login}'"
99
+ unless quiet?(options)
100
+ security_admin = api.group('security_admin')
101
+ security_administrators = security_admin.role.members.select{|m| m.member.roleid.split(':')[1..-1] != [ 'user', 'admin'] }
102
+ $stderr.puts "Current 'security_admin' members are : #{security_administrators.map{|m| m.member.roleid.split(':', 3)[1..-1].join(':')}.sort.join(', ')}" unless security_administrators.blank?
103
+ created_user = nil
104
+ if security_administrators.empty? || agree("Create a new security_admin? (answer 'y' or 'yes'):")
105
+ username = ask("Enter #{security_administrators.empty? ? 'your' : 'the'} username:")
106
+ password = prompt_for_password
107
+ begin
108
+ # Don't echo the new admin user's password
109
+ Conjur.log = nil
110
+ $stderr.puts "Creating user '#{username}'"
111
+ created_user = user = api.create_user(username, password: password)
112
+ ensure
113
+ Conjur.log = saved_log
114
+ end
115
+ Conjur::API.new_from_key(user.login, password).user(user.login).resource.give_to security_admin
116
+ $stderr.puts "User created"
117
+ $stderr.puts "Making '#{username}' a member and admin of group 'security_admin'"
118
+ security_admin.add_member user, admin_option: true
119
+ $stderr.puts "Adminship granted"
120
+ end
121
+
122
+ if created_user && agree("Login as user '#{created_user.login}'? (answer 'y' or 'yes'):")
123
+ Conjur::Authn.fetch_credentials(username: created_user.login, password: created_user.api_key)
124
+ $stderr.puts "Logged in as '#{created_user.login}'"
125
+ end
136
126
  end
137
127
  end
138
128
  end
@@ -44,6 +44,9 @@ class Conjur::Command::HostFactories < Conjur::Command
44
44
  layers = (options[:layer] || "").split(/\s/)
45
45
  exit_now! "Provide at least one layer" unless layers.count > 0
46
46
 
47
+ unless has_admin?(current_role, owner_role)
48
+ exit_now! "#{owner_role.id} must be an admin of role '#{owner_role.roleid}' to create a host factory for it"
49
+ end
47
50
  layers.each do |layerid|
48
51
  layer = api.layer(layerid)
49
52
  exit_now! "Layer '#{layerid}' does not exist" unless layer.exists?
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (C) 2014-2015 Conjur Inc.
2
+ # Copyright (C) 2014-2016 Conjur Inc.
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining a copy of
5
5
  # this software and associated documentation files (the "Software"), to deal in
@@ -19,6 +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.29.0"
22
+ VERSION = "4.30.0"
23
23
  ::Version=VERSION
24
24
  end
data/publish.sh CHANGED
@@ -1,6 +1,9 @@
1
- #!/bin/bash -ex
1
+ #!/bin/bash -exu
2
2
 
3
3
  export DEBUG=true
4
4
  export GLI_DEBUG=true
5
5
 
6
- debify publish 4.6 cli
6
+ DISTRIBUTION=$1
7
+ COMPONENT=${2:-`echo $GIT_BRANCH | sed 's/^origin\///' | tr '/' '.'`}
8
+
9
+ debify publish --component $COMPONENT $DISTRIBUTION cli
@@ -3,18 +3,20 @@ require 'conjur/command/host_factories'
3
3
 
4
4
  describe Conjur::Command::HostFactories, :logged_in => true do
5
5
  let (:group_memberships) { double(:group_memberships, :roleid => 'the-account:group:security_admin') }
6
- let (:group) { double(:group, :exists? => true, :memberships => [group_memberships]) }
6
+ let (:current_role) { double(:current_role, roleid: 'the-account:user:dknuth', :memberships => [ double(:current_role_role, roleid: 'the-account:user:dknuth') ]) }
7
+ let (:group_members) { double(:layer_members, :member => double(:member, :roleid => 'the-account:user:dknuth'), :admin_option => true ) }
8
+ let (:group) { double(:group, roleid: 'the-account:group:the-group', :exists? => true, :memberships => [group_memberships], :members => [group_members]) }
7
9
  let (:layer_members) { double(:layer_members, :member => double(:member, :roleid => 'the-account:group:security_admin'), :admin_option => true ) }
8
- let (:layer_role) { double(:layer_role, :members => [layer_members]) }
10
+ let (:layer_role) { double(:layer_role, roleid: 'the-account:layer:layer1', :members => [layer_members]) }
9
11
  let (:layer) { double(:layer, :exists? => true, :role => layer_role) }
10
12
 
11
13
  before do
14
+ allow(Conjur::Command.api).to receive(:role).with("user:dknuth").and_return current_role
12
15
  allow(Conjur::Command.api).to receive(:role).with("the-account:group:the-group").and_return group
13
16
  allow(Conjur::Command.api).to receive(:layer).with("layer1").and_return layer
14
17
  end
15
18
 
16
19
  describe_command 'hostfactory:create --as-group the-group --layer layer1 hf1 ' do
17
-
18
20
  it 'calls api.create_host_factory and prints the results' do
19
21
  expect_any_instance_of(Conjur::API).to receive(:create_host_factory).and_return '{}'
20
22
  expect { invoke }.to write('{}')
@@ -32,7 +34,5 @@ describe Conjur::Command::HostFactories, :logged_in => true do
32
34
  expect {invoke}.to raise_error('Provide at least one layer')
33
35
  end
34
36
  end
35
-
36
37
  end
37
-
38
38
  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.29.0
4
+ version: 4.30.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rafal Rzepecki
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-02-05 00:00:00.000000000 Z
12
+ date: 2016-02-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -297,6 +297,7 @@ files:
297
297
  - acceptance-features/authorization/role/graph.feature
298
298
  - acceptance-features/authorization/role/members.feature
299
299
  - acceptance-features/authorization/role/memberships.feature
300
+ - acceptance-features/bootstrap.feature
300
301
  - acceptance-features/conjurenv/check.feature
301
302
  - acceptance-features/conjurenv/run.feature
302
303
  - acceptance-features/conjurenv/template.feature
@@ -365,6 +366,7 @@ files:
365
366
  - features/support/host.json
366
367
  - features/support/world.rb
367
368
  - jenkins.sh
369
+ - lib/conjur-cli.rb
368
370
  - lib/conjur.rb
369
371
  - lib/conjur/audit/follower.rb
370
372
  - lib/conjur/authn.rb