inspec 1.0.0 → 1.35.1
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 +4 -4
- data/CHANGELOG.md +933 -101
- data/Gemfile +8 -17
- data/MAINTAINERS.md +2 -1
- data/MAINTAINERS.toml +9 -4
- data/README.md +49 -28
- data/Rakefile +54 -39
- data/bin/inspec +1 -1
- data/docs/dsl_inspec.md +17 -4
- data/docs/dsl_resource.md +1 -1
- data/docs/habitat.md +192 -0
- data/docs/inspec_and_friends.md +4 -2
- data/docs/matchers.md +11 -0
- data/docs/migration.md +293 -0
- data/docs/profiles.md +124 -76
- data/docs/resources/aide_conf.md.erb +81 -0
- data/docs/resources/apache_conf.md.erb +10 -10
- data/docs/resources/apt.md.erb +13 -13
- data/docs/resources/audit_policy.md.erb +10 -10
- data/docs/resources/auditd_conf.md.erb +10 -10
- data/docs/resources/auditd_rules.md.erb +11 -11
- data/docs/resources/bash.md.erb +12 -12
- data/docs/resources/bond.md.erb +15 -15
- data/docs/resources/bridge.md.erb +11 -11
- data/docs/resources/bsd_service.md.erb +11 -11
- data/docs/resources/command.md.erb +23 -23
- data/docs/resources/crontab.md.erb +84 -0
- data/docs/resources/csv.md.erb +10 -10
- data/docs/resources/dh_params.md +191 -0
- data/docs/resources/directory.md.erb +8 -8
- data/docs/resources/docker.md.erb +160 -0
- data/docs/resources/docker_container.md.erb +89 -0
- data/docs/resources/docker_image.md.erb +86 -0
- data/docs/resources/etc_group.md.erb +16 -16
- data/docs/resources/etc_hosts.md.erb +62 -0
- data/docs/resources/file.md.erb +80 -58
- data/docs/resources/gem.md.erb +32 -13
- data/docs/resources/group.md.erb +12 -12
- data/docs/resources/grub_conf.md.erb +11 -11
- data/docs/resources/host.md.erb +27 -18
- data/docs/resources/http.md.erb +104 -0
- data/docs/resources/iis_app.md.erb +126 -0
- data/docs/resources/iis_site.md.erb +17 -17
- data/docs/resources/inetd_conf.md.erb +10 -10
- data/docs/resources/ini.md.erb +9 -9
- data/docs/resources/interface.md.erb +13 -13
- data/docs/resources/iptables.md.erb +21 -14
- data/docs/resources/json.md.erb +11 -11
- data/docs/resources/kernel_module.md.erb +73 -12
- data/docs/resources/kernel_parameter.md.erb +12 -12
- data/docs/resources/key_rsa.md.erb +70 -0
- data/docs/resources/launchd_service.md.erb +11 -11
- data/docs/resources/limits_conf.md.erb +10 -10
- data/docs/resources/login_def.md.erb +12 -12
- data/docs/resources/mount.md.erb +14 -14
- data/docs/resources/mssql_session.md.erb +62 -0
- data/docs/resources/mysql_conf.md.erb +14 -14
- data/docs/resources/mysql_session.md.erb +22 -10
- data/docs/resources/npm.md.erb +13 -13
- data/docs/resources/ntp_conf.md.erb +9 -9
- data/docs/resources/oneget.md.erb +11 -11
- data/docs/resources/oracledb_session.md.erb +53 -0
- data/docs/resources/os.md.erb +17 -17
- data/docs/resources/os_env.md.erb +12 -12
- data/docs/resources/package.md.erb +29 -16
- data/docs/resources/parse_config.md.erb +18 -18
- data/docs/resources/parse_config_file.md.erb +29 -23
- data/docs/resources/{etc_passwd.md.erb → passwd.md.erb} +17 -17
- data/docs/resources/pip.md.erb +15 -15
- data/docs/resources/port.md.erb +23 -23
- data/docs/resources/postgres_conf.md.erb +15 -13
- data/docs/resources/postgres_hba_conf.md.erb +104 -0
- data/docs/resources/postgres_ident_conf.md.erb +87 -0
- data/docs/resources/postgres_session.md.erb +28 -21
- data/docs/resources/powershell.md.erb +14 -14
- data/docs/resources/processes.md.erb +123 -0
- data/docs/resources/rabbitmq_config.md.erb +55 -0
- data/docs/resources/registry_key.md.erb +44 -21
- data/docs/resources/runit_service.md.erb +11 -11
- data/docs/resources/security_policy.md.erb +10 -10
- data/docs/resources/service.md.erb +18 -18
- data/docs/resources/{etc_shadow.md.erb → shadow.md.erb} +19 -19
- data/docs/resources/ssh_config.md.erb +13 -13
- data/docs/resources/sshd_config.md.erb +15 -15
- data/docs/resources/ssl.md.erb +13 -13
- data/docs/resources/sys_info.md.erb +10 -10
- data/docs/resources/systemd_service.md.erb +11 -11
- data/docs/resources/sysv_service.md.erb +11 -11
- data/docs/resources/upstart_service.md.erb +11 -11
- data/docs/resources/user.md.erb +20 -20
- data/docs/resources/users.md.erb +19 -19
- data/docs/resources/vbscript.md.erb +13 -13
- data/docs/resources/virtualization.md.erb +71 -0
- data/docs/resources/windows_feature.md.erb +10 -10
- data/docs/resources/windows_task.md.erb +103 -0
- data/docs/resources/wmi.md.erb +10 -10
- data/docs/resources/x509_certificate.md.erb +146 -0
- data/docs/resources/xinetd_conf.md.erb +17 -17
- data/docs/resources/xml.md.erb +75 -0
- data/docs/resources/yaml.md.erb +25 -11
- data/docs/resources/yum.md.erb +24 -16
- data/docs/resources/zfs_dataset.md.erb +63 -0
- data/docs/resources/zfs_pool.md.erb +57 -0
- data/docs/ruby_usage.md +50 -0
- data/docs/shared/matcher_cmp.md.erb +4 -6
- data/examples/inheritance/README.md +49 -3
- data/examples/inheritance/controls/example.rb +4 -1
- data/examples/inheritance/inspec.yml +3 -1
- data/examples/meta-profile/README.md +29 -3
- data/examples/meta-profile/controls/example.rb +10 -5
- data/examples/meta-profile/inspec.yml +4 -8
- data/examples/profile/README.md +1 -1
- data/examples/profile/controls/example.rb +0 -1
- data/examples/profile/controls/gordon.rb +0 -1
- data/examples/profile/inspec.yml +1 -1
- data/examples/profile-attribute/inspec.yml +1 -1
- data/examples/profile-sensitive/README.md +29 -0
- data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -0
- data/examples/profile-sensitive/controls/sensitive.rb +9 -0
- data/examples/profile-sensitive/inspec.yml +8 -0
- data/inspec.gemspec +10 -2
- data/lib/bundles/inspec-artifact/README.md +1 -0
- data/lib/bundles/inspec-artifact/cli.rb +284 -0
- data/lib/bundles/inspec-artifact.rb +7 -0
- data/lib/bundles/inspec-compliance/README.md +44 -15
- data/lib/bundles/inspec-compliance/api.rb +135 -29
- data/lib/bundles/inspec-compliance/cli.rb +128 -21
- data/lib/bundles/inspec-compliance/configuration.rb +8 -0
- data/lib/bundles/inspec-compliance/http.rb +26 -19
- data/lib/bundles/inspec-compliance/target.rb +50 -25
- data/lib/bundles/inspec-habitat/cli.rb +31 -0
- data/lib/bundles/inspec-habitat/log.rb +10 -0
- data/lib/bundles/inspec-habitat/profile.rb +372 -0
- data/lib/bundles/inspec-habitat.rb +12 -0
- data/lib/bundles/inspec-init/templates/profile/controls/example.rb +0 -1
- data/lib/bundles/inspec-init/templates/profile/inspec.yml +1 -1
- data/lib/bundles/inspec-supermarket/api.rb +7 -5
- data/lib/bundles/inspec-supermarket/cli.rb +2 -2
- data/lib/fetchers/git.rb +4 -2
- data/lib/fetchers/local.rb +4 -1
- data/lib/fetchers/url.rb +64 -10
- data/lib/inspec/archive/tar.rb +1 -1
- data/lib/inspec/backend.rb +26 -3
- data/lib/inspec/base_cli.rb +44 -7
- data/lib/inspec/cached_fetcher.rb +2 -2
- data/lib/inspec/cli.rb +34 -12
- data/lib/inspec/completions/fish.sh.erb +34 -0
- data/lib/inspec/control_eval_context.rb +0 -2
- data/lib/inspec/dependencies/cache.rb +0 -1
- data/lib/inspec/dependencies/dependency_set.rb +2 -2
- data/lib/inspec/dependencies/lockfile.rb +13 -6
- data/lib/inspec/dependencies/requirement.rb +6 -6
- data/lib/inspec/dependencies/resolver.rb +4 -4
- data/lib/inspec/dsl.rb +3 -5
- data/lib/inspec/env_printer.rb +9 -1
- data/lib/inspec/exceptions.rb +8 -0
- data/lib/inspec/fetcher.rb +1 -1
- data/lib/inspec/file_provider.rb +47 -11
- data/lib/inspec/library_eval_context.rb +1 -1
- data/lib/inspec/metadata.rb +62 -18
- data/lib/inspec/method_source.rb +24 -0
- data/lib/inspec/objects/attribute.rb +21 -0
- data/lib/inspec/objects/control.rb +21 -3
- data/lib/inspec/objects/each_loop.rb +2 -1
- data/lib/inspec/objects/list.rb +1 -1
- data/lib/inspec/objects/or_test.rb +17 -2
- data/lib/inspec/objects/tag.rb +27 -0
- data/lib/inspec/objects/test.rb +9 -8
- data/lib/inspec/objects.rb +1 -0
- data/lib/inspec/plugins/fetcher.rb +4 -5
- data/lib/inspec/plugins/resource.rb +1 -2
- data/lib/inspec/plugins/source_reader.rb +3 -3
- data/lib/inspec/plugins.rb +1 -1
- data/lib/inspec/polyfill.rb +0 -1
- data/lib/inspec/profile.rb +92 -23
- data/lib/inspec/profile_context.rb +1 -1
- data/lib/inspec/profile_vendor.rb +66 -0
- data/lib/inspec/resource.rb +29 -3
- data/lib/inspec/rspec_json_formatter.rb +672 -285
- data/lib/inspec/rule.rb +12 -16
- data/lib/inspec/runner.rb +26 -15
- data/lib/inspec/runner_rspec.rb +1 -0
- data/lib/inspec/runtime_profile.rb +26 -0
- data/lib/inspec/schema.rb +185 -0
- data/lib/inspec/secrets/yaml.rb +8 -1
- data/lib/inspec/secrets.rb +1 -1
- data/lib/inspec/shell.rb +92 -22
- data/lib/inspec/source_reader.rb +1 -1
- data/lib/inspec/version.rb +1 -1
- data/lib/inspec.rb +1 -1
- data/lib/matchers/matchers.rb +67 -17
- data/lib/resources/aide_conf.rb +162 -0
- data/lib/resources/apache.rb +0 -1
- data/lib/resources/apache_conf.rb +3 -3
- data/lib/resources/apt.rb +2 -1
- data/lib/resources/audit_policy.rb +0 -1
- data/lib/resources/auditd_conf.rb +1 -2
- data/lib/resources/auditd_rules.rb +5 -5
- data/lib/resources/bond.rb +1 -1
- data/lib/resources/bridge.rb +1 -1
- data/lib/resources/command.rb +5 -3
- data/lib/resources/crontab.rb +102 -0
- data/lib/resources/csv.rb +18 -1
- data/lib/resources/dh_params.rb +84 -0
- data/lib/resources/directory.rb +7 -3
- data/lib/resources/docker.rb +198 -0
- data/lib/resources/docker_container.rb +114 -0
- data/lib/resources/docker_image.rb +96 -0
- data/lib/resources/etc_group.rb +2 -3
- data/lib/resources/etc_hosts.rb +81 -0
- data/lib/resources/file.rb +88 -30
- data/lib/resources/gem.rb +26 -6
- data/lib/resources/groups.rb +4 -5
- data/lib/resources/grub_conf.rb +3 -4
- data/lib/resources/host.rb +175 -35
- data/lib/resources/http.rb +73 -0
- data/lib/resources/iis_app.rb +103 -0
- data/lib/resources/iis_site.rb +23 -0
- data/lib/resources/inetd_conf.rb +9 -4
- data/lib/resources/interface.rb +4 -3
- data/lib/resources/json.rb +37 -14
- data/lib/resources/kernel_module.rb +77 -10
- data/lib/resources/kernel_parameter.rb +0 -1
- data/lib/resources/key_rsa.rb +67 -0
- data/lib/resources/limits_conf.rb +3 -4
- data/lib/resources/login_def.rb +2 -3
- data/lib/resources/mount.rb +34 -4
- data/lib/resources/mssql_session.rb +81 -12
- data/lib/resources/mysql.rb +0 -1
- data/lib/resources/mysql_conf.rb +1 -2
- data/lib/resources/mysql_session.rb +18 -7
- data/lib/resources/nginx_conf.rb +95 -0
- data/lib/resources/ntp_conf.rb +2 -3
- data/lib/resources/oracledb_session.rb +138 -0
- data/lib/resources/os_env.rb +7 -5
- data/lib/resources/package.rb +70 -13
- data/lib/resources/packages.rb +111 -0
- data/lib/resources/parse_config.rb +3 -4
- data/lib/resources/passwd.rb +4 -5
- data/lib/resources/pip.rb +29 -21
- data/lib/resources/port.rb +133 -14
- data/lib/resources/postgres.rb +53 -43
- data/lib/resources/postgres_conf.rb +40 -13
- data/lib/resources/postgres_hba_conf.rb +101 -0
- data/lib/resources/postgres_ident_conf.rb +79 -0
- data/lib/resources/postgres_session.rb +28 -20
- data/lib/resources/powershell.rb +2 -2
- data/lib/resources/processes.rb +61 -26
- data/lib/resources/rabbitmq_conf.rb +53 -0
- data/lib/resources/registry_key.rb +34 -11
- data/lib/resources/security_policy.rb +2 -2
- data/lib/resources/service.rb +17 -7
- data/lib/resources/ssh_conf.rb +17 -6
- data/lib/resources/ssl.rb +3 -4
- data/lib/resources/sys_info.rb +1 -1
- data/lib/resources/toml.rb +26 -0
- data/lib/resources/users.rb +41 -41
- data/lib/resources/virtualization.rb +252 -0
- data/lib/resources/windows_task.rb +106 -0
- data/lib/resources/x509_certificate.rb +143 -0
- data/lib/resources/xinetd.rb +18 -2
- data/lib/resources/xml.rb +27 -0
- data/lib/resources/yaml.rb +10 -2
- data/lib/resources/yum.rb +25 -7
- data/lib/resources/zfs_dataset.rb +60 -0
- data/lib/resources/zfs_pool.rb +49 -0
- data/lib/source_readers/flat.rb +2 -1
- data/lib/source_readers/inspec.rb +30 -11
- data/lib/utils/command_wrapper.rb +3 -3
- data/lib/utils/database_helpers.rb +77 -0
- data/lib/utils/erlang_parser.rb +192 -0
- data/lib/utils/filter.rb +2 -1
- data/lib/utils/filter_array.rb +0 -1
- data/lib/utils/find_files.rb +1 -2
- data/lib/utils/latest_version.rb +21 -0
- data/lib/utils/nginx_parser.rb +76 -0
- data/lib/utils/object_traversal.rb +5 -4
- data/lib/utils/parser.rb +23 -4
- data/lib/utils/plugin_registry.rb +3 -3
- data/lib/utils/simpleconfig.rb +25 -8
- data/lib/utils/spdx.rb +13 -0
- data/lib/utils/spdx.txt +344 -0
- metadata +168 -22
- data/docs/cli.md +0 -342
- data/docs/resources/process.md.erb +0 -73
- /data/docs/{plugin_kitchen_inspec.html.md → plugin_kitchen_inspec.md} +0 -0
data/docs/ruby_usage.md
CHANGED
|
@@ -152,3 +152,53 @@ describe command('ls -al /') do
|
|
|
152
152
|
its('exit_status') { should eq 0 }
|
|
153
153
|
end
|
|
154
154
|
```
|
|
155
|
+
|
|
156
|
+
## Shelling out in tests
|
|
157
|
+
|
|
158
|
+
When writing tests you can not use standard ruby methods to shellout as it tries to execute those commands locally.
|
|
159
|
+
However, the `command` resource has a `.stdout` method that will allow you to manipulate the results.
|
|
160
|
+
Using the above example, you could check the writes on several subdirectories.
|
|
161
|
+
|
|
162
|
+
### Example 1:
|
|
163
|
+
```ruby
|
|
164
|
+
$ inspec shell
|
|
165
|
+
Welcome to the interactive InSpec Shell
|
|
166
|
+
To find out how to use it, type: help
|
|
167
|
+
|
|
168
|
+
inspec> output=command('echo test').stdout
|
|
169
|
+
=> "test\n"
|
|
170
|
+
inspec> describe command('echo test') do
|
|
171
|
+
inspec> its('stdout') { should eq output }
|
|
172
|
+
inspec> end
|
|
173
|
+
|
|
174
|
+
Profile: inspec-shell
|
|
175
|
+
Version: (not specified)
|
|
176
|
+
|
|
177
|
+
Command echo
|
|
178
|
+
✔ test stdout should eq "test\n"
|
|
179
|
+
|
|
180
|
+
Test Summary: 1 successful, 0 failures, 0 skipped
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Example 2:
|
|
184
|
+
```ruby
|
|
185
|
+
$ inspec shell
|
|
186
|
+
Welcome to the interactive InSpec Shell
|
|
187
|
+
To find out how to use it, type: help
|
|
188
|
+
|
|
189
|
+
inspec> dirs = command('ls -d /home/gordon/git/inspec/docs').stdout.split("\n")
|
|
190
|
+
=> ["/home/gordon/git/inspec/docs"]
|
|
191
|
+
inspec> dirs.each do |dir|
|
|
192
|
+
inspec> describe directory(dir) do
|
|
193
|
+
inspec> its('mode') { should cmp '0775' }
|
|
194
|
+
inspec> end
|
|
195
|
+
inspec> end
|
|
196
|
+
|
|
197
|
+
Profile: inspec-shell
|
|
198
|
+
Version: (not specified)
|
|
199
|
+
|
|
200
|
+
File /home/gordon/git/inspec/docs/
|
|
201
|
+
✔ mode should cmp == "0775"
|
|
202
|
+
|
|
203
|
+
Test Summary: 1 successful, 0 failures, 0 skipped
|
|
204
|
+
```
|
|
@@ -28,12 +28,10 @@ vs:
|
|
|
28
28
|
|
|
29
29
|
Ignoring case sensitivity:
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
its('setting') { should cmp 'RAW' }
|
|
36
|
-
end
|
|
31
|
+
describe some_resource do
|
|
32
|
+
its('setting') { should cmp 'raw' }
|
|
33
|
+
its('setting') { should cmp 'RAW' }
|
|
34
|
+
end
|
|
37
35
|
|
|
38
36
|
Printing octal values:
|
|
39
37
|
|
|
@@ -7,13 +7,59 @@ This example shows the use of InSpec [profile](../../docs/profiles.rst) inherita
|
|
|
7
7
|
InSpec ships with built-in features to verify a profile structure.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
$ inspec check examples/inheritance
|
|
10
|
+
$ inspec check examples/inheritance
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Execute a profile
|
|
14
14
|
|
|
15
|
-
To run a profile on a local machine use `inspec exec /path/to/profile`.
|
|
15
|
+
To run a profile on a local machine use `inspec exec /path/to/profile`. All dependencies are automatically resolved.
|
|
16
16
|
|
|
17
17
|
```bash
|
|
18
|
-
$ inspec exec examples/inheritance
|
|
18
|
+
$ inspec exec examples/inheritance
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Set attributes for dependent profiles
|
|
22
|
+
|
|
23
|
+
Without setting attributes, an `inspec exec` would return the following:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
$ inspec git:(master) ✗ b inspec exec examples/inheritance
|
|
27
|
+
|
|
28
|
+
Profile: InSpec example inheritance (inheritance)
|
|
29
|
+
Version: 1.0.0
|
|
30
|
+
Target: local://
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
○ gordon-1.0: Verify the version number of Gordon (1 skipped)
|
|
34
|
+
○ Can't find file "/tmp/gordon/config.yaml"
|
|
35
|
+
✔ File content should match nil
|
|
36
|
+
✔ ssh-1: Allow only SSH Protocol 2
|
|
37
|
+
✔ File /bin/sh should be owned by "root"
|
|
38
|
+
|
|
39
|
+
File /tmp
|
|
40
|
+
✔ should be directory
|
|
41
|
+
alice should
|
|
42
|
+
✖ eq "bob"
|
|
43
|
+
|
|
44
|
+
expected: "bob"
|
|
45
|
+
got: "alice"
|
|
46
|
+
|
|
47
|
+
(compared using ==)
|
|
48
|
+
|
|
49
|
+
should eq
|
|
50
|
+
✖ "secret"
|
|
51
|
+
|
|
52
|
+
expected: "secret"
|
|
53
|
+
got: nil
|
|
54
|
+
|
|
55
|
+
(compared using ==)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
Test Summary: 3 successful, 2 failures, 1 skipped
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
To pass in attributes, just call:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
$ inspec exec examples/inheritance --attrs examples/profile-attribute.yml
|
|
19
65
|
```
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# copyright: 2016, Chef Software, Inc.
|
|
3
|
-
# license: All rights reserved
|
|
4
3
|
|
|
4
|
+
# manipulate controls of `profile`
|
|
5
5
|
include_controls 'profile' do
|
|
6
6
|
skip_control 'tmp-1.0'
|
|
7
7
|
|
|
@@ -9,3 +9,6 @@ include_controls 'profile' do
|
|
|
9
9
|
impact 0.0
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
|
+
|
|
13
|
+
# load all controls of `profile-attribute`
|
|
14
|
+
include_controls 'profile-attribute'
|
|
@@ -3,7 +3,7 @@ title: InSpec example inheritance
|
|
|
3
3
|
maintainer: Chef Software, Inc.
|
|
4
4
|
copyright: Chef Software, Inc.
|
|
5
5
|
copyright_email: support@chef.io
|
|
6
|
-
license: Apache
|
|
6
|
+
license: Apache-2.0
|
|
7
7
|
summary: Demonstrates the use of InSpec profile inheritance
|
|
8
8
|
version: 1.0.0
|
|
9
9
|
supports:
|
|
@@ -11,3 +11,5 @@ supports:
|
|
|
11
11
|
depends:
|
|
12
12
|
- name: profile
|
|
13
13
|
path: ../profile
|
|
14
|
+
- name: profile-attribute
|
|
15
|
+
path: ../profile-attribute
|
|
@@ -5,7 +5,33 @@ from non-local sources such as Git or an HTTP url. This feature can
|
|
|
5
5
|
be used to build up a environment-wide profile that is based on more
|
|
6
6
|
specific profiles managed by others.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
InSpec supports multiple profile locations:
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
```
|
|
11
|
+
depends:
|
|
12
|
+
# defaults to supermarket
|
|
13
|
+
- name: hardening/ssh-hardening
|
|
14
|
+
# remote tar or zip file
|
|
15
|
+
- name: os-hardening
|
|
16
|
+
url: https://github.com/dev-sec/tests-os-hardening/archive/master.zip
|
|
17
|
+
# git
|
|
18
|
+
- git: https://github.com/dev-sec/ssl-baseline.git
|
|
19
|
+
- name: windows-patch-benchmark
|
|
20
|
+
git: https://github.com/chris-rock/windows-patch-benchmark.git
|
|
21
|
+
# Chef Compliance
|
|
22
|
+
- name: linux
|
|
23
|
+
compliance: base/linux
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
You could use those dependencies in your `example.rb`:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
include_controls 'hardening/ssh-hardening'
|
|
31
|
+
include_controls 'os-hardening'
|
|
32
|
+
include_controls 'ssl-baseline'
|
|
33
|
+
include_controls 'linux'
|
|
34
|
+
include_controls 'windows-patch-benchmark'
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Further details are described in our [InSpec Docs](https://www.inspec.io/docs/reference/profiles/)
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
# encoding: utf-8
|
|
2
2
|
# copyright: 2015, The Authors
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
include_controls '
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
|
|
4
|
+
# import full profile
|
|
5
|
+
include_controls 'dev-sec/ssh-baseline'
|
|
6
|
+
|
|
7
|
+
# select only individual controls
|
|
8
|
+
include_controls 'ssl-baseline' do
|
|
9
|
+
control "tls1.2"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# inspec knows that it cannot run Windows tests on Linux
|
|
8
13
|
include_controls 'windows-patch-benchmark'
|
|
@@ -3,15 +3,11 @@ title: Meta Compliance Profile
|
|
|
3
3
|
maintainer: InSpec Authors
|
|
4
4
|
copyright: InSpec Authors
|
|
5
5
|
copyright_email: support@chef.io
|
|
6
|
-
license: Apache
|
|
6
|
+
license: Apache-2.0
|
|
7
7
|
summary: InSpec Profile that is only consuming dependencies
|
|
8
8
|
version: 0.2.0
|
|
9
9
|
depends:
|
|
10
|
-
- name:
|
|
11
|
-
-
|
|
12
|
-
url: https://github.com/dev-sec/tests-os-hardening/archive/master.zip
|
|
13
|
-
- git: https://github.com/dev-sec/ssl-benchmark.git
|
|
10
|
+
- name: dev-sec/ssh-baseline # defaults to supermarket
|
|
11
|
+
- url: https://github.com/dev-sec/ssl-baseline
|
|
14
12
|
- name: windows-patch-benchmark
|
|
15
|
-
|
|
16
|
-
- name: linux
|
|
17
|
-
compliance: base/linux
|
|
13
|
+
url: https://github.com/chris-rock/windows-patch-benchmark
|
data/examples/profile/README.md
CHANGED
data/examples/profile/inspec.yml
CHANGED
|
@@ -3,7 +3,7 @@ title: InSpec Example Profile
|
|
|
3
3
|
maintainer: Chef Software, Inc.
|
|
4
4
|
copyright: Chef Software, Inc.
|
|
5
5
|
copyright_email: support@chef.io
|
|
6
|
-
license: Apache
|
|
6
|
+
license: Apache-2.0
|
|
7
7
|
summary: Demonstrates the use of InSpec Compliance Profile
|
|
8
8
|
version: 1.0.0
|
|
9
9
|
supports:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Example InSpec Profile with Sensitive failures
|
|
2
|
+
|
|
3
|
+
This profile demostrates resources flagged as sensitive
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
$ inspec exec examples/profile-sensitive
|
|
9
|
+
....
|
|
10
|
+
|
|
11
|
+
bob should
|
|
12
|
+
∅ eq "billy"
|
|
13
|
+
|
|
14
|
+
expected: "billy"
|
|
15
|
+
got: "bob"
|
|
16
|
+
|
|
17
|
+
(compared using ==)
|
|
18
|
+
|
|
19
|
+
sensitivepassword should
|
|
20
|
+
∅ eq "secret"
|
|
21
|
+
*** sensitive output suppressed ***
|
|
22
|
+
bob should
|
|
23
|
+
✔ eq "bob"
|
|
24
|
+
sensitivepassword should
|
|
25
|
+
✔ eq "sensitivepassword"
|
|
26
|
+
|
|
27
|
+
Test Summary: 2 successful, 2 failures, 0 skipped
|
|
28
|
+
|
|
29
|
+
```
|
data/inspec.gemspec
CHANGED
|
@@ -24,7 +24,9 @@ Gem::Specification.new do |spec|
|
|
|
24
24
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
25
25
|
spec.require_paths = ['lib']
|
|
26
26
|
|
|
27
|
-
spec.
|
|
27
|
+
spec.required_ruby_version = '>= 2.1'
|
|
28
|
+
|
|
29
|
+
spec.add_dependency 'train', '~> 0.26'
|
|
28
30
|
spec.add_dependency 'thor', '~> 0.19'
|
|
29
31
|
spec.add_dependency 'json', '>= 1.8', '< 3.0'
|
|
30
32
|
spec.add_dependency 'rainbow', '~> 2'
|
|
@@ -35,6 +37,12 @@ Gem::Specification.new do |spec|
|
|
|
35
37
|
spec.add_dependency 'pry', '~> 0'
|
|
36
38
|
spec.add_dependency 'hashie', '~> 3.4'
|
|
37
39
|
spec.add_dependency 'mixlib-log'
|
|
38
|
-
spec.add_dependency 'sslshake', '~> 1'
|
|
40
|
+
spec.add_dependency 'sslshake', '~> 1.2'
|
|
39
41
|
spec.add_dependency 'parallel', '~> 1.9'
|
|
42
|
+
spec.add_dependency 'faraday', '>=0.9.0'
|
|
43
|
+
spec.add_dependency 'toml', '~> 0.1'
|
|
44
|
+
spec.add_dependency 'addressable', '~> 2.4'
|
|
45
|
+
spec.add_dependency 'parslet', '~> 1.5'
|
|
46
|
+
spec.add_dependency 'semverse'
|
|
47
|
+
spec.add_dependency 'htmlentities'
|
|
40
48
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# TODO
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
require 'base64'
|
|
4
|
+
require 'openssl'
|
|
5
|
+
require 'pathname'
|
|
6
|
+
require 'set'
|
|
7
|
+
require 'tempfile'
|
|
8
|
+
require 'yaml'
|
|
9
|
+
|
|
10
|
+
# Notes:
|
|
11
|
+
#
|
|
12
|
+
# Generate keys
|
|
13
|
+
# The initial implementation uses 2048 bit RSA key pairs (public + private).
|
|
14
|
+
# Public keys must be available for a customer to install and verify an artifact.
|
|
15
|
+
# Private keys should be stored in a secure location and NOT be distributed.
|
|
16
|
+
# (They're only for creating artifacts).
|
|
17
|
+
#
|
|
18
|
+
#
|
|
19
|
+
# .IAF file format
|
|
20
|
+
# .iaf = "Inspec Artifact File", easy to rename if you'd like something more appropriate.
|
|
21
|
+
# The iaf file wraps a binary artifact with some metadata. The first implementation
|
|
22
|
+
# looks like this:
|
|
23
|
+
#
|
|
24
|
+
# INSPEC-PROFILE-1
|
|
25
|
+
# name_of_signing_key
|
|
26
|
+
# algorithm
|
|
27
|
+
# signature
|
|
28
|
+
# <empty line>
|
|
29
|
+
# binary-blob
|
|
30
|
+
# <eof>
|
|
31
|
+
#
|
|
32
|
+
# Let's look at each line:
|
|
33
|
+
# INSPEC-PROFILE-1:
|
|
34
|
+
# This is the artifact version descriptor. It should't change unless the
|
|
35
|
+
# format of the archive changes.
|
|
36
|
+
#
|
|
37
|
+
# name_of_signing_key
|
|
38
|
+
# The name of the public key that can be used to verify an artifact
|
|
39
|
+
#
|
|
40
|
+
# algorithm
|
|
41
|
+
# The digest used to sign, I picked SHA512 to start with.
|
|
42
|
+
# If we support multiple digests, we'll need to have the verify() method
|
|
43
|
+
# support each digest.
|
|
44
|
+
#
|
|
45
|
+
# signature
|
|
46
|
+
# The result of passing the binary artifact through the digest algorithm above.
|
|
47
|
+
# Result is base64 encoded.
|
|
48
|
+
#
|
|
49
|
+
# <empty line>
|
|
50
|
+
# We use an empty line to separate artifact header from artifact body (binary blob).
|
|
51
|
+
# The artifact body can be anything you like.
|
|
52
|
+
#
|
|
53
|
+
# binary-blob
|
|
54
|
+
# A binary blob, most likely a .tar.gz or tar.xz file. We'll need to pick one and
|
|
55
|
+
# stick with it as part of the "INSPEC-PROFILE-1" artifact version. If we change block
|
|
56
|
+
# format, the artifact version descriptor must be incremented, and the sign()
|
|
57
|
+
# and verify() methods must be updated to support a newer version.
|
|
58
|
+
#
|
|
59
|
+
#
|
|
60
|
+
# Key revocation
|
|
61
|
+
# This implementation doesn't support key revocation. However, a customer
|
|
62
|
+
# can remove the public cert file before installation, and artifacts will then
|
|
63
|
+
# fail verification.
|
|
64
|
+
#
|
|
65
|
+
# Key locations
|
|
66
|
+
# This implementation uses the current working directory to find public and
|
|
67
|
+
# private keys. We should establish a common key directory (similar to /hab/cache/keys
|
|
68
|
+
# or ~/.hab/cache/keys in Habitat).
|
|
69
|
+
#
|
|
70
|
+
# Extracting artifacts outside of Inspec
|
|
71
|
+
# As in Habitat, the artifact format for Inspec allows the use of common
|
|
72
|
+
# Unix tools to read the header and body of an artifact.
|
|
73
|
+
# To extract the header from a .iaf:
|
|
74
|
+
# sed '/^$/q' foo.iaf
|
|
75
|
+
# To extract the raw content from a .iaf:
|
|
76
|
+
# sed '1,/^$/d' foo.iaf
|
|
77
|
+
|
|
78
|
+
module Artifact
|
|
79
|
+
KEY_BITS=2048
|
|
80
|
+
KEY_ALG=OpenSSL::PKey::RSA
|
|
81
|
+
|
|
82
|
+
INSPEC_PROFILE_VERSION_1='INSPEC-PROFILE-1'.freeze
|
|
83
|
+
INSPEC_REPORT_VERSION_1='INSPEC-REPORT-1'.freeze
|
|
84
|
+
|
|
85
|
+
ARTIFACT_DIGEST=OpenSSL::Digest::SHA512
|
|
86
|
+
ARTIFACT_DIGEST_NAME='SHA512'.freeze
|
|
87
|
+
|
|
88
|
+
VALID_PROFILE_VERSIONS=Set.new [INSPEC_PROFILE_VERSION_1]
|
|
89
|
+
VALID_PROFILE_DIGESTS=Set.new [ARTIFACT_DIGEST_NAME]
|
|
90
|
+
|
|
91
|
+
SIGNED_PROFILE_SUFFIX='iaf'.freeze
|
|
92
|
+
SIGNED_REPORT_SUFFIX='iar'.freeze
|
|
93
|
+
|
|
94
|
+
# rubocop:disable Metrics/ClassLength
|
|
95
|
+
class CLI < Inspec::BaseCLI
|
|
96
|
+
namespace 'artifact'
|
|
97
|
+
|
|
98
|
+
# TODO: find another solution, once https://github.com/erikhuda/thor/issues/261 is fixed
|
|
99
|
+
def self.banner(command, _namespace = nil, _subcommand = false)
|
|
100
|
+
"#{basename} #{subcommand_prefix} #{command.usage}"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def self.subcommand_prefix
|
|
104
|
+
namespace
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
desc 'generate', 'Generate a RSA key pair for signing and verification'
|
|
108
|
+
option :keyname, type: :string, required: true,
|
|
109
|
+
desc: 'Desriptive name of key'
|
|
110
|
+
option :keydir, type: :string, default: './',
|
|
111
|
+
desc: 'Directory to search for keys'
|
|
112
|
+
def generate_keys
|
|
113
|
+
puts 'Generating keys'
|
|
114
|
+
keygen
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
desc 'sign-profile', 'Create a signed .iaf artifact'
|
|
118
|
+
option :profile, type: :string, required: true,
|
|
119
|
+
desc: 'Path to profile directory'
|
|
120
|
+
option :keyname, type: :string, required: true,
|
|
121
|
+
desc: 'Desriptive name of key'
|
|
122
|
+
def sign_profile
|
|
123
|
+
profile_sign
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
desc 'verify-profile', 'Verify a signed .iaf artifact'
|
|
127
|
+
option :infile, type: :string, required: true,
|
|
128
|
+
desc: '.iaf file to verify'
|
|
129
|
+
def verify_profile
|
|
130
|
+
profile_verify
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
desc 'install-profile', 'Verify and install a signed .iaf artifact'
|
|
134
|
+
option :infile, type: :string, required: true,
|
|
135
|
+
desc: '.iaf file to install'
|
|
136
|
+
option :destdir, type: :string, required: true,
|
|
137
|
+
desc: 'Installation directory'
|
|
138
|
+
def install_profile
|
|
139
|
+
profile_install
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
private
|
|
143
|
+
|
|
144
|
+
def keygen
|
|
145
|
+
key = KEY_ALG.new KEY_BITS
|
|
146
|
+
puts 'Generating private key'
|
|
147
|
+
open "#{options['keyname']}.pem.key", 'w' do |io| io.write key.to_pem end
|
|
148
|
+
puts 'Generating public key'
|
|
149
|
+
open "#{options['keyname']}.pem.pub", 'w' do |io| io.write key.public_key.to_pem end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def read_profile_metadata(path_to_profile)
|
|
153
|
+
begin
|
|
154
|
+
p = Pathname.new(path_to_profile)
|
|
155
|
+
p = p.join('inspec.yml')
|
|
156
|
+
if not p.exist?
|
|
157
|
+
raise "#{path_to_profile} doesn't appear to be a valid Inspec profile"
|
|
158
|
+
end
|
|
159
|
+
yaml = YAML.load_file(p.to_s)
|
|
160
|
+
yaml = yaml.to_hash
|
|
161
|
+
|
|
162
|
+
if not yaml.key? 'name'
|
|
163
|
+
raise 'Profile is invalid, name is not defined'
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
if not yaml.key? 'version'
|
|
167
|
+
raise 'Profile is invalid, version is not defined'
|
|
168
|
+
end
|
|
169
|
+
rescue => e
|
|
170
|
+
# rewrap it and pass it up to the CLI
|
|
171
|
+
raise "Error reading Inspec profile metadata: #{e}"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
yaml
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def profile_compress(path_to_profile, profile_md, workdir)
|
|
178
|
+
profile_name = profile_md['name']
|
|
179
|
+
profile_version = profile_md['version']
|
|
180
|
+
outfile_name = "#{workdir}/#{profile_name}-#{profile_version}.tar.gz"
|
|
181
|
+
`tar czf #{outfile_name} -C #{path_to_profile} .`
|
|
182
|
+
outfile_name
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def profile_sign
|
|
186
|
+
Dir.mktmpdir do |workdir|
|
|
187
|
+
puts "Signing #{options['profile']} with key #{options['keyname']}"
|
|
188
|
+
path_to_profile = options['profile']
|
|
189
|
+
profile_md = read_profile_metadata(path_to_profile)
|
|
190
|
+
artifact_filename = "#{profile_md['name']}-#{profile_md['version']}.#{SIGNED_PROFILE_SUFFIX}"
|
|
191
|
+
tarfile = profile_compress(path_to_profile, profile_md, workdir)
|
|
192
|
+
content = IO.binread(tarfile)
|
|
193
|
+
signing_key = KEY_ALG.new File.read "#{options['keyname']}.pem.key"
|
|
194
|
+
sha = ARTIFACT_DIGEST.new
|
|
195
|
+
signature = signing_key.sign sha, content
|
|
196
|
+
# convert the signature to Base64
|
|
197
|
+
signature_base64 = Base64.encode64(signature)
|
|
198
|
+
tar_content = IO.binread(tarfile)
|
|
199
|
+
File.open(artifact_filename, 'wb') do |f|
|
|
200
|
+
f.puts(INSPEC_PROFILE_VERSION_1)
|
|
201
|
+
f.puts(options['keyname'])
|
|
202
|
+
f.puts(ARTIFACT_DIGEST_NAME)
|
|
203
|
+
f.puts(signature_base64)
|
|
204
|
+
f.puts('') # newline separates artifact header with body
|
|
205
|
+
f.write(tar_content)
|
|
206
|
+
end
|
|
207
|
+
puts "Successfully generated #{artifact_filename}"
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
def valid_header?(file_alg, file_version, file_keyname)
|
|
212
|
+
public_keyfile = "#{file_keyname}.pem.pub"
|
|
213
|
+
puts "Looking for #{public_keyfile} to verify artifact"
|
|
214
|
+
if not File.exist? public_keyfile
|
|
215
|
+
raise "Can't find #{public_keyfile}"
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
if not VALID_PROFILE_DIGESTS.member? file_alg
|
|
219
|
+
raise 'Invalid artifact digest algorithm detected'
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
if not VALID_PROFILE_VERSIONS.member? file_version
|
|
223
|
+
raise 'Invalid artifact version detected'
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def verify(file_to_verifiy, &content_block)
|
|
228
|
+
f = File.open(file_to_verifiy, 'r')
|
|
229
|
+
file_version = f.readline.strip!
|
|
230
|
+
file_keyname = f.readline.strip!
|
|
231
|
+
file_alg = f.readline.strip!
|
|
232
|
+
|
|
233
|
+
file_sig = ''
|
|
234
|
+
# the signature is multi-line
|
|
235
|
+
while (line = f.readline) != "\n"
|
|
236
|
+
file_sig += line
|
|
237
|
+
end
|
|
238
|
+
file_sig.strip!
|
|
239
|
+
f.close
|
|
240
|
+
|
|
241
|
+
valid_header?(file_alg, file_version, file_keyname)
|
|
242
|
+
|
|
243
|
+
public_keyfile = "#{file_keyname}.pem.pub"
|
|
244
|
+
verification_key = KEY_ALG.new File.read public_keyfile
|
|
245
|
+
|
|
246
|
+
f = File.open(file_to_verifiy, 'r')
|
|
247
|
+
while f.readline != "\n" do end
|
|
248
|
+
content = f.read
|
|
249
|
+
|
|
250
|
+
signature = Base64.decode64(file_sig)
|
|
251
|
+
digest = ARTIFACT_DIGEST.new
|
|
252
|
+
if verification_key.verify digest, signature, content
|
|
253
|
+
content_block.yield(content)
|
|
254
|
+
else
|
|
255
|
+
puts 'Artifact is invalid'
|
|
256
|
+
end
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def profile_verify
|
|
260
|
+
file_to_verifiy = options['infile']
|
|
261
|
+
puts "Verifying #{file_to_verifiy}"
|
|
262
|
+
verify(file_to_verifiy) do ||
|
|
263
|
+
puts 'Artifact is valid'
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def profile_install
|
|
268
|
+
puts 'Installing profile'
|
|
269
|
+
file_to_verifiy = options['infile']
|
|
270
|
+
dest_dir = options['destdir']
|
|
271
|
+
verify(file_to_verifiy) do |content|
|
|
272
|
+
Dir.mktmpdir do |workdir|
|
|
273
|
+
tmpfile = Pathname.new(workdir).join('artifact_to_install.tar.gz')
|
|
274
|
+
File.write(tmpfile, content)
|
|
275
|
+
puts "Installing to #{dest_dir}"
|
|
276
|
+
`tar xzf #{tmpfile} -C #{dest_dir}`
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
# register the subcommand to Inspec CLI registry
|
|
283
|
+
Inspec::Plugins::CLI.add_subcommand(Artifact::CLI, 'artifact', 'artifact SUBCOMMAND ...', 'Sign, verify and install artifacts', {})
|
|
284
|
+
end
|