inspec 1.42.3 → 1.43.5

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.
@@ -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