Chef 防火墙说明书不适用于自定义 JSON 对象

Chef firewall cookbook not working with custom JSON objects

我正在玩 firewall cookbookcookbook 'firewall', '~> 2.7.0'

不确定是不是我一个人,但说明不是很清楚,但我给了它旧的大学尝试...

我想做的是构建一个配方,让我可以使用 data_bags 和环境来指定规则。大多数节点将是 CentOS 7,但我也有一些 Ubuntu 16(可能是不同的版本等待第三方软件)。大多数节点将有 2 个 NIC,1 个带区域 public,另一个带 trusted。因此,如果可能的话,我宁愿尝试坚持 firewall 食谱。

在开发过程中,我使用了 rspec,一切都按预期进行。当我去 Test Kitchen 时,嗯,那是我发现没有任何效果的时候。所以我进入节点并意识到没有应用任何规则。

理想情况下,我首先希望默认区域为 :public。 然后我想将规则应用于 json 对象中的每个区域。 使用 rspec 进行测试时,一切看起来都不错。 当我使用 Test Kitchen 时,甚至什么都没有发生。

希望我只是在做一些愚蠢的事情。我希望在这里朝着正确的方向前进...... 应该注意的是,我开始这个有一段时间了,但由于另一个项目而停止了。现在我又回到了这个问题上,我正在努力找出问题所在。

感谢您的宝贵时间。

一个环境示例 (dev):

{
  "name": "dev",
  "description": "DEV Environment for Nodes",
  "chef_type": "environment",
  "json_class": "Chef::Environment",
  "default_attributes": {
    "oly": {
      "environment": "dev",
      "type" : "node",
      "firewall": {
        "status": "enabled",
        "zones": {
          "public": {
            "22": {
              "private_ip_1": "10.0.0.0/8",
              "private_ip_2": "172.16.0.0/12",
              "private_ip_3": "192.168.0.0/16",
              "private_ip_4": "169.254.0.0/16",
              "private_ip_5": "100.64.0.0/10"
            }
          }
        }
      }
    }
  },
  "cookbook_versions": {
    "oly-client": "= 4.0.0"
  }
}

上述环境有一个防火墙区域配置,为所有私有 IP 地址打开端口 22

data_bag(防火墙:全局)的一个例子是:

{
  "id": "global",
  "zones": {
    "public": {
      "22": {
          "office_1": "1.1.1.1/32",
          "office_2": "2.2.2.2/32",
          "office_3": "3.3.3.3/32",
          "office_4": "4.4.4.4/32",
          "office_5": "5.5.5.5/32"
      }
    }
  }
}

理想情况下,这允许将全局规则应用于配方。

我正在编写的食谱:

#
# Cookbook:: oly-client
# Recipe:: firewall
# 
# TODO: Create a method to optimize code (code repetition is real here)

# Fetch firewall settings
_firewallSettings = node['oly']['firewall']

# Make sure we have firewall settings and that they are enabled
if (!_firewallSettings.to_a.empty? && _firewallSettings.key?("status") && 'enabled' == _firewallSettings['status'].downcase)
  # include the base firewall recipe
  include_recipe "firewall::default"

  # Enable platform default firewall and set default zone
  firewall "default" do
    action [:install]
    enabled_zone :public
  end

  # START global firewall rules
  _globalFirewallRules = data_bag_item('firewall', 'global')
  if (_globalFirewallRules && _globalFirewallRules.key?("zones"))

    # Loop over each firewall zone and build rules from data
    _globalFirewallRules['zones'].each do |_zone, _zoneData|

      # Ensure we have zone data
      if (_zoneData)

        # Ensure the firewall is installed for the zone
        firewall "#{_zone}" do
          enabled_zone "#{_zone}".to_sym
          action [:install]
        end

        # Process rules for firewall
        _zoneData.each do |_port, _portRules|
          # Verify rules exist
          if (_portRules)
            # Build rules
            _portRules.each do |_ipComment, _ipAddress|

              # Define rule
              firewall_rule "#{_zone} - #{_port}: #{_ipComment} - #{_ipAddress}" do
                firewall_name "#{_zone}"
                port _port.to_i
                source _ipAddress
                direction :in
                command :allow
              end

            end
          end
        end

        # Save the firewall settings
        firewall "#{_zone}" do
          # action :save
          action [:save]
        end

      end

    end

  end
  # END global firewall rules

  # Check if environment has any zones configured
  if (_firewallSettings.key?("zones"))

    # Loop over each firewall zone and build rules from data
    _firewallSettings['zones'].each do |_zone, _zoneData|

      # Ensure we have zone data
      if (_zoneData)

        # Ensure the firewall is installed for the zone (in case global zones does not include)
        firewall "#{_zone}" do
          enabled_zone "#{_zone}".to_sym
          # action :install
          action [:install]
        end

        # Process rules for firewall
        _zoneData.each do |_port, _portRules|
          # Verify rules exist
          if (_portRules)
            # Build rules
            _portRules.each do |_ipComment, _ipAddress|

              # Define rule
              firewall_rule "#{_zone} - #{_port}: #{_ipComment} - #{_ipAddress}" do
                firewall_name "#{_zone}"
                port _port.to_i
                source _ipAddress
                direction :in
                command :allow
              end

            end
          end
        end

        # Save the firewall settings
        firewall "#{_zone}" do
          # action :save
          action [:save]
        end

      end

    end


  end
  # END environment firewall rules

  # TODO Add logic for custom rules (with search capabilites, like users - Did not do yet as this is edge case if needed at all)

  # Save the firewall settings
  firewall "default" do
    # action :save
    action [:save]
  end

