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.
Files changed (286) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +933 -101
  3. data/Gemfile +8 -17
  4. data/MAINTAINERS.md +2 -1
  5. data/MAINTAINERS.toml +9 -4
  6. data/README.md +49 -28
  7. data/Rakefile +54 -39
  8. data/bin/inspec +1 -1
  9. data/docs/dsl_inspec.md +17 -4
  10. data/docs/dsl_resource.md +1 -1
  11. data/docs/habitat.md +192 -0
  12. data/docs/inspec_and_friends.md +4 -2
  13. data/docs/matchers.md +11 -0
  14. data/docs/migration.md +293 -0
  15. data/docs/profiles.md +124 -76
  16. data/docs/resources/aide_conf.md.erb +81 -0
  17. data/docs/resources/apache_conf.md.erb +10 -10
  18. data/docs/resources/apt.md.erb +13 -13
  19. data/docs/resources/audit_policy.md.erb +10 -10
  20. data/docs/resources/auditd_conf.md.erb +10 -10
  21. data/docs/resources/auditd_rules.md.erb +11 -11
  22. data/docs/resources/bash.md.erb +12 -12
  23. data/docs/resources/bond.md.erb +15 -15
  24. data/docs/resources/bridge.md.erb +11 -11
  25. data/docs/resources/bsd_service.md.erb +11 -11
  26. data/docs/resources/command.md.erb +23 -23
  27. data/docs/resources/crontab.md.erb +84 -0
  28. data/docs/resources/csv.md.erb +10 -10
  29. data/docs/resources/dh_params.md +191 -0
  30. data/docs/resources/directory.md.erb +8 -8
  31. data/docs/resources/docker.md.erb +160 -0
  32. data/docs/resources/docker_container.md.erb +89 -0
  33. data/docs/resources/docker_image.md.erb +86 -0
  34. data/docs/resources/etc_group.md.erb +16 -16
  35. data/docs/resources/etc_hosts.md.erb +62 -0
  36. data/docs/resources/file.md.erb +80 -58
  37. data/docs/resources/gem.md.erb +32 -13
  38. data/docs/resources/group.md.erb +12 -12
  39. data/docs/resources/grub_conf.md.erb +11 -11
  40. data/docs/resources/host.md.erb +27 -18
  41. data/docs/resources/http.md.erb +104 -0
  42. data/docs/resources/iis_app.md.erb +126 -0
  43. data/docs/resources/iis_site.md.erb +17 -17
  44. data/docs/resources/inetd_conf.md.erb +10 -10
  45. data/docs/resources/ini.md.erb +9 -9
  46. data/docs/resources/interface.md.erb +13 -13
  47. data/docs/resources/iptables.md.erb +21 -14
  48. data/docs/resources/json.md.erb +11 -11
  49. data/docs/resources/kernel_module.md.erb +73 -12
  50. data/docs/resources/kernel_parameter.md.erb +12 -12
  51. data/docs/resources/key_rsa.md.erb +70 -0
  52. data/docs/resources/launchd_service.md.erb +11 -11
  53. data/docs/resources/limits_conf.md.erb +10 -10
  54. data/docs/resources/login_def.md.erb +12 -12
  55. data/docs/resources/mount.md.erb +14 -14
  56. data/docs/resources/mssql_session.md.erb +62 -0
  57. data/docs/resources/mysql_conf.md.erb +14 -14
  58. data/docs/resources/mysql_session.md.erb +22 -10
  59. data/docs/resources/npm.md.erb +13 -13
  60. data/docs/resources/ntp_conf.md.erb +9 -9
  61. data/docs/resources/oneget.md.erb +11 -11
  62. data/docs/resources/oracledb_session.md.erb +53 -0
  63. data/docs/resources/os.md.erb +17 -17
  64. data/docs/resources/os_env.md.erb +12 -12
  65. data/docs/resources/package.md.erb +29 -16
  66. data/docs/resources/parse_config.md.erb +18 -18
  67. data/docs/resources/parse_config_file.md.erb +29 -23
  68. data/docs/resources/{etc_passwd.md.erb → passwd.md.erb} +17 -17
  69. data/docs/resources/pip.md.erb +15 -15
  70. data/docs/resources/port.md.erb +23 -23
  71. data/docs/resources/postgres_conf.md.erb +15 -13
  72. data/docs/resources/postgres_hba_conf.md.erb +104 -0
  73. data/docs/resources/postgres_ident_conf.md.erb +87 -0
  74. data/docs/resources/postgres_session.md.erb +28 -21
  75. data/docs/resources/powershell.md.erb +14 -14
  76. data/docs/resources/processes.md.erb +123 -0
  77. data/docs/resources/rabbitmq_config.md.erb +55 -0
  78. data/docs/resources/registry_key.md.erb +44 -21
  79. data/docs/resources/runit_service.md.erb +11 -11
  80. data/docs/resources/security_policy.md.erb +10 -10
  81. data/docs/resources/service.md.erb +18 -18
  82. data/docs/resources/{etc_shadow.md.erb → shadow.md.erb} +19 -19
  83. data/docs/resources/ssh_config.md.erb +13 -13
  84. data/docs/resources/sshd_config.md.erb +15 -15
  85. data/docs/resources/ssl.md.erb +13 -13
  86. data/docs/resources/sys_info.md.erb +10 -10
  87. data/docs/resources/systemd_service.md.erb +11 -11
  88. data/docs/resources/sysv_service.md.erb +11 -11
  89. data/docs/resources/upstart_service.md.erb +11 -11
  90. data/docs/resources/user.md.erb +20 -20
  91. data/docs/resources/users.md.erb +19 -19
  92. data/docs/resources/vbscript.md.erb +13 -13
  93. data/docs/resources/virtualization.md.erb +71 -0
  94. data/docs/resources/windows_feature.md.erb +10 -10
  95. data/docs/resources/windows_task.md.erb +103 -0
  96. data/docs/resources/wmi.md.erb +10 -10
  97. data/docs/resources/x509_certificate.md.erb +146 -0
  98. data/docs/resources/xinetd_conf.md.erb +17 -17
  99. data/docs/resources/xml.md.erb +75 -0
  100. data/docs/resources/yaml.md.erb +25 -11
  101. data/docs/resources/yum.md.erb +24 -16
  102. data/docs/resources/zfs_dataset.md.erb +63 -0
  103. data/docs/resources/zfs_pool.md.erb +57 -0
  104. data/docs/ruby_usage.md +50 -0
  105. data/docs/shared/matcher_cmp.md.erb +4 -6
  106. data/examples/inheritance/README.md +49 -3
  107. data/examples/inheritance/controls/example.rb +4 -1
  108. data/examples/inheritance/inspec.yml +3 -1
  109. data/examples/meta-profile/README.md +29 -3
  110. data/examples/meta-profile/controls/example.rb +10 -5
  111. data/examples/meta-profile/inspec.yml +4 -8
  112. data/examples/profile/README.md +1 -1
  113. data/examples/profile/controls/example.rb +0 -1
  114. data/examples/profile/controls/gordon.rb +0 -1
  115. data/examples/profile/inspec.yml +1 -1
  116. data/examples/profile-attribute/inspec.yml +1 -1
  117. data/examples/profile-sensitive/README.md +29 -0
  118. data/examples/profile-sensitive/controls/sensitive-failures.rb +9 -0
  119. data/examples/profile-sensitive/controls/sensitive.rb +9 -0
  120. data/examples/profile-sensitive/inspec.yml +8 -0
  121. data/inspec.gemspec +10 -2
  122. data/lib/bundles/inspec-artifact/README.md +1 -0
  123. data/lib/bundles/inspec-artifact/cli.rb +284 -0
  124. data/lib/bundles/inspec-artifact.rb +7 -0
  125. data/lib/bundles/inspec-compliance/README.md +44 -15
  126. data/lib/bundles/inspec-compliance/api.rb +135 -29
  127. data/lib/bundles/inspec-compliance/cli.rb +128 -21
  128. data/lib/bundles/inspec-compliance/configuration.rb +8 -0
  129. data/lib/bundles/inspec-compliance/http.rb +26 -19
  130. data/lib/bundles/inspec-compliance/target.rb +50 -25
  131. data/lib/bundles/inspec-habitat/cli.rb +31 -0
  132. data/lib/bundles/inspec-habitat/log.rb +10 -0
  133. data/lib/bundles/inspec-habitat/profile.rb +372 -0
  134. data/lib/bundles/inspec-habitat.rb +12 -0
  135. data/lib/bundles/inspec-init/templates/profile/controls/example.rb +0 -1
  136. data/lib/bundles/inspec-init/templates/profile/inspec.yml +1 -1
  137. data/lib/bundles/inspec-supermarket/api.rb +7 -5
  138. data/lib/bundles/inspec-supermarket/cli.rb +2 -2
  139. data/lib/fetchers/git.rb +4 -2
  140. data/lib/fetchers/local.rb +4 -1
  141. data/lib/fetchers/url.rb +64 -10
  142. data/lib/inspec/archive/tar.rb +1 -1
  143. data/lib/inspec/backend.rb +26 -3
  144. data/lib/inspec/base_cli.rb +44 -7
  145. data/lib/inspec/cached_fetcher.rb +2 -2
  146. data/lib/inspec/cli.rb +34 -12
  147. data/lib/inspec/completions/fish.sh.erb +34 -0
  148. data/lib/inspec/control_eval_context.rb +0 -2
  149. data/lib/inspec/dependencies/cache.rb +0 -1
  150. data/lib/inspec/dependencies/dependency_set.rb +2 -2
  151. data/lib/inspec/dependencies/lockfile.rb +13 -6
  152. data/lib/inspec/dependencies/requirement.rb +6 -6
  153. data/lib/inspec/dependencies/resolver.rb +4 -4
  154. data/lib/inspec/dsl.rb +3 -5
  155. data/lib/inspec/env_printer.rb +9 -1
  156. data/lib/inspec/exceptions.rb +8 -0
  157. data/lib/inspec/fetcher.rb +1 -1
  158. data/lib/inspec/file_provider.rb +47 -11
  159. data/lib/inspec/library_eval_context.rb +1 -1
  160. data/lib/inspec/metadata.rb +62 -18
  161. data/lib/inspec/method_source.rb +24 -0
  162. data/lib/inspec/objects/attribute.rb +21 -0
  163. data/lib/inspec/objects/control.rb +21 -3
  164. data/lib/inspec/objects/each_loop.rb +2 -1
  165. data/lib/inspec/objects/list.rb +1 -1
  166. data/lib/inspec/objects/or_test.rb +17 -2
  167. data/lib/inspec/objects/tag.rb +27 -0
  168. data/lib/inspec/objects/test.rb +9 -8
  169. data/lib/inspec/objects.rb +1 -0
  170. data/lib/inspec/plugins/fetcher.rb +4 -5
  171. data/lib/inspec/plugins/resource.rb +1 -2
  172. data/lib/inspec/plugins/source_reader.rb +3 -3
  173. data/lib/inspec/plugins.rb +1 -1
  174. data/lib/inspec/polyfill.rb +0 -1
  175. data/lib/inspec/profile.rb +92 -23
  176. data/lib/inspec/profile_context.rb +1 -1
  177. data/lib/inspec/profile_vendor.rb +66 -0
  178. data/lib/inspec/resource.rb +29 -3
  179. data/lib/inspec/rspec_json_formatter.rb +672 -285
  180. data/lib/inspec/rule.rb +12 -16
  181. data/lib/inspec/runner.rb +26 -15
  182. data/lib/inspec/runner_rspec.rb +1 -0
  183. data/lib/inspec/runtime_profile.rb +26 -0
  184. data/lib/inspec/schema.rb +185 -0
  185. data/lib/inspec/secrets/yaml.rb +8 -1
  186. data/lib/inspec/secrets.rb +1 -1
  187. data/lib/inspec/shell.rb +92 -22
  188. data/lib/inspec/source_reader.rb +1 -1
  189. data/lib/inspec/version.rb +1 -1
  190. data/lib/inspec.rb +1 -1
  191. data/lib/matchers/matchers.rb +67 -17
  192. data/lib/resources/aide_conf.rb +162 -0
  193. data/lib/resources/apache.rb +0 -1
  194. data/lib/resources/apache_conf.rb +3 -3
  195. data/lib/resources/apt.rb +2 -1
  196. data/lib/resources/audit_policy.rb +0 -1
  197. data/lib/resources/auditd_conf.rb +1 -2
  198. data/lib/resources/auditd_rules.rb +5 -5
  199. data/lib/resources/bond.rb +1 -1
  200. data/lib/resources/bridge.rb +1 -1
  201. data/lib/resources/command.rb +5 -3
  202. data/lib/resources/crontab.rb +102 -0
  203. data/lib/resources/csv.rb +18 -1
  204. data/lib/resources/dh_params.rb +84 -0
  205. data/lib/resources/directory.rb +7 -3
  206. data/lib/resources/docker.rb +198 -0
  207. data/lib/resources/docker_container.rb +114 -0
  208. data/lib/resources/docker_image.rb +96 -0
  209. data/lib/resources/etc_group.rb +2 -3
  210. data/lib/resources/etc_hosts.rb +81 -0
  211. data/lib/resources/file.rb +88 -30
  212. data/lib/resources/gem.rb +26 -6
  213. data/lib/resources/groups.rb +4 -5
  214. data/lib/resources/grub_conf.rb +3 -4
  215. data/lib/resources/host.rb +175 -35
  216. data/lib/resources/http.rb +73 -0
  217. data/lib/resources/iis_app.rb +103 -0
  218. data/lib/resources/iis_site.rb +23 -0
  219. data/lib/resources/inetd_conf.rb +9 -4
  220. data/lib/resources/interface.rb +4 -3
  221. data/lib/resources/json.rb +37 -14
  222. data/lib/resources/kernel_module.rb +77 -10
  223. data/lib/resources/kernel_parameter.rb +0 -1
  224. data/lib/resources/key_rsa.rb +67 -0
  225. data/lib/resources/limits_conf.rb +3 -4
  226. data/lib/resources/login_def.rb +2 -3
  227. data/lib/resources/mount.rb +34 -4
  228. data/lib/resources/mssql_session.rb +81 -12
  229. data/lib/resources/mysql.rb +0 -1
  230. data/lib/resources/mysql_conf.rb +1 -2
  231. data/lib/resources/mysql_session.rb +18 -7
  232. data/lib/resources/nginx_conf.rb +95 -0
  233. data/lib/resources/ntp_conf.rb +2 -3
  234. data/lib/resources/oracledb_session.rb +138 -0
  235. data/lib/resources/os_env.rb +7 -5
  236. data/lib/resources/package.rb +70 -13
  237. data/lib/resources/packages.rb +111 -0
  238. data/lib/resources/parse_config.rb +3 -4
  239. data/lib/resources/passwd.rb +4 -5
  240. data/lib/resources/pip.rb +29 -21
  241. data/lib/resources/port.rb +133 -14
  242. data/lib/resources/postgres.rb +53 -43
  243. data/lib/resources/postgres_conf.rb +40 -13
  244. data/lib/resources/postgres_hba_conf.rb +101 -0
  245. data/lib/resources/postgres_ident_conf.rb +79 -0
  246. data/lib/resources/postgres_session.rb +28 -20
  247. data/lib/resources/powershell.rb +2 -2
  248. data/lib/resources/processes.rb +61 -26
  249. data/lib/resources/rabbitmq_conf.rb +53 -0
  250. data/lib/resources/registry_key.rb +34 -11
  251. data/lib/resources/security_policy.rb +2 -2
  252. data/lib/resources/service.rb +17 -7
  253. data/lib/resources/ssh_conf.rb +17 -6
  254. data/lib/resources/ssl.rb +3 -4
  255. data/lib/resources/sys_info.rb +1 -1
  256. data/lib/resources/toml.rb +26 -0
  257. data/lib/resources/users.rb +41 -41
  258. data/lib/resources/virtualization.rb +252 -0
  259. data/lib/resources/windows_task.rb +106 -0
  260. data/lib/resources/x509_certificate.rb +143 -0
  261. data/lib/resources/xinetd.rb +18 -2
  262. data/lib/resources/xml.rb +27 -0
  263. data/lib/resources/yaml.rb +10 -2
  264. data/lib/resources/yum.rb +25 -7
  265. data/lib/resources/zfs_dataset.rb +60 -0
  266. data/lib/resources/zfs_pool.rb +49 -0
  267. data/lib/source_readers/flat.rb +2 -1
  268. data/lib/source_readers/inspec.rb +30 -11
  269. data/lib/utils/command_wrapper.rb +3 -3
  270. data/lib/utils/database_helpers.rb +77 -0
  271. data/lib/utils/erlang_parser.rb +192 -0
  272. data/lib/utils/filter.rb +2 -1
  273. data/lib/utils/filter_array.rb +0 -1
  274. data/lib/utils/find_files.rb +1 -2
  275. data/lib/utils/latest_version.rb +21 -0
  276. data/lib/utils/nginx_parser.rb +76 -0
  277. data/lib/utils/object_traversal.rb +5 -4
  278. data/lib/utils/parser.rb +23 -4
  279. data/lib/utils/plugin_registry.rb +3 -3
  280. data/lib/utils/simpleconfig.rb +25 -8
  281. data/lib/utils/spdx.rb +13 -0
  282. data/lib/utils/spdx.txt +344 -0
  283. metadata +168 -22
  284. data/docs/cli.md +0 -342
  285. data/docs/resources/process.md.erb +0 -73
  286. /data/docs/{plugin_kitchen_inspec.html.md → plugin_kitchen_inspec.md} +0 -0
