Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add OSX support #7

Merged
merged 1 commit into from Jan 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions README.md
Expand Up @@ -54,17 +54,20 @@ In this example, all Linux nodes will scan the `/opt` and `/usr` directories, wh
and all Windows nodes will scan `C:` and skip the Windows temp directory. It will scan Linux nodes every day
at 12:30 PM, and Windows nodes every other day.

Note that when using the class with OSX, you'll want to use the `osx_directories` and `osx_skip` parameters,
and you'll likely need to change the `scan_data_group` to `admin` rather than `root`.

### Task
Run a basic scan from the command line:
```bash
puppet task run log4jscanner::run_scan --nodes <nodes> directories=/opt,/var skip=/opt/puppetlabs
```

Note that for OSX, you'll want to run the `log4jscanner::run_scan_osx` task.
## Reference
### Manifest Parameters
- ensure: Set to 'absent' to remove artifacts (cron/scheduled tasks, files) from nodes. (default 'present')
- linux_directories: Array of directories to scan on Linux nodes. (default \['/'\])
- linux_skip: Array of glob patterns to skip scanning on Linux nodes. (default \['/proc','/sys'\])
- linux_skip: Array of glob patterns to skip scanning on Linux nodes. (default \['/proc','/sys','/tmp'\])
- scan_data_owner: User to own log4jscanner files. (default 'root')
- scan_data_group: Group to own log4jscanner files. (default 'root')
- cron_user: User to run the cron job for scanning. (default 'root')
Expand All @@ -76,6 +79,8 @@ puppet task run log4jscanner::run_scan --nodes <nodes> directories=/opt,/var ski
- windows_directories: Array of directories to scan on Windows nodes. (default \['C:'\])
- windows_skip: Array of glob patterns to skip scanning on Windows nodes. (default \["C:\\Windows\\Temp"\])
- scheduled_task_every: Run the scheduled task every X days. (default 1)
- osx_directories: Array of directories to scan on OSX nodes (default \['/'\])
- osx_skip: Array of glob patterns to skip scanning on OSX nodes (default \['/tmp', '/Users/osx', '/dev', '/private/var/db', '/private/var/folders', '/System/Volumes/Data/private/var/db', '/System/Volumes/Data/private/var/folders'\])

### Task Parameters
- directories: Comma-separated list of directories to search for vulnerable log4j jars
Expand Down
4 changes: 2 additions & 2 deletions lib/facter/log4jscanner.rb
@@ -1,13 +1,13 @@
Facter.add('log4jscanner') do
confine { ['Linux', 'windows'].include?(Facter.value(:kernel)) }
confine { ['Linux', 'Darwin', 'windows'].include?(Facter.value(:kernel)) }
setcode do
errors = []
warnings = {}
last_runtime = ''
data = {}