else
  # Firewall is disabled unless explicitly enabled
  include_recipe 'firewall::disable_firewall'
end

我的 rspec 测试(重新放置 IP 但应该工作相同):

#
# Cookbook:: oly-client
# Spec:: default
#
# Copyright:: 2017, The Authors, All Rights Reserved.

require 'spec_helper'

describe 'oly-client::firewall' do

  context 'on CentOS 7 Latest' do

    let(:chef_run) do
      ChefSpec::SoloRunner.new(platform: 'centos', version: '7') do |node|

        # Build node attributes for tests
        node.normal['oly']['firewall']['status'] = "enabled"
        node.normal['oly']['firewall']['zones'] = {
          "public": {
            "22": {
              "private_ip_1": "10.0.0.0/8",
              "private_ip_2": "172.16.0.0/12",
              "private_ip_3": "192.168.0.0/16",
              "private_ip_4": "169.254.0.0/16"
            }
          },
          "trusted": {
            "22": {
              "private_ip_5": "100.64.0.0/10"
            }
          }
        }

        # Firewall rules
        node.normal['firewall']['allow_icmp'] = true
        node.normal['firewall']['allow_ssh'] = true
        node.normal['firewall']['allow_winrm'] = false
        node.normal['firewall']['allow_mosh'] = false

      end.converge(described_recipe)
    end

    # Stub databags
    before do
      stub_data_bag('firewall').and_return(['global'])
      stub_data_bag_item('firewall', 'global').and_return({
        "id": "global",
        "zones": {
          "public": {
            "22": {
                  "office_1": "1.1.1.1/32",
                  "office_2": "2.2.2.2/32",
                  "office_3": "3.3.3.3/32"
            }
          },
          "trusted": {
            "22": {
              "office_1": "1.1.1.1/32",
              "office_3": "3.3.3.3/32",
              "office_4": "4.4.4.4/32",
              "office_5": "5.5.5.5/32"
            }
          }
        }
      })
    end

    it 'include the recipe to enable firewall' do
      expect(chef_run).to include_recipe('firewall::default')
    end

    it 'enables the firewall' do
      expect(chef_run).to install_firewall('public')
      expect(chef_run).to install_firewall('trusted')
    end

    it 'creates some rules' do
      _rules = [
        "allow loopback", 
        "allow icmp", 
        "allow world to ssh", 
        "established",
        "ipv6_icmp",
        "public - 22: private_ip_1 - 10.0.0.0/8",
        "public - 22: private_ip_2 - 172.16.0.0/12",
        "public - 22: private_ip_3 - 192.168.0.0/16",
        "public - 22: private_ip_4 - 169.254.0.0/16",
        "trusted - 22: private_ip_5 - 100.64.0.0/10",
        "public - 22: office_1 - 1.1.1.1/32",
        "public - 22: office_2 - 2.2.2.2/32",
        "public - 22: office_3 - 3.3.3.3/32",
        "trusted - 22: office_1 - 1.1.1.1/32",
        "trusted - 22: office_3 - 3.3.3.3/32",
        "trusted - 22: office_4 - 4.4.4.4/32",
        "trusted - 22: office_5 - 5.5.5.5/32"
      ]

      _rules.each do |r|
        expect(chef_run).to create_firewall_rule(r)
      end
    end


    it 'not to creates some rules' do
      _rules = [
        "allow world to winrm", 
        "allow world to mosh",
        "public - 22: office_4 - 4.4.4.4/32",
        "public - 22: office_5 - 5.5.5.5/32",
        "trusted - 22: office_2 - 2.2.2.2/32"
      ]

      _rules.each do |r|
        expect(chef_run).to_not create_firewall_rule(r)
      end
    end

  end

end

食谱目前不支持区域。我提交了 PR 以添加支持。虽然说明书的文档并不完全清楚,但我在此处发布的问题是由于缺少 firewalld 功能。