@@ -2,7 +2,7 @@
2
2
  # copyright: 2015, Vulcano Security GmbH
3
3
  # author: Dominik Richter
4
4
  # author: Christoph Hartmann
5
- # license: All rights reserved
5
+ # author: Aaron Lippold
6
6
 
7
7
  require 'utils/simpleconfig'
8
8
  require 'utils/find_files'
@@ -19,9 +19,13 @@ module Inspec::Resources
19
19
  "
20
20
 
21
21
  include FindFiles
22
+ include ObjectTraverser
22
23
 
23
24
  def initialize(conf_path = nil)
24
25
  @conf_path = conf_path || inspec.postgres.conf_path
26
+ if @conf_path.nil?
27
+ return skip_resource 'PostgreSQL conf path is not set'
28
+ end
25
29
  @conf_dir = File.expand_path(File.dirname(@conf_path))
26
30
  @files_contents = {}
27
31
  @content = nil
@@ -42,6 +46,25 @@ module Inspec::Resources
42
46
  res
43
47
  end
44
48
 
49
+ def value(key)
50
+ extract_value(key, @params)
51
+ end
52
+
53
+ def method_missing(*keys)
54
+ keys.shift if keys.is_a?(Array) && keys[0] == :[]
55
+ param = value(keys)
56
+ return nil if param.nil?
57
+ # extract first value if we have only one value in array
58
+ return param[0] if param.length == 1
59
+ param
60
+ end
61
+
62
+ def to_s
63
+ 'PostgreSQL Configuration'
64
+ end
65
+
66
+ private
67
+
45
68
  def read_content
