inspec 1.42.3 → 1.43.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -29,17 +29,31 @@ A `shadow` resource block declares one (or more) users and associated user infor
29
29
  its('users') { should_not include 'forbidden_user' }
30
30
  end
31
31
 
32
+ or with a single query:
33
+
34
+ describe shadow.users('root') do
35
+ its('count') { should eq 1 }
36
+ end
37
+
32
38
  or with a filter:
33
39
 
34
- describe shadow.uid(filter) do
35
- its('users') { should cmp 'root' }
40
+ describe shadow.filter(min_days: '0', max_days: '99999') do
36
41
  its('count') { should eq 1 }
37
42
  end
38
43
 
39
- where
44
+ The following properties are available:
45
+
46
+ * `users`
47
+ * `passwords`
48
+ * `last_changes`
49
+ * `min_days`
50
+ * `max_days`
51
+ * `warn_days`
52
+ * `inactive_days`
53
+ * `expiry_date`
54
+ * `reserved`
40
55
 
41
- * `homes`, `gids`, `passwords`, `shells`, `uids`, and `users` are valid accessors for `passwd`
42
- * `filter` one (or more) arguments, for example: `passwd.users(/name/)` used to define filtering; `filter` may take any of the following arguments: `count` (retrieves the number of entries), `lines` (provides raw `passwd` lines), and `params` (returns an array of maps for all entries)
56
+ Properties can be used as a single query or can be joined together with the `.filter` method.
43
57
 
44
58
  <br>
45
59
 
@@ -72,7 +86,7 @@ The `count` matcher tests the number of times the named user appears in `/etc/sh
72
86
 
73
87
  its('count') { should eq 1 }
74
88
 
75
- TThis matcher is best used in conjunction with filters. For example:
89
+ This matcher is best used in conjunction with filters. For example:
76
90
 
77
91
  describe shadow.users('dannos') do
78
92
  its('count') { should eq 1 }
@@ -2,18 +2,17 @@
2
2
 
3
3
  This extensions offers the following features:
4
4
 
5
- - list available profiles in Chef Compliance
6
- - execute profiles directly from Chef Compliance locally
7
- - upload a local profile to Chef Compliance
5
+ - list available profiles in Chef Automate/Chef Compliance
6
+ - execute profiles directly from Chef Automate/Chef Compliance locally
7
+ - upload a local profile to Chef Automate/Chef Compliance
8
8
 
9
9
  To use the CLI, this InSpec add-on adds the following commands:
10
10
 
11
- * `$ inspec compliance login` - authentication of the API token against Chef Compliance
12
- * `$ inspec compliance login_automate` - authentication of the API token against Chef Automate
13
- * `$ inspec compliance profiles` - list all available Chef Compliance profiles
14
- * `$ inspec exec compliance://profile` - runs a Chef Compliance profile
15
- * `$ inspec compliance upload path/to/local/profile` - uploads a local profile to Chef Compliance
16
- * `$ inspec compliance logout` - logout of Chef Compliance
11
+ * `$ inspec compliance login` - authentication of the API token against Chef Automate/Chef Compliance
12
+ * `$ inspec compliance profiles` - list all available Compliance profiles
13
+ * `$ inspec exec compliance://profile` - runs a Compliance profile
14
+ * `$ inspec compliance upload path/to/local/profile` - uploads a local profile to Chef Automate/Chef Compliance
15
+ * `$ inspec compliance logout` - logout of Chef Automate/Chef Compliance
17
16
 
18
17
  Compliance profiles can be executed in two mays:
19
18
 
@@ -31,8 +30,7 @@ Commands:
31
30
  inspec compliance download PROFILE # downloads a profile from Chef Compliance
32
31
  inspec compliance exec PROFILE # executes a Chef Compliance profile
33
32
  inspec compliance help [COMMAND] # Describe subcommands or one specific subcommand
