Only_if test against host - help!


#1

Guys,

I’m very new to InSpec and I’m baffled …

I need to do a specific check but only if it relates to a specific host so only_if would seem favourite. My frustration is that I cannot get the comparison working.

control ‘SEG_15.05.10’ do
title ‘SEG_15.05.10 - test1’
impact 0.5
desc ‘test1’

HostName = command(‘uname -n’).stdout.split
only_if { HostName cmp ‘Daves-MacBook-Pro.local’ }
describe file(’/etc/hosts’) do
it { should exist }
end
end

this is just to test the principal but this gets

Daves-MacBook-Pro:InSpec dave$ inspec exec initial --controls=SEG_15.05.10

Profile: InSpec Profile (SGCBUnixCompliance)
Version: 0.1.0
Target: local://

× SEG_15.05.10: SEG_15.05.10 - XWindows non installed
× Control Source Code Error initial/controls/Services.rb:4
undefined method `HostName’ for #<#Class:0x00007fdec484d0c8:0x00007fdec0ee55b0>

Profile Summary: 0 successful controls, 1 control failure, 0 controls skipped
Test Summary: 0 successful, 1 failure, 0 skipped

If I go into the shell the command gives me

inspec> command(‘uname -n’).stdout.split
=> [“Daves-MacBook-Pro.local”]

It’s obviously some comparison issue but it’s driving me mad.

Any assistance would be greatly appreciated


#2

should do the trick. The cmp matcher is not available inside only if methods, since its just available inside of describe blocks. In this case we need to rely on pure ruby comparison.


#3

OK - the cop was just my latest attempt - I initially tried the ==

Here’s what happens - I need to be able to trace what the variable gets set to - is there any equivalent to sh -x so I can see what’s going on ?

Daves-MacBook-Pro:InSpec dave$ cat initial/controls/Services.rb

encoding: utf-8

copyright: 2018, Unix & Storage Team

control ‘SEG_15.05.10’ do
title ‘SEG_15.05.10 - test1’
impact 0.5
desc ‘test1’

HostName = command(‘uname -n’).stdout.split
describe file(’/etc/hosts’) do
it { should exist }
end
only_if { HostName == ‘Daves-MacBook-Pro.local’ }
end
Daves-MacBook-Pro:InSpec dave$ inspec exec initial --controls=SEG_15.05.10

Profile: InSpec Profile (SGCBUnixCompliance)
Version: 0.1.0
Target: local://

↺ SEG_15.05.10: SEG_15.05.10 - test1
↺ Skipped control due to only_if condition.

Profile Summary: 0 successful controls, 0 control failures, 1 control skipped
Test Summary: 0 successful, 0 failures, 1 skipped
Daves-MacBook-Pro:InSpec dave$ inspec shell
Welcome to the interactive InSpec Shell
To find out how to use it, type: help

You are currently running on:

Name:      mac_os_x
Families:  darwin, bsd, unix, os
Release:   17.6.0
Arch:      x86_64

inspec> command(‘uname -n’).stdout.split
=> [“Daves-MacBook-Pro.local”]
inspec> quit


#4

I made an error in my initial example, the following is working now:

control 'SEG_15.05.10' do
    title 'SEG_15.05.10 - test1'
    impact 0.5
    desc 'test1'
    HostName = command('uname -n').stdout.strip
    describe file('/etc/hosts') do
        it { should exist }
    end
    only_if {
        HostName == 'Daves-MacBook-Pro.local'
    }
end

command(‘uname -n’).stdout.split returns an array, therefore HostName == ‘Daves-MacBook-Pro.local’ is never true. strip removes the whitespace (in this case the newline). I recommend to keep the hostname extraction where it is required. In this case the only_if block is the best.

control 'SEG_15.05.10' do
    title 'SEG_15.05.10 - test1'
    impact 0.5
    desc 'test1'
    describe file('/etc/hosts') do
        it { should exist }
    end
    only_if {
        HostName = command('uname -n').stdout.strip
        HostName == 'Daves-MacBook-Pro.local'
    }
end

If you need some debug outputs, you can easily output variables during execution with puts

control 'SEG_15.05.10' do
    title 'SEG_15.05.10 - test1'
    impact 0.5
    desc 'test1'
    describe file('/etc/hosts') do
        it { should exist }
    end
    only_if {
        HostName = command('uname -n').stdout.strip
        puts HostName
        HostName == 'Daves-MacBook-Pro.local'
    }
end

You can even simplify the resource by using the built-in sys_info resource from InSpec https://www.inspec.io/docs/reference/resources/sys_info/ Now the control could be written like:

control 'SEG_15.05.10' do
    title 'SEG_15.05.10 - test1'
    impact 0.5
    desc 'test1'
    describe file('/etc/hosts') do
        it { should exist }
    end
    only_if {
        sys_info.hostname == 'Daves-MacBook-Pro.local'
    }
end

#5

ok - I must be doing something bizarre with this - here’s what I am doing - based on the above but with all the right commands in, I note the sys_info stuff but I can’t use it as this box is Solaris and sys_info is not supported.

BoKSMaster = 'sol-boksp1'
 
control 'SEG_15.03.05' do
  title 'SEG_15.03.05 - Password must meet complexity requirements'
  impact 0.5
  desc 'Enforce at least on lowercase character'
 
  describe command('/opt/boksm/sbin/keonadm -S pswadm charclass') do
    its('stdout')  { should match /LOWER=1/ }
  end
  only_if {
    HostName = command('uname -n').stdout.split
    puts BoKSMaster
    puts HostName
    HostName == BoKSMaster
    }
end

When I run this I get the following (I’ve added puts to show the variables)

[root@lnx-dockd1 Inspec]# inspec exec sgcb --target=ssh://root@sol-boksp1 --key-files=SatKey --host=sol-boksp1 --controls=SEG_15.03.05
sol-boksp1
sol-boksp1

Profile: InSpec Profile for SGCB Compliance - Custom Controls (SGCBCustom)
Version: 0.1.0
Target: ssh://root@sol-boksp1:22

⺠SEG_15.03.05: SEG_15.03.05 - Password must meet complexity requirements
⺠Skipped control due to only_if condition.

Profile Summary: 0 successful controls, 0 control failures, 1 control skipped
Test Summary: 0 successful, 0 failures, 1 skipped


#6

Don’t know how this is different but it works now (Maybe I had some non-printable characters in there somewhere perhaps) Thanks for the assist.

BoKSMaster = 'sol-boksp1’
HostName = command(‘uname -n’).stdout.strip

control ‘SEG_15.03.01’ do
title ‘SEG_15.03.01 - Define minimum password length (8)’
impact 0.5
desc ‘The use of blank passwords not allowed, requiring at least 8 characters’

describe login_defs do
its(‘PASS_MIN_LEN’) { should eq ‘8’ }
end
end

control ‘SEG_15.03.02’ do
title ‘SEG_15.03.02 - Maximum Password Age’
impact 0.5
desc ‘Maximum Password Age’

describe command(’/opt/boksm/sbin/bksdef’) do
its(‘stdout’) { should match /^Password term of validity.*90/ }
end
only_if { HostName == BoKSMaster }
end

control ‘SEG_15.03.05’ do
title 'SEG_15.03.05 - Password must meet complexity requirements’
impact 0.5
desc 'Enforce at least on lowercase character’

describe command(’/opt/boksm/sbin/keonadm -S pswadm charclass’) do
its(‘stdout’) { should match /LOWER=1/ }
end
only_if { HostName == BoKSMaster }
end