46
69
  @content = ''
47
70
  @params = {}
@@ -51,34 +74,42 @@ module Inspec::Resources
51
74
  return skip_resource "Can't find file \"#{@conf_path}\""
52
75
  end
53
76
  raw_conf = read_file(@conf_path)
54
- if raw_conf.empty? && inspec.file(@conf_path).size > 0
77
+ if raw_conf.empty? && !inspec.file(@conf_path).empty?
55
78
  return skip_resource("Can't read file \"#{@conf_path}\"")
56
79
  end
57
80
 
58
81
  to_read = [@conf_path]
59
82
  until to_read.empty?
83
+ base_dir = File.dirname(to_read[0])
60
84
  raw_conf = read_file(to_read[0])
61
85
  @content += raw_conf
62
86
 
63
- params = SimpleConfig.new(raw_conf).params
87
+ opts = {
88
+ assignment_regex: /^\s*([^=]*?)\s*=\s*[']?\s*(.*?)\s*[']?\s*$/,
89
+ }
90
+ params = SimpleConfig.new(raw_conf, opts).params
64
91
  @params.merge!(params)
65
92
 
66
93
  to_read = to_read.drop(1)
67
94
  # see if there is more config files to include
68
95
 
69
- to_read += include_files(params).find_all do |fp|
96
+ to_read += include_files(params, base_dir).find_all do |fp|
70
97
  not @files_contents.key? fp
