conjur-cli 4.29.0 → 4.30.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: 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