inspec-gcp icon indicating copy to clipboard operation
inspec-gcp copied to clipboard

Fix (and / or spec help) with inspecting specific `compute_security_policy` rules

Open wyardley opened this issue 2 years ago • 1 comments

I'm trying to use the approaches described in https://megamorf.gitlab.io/cheat-sheets/inspec/ to inspect a specific compute policy. I've tried different ways to get it, but have had no luck so far.

Is there a currently supported way to do this?

If not implemented, could it be implemented? If it is implemented, could the docs be extended to provide an example (I can help with this part, if an example is given)

Describe the problem

The following code, as well as other things I've tried to accomplish similar things, does not seem to work:

describe google_compute_security_policy(project: PROJECT, name: 'kitchen-testpolicy') do
    it { is_expected.to exist }
​
    # Predictable because we're using the rules policy here
    its('rules.size') { is_expected.to eq(6) }
​
    its('rules.first.action') { is_expected.to eq('deny(403)') }
    its('rules.first.priority') { is_expected.to eq(1001) }
​
    describe 'rules.where(priority == 2000)' do
      it { is_expected.to exist }
      its('action') { is_expected.to eq('deny(403)') }
      its('config.src_ip_ranges.size') { is_expected.to eq(8) }
      its('config.src_ip_ranges.first') { is_expected.to eq('9.9.9.0/24') }
    end
end

This throws an error like undefined method where... and then prints out (typically) the entire object structure of the enclosing resource. I think this is because the rule itself isn't an inspec resource, and so there's no way to then describe the specific rule?

Using array slices (rules[2].action, rules.at(2).action) etc. doesn't seem to work either.

Possible Solution

wyardley avatar Aug 16 '22 20:08 wyardley

Interestingly, I can't use shift(N), but I can use rules.shift multiple times, and then refer to the new .first, which doesn't read well, but works:

    # Hacky way to get at other array slices
    its('rules.shift.priority') { is_expected.to eq(1001) }
    its('rules.shift.priority') { is_expected.to eq(1007) }
    # "first" is now Nth
    its('rules.first.description') { is_expected.to eq('Block IP ranges') }
    its('rules.first.action') { is_expected.to eq('deny(403)') }
    its('rules.first.match.config.src_ip_ranges.first') { is_expected.to eq('10.0.0.6/32') }
    its('rules.first.match.config.src_ip_ranges.last') { is_expected.to eq('10.0.0.85/32') }

    # Next IP block rule
    its('rules.shift.priority') { is_expected.to eq(2000) }
    its('rules.first.priority') { is_expected.to eq(2001) }
    its('rules.first.match.config.src_ip_ranges.last') { is_expected.to eq('192.168.106.0/23') }

wyardley avatar Aug 17 '22 13:08 wyardley

Got some tips on the Chef Slack. I think this is not an ideal way, but it does seem to work. Basically, if you assign to a variable, you can now use normal array methods.

control 'gcp_cloud_armor-1.0' do
  kitchen_testpolicy = google_compute_security_policy(project: PROJECT, name: 'kitchen-testpolicy')
  describe kitchen_testpolicy do
    it { is_expected.to exist }
    its('rules.size') { is_expected.to eq 8 }
    rules = kitchen_testpolicy.rules

    # Rules can now be tested by array slice, as well as by .first and .last
    context 'when examining first WAF rule' do
      describe rules[1] do
        its('priority') { is_expected.to eq 1001 }
        its('description') { is_expected.to eq 'Prevent Local File Inclusion Attacks' }
      end
    end
    # [....]
    context 'when examining second allowlist rule' do
      describe rules[3] do
        its('priority') { is_expected.to eq 11 }
        its('action') { is_expected.to eq 'allow' }
        its('match.config.src_ip_ranges.last') { is_expected.to eq '10.0.0.1/32' }
      end
    end
  end
end

wyardley avatar Jul 04 '23 20:07 wyardley