71
98
  end
72
99
  end
73
100
  @content
74
101
  end
75
102
 
76
- def include_files(params)
77
- include_files = params['include'] || []
78
- include_files += params['include_if_exists'] || []
79
- dirs = params['include_dir'] || []
103
+ def include_files(params, base_dir)
104
+ include_files = Array(params['include']) || []
105
+ include_files += Array(params['include_if_exists']) || []
106
+ include_files.map! do |f|
107
+ Pathname.new(f).absolute? ? f : File.join(base_dir, f)
108
+ end
109
+
110
+ dirs = Array(params['include_dir']) || []
80
111
  dirs.each do |dir|
81
- dir = File.join(@conf_dir, dir) if dir[0] != '/'
112
+ dir = File.join(base_dir, dir) if dir[0] != '/'
82
113
  include_files += find_files(dir, depth: 1, type: 'file')
83
114
  end
84
115
  include_files
@@ -87,9 +118,5 @@ module Inspec::Resources
87
118
  def read_file(path)
88
119
  @files_contents[path] ||= inspec.file(path).content
89
120
  end
90
-
91
- def to_s
92
- 'PostgreSQL Configuration'
93
- end
94
121
  end
95
122
  end
@@ -0,0 +1,101 @@
1
+ # encoding: utf-8
2
+ # author: Rony Xavier,rx294@nyu.edu
3
+ # author: Aaron Lippold, lippold@gmail.com
4
+
5
+ require 'resources/postgres'
6
+
7
+ module Inspec::Resources
8
+ class PostgresHbaConf < Inspec.resource(1)
9
+ name 'postgres_hba_conf'
10
+ desc 'Use the `postgres_hba_conf` InSpec audit resource to test the client
11
+ authentication data defined in the pg_hba.conf file.'
12
+ example "
13
+ describe postgres_hba_conf.where { type == 'local' } do
14
+ its('auth_method') { should eq ['peer'] }
15
+ end
16
+ "
17
+
18
+ attr_reader :conf_file, :params
19
+
20
+ # @todo add checks to ensure that we have data in our file
21
+ def initialize(hba_conf_path = nil)
22
+ return skip_resource 'The `postgres_hba_conf` resource is not supported on your OS.' unless inspec.os.linux?
23
+ @conf_file = hba_conf_path || File.expand_path('pg_hba.conf', inspec.postgres.conf_dir)
24
+ @content = ''
25
+ @params = {}
26
+ read_content
27
+ end
28
+
29
+ filter = FilterTable.create
30
+ filter.add_accessor(:where)
31
+ .add_accessor(:entries)
32
+ .add(:type, field: 'type')
33
+ .add(:database, field: 'database')
34
+ .add(:user, field: 'user')
35
+ .add(:address, field: 'address')
36
+ .add(:auth_method, field: 'auth_method')
37
+ .add(:auth_params, field: 'auth_params')
38
+
39
+ filter.connect(self, :params)
40
+
41
+ def to_s
42
+ "Postgres Hba Config #{@conf_file}"
43
+ end
44
+
45
+ private
46
+
47
+ def clean_conf_file(conf_file = @conf_file)
48
+ data = inspec.file(conf_file).content.to_s.lines
49
+ content = []
50
+ data.each do |line|
51
+ line.chomp!
52
+ content << line unless line.match(/^\s*#/) || line.empty?
53
+ end
54
+ content
55
+ end
56
+
57
+ def read_content(config_file = @conf_file)
58
+ file = inspec.file(config_file)
59
+
60
+ if !file.file?
61
+ return skip_resource "Can't find file \"#{@conf_file}\""
62
+ end
63
+
64
+ raw_conf = file.content
65
+
66
+ if raw_conf.empty? && !file.empty?
67
+ return skip_resource("Can't read the contents of \"#{@conf_file}\"")
68
+ end
69
+
70
+ # @todo use SimpleConfig here if we can
71
+ # ^\s*(\S+)\s+(\S+)\s+(\S+)\s(?:(\d*.\d*.\d*.\d*\/\d*)|(::\/\d+))\s+(\S+)\s*(.*)?\s*$
72
+
73
+ @content = clean_conf_file(@conf_file)
74
+ @params = parse_conf(@content)
75
+ @params.each do |line|
76
+ if line['type'] == 'local'
77
+ line['auth_method'] = line['address']
78
+ line['address'] = ''
79
+ end
80
+ end
81
+ end
82
+
83
+ def parse_conf(content)
84
+ content.map do |line|
85
+ parse_line(line)
86
+ end.compact
87
+ end
88
+
89
+ def parse_line(line)
90
+ x = line.split(/\s+/)
91
+ {
92
+ 'type' => x[0],
93
+ 'database' => x[1],
94
+ 'user' => x[2],
95
+ 'address' => x[3],
96
+ 'auth_method' => x[4],
97
+ 'auth_params' => ('' if x.length == 4) || x[5..-1].join(' '),
98
+ }
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+ # author: Rony Xavier, rx294@nyu.edu
3
+ # author: Aaron Lippold, lippold@gmail.com
4
+
5
+ require 'resources/postgres'
6
+
7
+ module Inspec::Resources
8
+ class PostgresIdentConf < Inspec.resource(1)
9
+ name 'postgres_ident_conf'
10
+ desc 'Use the postgres_ident_conf InSpec audit resource to test the client
11
+ authentication data is controlled by a pg_ident.conf file.'
12
+ example "
13
+ describe postgres_ident_conf.where { pg_username == 'acme_user' } do
14
+ its('map_name') { should eq ['ssl-test'] }
15
+ end
16
+ "
17
+
18
+ attr_reader :params, :conf_file
19
+
20
+ def initialize(ident_conf_path = nil)
21
+ return skip_resource 'The `postgres_ident_conf` resource is not supported on your OS.' unless inspec.os.linux?
22
+ @conf_file = ident_conf_path || File.expand_path('pg_ident.conf', inspec.postgres.conf_dir)
23
+ @content = nil
24
+ @params = nil
25
+ read_content
26
+ return skip_resource '`pg_ident_conf` is not yet supported on your OS' if inspec.os.windows?
27
+ end
28
+
29
+ filter = FilterTable.create
30
+ filter.add_accessor(:where)
31
+ .add_accessor(:entries)
32
+ .add(:map_name, field: 'map_name')
33
+ .add(:system_username, field: 'system_username')
34
+ .add(:pg_username, field: 'pg_username')
35
+
36
+ filter.connect(self, :params)
37
+
38
+ def to_s
39
+ "PostgreSQL Ident Config #{@conf_file}"
40
+ end
41
+
42
+ private
43
+
44
+ def filter_comments(data)
45
+ content = []
46
+ data.each do |line|
47
+ line.chomp!
48
+ content << line unless line.match(/^\s*#/) || line.empty?
49
+ end
50
+ content
51
+ end
52
+
53
+ def read_content
54
+ @content = ''
55
+ @params = {}
56
+ @content = filter_comments(read_file(@conf_file))
57
+ @params = parse_conf(@content)
58
+ end
59
+
60
+ def parse_conf(content)
61
+ content.map do |line|
62
+ parse_line(line)
63
+ end.compact
64
+ end
65
+
66
+ def parse_line(line)
67
+ x = line.split(/\s+/)
68
+ {
69
+ 'map_name' => x[0],
70
+ 'system_username' => x[1],
71
+ 'pg_username' => x[2],
72
+ }
73
+ end
74
+
75
+ def read_file(conf_file = @conf_file)
76
+ inspec.file(conf_file).content.lines
77
+ end
78
+ end
79
+ end
@@ -2,7 +2,9 @@
2
2
  # copyright: 2015, Vulcano Security GmbH
3
3
  # author: Dominik Richter
4
4
  # author: Christoph Hartmann
5
- # license: All rights reserved
5
+ # author: Aaron Lippold
6
+
7
+ require 'shellwords'
6
8
 
7
9
  module Inspec::Resources
8
10
  class Lines
@@ -26,39 +28,45 @@ module Inspec::Resources
26
28
  name 'postgres_session'
27
29
  desc 'Use the postgres_session InSpec audit resource to test SQL commands run against a PostgreSQL database.'
28
30
  example "
29
- sql = postgres_session('username', 'password')
31
+ sql = postgres_session('username', 'password', 'host')
32
+ query('sql_query', ['database_name'])` contains the query and (optional) database to execute
33
+
34
+ # default values:
35
+ # username: 'postgres'
36
+ # host: 'localhost'
37
+ # db: databse == db_user running the sql query
30
38
 
31
39
  describe sql.query('SELECT * FROM pg_shadow WHERE passwd IS NULL;') do
32
- its('output') { should eq('') }
40
+ its('output') { should eq '' }
33
41
  end
34
42
  "
35
43
 
36
- def initialize(user, pass)
44
+ def initialize(user, pass, host = nil)
37
45
  @user = user || 'postgres'
38
46
  @pass = pass
47
+ @host = host || 'localhost'
39
48
  end
40
49
 
41
50
  def query(query, db = [])
42
- dbs = db.map { |x| "-d #{x}" }.join(' ')
43
- # TODO: simple escape, must be handled by a library
44
- # that does this securely
45
- escaped_query = query.gsub(/\\/, '\\\\').gsub(/"/, '\\"').gsub(/\$/, '\\$')
46
- # run the query
47
- cmd = inspec.command("PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h localhost -c \"#{escaped_query}\"")
51
+ psql_cmd = create_psql_cmd(query, db)
52
+ cmd = inspec.command(psql_cmd)
48
53
  out = cmd.stdout + "\n" + cmd.stderr
49
- if cmd.exit_status != 0 or
50
- out =~ /could not connect to .*/ or
51
- out.downcase =~ /^error/
52
- # skip this test if the server can't run the query
54
+ if cmd.exit_status != 0 || out =~ /could not connect to .*/ || out.downcase =~ /^error:.*/
53
55
  skip_resource "Can't read run query #{query.inspect} on postgres_session: #{out}"
54
56
  else
55
- # remove the whole header (i.e. up to the first ^-----+------+------$)
56
- # remove the tail
57
- lines = cmd.stdout
58
- .sub(/(.*\n)+([-]+[+])*[-]+\n/, '')
59
- .sub(/\n[^\n]*\n\n$/, '')
60
- Lines.new(lines.strip, "PostgreSQL query: #{query}")
57
+ Lines.new(cmd.stdout.strip, "PostgreSQL query: #{query}")
61
58
  end
62
59
  end
60
+
61
+ private
62
+
63
+ def escaped_query(query)
64
+ Shellwords.escape(query)
65
+ end
66
+
67
+ def create_psql_cmd(query, db = [])
68
+ dbs = db.map { |x| "-d #{x}" }.join(' ')
69
+ "PGPASSWORD='#{@pass}' psql -U #{@user} #{dbs} -h #{@host} -A -t -c #{escaped_query(query)}"
70
+ end
63
71
  end
64
72
  end
@@ -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
  module Inspec::Resources
8
7
  class PowershellScript < Cmd
@@ -10,7 +9,7 @@ module Inspec::Resources
10
9
  desc 'Use the powershell InSpec audit resource to test a Windows PowerShell script on the Microsoft Windows platform.'
11
10
  example "
12
11
  script = <<-EOH
13
- # you powershell script
12
+ # your powershell script
14
13
  EOH
15
14
 
16
15
  describe powershell(script) do
@@ -20,6 +19,7 @@ module Inspec::Resources
20
19
 
21
20
  def initialize(script)
22
21
  unless inspec.os.windows?
22
+ super('')
23
23
  return skip_resource 'The `script` resource is not supported on your OS yet.'
24
24
  end
25
25
  # since WinRM 2.0 and the default use of powershell for local execution in
@@ -2,7 +2,8 @@
2
2
  # copyright: 2015, Vulcano Security GmbH
3
3
  # author: Dominik Richter
4
4
  # author: Christoph Hartmann
5
- # license: All rights reserved
5
+
6
+ require 'utils/filter'
6
7
 
7
8
  module Inspec::Resources
8
9
  class Processes < Inspec.resource(1)
@@ -10,72 +11,106 @@ module Inspec::Resources
10
11
  desc 'Use the processes InSpec audit resource to test properties for programs that are running on the system.'
11
12
  example "
12
13
  describe processes('mysqld') do
13
- its('list.length') { should eq 1 }
14
+ its('entries.length') { should eq 1 }
14
15
  its('users') { should eq ['mysql'] }
15
16
  its('states') { should include 'S' }
16
17
  end
18
+ describe processes(/.+/).where { label != 'unconfined' && pid < 1000 } do
19
+ its('users') { should cmp [] }
20
+ end
17
21
  "
18
22
 
19
- attr_reader :list,
20
- :users,
21
- :states
22
-
23
23
  def initialize(grep)
24
+ @grep = grep
24
25
  # turn into a regexp if it isn't one yet
25
26
  if grep.class == String
26
- grep = '(/[^/]*)*'+grep if grep[0] != '/'
27
- grep = Regexp.new('^' + grep + '(\s|$)')
27
+ # if windows ignore case as we can't make up our minds
28
+ if inspec.os.windows?
29
+ grep = '(?i)' + grep
30
+ else
31
+ grep = '(/[^/]*)*' + grep unless grep[0] == '/'
32
+ grep = '^' + grep + '(\s|$)'
33
+ end
34
+ grep = Regexp.new(grep)
28
35
  end
29
- all_cmds = ps_aux
36
+
37
+ all_cmds = ps_axo
30
38
  @list = all_cmds.find_all do |hm|
31
39
  hm[:command] =~ grep
32
40
  end
41
+ end
33
42
 
34
- { users: :user,
35
- states: :stat }.each do |var, key|
36
- instance_variable_set("@#{var}", @list.map { |l| l[key] }.uniq)
37
- end
43
+ def exists?
44
+ !@list.empty?
38
45
  end
39
46
 
40
47
  def to_s
41
- 'Processes'
48
+ "Processes #{@grep.class == String ? @grep : @grep.inspect}"
42
49
  end
43
50
 
51
+ def list
52
+ warn '[DEPRECATION] `processes.list` is deprecated. Please use `processes.entries` instead. It will be removed in version 2.0.0.'
53
+ @list
54
+ end
55
+
56
+ filter = FilterTable.create
57
+ filter.add_accessor(:where)
58
+ .add_accessor(:entries)
59
+ .add(:labels, field: 'label')
60
+ .add(:pids, field: 'pid')
61
+ .add(:cpus, field: 'cpu')
62
+ .add(:mem, field: 'mem')
63
+ .add(:vsz, field: 'vsz')
64
+ .add(:rss, field: 'rss')
65
+ .add(:tty, field: 'tty')
66
+ .add(:states, field: 'stat')
67
+ .add(:start, field: 'start')
68
+ .add(:time, field: 'time')
69
+ .add(:users, field: 'user')
70
+ .add(:commands, field: 'command')
71
+ .connect(self, :filtered_processes)
72
+
44
73
  private
45
74
 
46
- def ps_aux
75
+ def filtered_processes
76
+ @list
77
+ end
78
+
79
+ def ps_axo
47
80
  os = inspec.os
48
81
 
49
82
  if os.linux?
50
- command = 'ps auxZ'
51
- regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
83
+ command = 'ps axo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command'
84
+ regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
85
+ elsif os.windows?
86
+ command = '$Proc = Get-Process -IncludeUserName | Where-Object {$_.Path -ne $null } | Select-Object PriorityClass,Id,CPU,PM,VirtualMemorySize,NPM,SessionId,Responding,StartTime,TotalProcessorTime,UserName,Path | ConvertTo-Csv -NoTypeInformation;$Proc.Replace("""","").Replace("`r`n","`n")'
87
+ # Wanted to use /(?:^|,)([^,]*)/; works on rubular.com not sure why here?
88
+ regex = /^(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+)$/
52
89
  else
53
- command = 'ps aux'
54
- regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
90
+ command = 'ps axo pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user,command'
91
+ regex = /^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
55
92
  end
56
93
  build_process_list(command, regex, os)
57
94
  end
58
95
 
59
- Process = Struct.new(:label, :user, :pid,
96
+ Process = Struct.new(:label, :pid,
60
97
  :cpu, :mem, :vsz,
61
98
  :rss, :tty, :stat,
62
- :start, :time, :command)
99
+ :start, :time, :user, :command)
63
100
 
64
101
  def build_process_list(command, regex, os)
65
102
  cmd = inspec.command(command)
66
103
  all = cmd.stdout.split("\n")[1..-1]
67
104
  return [] if all.nil?
68
-
69
105
  lines = all.map do |line|
70
106
  line.match(regex)
71
107
  end.compact
72
-
73
108
  lines.map do |m|
74
109
  a = m.to_a[1..-1] # grab all matching groups
75
- a.unshift(nil) unless os.linux?
76
- a[2] = a[2].to_i
110
+ a.unshift(nil) unless os.linux? || os.windows?
111
+ a[1] = a[1].to_i
112
+ a[4] = a[4].to_i
77
113
  a[5] = a[5].to_i
78
- a[6] = a[6].to_i
79
114
  Process.new(*a)
80
115
  end
81
116
  end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ # author: Dominik Richter
3
+ # author: Christoph Hartmann
4
+
5
+ require 'utils/erlang_parser'
6
+
7
+ module Inspec::Resources
8
+ class RabbitmqConf < Inspec.resource(1)
9
+ name 'rabbitmq_config'
10
+ desc 'Use the rabbitmq_config InSpec resource to test configuration data '\
11
+ 'for the RabbitMQ service located in /etc/rabbitmq/rabbitmq.config on '\
12
+ 'Linux and UNIX platforms.'
13
+ example "
14
+ describe rabbitmq_config.params('rabbit', 'ssl_listeners') do
15
+ it { should cmp 5671 }
16
+ end
17
+ "
18
+
19
+ def initialize(conf_path = nil)
20
+ @conf_path = conf_path || '/etc/rabbitmq/rabbitmq.config'
21
+ end
22
+
23
+ def params(*opts)
24
+ opts.inject(read_params) do |res, nxt|
25
+ res.respond_to?(:key) ? res[nxt] : nil
26
+ end
27
+ end
28
+
29
+ def to_s
30
+ "rabbitmq_config #{@conf_path}"
31
+ end
32
+
33
+ private
34
+
35
+ def read_content
36
+ return @content if defined?(@content)
37
+ file = inspec.file(@conf_path)
38
+ if !file.file?
39
+ return skip_resource "Can't find file \"#{@conf_path}\""
40
+ end
41
+
42
+ @content = file.content
43
+ end
44
+
45
+ def read_params
46
+ return @params if defined?(@params)
47
+ return @params = {} if read_content.nil?
48
+ @params = ErlangConfigFile.parse(read_content)
49
+ rescue Parslet::ParseFailed
50
+ raise "Cannot parse RabbitMQ config: \"#{read_content}\""
51
+ end
52
+ end
53
+ end
@@ -1,7 +1,6 @@
1
1
  # encoding: utf-8
2
2
  # copyright: 2015, Vulcano Security GmbH
3
3
  # author: Christoph Hartmann
4
- # license: All rights reserved
5
4
 
6
5
  require 'json'
7
6
 
@@ -20,7 +19,7 @@ require 'json'
20
19
  # describe registry_key({
21
20
  # name: 'Task Scheduler',
22
21
  # hive: 'HKEY_LOCAL_MACHINE',
23
- # key: ''\SYSTEM\CurrentControlSet\services\Schedule'
22
+ # key: '\SYSTEM\CurrentControlSet\services\Schedule'
24
23
  # }) do
25
24
  # its('Start') { should eq 2 }
26
25
  # end
@@ -63,15 +62,15 @@ module Inspec::Resources
63
62
  @options = {}
64
63
  if reg_key && reg_key.is_a?(Hash)
65
64
  @options = @options.merge!(reg_key)
65
+
66
66
  # generate registry_key if we do not have a regular expression
67
- @options[:path] = @options[:hive]
68
- # add optional key path
69
- @options[:path] += '\\' + @options[:key] if @options[:key]
67
+ @options[:path] = generate_registry_key_path_from_options
70
68
  @options[:name] ||= @options[:path]
71
69
  else
72
70
  @options[:name] = name
73
71
  @options[:path] = reg_key
74
72
  end
73
+
75
74
  return skip_resource 'The `registry_key` resource is not supported on your OS yet.' if !inspec.os.windows?
76
75
  end
77
76
 
@@ -147,6 +146,11 @@ module Inspec::Resources
147
146
  script = <<-EOH
148
147
  Function InSpec-GetRegistryKey($path) {
149
148
  $reg = Get-Item ('Registry::' + $path)
149
+ if ($reg -eq $null) {
150
+ Write-Error "InSpec: Failed to find registry key"
151
+ exit 1001
152
+ }
153
+
150
154
  $properties = New-Object -Type PSObject
151
155
  $reg.Property | ForEach-Object {
152
156
  $key = $_
@@ -160,18 +164,23 @@ module Inspec::Resources
160
164
  $properties
161
165
  }
162
166
  $path = '#{path}'
163
- InSpec-GetRegistryKey($path) | ConvertTo-Json
167
+ InSpec-GetRegistryKey($path) | ConvertTo-Json -Compress
164
168
  EOH
165
169
 
166
170
  cmd = inspec.powershell(script)
167
171
  # cannot rely on exit code for now, successful command returns exit code 1
168
172
  # return nil if cmd.exit_status != 0, try to parse json
169
173
  begin
170
- @registry_cache = JSON.parse(cmd.stdout)
171
- # convert keys to lower case
172
- @registry_cache = Hash[@registry_cache.map do |key, value|
173
- [key.downcase, value]
174
- end]
174
+ if cmd.exit_status == 1001 && cmd.stderr =~ /InSpec: Failed to find registry key/
175
+ # TODO: provide the stderr output
176
+ @registry_cache = nil
177
+ else
178
+ @registry_cache = JSON.parse(cmd.stdout)
179
+ # convert keys to lower case
180
+ @registry_cache = Hash[@registry_cache.map do |key, value|
181
+ [key.downcase, value]
182
+ end]
183
+ end
175
184
  rescue JSON::ParserError => _e
176
185
  @registry_cache = nil
177
186
  end
@@ -245,6 +254,20 @@ module Inspec::Resources
245
254
 
246
255
  options[symbol]
247
256
  end
257
+
258
+ def generate_registry_key_path_from_options
259
+ path = @options[:hive]
260
+ path += format_key_from_options
261
+
262
+ path
263
+ end
264
+
265
+ def format_key_from_options
266
+ key = @options[:key]
267
+ return '' unless key
268
+
269
+ key.start_with?('\\') ? key : "\\#{key}"
270
+ end
248
271
  end
249
272
 
250
273
  # for compatability with serverspec