mirror of
https://github.com/inspec/inspec
synced 2025-02-17 06:28:40 +00:00
Added windows support to the processes resource
Signed-off-by: username-is-already-taken2 <digitalgaz@hotmail.com>
This commit is contained in:
parent
75728f786c
commit
9d9baeb09f
5 changed files with 90 additions and 12 deletions
|
@ -60,18 +60,33 @@ The following examples show how to use this InSpec audit resource.
|
||||||
its('list.length') { should eq 1 }
|
its('list.length') { should eq 1 }
|
||||||
end
|
end
|
||||||
|
|
||||||
### Test if the init process is owned by the root user
|
### Test if the process is owned by a specifc user
|
||||||
|
|
||||||
describe processes('init') do
|
describe processes('init') do
|
||||||
its('users') { should eq ['root'] }
|
its('users') { should eq ['root'] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe processes('winlogon') do
|
||||||
|
its('users') { should cmp "NT AUTHORITY\\SYSTEM" }
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
### Test if a high-priority process is running
|
### Test if a high-priority process is running
|
||||||
|
|
||||||
describe processes('some_process') do
|
describe processes('linux_process') do
|
||||||
its('states') { should eq ['R<'] }
|
its('states') { should eq ['R<'] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe processes('windows_process') do
|
||||||
|
its('labels') { should cmp "High" }
|
||||||
|
end
|
||||||
|
|
||||||
|
### Test if a process exists on the system
|
||||||
|
|
||||||
|
describe processes('some_process') do
|
||||||
|
it { should exist }
|
||||||
|
end
|
||||||
|
|
||||||
### Test for a process using a specific Regexp
|
### Test for a process using a specific Regexp
|
||||||
|
|
||||||
If the process name is too common for a string to uniquely find it,
|
If the process name is too common for a string to uniquely find it,
|
||||||
|
@ -81,3 +96,28 @@ needed.
|
||||||
describe processes(Regexp.new("/usr/local/bin/swap -d")) do
|
describe processes(Regexp.new("/usr/local/bin/swap -d")) do
|
||||||
its('list.length') { should eq 1 }
|
its('list.length') { should eq 1 }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
### Notes for auditing Windows systems
|
||||||
|
|
||||||
|
Sometimes with system properties there isn't a direct comparison between different operating systems.
|
||||||
|
Most of the `property_name`'s do align between the different OS's.
|
||||||
|
|
||||||
|
There are however some exception's, for example, within linux `states` offers multiple properties.
|
||||||
|
Windows doesn't have direct comparison that is a single property so instead `states` is mapped to the property of `Responding`, This is a boolean true/false flag to help determine if the process is hung.
|
||||||
|
|
||||||
|
Below is a mapping table to help you understand what property the unix field maps to the windows `Get-Process` Property
|
||||||
|
|
||||||
|
| *unix ps field* | *windows PowerShell Property* |
|
||||||
|
|:---------------:|:-----------------------------:|
|
||||||
|
|labels |PriorityClass|
|
||||||
|
|pids |Id|
|
||||||
|
|cpus |CPU|
|
||||||
|
|mem |PM|
|
||||||
|
|vsz |VirtualMemorySize|
|
||||||
|
|rss |NPM|
|
||||||
|
|tty |SessionId|
|
||||||
|
|states |Responding|
|
||||||
|
|start |StartTime|
|
||||||
|
|time |TotalProcessorTime|
|
||||||
|
|users |UserName|
|
||||||
|
|commands |Path|
|
||||||
|
|
|
@ -25,15 +25,24 @@ module Inspec::Resources
|
||||||
@grep = grep
|
@grep = grep
|
||||||
# turn into a regexp if it isn't one yet
|
# turn into a regexp if it isn't one yet
|
||||||
if grep.class == String
|
if grep.class == String
|
||||||
grep = '(/[^/]*)*' + grep if grep[0] != '/'
|
# if windows ignore case as we can't make up our minds
|
||||||
grep = Regexp.new('^' + grep + '(\s|$)')
|
if inspec.os.windows?
|
||||||
|
grep = '(?i)' + grep
|
||||||
|
else
|
||||||
|
grep = '(/[^/]*)*' + grep unless grep[0] == '/'
|
||||||
|
grep = '^' + grep + '(\s|$)'
|
||||||
|
end
|
||||||
|
grep = Regexp.new(grep)
|
||||||
end
|
end
|
||||||
|
|
||||||
all_cmds = ps_axo
|
all_cmds = ps_axo
|
||||||
@list = all_cmds.find_all do |hm|
|
@list = all_cmds.find_all do |hm|
|
||||||
hm[:command] =~ grep
|
hm[:command] =~ grep
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return skip_resource 'The `processes` resource is not supported on your OS yet.' if inspec.os.windows?
|
def exists?
|
||||||
|
!@list.empty?
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
|
@ -74,6 +83,10 @@ module Inspec::Resources
|
||||||
if os.linux?
|
if os.linux?
|
||||||
command = 'ps axo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command'
|
command = 'ps axo label,pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user:32,command'
|
||||||
regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
regex = /^([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(\w{3} \d{2}|\d{2}:\d{2}:\d{2})\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
||||||
|
elsif os.windows?
|
||||||
|
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")'
|
||||||
|
# Wanted to use /(?:^|,)([^,]*)/; works on rubular.com not sure why here?
|
||||||
|
regex = /^(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+),(.+)$/
|
||||||
else
|
else
|
||||||
command = 'ps axo pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user,command'
|
command = 'ps axo pid,pcpu,pmem,vsz,rss,tty,stat,start,time,user,command'
|
||||||
regex = /^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
regex = /^\s*([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+(.*)$/
|
||||||
|
@ -95,7 +108,7 @@ module Inspec::Resources
|
||||||
end.compact
|
end.compact
|
||||||
lines.map do |m|
|
lines.map do |m|
|
||||||
a = m.to_a[1..-1] # grab all matching groups
|
a = m.to_a[1..-1] # grab all matching groups
|
||||||
a.unshift(nil) unless os.linux?
|
a.unshift(nil) unless os.linux? || os.windows?
|
||||||
a[1] = a[1].to_i
|
a[1] = a[1].to_i
|
||||||
a[4] = a[4].to_i
|
a[4] = a[4].to_i
|
||||||
a[5] = a[5].to_i
|
a[5] = a[5].to_i
|
||||||
|
|
|
@ -303,10 +303,10 @@ class MockLoader
|
||||||
'crontab -l' => cmd.call('crontab-root'),
|
'crontab -l' => cmd.call('crontab-root'),
|
||||||
# crontab display for non-current user
|
# crontab display for non-current user
|
||||||
'crontab -l -u foouser' => cmd.call('crontab-foouser'),
|
'crontab -l -u foouser' => cmd.call('crontab-foouser'),
|
||||||
# zfs output for dataset tank/tmp
|
# zfs output for dataset tank/tmp
|
||||||
'/sbin/zfs get -Hp all tank/tmp' => cmd.call('zfs-get-all-tank-tmp'),
|
'/sbin/zfs get -Hp all tank/tmp' => cmd.call('zfs-get-all-tank-tmp'),
|
||||||
# zfs output for pool tank
|
# zfs output for pool tank
|
||||||
'/sbin/zpool get -Hp all tank' => cmd.call('zpool-get-all-tank'),
|
'/sbin/zpool get -Hp all tank' => cmd.call('zpool-get-all-tank'),
|
||||||
# docker
|
# docker
|
||||||
"docker ps -a --no-trunc --format '{{ json . }}'" => cmd.call('docker-ps-a'),
|
"docker ps -a --no-trunc --format '{{ json . }}'" => cmd.call('docker-ps-a'),
|
||||||
"docker version --format '{{ json . }}'" => cmd.call('docker-version'),
|
"docker version --format '{{ json . }}'" => cmd.call('docker-version'),
|
||||||
|
@ -314,8 +314,9 @@ class MockLoader
|
||||||
"docker inspect 71b5df59442b" => cmd.call('docker-inspec'),
|
"docker inspect 71b5df59442b" => cmd.call('docker-inspec'),
|
||||||
# docker images
|
# docker images
|
||||||
"83c36bfade9375ae1feb91023cd1f7409b786fd992ad4013bf0f2259d33d6406" => cmd.call('docker-images'),
|
"83c36bfade9375ae1feb91023cd1f7409b786fd992ad4013bf0f2259d33d6406" => cmd.call('docker-images'),
|
||||||
}
|
# get-process cmdlet for processes resource
|
||||||
|
'$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")' => cmd.call('get-process_processes')
|
||||||
|
}
|
||||||
@backend
|
@backend
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
3
test/unit/mock/cmd/get-process_processes
Normal file
3
test/unit/mock/cmd/get-process_processes
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
PriorityClass,Id,CPU,PM,VirtualMemorySize,NPM,SessionId,Responding,StartTime,TotalProcessorTime,UserName,Path
|
||||||
|
Normal,2456,0.296875,4808704,118202368,14576,1,True,5/31/2017 9:13:17 AM,00:00:00.2968750,WINVAGR-QQQNHPN\Administrator,C:\Windows\system32\mmc.exe
|
||||||
|
High,396,0.15625,1323008,53710848,7776,1,True,5/31/2017 9:12:56 AM,00:00:00.1562500,NT AUTHORITY\SYSTEM,C:\Windows\system32\winlogon.exe
|
|
@ -109,6 +109,7 @@ describe 'Inspec::Resources::Processes' do
|
||||||
resource = MockLoader.new(:centos6).load_resource('processes', 'postgres: bifrost bifrost')
|
resource = MockLoader.new(:centos6).load_resource('processes', 'postgres: bifrost bifrost')
|
||||||
_(resource.users.sort).must_equal ['opscode-pgsql']
|
_(resource.users.sort).must_equal ['opscode-pgsql']
|
||||||
_(resource.states.sort).must_equal ['Ss']
|
_(resource.states.sort).must_equal ['Ss']
|
||||||
|
_(resource.exists?).must_equal true
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'command name matches with output (string)' do
|
it 'command name matches with output (string)' do
|
||||||
|
@ -120,4 +121,24 @@ describe 'Inspec::Resources::Processes' do
|
||||||
resource = MockLoader.new(:centos6).load_resource('processes', /mysqld/)
|
resource = MockLoader.new(:centos6).load_resource('processes', /mysqld/)
|
||||||
_(resource.to_s).must_equal 'Processes /mysqld/'
|
_(resource.to_s).must_equal 'Processes /mysqld/'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'command name matches with output (string)' do
|
||||||
|
resource = MockLoader.new(:windows).load_resource('processes', 'winlogon.exe')
|
||||||
|
_(resource.to_s).must_equal 'Processes winlogon.exe'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'retrieves the users and states as arrays on windows os' do
|
||||||
|
resource = MockLoader.new(:windows).load_resource('processes', 'winlogon.exe')
|
||||||
|
_(resource.users.sort).must_equal ['NT AUTHORITY\\SYSTEM']
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'process should exist' do
|
||||||
|
resource = MockLoader.new(:windows).load_resource('processes', 'winlogon.exe')
|
||||||
|
_(resource.exists?).must_equal true
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'process should_not exist' do
|
||||||
|
resource = MockLoader.new(:windows).load_resource('processes', 'unicorn.exe')
|
||||||
|
_(resource.exists?).must_equal false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Add table
Reference in a new issue