34
- inspec compliance login SERVER # Log in to a Chef Compliance SERVER
35
- inspec compliance login_automate SERVER # Log in to an Automate SERVER
33
+ inspec compliance login SERVER # Log in to a Chef Automate/Chef Compliance SERVER
36
34
  inspec compliance logout # user logout from Chef Compliance
37
35
  inspec compliance profiles # list all available profiles in Chef Compliance
38
36
  inspec compliance upload PATH # uploads a local profile to Chef Compliance
@@ -41,29 +39,22 @@ Commands:
41
39
 
42
40
  ### Login with Chef Automate
43
41
 
44
- You need a Chef Automate server up and running. Compliance features need to [be activated](https://docs.chef.io/install_chef_automate.html#compliance), too.
45
-
46
- Now, you need a user token. You can retrieve that via [UI](https://docs.chef.io/api_delivery.html) or [CLI](https://docs.chef.io/ctl_delivery.html#delivery-token).
42
+ You will need an access token for authentication. You can retrieve one via [UI](https://docs.chef.io/api_delivery.html) or [CLI](https://docs.chef.io/ctl_delivery.html#delivery-token).
47
43
 
48
44
  ```
49
- inspec compliance login_automate https://automate.compliance.test --insecure --user 'admin' --ent 'brewinc' --usertoken 'zuop..._KzE'
45
+ $ inspec compliance login https://automate.compliance.test --insecure --user 'admin' --ent 'brewinc' --token 'zuop..._KzE'
50
46
  ```
51
47
 
52
48
  ### Login with Chef Compliance
53
49
 
54
- Before you start using the compliance plugin, you need a running [Chef Compliance](https://www.chef.io/compliance/) server. Please login and gather the access token:
50
+ You will need an access token for authentication. You can retrieve one via:
55
51
 
56
52
  ![Chef Compliance Token](images/cc-token.png)
57
53
 
58
54
  You can choose the access token (`--token`) or the refresh token (`--refresh_token`)
59
55
 
60
56
  ```
61
- # login to chef compliance server
62
57
  $ inspec compliance login https://compliance.test --user admin --insecure --token '...'
63
-
64
- # display the chef compliance server version
65
- $ inspec compliance version
66
- Chef Compliance version: 1.0.11
67
58
  ```
68
59
 
69
60
  ### List available profiles via Chef Compliance / Automate
@@ -131,7 +122,7 @@ Available profiles:
131
122
  * cis/cis-ubuntu14.04lts-level2
132
123
  ```
133
124
 
134
- ### Run a profile from Chef Compliance / Automate on Workstation
125
+ ### Run a profile from Chef Compliance / Chef Automate on Workstation
135
126
 
136
127
  ```
137
128
  $ inspec exec compliance://admin/profile
@@ -5,13 +5,16 @@
5
5
  require 'net/http'
6
6
  require 'uri'
7
7
 
8
+ require_relative 'api/login'
9
+
8
10
  module Compliance
9
- class ServerConfigurationMissing < StandardError
10
- end
11
+ class ServerConfigurationMissing < StandardError; end
11
12
 
12
13
  # API Implementation does not hold any state by itself,
13
14
  # everything will be stored in local Configuration store
14
15
  class API # rubocop:disable Metrics/ClassLength
16
+ extend Compliance::API::Login
17
+
15
18
  # return all compliance profiles available for the user
16
19
  def self.profiles(config)
17
20
  # Chef Compliance
@@ -238,5 +241,13 @@ module Compliance
238
241
  return nil unless config['version'].is_a?(Hash)
239
242
  config['version']['version']
240
243
  end
244
+
245
+ def self.determine_server_type(url, insecure)
246
+ if Compliance::HTTP.get(url + '/compliance/version', nil, insecure).code == '401'
247
+ :automate
248
+ elsif Compliance::HTTP.get(url + '/api/version', nil, insecure).code == '200'
249
+ :compliance
250
+ end
251
+ end
241
252
  end
242
253
  end
@@ -0,0 +1,150 @@
1
+ # encoding: utf-8
2
+ # author: Christoph Hartmann
3
+ # author: Dominik Ricter
4
+ # author: Jerry Aldrich
5
+
6
+ module Compliance
7
+ class API
8
+ module Login
9
+ class CannotDetermineServerType < StandardError; end
10
+
11
+ def login(options)
12
+ raise ArgumentError, 'Please specify a server using `inspec compliance login https://SERVER`' unless options['server']
13
+
14
+ options['server_type'] = Compliance::API.determine_server_type(options['server'], options['insecure'])
15
+
16
+ case options['server_type']
17
+ when :automate
18
+ config = Login::AutomateServer.login(options)
19
+ when :compliance
20
+ config = Login::ComplianceServer.login(options)
21
+ else
22
+ raise CannotDetermineServerType, "Unable to determine if #{options['server']} is a Chef Automate or Chef Compliance server"
23
+ end
24
+
25
+ puts "Stored configuration for Chef #{config['server_type'].capitalize}: #{config['server']}' with user: '#{config['user']}'"
26
+ end
27
+
28
+ module AutomateServer
29
+ def self.login(options)
30
+ verify_thor_options(options)
31
+
32
+ options['url'] = options['server'] + '/compliance'
33
+ token = options['dctoken'] || options['token']
34
+ store_access_token(options, token)
35
+ end
36
+
37
+ def self.store_access_token(options, token)
38
+ token_type = if options['token']
39
+ 'usertoken'
40
+ else
41
+ 'dctoken'
42
+ end
43
+
44
+ config = Compliance::Configuration.new
45
+
46
+ config.clean
47
+
48
+ config['automate'] = {}
49
+ config['automate']['ent'] = options['ent']
50
+ config['automate']['token_type'] = token_type
51
+ config['server'] = options['url']
52
+ config['user'] = options['user']
53
+ config['insecure'] = options['insecure'] || false
54
+ config['server_type'] = options['server_type'].to_s
55
+ config['token'] = token
56
+ config['version'] = Compliance::API.version(config)
57
+
58
+ config.store
59
+ config
60
+ end
61
+
62
+ # Automate login requires `--ent`, `--user`, and either `--token` or `--dctoken`
63
+ def self.verify_thor_options(o)
64
+ error_msg = []
65
+
66
+ error_msg.push('Please specify a user using `--user=\'USER\'`') if o['user'].nil?
67
+ error_msg.push('Please specify an enterprise using `--ent=\'automate\'`') if o['ent'].nil?
68
+
69
+ if o['token'].nil? && o['dctoken'].nil?
70
+ error_msg.push('Please specify a token using `--token=\'AUTOMATE_TOKEN\'` or `--dctoken=\'DATA_COLLECTOR_TOKEN\'`')
71
+ end
72
+
73
+ raise ArgumentError, error_msg.join("\n") unless error_msg.empty?
74
+ end
75
+ end
76
+
77
+ module ComplianceServer
78
+ def self.login(options)
79
+ compliance_verify_thor_options(options)
80
+
81
+ options['url'] = options['server'] + '/api'
82
+
83
+ if options['user'] && options['token']
84
+ compliance_store_access_token(options, options['token'])
85
+ elsif options['user'] && options['password']
86
+ compliance_login_user_pass(options)
87
+ elsif options['refresh_token']
88
+ compliance_login_refresh_token(options)
89
+ end
90
+ end
91
+
92
+ def self.compliance_login_user_pass(options)
93
+ success, msg, token = Compliance::API.get_token_via_password(
94
+ options['url'],
95
+ options['user'],
96
+ options['password'],
97
+ options['insecure'],
98
+ )
99
+
100
+ raise msg unless success
101
+ compliance_store_access_token(options, token)
102
+ end
103
+
104
+ def self.compliance_login_refresh_token(options)
105
+ success, msg, token = Compliance::API.get_token_via_refresh_token(
106
+ options['url'],
107
+ options['refresh_token'],
108
+ options['insecure'],
109
+ )
110
+
111
+ raise msg unless success
112
+ compliance_store_access_token(options, token)
113
+ end
114
+
115
+ def self.compliance_store_access_token(options, token)
116
+ config = Compliance::Configuration.new
117
+ config.clean
118
+
119
+ config['user'] = options['user'] if options['user']
120
+ config['server'] = options['url']
121
+ config['insecure'] = options['insecure'] || false
122
+ config['server_type'] = options['server_type'].to_s
123
+ config['token'] = token
124
+ config['version'] = Compliance::API.version(config)
125
+
126
+ config.store
127
+ config
128
+ end
129
+
130
+ # Compliance login requires `--user` or `--refresh_token`
131
+ # If `--user` then either `--password`, `--token`, or `--refresh-token`, is required
132
+ def self.compliance_verify_thor_options(o)
133
+ error_msg = []
134
+
135
+ error_msg.push('Please specify a server using `inspec compliance login https://SERVER`') if o['server'].nil?
136
+
137
+ if o['user'].nil? && o['refresh_token'].nil?
138
+ error_msg.push('Please specify a `--user=\'USER\'` or a `--refresh-token=\'TOKEN\'`')
139
+ end
140
+
141
+ if o['user'] && o['password'].nil? && o['token'].nil? && o['refresh_token'].nil?
142
+ error_msg.push('Please specify either a `--password`, `--token`, or `--refresh-token`')
143
+ end
144
+
145
+ raise ArgumentError, error_msg.join("\n") unless error_msg.empty?
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -18,78 +18,64 @@ module Compliance
18
18
  namespace
19
19
  end
20
20
 
21
- desc "login SERVER --insecure --user='USER' --token='TOKEN'", 'Log in to a Chef Compliance SERVER'
21
+ desc "login https://SERVER --insecure --user='USER' --ent='ENTERPRISE' --token='TOKEN'", 'Log in to a Chef Compliance/Chef Automate SERVER'
22
+ long_desc <<-LONGDESC
23
+ `login` allows you to use InSpec with Chef Automate or a Chef Compliance Server
24
+
25
+ You need to a token for communication. More information about token retrieval
26
+ is available at:
27
+ https://docs.chef.io/api_automate.html#authentication-methods
28
+ https://docs.chef.io/api_compliance.html#obtaining-an-api-token
29
+ LONGDESC
22
30
  option :insecure, aliases: :k, type: :boolean,
23
31
  desc: 'Explicitly allows InSpec to perform "insecure" SSL connections and transfers'
24
32
  option :user, type: :string, required: false,
25
- desc: 'Chef Compliance Username'
33
+ desc: 'Username'
26
34
  option :password, type: :string, required: false,
27
- desc: 'Chef Compliance Password'
28
- option :apipath, type: :string, default: '/api',
29
- desc: 'Set the path to the API, defaults to /api'
35
+ desc: 'Password (Chef Compliance Only)'
30
36
  option :token, type: :string, required: false,
31
- desc: 'Chef Compliance access token'
37
+ desc: 'Access token'
32
38
  option :refresh_token, type: :string, required: false,
33
- desc: 'Chef Compliance refresh token'
34
- def login(server) # rubocop:disable Metrics/AbcSize
35
- # show warning if the Compliance Server does not support
36
-
39
+ desc: 'Chef Compliance refresh token (Chef Compliance Only)'
40
+ option :dctoken, type: :string, required: false,
41
+ desc: 'Data Collector token (Chef Automate Only)'
42
+ option :ent, type: :string, required: false,
43
+ desc: 'Enterprise for Chef Automate reporting (Chef Automate Only)'
44
+ def login(server)
37
45
  options['server'] = server
38
- url = options['server'] + options['apipath']
39
-
40
- if !options['user'].nil? && !options['password'].nil?
41
- # username / password
42
- _success, msg = login_username_password(url, options['user'], options['password'], options['insecure'])
43
- elsif !options['user'].nil? && !options['token'].nil?
44
- # access token
45
- _success, msg = store_access_token(url, options['user'], options['token'], options['insecure'])
46
- elsif !options['refresh_token'].nil? && !options['user'].nil?
47
- # refresh token
48
- _success, msg = store_refresh_token(url, options['refresh_token'], true, options['user'], options['insecure'])
49
- # TODO: we should login with the refreshtoken here
50
- elsif !options['refresh_token'].nil?
51
- _success, msg = login_refreshtoken(url, options)
52
- else
53
- puts 'Please run `inspec compliance login SERVER` with options --token or --refresh_token, --user, and --insecure or --not-insecure'
54
- exit 1
55
- end
56
-
57
- puts '', msg
46
+ Compliance::API.login(options)
58
47
  end
59
48
 
60
- desc "login_automate SERVER --insecure --user='USER' --ent='ENT' --usertoken='TOKEN'", 'Log in to an Automate SERVER'
49
+ desc "login_automate https://SERVER --insecure --user='USER' --ent='ENTERPRISE' --usertoken='TOKEN'", 'Log in to a Chef Automate SERVER (DEPRECATED: Please use `login`)'
61
50
  long_desc <<-LONGDESC
62
- `login_automate` allows you to use InSpec with Chef Automate
51
+ This commmand is deprecated and will be removed, please use `--login`.
52
+
53
+ `login_automate` allows you to use InSpec with Chef Automate.
63
54
 
64
- You need to a user-token for communication with Chef Automate. More
65
- information about token retrieval for Automate is available at:
66
- https://docs.chef.io/api_delivery.html
55
+ You need to a token for communication. More information about token retrieval
56
+ is available at:
57
+ https://docs.chef.io/api_automate.html#authentication-methods
58
+ https://docs.chef.io/api_compliance.html#obtaining-an-api-token
67
59
  LONGDESC
68
- option :dctoken, type: :string,
69
- desc: 'Data Collector token'
70
- option :usertoken, type: :string,
71
- desc: 'Automate user token'
72
- option :user, type: :string,
73
- desc: 'Automate username'
74
- option :ent, type: :string,
75
- desc: 'Enterprise for Chef Automate reporting'
76
60
  option :insecure, aliases: :k, type: :boolean,
77
61
  desc: 'Explicitly allows InSpec to perform "insecure" SSL connections and transfers'
78
- def login_automate(server) # rubocop:disable Metrics/AbcSize
62
+ option :user, type: :string, required: true,
63
+ desc: 'Username'
64
+ option :usertoken, type: :string, required: false,
65
+ desc: 'Access token (DEPRECATED: Please use `--token`)'
66
+ option :token, type: :string, required: false,
67
+ desc: 'Access token'
68
+ option :dctoken, type: :string, required: false,
69
+ desc: 'Data Collector token'
70
+ option :ent, type: :string, required: true,
71
+ desc: 'Enterprise for Chef Automate reporting'
72
+ def login_automate(server)
73
+ warn '[DEPRECATION] `inspec compliance login_automate` is deprecated. Please use `inspec compliance login`'
79
74
  options['server'] = server
80
- url = options['server'] + '/compliance'
81
75
 
82
- if url && !options['user'].nil? && !options['ent'].nil? && (!options['dctoken'].nil? || !options['usertoken'].nil?)
83
- msg = login_automate_config(url, options['user'], options['dctoken'], options['usertoken'], options['ent'], options['insecure'])
84
- puts '', msg
85
- exit 0
86
- end
76
+ options['token'] = options['usertoken'] if options['usertoken']
87
77
 
88
- # parameters are missing if we reach here
89
- puts 'Please specify an user using `--user \'USER\'`' if options['user'].nil?
90
- puts 'Please specify an enterprise using `--ent \'cd\'`' if options['ent'].nil?
91
- puts 'Please specify a token using `--usertoken=\'AUTOMATE_TOKEN\'`' if options['usertoken'].nil? && options['dctoken'].nil?
92
- exit 1
78
+ Compliance::API.login(options)
93
79
  end
94
80
 
95
81
  desc 'profiles', 'list all available profiles in Chef Compliance'
@@ -111,7 +97,7 @@ module Compliance
111
97
  exit 1
112
98
  end
113
99
  rescue Compliance::ServerConfigurationMissing
114
- puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
100
+ STDERR.puts "\nServer configuration information is missing. Please login using `inspec compliance login`"
115
101
  exit 1
116
102
  end
117
103
 
@@ -272,109 +258,9 @@ module Compliance
272
258
 
273
259
  private
274
260
 
275
- def login_automate_config(url, user, dctoken, usertoken, ent, insecure) # rubocop:disable Metrics/ParameterLists
276
- config = Compliance::Configuration.new
277
- config.clean
278
- config['user'] = user
279
- config['server'] = url
280
- config['automate'] = {}
281
- config['automate']['ent'] = ent
282
- config['server_type'] = 'automate'
283
- config['insecure'] = insecure
284
-
285
- # determine token method being used
286
- if !dctoken.nil?
287
- config['token'] = dctoken
288
- token_type = 'dctoken'
289
- token_msg = 'data collector token'
290
- else
291
- config['token'] = usertoken
292
- token_type = 'usertoken'
293
- token_msg = 'automate user token'
294
- end
295
- config['automate']['token_type'] = token_type
296
- config['version'] = Compliance::API.version(config)
297
- config.store
298
- msg = "Stored configuration for Chef Automate: '#{url}' with user: '#{user}', ent: '#{ent}' and your #{token_msg}"
299
- msg
300
- end
301
-
302
- def login_refreshtoken(url, options)
303
- success, msg, _access_token = Compliance::API.get_token_via_refresh_token(url, options['refresh_token'], options['insecure'])
304
- if success
305
- config = Compliance::Configuration.new
306
- config.clean
307
- config['server'] = url
308
- config['insecure'] = options['insecure']
309
- config['server_type'] = 'compliance'
310
- config['version'] = Compliance::API.version(config)
311
- config.store
312
- end
313
-
314
- [success, msg]
315
- end
316
-
317
- def login_username_password(url, username, password, insecure)
318
- config = Compliance::Configuration.new
319
- config.clean
320
- success, msg, api_token = Compliance::API.get_token_via_password(url, username, password, insecure)
321
- if success
322
- config['server'] = url
323
- config['user'] = username
324
- config['token'] = api_token
325
- config['insecure'] = insecure
326
- config['server_type'] = 'compliance'
327
- config['version'] = Compliance::API.version(config)
328
- config.store
329
- success = true
330
- end
331
- [success, msg]
332
- end
333
-
334
- # saves a user access token (limited time)
335
- def store_access_token(url, user, token, insecure)
336
- config = Compliance::Configuration.new
337
- config.clean
338
- config['server'] = url
339
- config['insecure'] = insecure
340
- config['user'] = user
341
- config['token'] = token
342
- config['server_type'] = 'compliance'
343
- config['version'] = Compliance::API.version(config)
344
- config.store
345
-
346
- [true, 'API access token stored']
347
- end
348
-
349
- # saves a refresh token supplied by the user
350
- def store_refresh_token(url, refresh_token, verify, user, insecure)
351
- config = Compliance::Configuration.new
352
- config.clean
353
- config['server'] = url
354
- config['refresh_token'] = refresh_token
355
- config['user'] = user
356
- config['insecure'] = insecure
357
- config['server_type'] = 'compliance'
358
- config['version'] = Compliance::API.version(config)
359
-
360
- if !verify
361
- config.store
362
- success = true
363
- msg = 'API refresh token stored'
364
- else
365
- success, msg, _access_token= Compliance::API.get_token_via_refresh_token(url, refresh_token, insecure)
366
- if success
367
- config.store
368
- msg = 'API access token verified'
369
- end
370
- end
371
-
372
- [success, msg]
373
- end
374
-
375
261
  def loggedin(config)
376
262
  serverknown = !config['server'].nil?
377
- puts 'You need to login first with `inspec compliance login` or `inspec compliance login_automate`' if !serverknown
263
+ puts 'You need to login first with `inspec compliance login`' if !serverknown
378
264
  serverknown
379
265
  end
380
266
  end