cache_dir = case Facter.value(:kernel)
when 'Linux'
when 'Linux', 'Darwin'
'/opt/puppetlabs/log4jscanner'
when 'windows'
'C:\ProgramData\PuppetLabs\log4jscanner'
Expand Down
54 changes: 50 additions & 4 deletions manifests/init.pp
Expand Up @@ -20,10 +20,14 @@
# Which directories to skip on Windows nodes
# @param scheduled_task_every
# How often the task should run, as a number of days
# @param osx_directories
# Which directories to scan on OSX nodes
# @param osx_skip
# Which directories to skip on OSX nodes
class log4jscanner (
Enum['present', 'absent'] $ensure = 'present',
Array[String] $linux_directories = ['/'],
Array[String] $linux_skip = ['/proc','/sys'],
Array[String] $linux_skip = ['/proc', '/sys', '/tmp'],
String $scan_data_owner = 'root',
String $scan_data_group = 'root',
String $cron_user = 'root',
Expand All @@ -35,6 +39,8 @@
Array[String] $windows_directories = ['C:'],
Array[String] $windows_skip = ['C:\Windows\Temp'],
Integer $scheduled_task_every = 1,
Array[String] $osx_directories = ['/'],
Array[String] $osx_skip = ['/tmp', '/Users/osx', '/dev', '/private/var/db', '/private/var/folders', '/System/Volumes/Data/private/var/db', '/System/Volumes/Data/private/var/folders'],
) {

# Run things/set up files, or clean up when ensure=>absent?
Expand Down Expand Up @@ -67,9 +73,9 @@
case $facts['kernel'] {
'Linux': {
$fact_upload_cmd = "/opt/puppetlabs/bin/puppet facts upload --environment ${environment}"
$cache_dir = '/opt/puppetlabs/log4jscanner'
$scan_script = 'scan_data_generation.sh'
$scan_script_mode = '0700'
$cache_dir = '/opt/puppetlabs/log4jscanner'
$scan_script = 'scan_data_generation.sh'
$scan_script_mode = '0700'
File {
owner => $scan_data_owner,
group => $scan_data_group,
Expand Down Expand Up @@ -104,6 +110,45 @@
require => File[$scan_cmd],
}
}
'Darwin': {
$fact_upload_cmd = "/opt/puppetlabs/bin/puppet facts upload --environment ${environment}"
$cache_dir = '/opt/puppetlabs/log4jscanner'
$scan_script = 'scan_data_generation.sh'
$scan_script_mode = '0700'
File {
owner => $scan_data_owner,
group => $scan_data_group,
mode => '0644',
}
$dirs = $osx_directories
$skip_dirs = $osx_skip
$scan_bin = 'log4jscanner_osx'
$checksum = 'b81bb538179909213aea0ae414492dd4a5f05e4a243b55894d8507dffcb9d23a'
$scan_cmd = "${cache_dir}/${scan_script}"

if $generate_scan_data_exec {
exec { $generate_scan_data_exec:
command => $scan_cmd,
user => $scan_data_owner,
group => $scan_data_group,
refreshonly => true,
require => File[$scan_cmd],
timeout => 0,
}
}

cron { 'Log4jscanner - Cache scan data':
ensure => $ensure,
command => $scan_cmd,
user => $cron_user,
hour => $cron_hour,
minute => $cron_minute,
month => $cron_month,
monthday => $cron_monthday,
weekday => $cron_weekday,
require => File[$scan_cmd],
}
}
'windows': {
$fact_upload_cmd = "\"${windows_puppet_install_path}\\bin\\puppet.bat\" facts upload --environment ${environment}"
$cache_dir = 'C:/ProgramData/PuppetLabs/log4jscanner'
Expand Down Expand Up @@ -160,6 +205,7 @@
'skip' => $skip_dirs,
'cache_dir' => $cache_dir,
'fact_upload_cmd' => $fact_upload_cmd,
'scan_bin' => $scan_bin,
}
file { $scan_cmd:
ensure => $ensure_file,
Expand Down
9 changes: 9 additions & 0 deletions metadata.json
Expand Up @@ -97,6 +97,15 @@
"2019",
"10"
]
},
{
"operatingsystem": "OSX",
"operatingsystemrelease": [
"10.13",
"10.14",
"10.15",
"11"
]
}
],
"requirements": [
Expand Down
43 changes: 36 additions & 7 deletions spec/classes/log4jscanner_spec.rb
@@ -1,12 +1,9 @@
require 'spec_helper'
describe 'log4jscanner' do
# I don't think rspec-puppet-facts supports OSX, but the code is here
# in case that gets added at some point.
on_supported_os.each do |os, os_facts|
context "on #{os}" do
let(:facts) { os_facts }
let(:environment) { 'production' }
let(:params) { { 'cron_minute' => 11 } }
let(:scan_cmd) { "#{cache_dir}/#{scan_script}" }

case os_facts[:kernel]
when 'Linux'
let(:fact_upload_cmd) { '/opt/puppetlabs/bin/puppet facts upload --environment production' }
Expand All @@ -16,6 +13,14 @@
let(:scan_bin) { 'log4jscanner_nix' }
let(:checksum) { '1e8d28e53cde54b3b81c66401afd4485adfecdf6cbaf622ff0324fe2b3a1649b' }
let(:default_script_regex) { %r{CACHEDIR=#{cache_dir}} }
when 'Darwin'
let(:fact_upload_cmd) { '/opt/puppetlabs/bin/puppet facts upload --environment production' }
let(:cache_dir) { '/opt/puppetlabs/log4jscanner' }
let(:scan_script) { 'scan_data_generation.sh' }
let(:scan_script_mode) { '0700' }
let(:scan_bin) { 'log4jscanner_osx' }
let(:checksum) { 'b81bb538179909213aea0ae414492dd4a5f05e4a243b55894d8507dffcb9d23a' }
let(:default_script_regex) { %r{CACHEDIR=#{cache_dir}} }
when 'windows'
let(:fact_upload_cmd) { '"C:\Program Files\Puppet Labs\Puppet\bin\puppet.bat" facts upload --environment production' }
let(:cache_dir) { 'C:/ProgramData/PuppetLabs/log4jscanner' }
Expand All @@ -26,6 +31,11 @@
let(:default_script_regex) { %r{\$CacheDir = "#{cache_dir}"} }
end

let(:facts) { os_facts }
let(:environment) { 'production' }
let(:params) { { 'cron_minute' => 11 } }
let(:scan_cmd) { "#{cache_dir}/#{scan_script}" }

context 'with default parameters' do
it do
is_expected.to compile.with_all_deps
Expand All @@ -49,7 +59,7 @@
.with_refreshonly(true)
.with_subscribe(["File[#{scan_cmd}]", "File[#{cache_dir}]"])
case os_facts[:kernel]
when 'Linux'
when 'Linux', 'Darwin'
is_expected.to contain_exec('Log4jscanner generate scan data')
.with_command(scan_cmd)
.with_user('root')
Expand Down Expand Up @@ -101,7 +111,7 @@
is_expected.not_to contain_exec('Log4jscanner generate scan data')
is_expected.not_to contain_exec('Log4jscanner fact upload')
case os_facts[:kernel]
when 'Linux'
when 'Linux', 'Darwin'
is_expected.to contain_cron('Log4jscanner - Cache scan data').with_ensure('absent')
when 'windows'
is_expected.to contain_scheduled_task('Log4jscanner - Cache scan data').with_ensure('absent')
Expand All @@ -123,6 +133,8 @@
params['windows_directories'] = ['C:\LiveLong', 'C:\AndProsper']
params['windows_skip'] = ['C:\PeaceAnd', 'C:\LongLife']
params['scheduled_task_every'] = 2
params['osx_directories'] = ['/livelongosx', '/andprosperosx']
params['osx_skip'] = ['/peaceandosx', '/longlifeosx']

is_expected.to compile.with_all_deps
case os_facts[:kernel]
Expand All @@ -143,6 +155,23 @@
.with_month(2)
.with_monthday(3)
.with_weekday(4)
when 'Darwin'
is_expected.to contain_file(scan_cmd)
.with_ensure('file')
.with_content(%r{--skip /peaceandosx.*--skip /longlifeosx.*/livelongosx /andprosperosx}m)
is_expected.to contain_exec('Log4jscanner generate scan data')
.with_command(scan_cmd)
.with_user('picard')
.with_group('starfleet')
is_expected.to contain_cron('Log4jscanner - Cache scan data')
.with_ensure('present')
.with_command(scan_cmd)
.with_user('riker')
.with_hour(1)
.with_minute(11)
.with_month(2)
.with_monthday(3)
.with_weekday(4)
when 'windows'
is_expected.to contain_file(scan_cmd)
.with_ensure('file')
Expand Down
27 changes: 27 additions & 0 deletions tasks/osx.sh
@@ -0,0 +1,27 @@
#!/usr/bin/env bash

set -e

skip=""
if [ -n "${PT_skip}" ]; then
while IFS=',' read -ra skipdirs; do
for glob in "${skipdirs[@]}"; do
skip="${skip} --skip ${glob}"
done
done <<< "${PT_skip}"
fi

rewrite=""
if [ -n "${PT_rewrite}" ] && [ "${PT_rewrite}" = "true" ]; then
rewrite="--rewrite"
fi

dirs=""
while IFS=',' read -ra directories; do
for d in "${directories[@]}"; do
dirs="${dirs} ${d}"
done
done <<< "${PT_directories}"

echo "Command: ${PT__installdir}/log4jscanner/files/log4jscanner_osx ${skip} ${rewrite} ${dirs}"
${PT__installdir}/log4jscanner/files/log4jscanner_osx ${skip} ${rewrite} ${dirs} 2>&1
1 change: 1 addition & 0 deletions tasks/run_scan.json
Expand Up @@ -16,6 +16,7 @@
}
},
"implementations": [
{ "name": "osx.sh", "requirements": ["darwin"], "files": ["log4jscanner/files/log4jscanner_osx"], "input_method": "environment" },
{ "name": "nix.sh", "requirements": ["shell"], "files": ["log4jscanner/files/log4jscanner_nix"], "input_method": "environment" },
{ "name": "win.ps1", "requirements": ["powershell"], "files": ["log4jscanner/files/log4jscanner.exe"], "input_method": "powershell" }
]
Expand Down
21 changes: 21 additions & 0 deletions tasks/run_scan_osx.json
@@ -0,0 +1,21 @@
{
"description": "Runs Google's log4jscanner on an OSX target node",
"support_noop": false,
"parameters": {
"directories": {
"description": "Comma-separated list of directories to search for vulnerable log4j JARs",
"type": "String"
},
"skip": {
"description": "Comma-separated list of glob patterns to skip when scanning (e.g. '/var/run/*')",
"type": "Optional[String]"
},
"rewrite": {
"description": "Rewrite vulnerable JARs as they are detected",
"type": "Optional[Boolean]"
}
},
"implementations": [
{ "name": "osx.sh", "requirements": ["shell"], "files": ["log4jscanner/files/log4jscanner_osx"], "input_method": "environment" }
]
}
2 changes: 1 addition & 1 deletion templates/scan_data_generation.sh.epp
Expand Up @@ -31,7 +31,7 @@ else
touch "${UPDATEFILE}.previous"
fi

${CACHEDIR}/log4jscanner_nix ${skip} ${dirs} 1>${UPDATEFILE} 2>${ERRORFILE}
${CACHEDIR}/<%= $scan_bin %> ${skip} ${dirs} 1>${UPDATEFILE} 2>${ERRORFILE}
diff=$(diff -y --suppress-common "${UPDATEFILE}" "${UPDATEFILE}.previous" | wc -l)
rm -f "${UPDATEFILE}.previous"
if [ "${diff}" != "0" ]; then
Expand Down