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
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Doc Walker
|
|
3
|
+
|
|
4
|
+
require 'openssl'
|
|
5
|
+
|
|
6
|
+
class DhParams < Inspec.resource(1)
|
|
7
|
+
name 'dh_params'
|
|
8
|
+
|
|
9
|
+
desc '
|
|
10
|
+
Use the `dh_params` InSpec audit resource to test Diffie-Hellman (DH)
|
|
11
|
+
parameters.
|
|
12
|
+
'
|
|
13
|
+
|
|
14
|
+
example "
|
|
15
|
+
describe dh_params('/path/to/file.dh_pem') do
|
|
16
|
+
it { should be_dh_params }
|
|
17
|
+
it { should be_valid }
|
|
18
|
+
its('generator') { should eq 2 }
|
|
19
|
+
its('modulus') { should eq '00:91:a0:15:89:e5:bc:38:93:12:02:fc:...' }
|
|
20
|
+
its('prime_length') { should eq 2048 }
|
|
21
|
+
its('pem') { should eq '-----BEGIN DH PARAMETERS...' }
|
|
22
|
+
its('text') { should eq 'PKCS#3 DH Parameters: (2048 bit)...' }
|
|
23
|
+
end
|
|
24
|
+
"
|
|
25
|
+
|
|
26
|
+
def initialize(filename)
|
|
27
|
+
@dh_params_path = filename
|
|
28
|
+
file = inspec.file(@dh_params_path)
|
|
29
|
+
return skip_resource 'Unable to find DH parameters file ' \
|
|
30
|
+
"#{@dh_params_path}" unless file.exist?
|
|
31
|
+
|
|
32
|
+
begin
|
|
33
|
+
@dh_params = OpenSSL::PKey::DH.new file.content
|
|
34
|
+
rescue
|
|
35
|
+
@dh_params = nil
|
|
36
|
+
return skip_resource "Unable to load DH parameters #{@dh_params_path}"
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# it { should be_dh_params }
|
|
41
|
+
def dh_params?
|
|
42
|
+
!@dh_params.nil?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# its('generator') { should eq 2 }
|
|
46
|
+
def generator
|
|
47
|
+
return if @dh_params.nil?
|
|
48
|
+
@dh_params.g.to_i
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# its('modulus') { should eq '00:91:a0:15:89:e5:bc:38:93:12:02:fc:...' }
|
|
52
|
+
def modulus
|
|
53
|
+
return if @dh_params.nil?
|
|
54
|
+
'00:' + @dh_params.p.to_s(16).downcase.scan(/.{2}/).join(':')
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# its('pem') { should eq '-----BEGIN DH PARAMETERS...' }
|
|
58
|
+
def pem
|
|
59
|
+
return if @dh_params.nil?
|
|
60
|
+
@dh_params.to_pem
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# its('prime_length') { should be 2048 }
|
|
64
|
+
def prime_length
|
|
65
|
+
return if @dh_params.nil?
|
|
66
|
+
@dh_params.p.num_bits
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# its('text') { should eq 'human-readable-text' }
|
|
70
|
+
def text
|
|
71
|
+
return if @dh_params.nil?
|
|
72
|
+
@dh_params.to_text
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# it { should be_valid }
|
|
76
|
+
def valid?
|
|
77
|
+
return if @dh_params.nil?
|
|
78
|
+
@dh_params.params_ok?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def to_s
|
|
82
|
+
"dh_params #{@dh_params_path}"
|
|
83
|
+
end
|
|
84
|
+
end
|
data/lib/resources/directory.rb
CHANGED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2017, Christoph Hartmann
|
|
4
|
+
#
|
|
5
|
+
# author: Christoph Hartmann
|
|
6
|
+
# author: Patrick Muench
|
|
7
|
+
# author: Dominik Richter
|
|
8
|
+
|
|
9
|
+
require 'utils/filter'
|
|
10
|
+
require 'hashie/mash'
|
|
11
|
+
|
|
12
|
+
module Inspec::Resources
|
|
13
|
+
class DockerContainerFilter
|
|
14
|
+
# use filtertable for containers
|
|
15
|
+
filter = FilterTable.create
|
|
16
|
+
filter.add_accessor(:where)
|
|
17
|
+
.add_accessor(:entries)
|
|
18
|
+
.add(:commands, field: 'command')
|
|
19
|
+
.add(:ids, field: 'id')
|
|
20
|
+
.add(:images, field: 'image')
|
|
21
|
+
.add(:labels, field: 'labels')
|
|
22
|
+
.add(:local_volumes, field: 'localvolumes')
|
|
23
|
+
.add(:mounts, field: 'mounts')
|
|
24
|
+
.add(:names, field: 'names')
|
|
25
|
+
.add(:networks, field: 'networks')
|
|
26
|
+
.add(:ports, field: 'ports')
|
|
27
|
+
.add(:running_for, field: 'runningfor')
|
|
28
|
+
.add(:sizes, field: 'size')
|
|
29
|
+
.add(:status, field: 'status')
|
|
30
|
+
.add(:exists?) { |x| !x.entries.empty? }
|
|
31
|
+
.add(:running?) { |x|
|
|
32
|
+
x.where { status.downcase.start_with?('up') }
|
|
33
|
+
}
|
|
34
|
+
filter.connect(self, :containers)
|
|
35
|
+
|
|
36
|
+
attr_reader :containers
|
|
37
|
+
def initialize(containers)
|
|
38
|
+
@containers = containers
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
class DockerImageFilter
|
|
43
|
+
filter = FilterTable.create
|
|
44
|
+
filter.add_accessor(:where)
|
|
45
|
+
.add_accessor(:entries)
|
|
46
|
+
.add(:ids, field: 'id')
|
|
47
|
+
.add(:repositories, field: 'repository')
|
|
48
|
+
.add(:tags, field: 'tag')
|
|
49
|
+
.add(:sizes, field: 'size')
|
|
50
|
+
.add(:digests, field: 'digest')
|
|
51
|
+
.add(:created, field: 'createdat')
|
|
52
|
+
.add(:created_since, field: 'createdsize')
|
|
53
|
+
.add(:exists?) { |x| !x.entries.empty? }
|
|
54
|
+
filter.connect(self, :images)
|
|
55
|
+
|
|
56
|
+
attr_reader :images
|
|
57
|
+
def initialize(images)
|
|
58
|
+
@images = images
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# This resource helps to parse information from the docker host
|
|
63
|
+
# For compatability with Serverspec we also offer the following resouses:
|
|
64
|
+
# - docker_container
|
|
65
|
+
# - docker_image
|
|
66
|
+
class Docker < Inspec.resource(1)
|
|
67
|
+
name 'docker'
|
|
68
|
+
|
|
69
|
+
desc "
|
|
70
|
+
A resource to retrieve information about docker
|
|
71
|
+
"
|
|
72
|
+
|
|
73
|
+
example "
|
|
74
|
+
describe docker.containers do
|
|
75
|
+
its('images') { should_not include 'u12:latest' }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
describe docker.images do
|
|
79
|
+
its('repositories') { should_not include 'inssecure_image' }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe docker.version do
|
|
83
|
+
its('Server.Version') { should cmp >= '1.12'}
|
|
84
|
+
its('Client.Version') { should cmp >= '1.12'}
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe docker.object(id) do
|
|
88
|
+
its('Configuration.Path') { should eq 'value' }
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
docker.containers.ids.each do |id|
|
|
92
|
+
# call docker inspect for a specific container id
|
|
93
|
+
describe docker.object(id) do
|
|
94
|
+
its(%w(HostConfig Privileged)) { should cmp false }
|
|
95
|
+
its(%w(HostConfig Privileged)) { should_not cmp true }
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
"
|
|
99
|
+
|
|
100
|
+
def containers
|
|
101
|
+
DockerContainerFilter.new(parse_containers)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def images
|
|
105
|
+
DockerImageFilter.new(parse_images)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def version
|
|
109
|
+
return @version if defined?(@version)
|
|
110
|
+
data = {}
|
|
111
|
+
cmd = inspec.command('docker version --format \'{{ json . }}\'')
|
|
112
|
+
data = JSON.parse(cmd.stdout) if cmd.exit_status == 0
|
|
113
|
+
@version = Hashie::Mash.new(data)
|
|
114
|
+
rescue JSON::ParserError => _e
|
|
115
|
+
return Hashie::Mash.new({})
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def info
|
|
119
|
+
return @info if defined?(@info)
|
|
120
|
+
data = {}
|
|
121
|
+
# docke info format is only supported for Docker 17.03+
|
|
122
|
+
cmd = inspec.command('docker info --format \'{{ json . }}\'')
|
|
123
|
+
data = JSON.parse(cmd.stdout) if cmd.exit_status == 0
|
|
124
|
+
@info = Hashie::Mash.new(data)
|
|
125
|
+
rescue JSON::ParserError => _e
|
|
126
|
+
return Hashie::Mash.new({})
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# returns information about docker objects
|
|
130
|
+
def object(id)
|
|
131
|
+
return @inspect if defined?(@inspect)
|
|
132
|
+
data = JSON.parse(inspec.command("docker inspect #{id}").stdout)
|
|
133
|
+
data = data[0] if data.is_a?(Array)
|
|
134
|
+
@inspect = Hashie::Mash.new(data)
|
|
135
|
+
rescue JSON::ParserError => _e
|
|
136
|
+
return Hashie::Mash.new({})
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def to_s
|
|
140
|
+
'Docker Host'
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def parse_containers
|
|
146
|
+
# @see https://github.com/moby/moby/issues/20625, works for docker 1.13+
|
|
147
|
+
# raw_containers = inspec.command('docker ps -a --no-trunc --format \'{{ json . }}\'').stdout
|
|
148
|
+
# therefore we stick with older approach
|
|
149
|
+
labels = %w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status}
|
|
150
|
+
|
|
151
|
+
# Networks LocalVolumes work with 1.13+ only
|
|
152
|
+
if !version.empty? && Gem::Version.new(version['Client']['Version']) >= Gem::Version.new('1.13')
|
|
153
|
+
labels.push('Networks')
|
|
154
|
+
labels.push('LocalVolumes')
|
|
155
|
+
end
|
|
156
|
+
# build command
|
|
157
|
+
format = labels.map { |label| "\"#{label}\": {{json .#{label}}}" }
|
|
158
|
+
raw_containers = inspec.command("docker ps -a --no-trunc --format '{#{format.join(', ')}}'").stdout
|
|
159
|
+
ps = []
|
|
160
|
+
# since docker is not outputting valid json, we need to parse each row
|
|
161
|
+
raw_containers.each_line { |entry|
|
|
162
|
+
j = JSON.parse(entry)
|
|
163
|
+
# convert all keys to lower_case to work well with ruby and filter table
|
|
164
|
+
j = j.map { |k, v|
|
|
165
|
+
[k.downcase, v]
|
|
166
|
+
}.to_h
|
|
167
|
+
|
|
168
|
+
# ensure all keys are there
|
|
169
|
+
j = ensure_container_keys(j)
|
|
170
|
+
ps.push(j)
|
|
171
|
+
}
|
|
172
|
+
ps
|
|
173
|
+
rescue JSON::ParserError => _e
|
|
174
|
+
warn 'Could not parse `docker ps` output'
|
|
175
|
+
[]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def ensure_container_keys(entry)
|
|
179
|
+
%w{Command CreatedAt ID Image Labels Mounts Names Ports RunningFor Size Status Networks LocalVolumes}.each { |key|
|
|
180
|
+
entry[key.downcase] = nil if !entry.key?(key.downcase)
|
|
181
|
+
}
|
|
182
|
+
entry
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def parse_images
|
|
186
|
+
# docker does not support the `json .` function here, therefore we need to emulate that behavior.
|
|
187
|
+
raw_images = inspec.command('docker images -a --no-trunc --format \'{ "id": {{json .ID}}, "repository": {{json .Repository}}, "tag": {{json .Tag}}, "size": {{json .Size}}, "digest": {{json .Digest}}, "createdat": {{json .CreatedAt}}, "createdsize": {{json .CreatedSince}} }\'').stdout
|
|
188
|
+
c_images = []
|
|
189
|
+
raw_images.each_line { |entry|
|
|
190
|
+
c_images.push(JSON.parse(entry))
|
|
191
|
+
}
|
|
192
|
+
c_images
|
|
193
|
+
rescue JSON::ParserError => _e
|
|
194
|
+
warn 'Could not parse `docker images` output'
|
|
195
|
+
[]
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2017, Christoph Hartmann
|
|
4
|
+
#
|
|
5
|
+
# author: Christoph Hartmann
|
|
6
|
+
# author: Patrick Muench
|
|
7
|
+
# author: Dominik Richter
|
|
8
|
+
|
|
9
|
+
module Inspec::Resources
|
|
10
|
+
class DockerContainer < Inspec.resource(1)
|
|
11
|
+
name 'docker_container'
|
|
12
|
+
desc ''
|
|
13
|
+
example "
|
|
14
|
+
describe docker_container('an-echo-server') do
|
|
15
|
+
it { should exist }
|
|
16
|
+
it { should be_running }
|
|
17
|
+
its('id') { should_not eq '' }
|
|
18
|
+
its('image') { should eq 'busybox:latest' }
|
|
19
|
+
its('repo') { should eq 'busybox' }
|
|
20
|
+
its('tag') { should eq 'latest' }
|
|
21
|
+
its('ports') { should eq [] }
|
|
22
|
+
its('command') { should eq 'nc -ll -p 1234 -e /bin/cat' }
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe docker_container(id: 'e2c52a183358') do
|
|
26
|
+
it { should exist }
|
|
27
|
+
it { should be_running }
|
|
28
|
+
end
|
|
29
|
+
"
|
|
30
|
+
|
|
31
|
+
def initialize(opts = {})
|
|
32
|
+
# if a string is provided, we expect it is the name
|
|
33
|
+
if opts.is_a?(String)
|
|
34
|
+
@opts = { name: opts }
|
|
35
|
+
else
|
|
36
|
+
@opts = opts
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def exist?
|
|
41
|
+
container_info.exists?
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# is allways returning the full id
|
|
45
|
+
def id
|
|
46
|
+
container_info.ids[0] if container_info.entries.length == 1
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def running?
|
|
50
|
+
status.downcase.start_with?('up') if container_info.entries.length == 1
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def status
|
|
54
|
+
container_info.status[0] if container_info.entries.length == 1
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def labels
|
|
58
|
+
container_info.labels[0] if container_info.entries.length == 1
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def ports
|
|
62
|
+
container_info.ports[0] if container_info.entries.length == 1
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def command
|
|
66
|
+
if container_info.entries.length == 1
|
|
67
|
+
cmd = container_info.commands[0]
|
|
68
|
+
cmd.slice(1, cmd.length - 2)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def image
|
|
73
|
+
container_info.images[0] if container_info.entries.length == 1
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def repo
|
|
77
|
+
return if image.nil? || image_name_from_image.nil?
|
|
78
|
+
if image.include?('/') # host:port/ubuntu:latest
|
|
79
|
+
repo_part, image_part = image.split('/') # host:port, ubuntu:latest
|
|
80
|
+
repo_part + '/' + image_part.split(':')[0] # host:port + / + ubuntu
|
|
81
|
+
else
|
|
82
|
+
image_name_from_image.split(':')[0]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def tag
|
|
87
|
+
return if image_name_from_image.nil?
|
|
88
|
+
image_name_from_image.split(':')[1]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def to_s
|
|
92
|
+
name = @opts[:name] || @opts[:id]
|
|
93
|
+
"Docker Container #{name}"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
private
|
|
97
|
+
|
|
98
|
+
def image_name_from_image
|
|
99
|
+
return if image.nil?
|
|
100
|
+
# possible image names include:
|
|
101
|
+
# alpine
|
|
102
|
+
# ubuntu:14.04
|
|
103
|
+
# repo.example.com:5000/ubuntu
|
|
104
|
+
# repo.example.com:5000/ubuntu:1404
|
|
105
|
+
image.include?('/') ? image.split('/')[1] : image
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def container_info
|
|
109
|
+
return @info if defined?(@info)
|
|
110
|
+
opts = @opts
|
|
111
|
+
@info = inspec.docker.containers.where { names == opts[:name] || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id]))) }
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2017, Christoph Hartmann
|
|
4
|
+
#
|
|
5
|
+
# author: Christoph Hartmann
|
|
6
|
+
# author: Patrick Muench
|
|
7
|
+
# author: Dominik Richter
|
|
8
|
+
|
|
9
|
+
module Inspec::Resources
|
|
10
|
+
class DockerImage < Inspec.resource(1)
|
|
11
|
+
name 'docker_image'
|
|
12
|
+
desc ''
|
|
13
|
+
example "
|
|
14
|
+
describe docker_image('alpine:latest') do
|
|
15
|
+
it { should exist }
|
|
16
|
+
its('id') { should_not eq '' }
|
|
17
|
+
its('image') { should eq 'alpine:latest' }
|
|
18
|
+
its('repo') { should eq 'alpine' }
|
|
19
|
+
its('tag') { should eq 'latest' }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe docker_image('alpine:latest') do
|
|
23
|
+
it { should exist }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe docker_image(id: '4a415e366388') do
|
|
27
|
+
it { should exist }
|
|
28
|
+
end
|
|
29
|
+
"
|
|
30
|
+
|
|
31
|
+
def initialize(opts = {})
|
|
32
|
+
# do sanitizion of input values
|
|
33
|
+
o = opts.dup
|
|
34
|
+
o = { image: opts } if opts.is_a?(String)
|
|
35
|
+
@opts = sanitize_options(o)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def exist?
|
|
39
|
+
image_info.exists?
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def id
|
|
43
|
+
image_info.ids[0] if image_info.entries.size == 1
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def image
|
|
47
|
+
"#{repo}:#{tag}" if image_info.entries.size == 1
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def repo
|
|
51
|
+
image_info.repositories[0] if image_info.entries.size == 1
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def tag
|
|
55
|
+
image_info.tags[0] if image_info.entries.size == 1
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def to_s
|
|
59
|
+
img = @opts[:image] || @opts[:id]
|
|
60
|
+
"Docker Image #{img}"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def sanitize_options(opts)
|
|
66
|
+
if !opts[:image].nil?
|
|
67
|
+
if !opts[:image].index(':').nil?
|
|
68
|
+
repo, tag = opts[:image].split(':')
|
|
69
|
+
else
|
|
70
|
+
opts[:repo] = opts[:image]
|
|
71
|
+
opts[:image] = nil
|
|
72
|
+
end
|
|
73
|
+
opts[:repo] ||= repo
|
|
74
|
+
opts[:tag] ||= tag
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
if !opts[:id].nil?
|
|
78
|
+
if opts[:id].index(':').nil?
|
|
79
|
+
opts[:id] = 'sha256:' + opts[:id]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
opts[:tag] ||= 'latest'
|
|
84
|
+
opts[:image] ||= "#{opts[:repo]}:#{opts[:tag]}" unless opts[:repo].nil?
|
|
85
|
+
opts
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def image_info
|
|
89
|
+
return @info if defined?(@info)
|
|
90
|
+
opts = @opts
|
|
91
|
+
@info = inspec.docker.images.where {
|
|
92
|
+
(repository == opts[:repo] && tag == opts[:tag]) || (!id.nil? && !opts[:id].nil? && (id == opts[:id] || id.start_with?(opts[:id])))
|
|
93
|
+
}
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
data/lib/resources/etc_group.rb
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
# copyright: 2015, Vulcano Security GmbH
|
|
3
3
|
# author: Christoph Hartmann
|
|
4
4
|
# author: Dominik Richter
|
|
5
|
-
# license: All rights reserved
|
|
6
5
|
|
|
7
6
|
# The file format consists of
|
|
8
7
|
# - group name
|
|
@@ -107,7 +106,7 @@ module Inspec::Resources
|
|
|
107
106
|
# iterate over each line and filter comments
|
|
108
107
|
@content.split("\n").each_with_object([]) do |line, lines|
|
|
109
108
|
grp_info = parse_group_line(line)
|
|
110
|
-
lines.push(grp_info) if !grp_info.nil? && grp_info.
|
|
109
|
+
lines.push(grp_info) if !grp_info.nil? && !grp_info.empty?
|
|
111
110
|
end
|
|
112
111
|
end
|
|
113
112
|
|
|
@@ -119,7 +118,7 @@ module Inspec::Resources
|
|
|
119
118
|
line, _idx_nl = parse_comment_line(line, opts)
|
|
120
119
|
x = line.split(':')
|
|
121
120
|
# abort if we have an empty or comment line
|
|
122
|
-
return nil if x.
|
|
121
|
+
return nil if x.empty?
|
|
123
122
|
# map data
|
|
124
123
|
{
|
|
125
124
|
'name' => x.at(0), # Name of the group.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# author: Matthew Dromazos
|
|
3
|
+
|
|
4
|
+
require 'utils/parser'
|
|
5
|
+
|
|
6
|
+
class EtcHosts < Inspec.resource(1)
|
|
7
|
+
name 'etc_hosts'
|
|
8
|
+
desc 'Use the etc_hosts InSpec audit resource to find an
|
|
9
|
+
ip_address and its associated hosts'
|
|
10
|
+
example "
|
|
11
|
+
describe etc_hosts.where { ip_address == '127.0.0.1' } do
|
|
12
|
+
its('ip_address') { should cmp '127.0.0.1' }
|
|
13
|
+
its('primary_name') { should cmp 'localhost' }
|
|
14
|
+
its('all_host_names') { should eq [['localhost', 'localhost.localdomain', 'localhost4', 'localhost4.localdomain4']] }
|
|
15
|
+
end
|
|
16
|
+
"
|
|
17
|
+
|
|
18
|
+
attr_reader :params
|
|
19
|
+
|
|
20
|
+
include CommentParser
|
|
21
|
+
|
|
22
|
+
def initialize(hosts_path = nil)
|
|
23
|
+
return skip_resource 'The `etc_hosts` resource is not supported on your OS.' unless inspec.os.linux? || inspec.os.windows?
|
|
24
|
+
@conf_path = hosts_path || default_hosts_file_path
|
|
25
|
+
@content = nil
|
|
26
|
+
@params = nil
|
|
27
|
+
read_content
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
filter = FilterTable.create
|
|
31
|
+
filter.add_accessor(:where)
|
|
32
|
+
.add_accessor(:entries)
|
|
33
|
+
.add(:ip_address, field: 'ip_address')
|
|
34
|
+
.add(:primary_name, field: 'primary_name')
|
|
35
|
+
.add(:all_host_names, field: 'all_host_names')
|
|
36
|
+
|
|
37
|
+
filter.connect(self, :params)
|
|
38
|
+
|
|
39
|
+
private
|
|
40
|
+
|
|
41
|
+
def default_hosts_file_path
|
|
42
|
+
inspec.os.windows? ? 'C:\windows\system32\drivers\etc\hosts' : '/etc/hosts'
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def read_content
|
|
46
|
+
@content = ''
|
|
47
|
+
@params = {}
|
|
48
|
+
@content = read_file(@conf_path)
|
|
49
|
+
@params = parse_conf(@content)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parse_conf(content)
|
|
53
|
+
content.map do |line|
|
|
54
|
+
data, = parse_comment_line(line, comment_char: '#', standalone_comments: false)
|
|
55
|
+
parse_line(data) unless data == ''
|
|
56
|
+
end.compact
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def parse_line(line)
|
|
60
|
+
line_parts = line.split
|
|
61
|
+
return nil unless line_parts.length >= 2
|
|
62
|
+
{
|
|
63
|
+
'ip_address' => line_parts[0],
|
|
64
|
+
'primary_name' => line_parts[1],
|
|
65
|
+
'all_host_names' => line_parts[1..-1],
|
|
66
|
+
}
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def read_file(conf_path = @conf_path)
|
|
70
|
+
file = inspec.file(conf_path)
|
|
71
|
+
if !file.file?
|
|
72
|
+
return skip_resource "Can't find file. \"#{@conf_path}\""
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
raw_conf = file.content
|
|
76
|
+
if raw_conf.empty? && !file.empty?
|
|
77
|
+
return skip_resource("Could not read file contents\" #{@conf_path}\"")
|
|
78
|
+
end
|
|
79
|
+
raw_conf.lines
|
|
80
|
+
end
|
|
81
|
+
end
|