Defined Type: ipset::set

Defined in:
manifests/set.pp

Overview

Declare an IP Set.

Examples:

An IP set containing individual IP addresses, specified in the code.

ipset::set { 'a-few-ip-addresses':
  set => ['10.0.0.1', '10.0.0.2', '10.0.0.42'],
}

An IP set containing IP networks, specified with Hiera.

ipset::set { 'hiera-networks':
  set  => lookup('foo', IP::Address::V4::CIDR),
  type => 'hash:net',
}

An IP set of IP addresses, based on a file stored in a module.

ipset::set { 'from-puppet-module':
  set => "puppet:///modules/${module_name}/ip-addresses",
}

An IP set of IP networks, based on a file stored on the filesystem.

ipset::set { 'from-filesystem':
  set => 'file:///path/to/ip-addresses',
}

setup multiple ipsets based on a hiera hash with multiple arrays and multiple IPv4/IPv6 prefixes. Use the voxpupuli/ferm module to create suitable iptables rules.

$ip_ranges = lookup('ip_net_vlans').flatten.unique
$ip_ranges_ipv4 = $ip_ranges.filter |$ip_range| { $ip_range =~ Stdlib::IP::Address::V4 }
$ip_ranges_ipv6 = $ip_ranges.filter |$ip_range| { $ip_range =~ Stdlib::IP::Address::V6 }

ipset::set{'v4':
  ensure => 'present',
  set    => $ip_ranges_ipv4,
  type   => 'hash:net',
}

ipset::set{'v6':
  ensure  => 'present',
  set     => $ip_ranges_ipv6,
  type    => 'hash:net',
  options => {
    'family' => 'inet6',
  },
}

ferm::ipset{'INPUT':
  ip_version => 'ip6',
  sets       => {
    'v6' => 'ACCEPT',
  },
}

ferm::ipset{'INPUT':
  ip_version => 'ip',
  sets       => {
    'v4' => 'ACCEPT',
  },
}

Parameters:

  • set (IPSet::Settype)

    IP set content or source.

  • ensure (Enum['present', 'absent']) (defaults to: 'present')

    Should the IP set be created or removed ?

  • type (IPSet::Type) (defaults to: 'hash:ip')

    Type of IP set.

  • options (IPSet::Options) (defaults to: {})

    IP set options.

  • ignore_contents (Boolean) (defaults to: false)

    If “true“, only the IP set declaration will be managed, but not its content.

  • keep_in_sync (Boolean) (defaults to: true)

    If “true“, Puppet will update the IP set in the kernel memory. If “false“, it will only update the IP sets on the filesystem.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'manifests/set.pp', line 67

define ipset::set (
  IPSet::Settype $set,
  Enum['present', 'absent'] $ensure = 'present',
  IPSet::Type $type = 'hash:ip',
  IPSet::Options $options = {},
  # do not touch what is inside the set, just its header (properties)
  Boolean $ignore_contents = false,
  # keep definition file and in-kernel runtime state in sync
  Boolean $keep_in_sync = true,
) {
  assert_type(String[1, 26], $title) |$expected, $actual| {
    fail("the title of an `ipset::set` needs to be 26 chars or less, but we got ${actual}")
  }

  include ipset

  $config_path = $ipset::config_path

  $default_options = {
    'family'   => 'inet',
    'hashsize' => '1024',
    'maxelem'  => '65536',
  }

  $actual_options = merge($default_options, $options)

  if $ensure == 'present' {
    # assert "present" target

    $opt_string = inline_template('<%= (@actual_options.sort.map { |k,v| k.to_s + " " + v.to_s }).join(" ") %>')

    # header
    file { "${config_path}/${title}.hdr":
      ensure  => file,
      owner   => 'root',
      group   => 'root',
      mode    => '0640',
      content => "create ${title} ${type} ${opt_string}\n",
      notify  => Exec["sync_ipset_${title}"],
    }

    # content
    case $set {
      IPSet::Set::Array: { # lint:ignore:unquoted_string_in_case
        $new_set = join($set, "\n")
        # create file with ipset, one record per line
        file { "${config_path}/${title}.set":
          ensure  => file,
          owner   => 'root',
          group   => 'root',
          mode    => '0640',
          content => "${new_set}\n",
          replace => !$ignore_contents,
        }
      }
      IPSet::Set::Puppet_URL: { # lint:ignore:unquoted_string_in_case
        # passed as puppet file
        file { "${config_path}/${title}.set":
          ensure  => file,
          owner   => 'root',
          group   => 'root',
          mode    => '0640',
          source  => $set,
          replace => !$ignore_contents,
        }
      }
      IPSet::Set::File_URL: { # lint:ignore:unquoted_string_in_case
        # passed as target node file
        file { "${config_path}/${title}.set":
          ensure  => file,
          owner   => 'root',
          group   => 'root',
          mode    => '0640',
          source  => regsubst($set, '^.{7}', ''),
          replace => !$ignore_contents,
        }
      }
      String: {
        # passed directly as content string (from template for example)
        file { "${config_path}/${title}.set":
          ensure  => file,
          owner   => 'root',
          group   => 'root',
          mode    => '0640',
          content => $set,
          replace => !$ignore_contents,
        }
      }
      default: {
        fail('Typing prevent reaching this branch')
      }
    }

    # add switch to script, if we
    if $ignore_contents {
      $ignore_contents_opt = ' -n'
    } else {
      $ignore_contents_opt = ''
    }

    # sync if needed by helper script
    exec { "sync_ipset_${title}":
      path        => ['/sbin', '/usr/sbin', '/bin', '/usr/bin', '/usr/local/bin', '/usr/local/sbin'],
      # use helper script to do the sync
      command     => "ipset_sync -c '${config_path}'    -i ${title}${ignore_contents_opt}",
      # only when difference with in-kernel set is detected
      unless      => "ipset_sync -c '${config_path}' -d -i ${title}${ignore_contents_opt}",
      require     => [Package['ipset'], File['/usr/local/bin/ipset_sync']],
      refreshonly => true,
    }

    if $keep_in_sync {
      File["${config_path}/${title}.set"] ~> Exec["sync_ipset_${title}"]
    }
  } elsif $ensure == 'absent' {
    # ensuring absence

    # do not contain config files
    file { ["${config_path}/${title}.set", "${config_path}/${title}.hdr"]:
      ensure  => absent,
    }

    # clear ipset from kernel
    exec { "ipset destroy ${title}":
      path    => ['/sbin', '/usr/sbin', '/bin', '/usr/bin'],
      command => "ipset destroy ${title}",
      onlyif  => "ipset list ${title}",
      require => Package['ipset'],
    }
  } else {
    fail('Typing prevent reaching this branch')
  }
}