Просмотр исходного кода

Refactor from the scratch

Customer-Found
Prod-Related: CEEMCP-19
Prod-Related: PROD-22620

Change-Id: Ib14838becc409c2f735d93b5fa8a8ead6ea1a5ec
pull/19/head
Dzmitry Stremkouski 6 лет назад
Родитель
Сommit
e353ce3c49
24 измененных файлов: 799 добавлений и 504 удалений
  1. +2
    -3
      .kitchen.yml
  2. +5
    -5
      .travis.yml
  3. +4
    -5
      CHANGELOG.rst
  4. +2
    -2
      LICENSE
  5. +64
    -155
      README.rst
  6. +1
    -1
      VERSION
  7. +231
    -0
      _modules/iptables_extra.py
  8. +2
    -8
      debian/changelog
  9. +6
    -6
      debian/control
  10. +3
    -3
      debian/copyright
  11. +0
    -94
      iptables/_rule.sls
  12. +20
    -3
      iptables/init.sls
  13. +79
    -9
      iptables/map.jinja
  14. +0
    -117
      iptables/rules.sls
  15. +0
    -63
      iptables/service.sls
  16. +72
    -0
      iptables/v1/files/v4_rules
  17. +72
    -0
      iptables/v1/files/v6_rules
  18. +6
    -0
      iptables/v1/init.sls
  19. +0
    -0
      iptables/v1/meta/sphinx.yml
  20. +79
    -0
      iptables/v1/v4_service.sls
  21. +79
    -0
      iptables/v1/v6_service.sls
  22. +1
    -2
      metadata.yml
  23. +71
    -0
      tests/pillar/iptables.sls
  24. +0
    -28
      tests/pillar/iptables_server.sls

+ 2
- 3
.kitchen.yml Просмотреть файл

@@ -36,8 +36,7 @@ platforms:

suites:

- name: iptables_server
- name: iptables
provisioner:
pillars-from-files:
iptables.sls: tests/pillar/iptables_server.sls
# vim: ft=yaml sw=2 ts=2 sts=2 tw=125
iptables.sls: tests/pillar/iptables.sls

+ 5
- 5
.travis.yml Просмотреть файл

@@ -20,11 +20,11 @@ install:
- bundle install

env:
- PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2016.3 SUITE=iptables-server
- PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2017.7 SUITE=iptables-server
- PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2018.3 SUITE=iptables-server
# - PLATFORM=epcim/salt:saltstack-ubuntu-bionic-salt-2017.7 SUITE=iptables-server
# - PLATFORM=epcim/salt:saltstack-ubuntu-bionic-salt-2018.3 SUITE=iptables-server
- PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2016.3 SUITE=iptables
- PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2017.7 SUITE=iptables
- PLATFORM=epcim/salt:saltstack-ubuntu-xenial-salt-2018.3 SUITE=iptables
# - PLATFORM=epcim/salt:saltstack-ubuntu-bionic-salt-2017.7 SUITE=iptables
# - PLATFORM=epcim/salt:saltstack-ubuntu-bionic-salt-2018.3 SUITE=iptables

before_script:
- set -o pipefail

+ 4
- 5
CHANGELOG.rst Просмотреть файл

@@ -1,7 +1,6 @@
iptables-salt-formula
=====================

iptables-formula
================
1.0.0

0.0.1 (2015-08-03)

- Initial formula setup
- Initial setup

+ 2
- 2
LICENSE Просмотреть файл

@@ -1,4 +1,4 @@
Copyright (c) 2014-2015 tcp cloud a.s.
Copyright (c) 2018 Mirantis a.s.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -10,4 +10,4 @@ Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
limitations under the License.

+ 64
- 155
README.rst Просмотреть файл

@@ -1,7 +1,6 @@

================
iptables formula
================
=====================
iptables salt formula
=====================

Iptables is used to set up, maintain, and inspect the tables of IPv4 packet
filter rules in the Linux kernel. Several different tables may be defined.
@@ -11,154 +10,76 @@ packets. Each rule specifies what to do with a packet that matches. This is
called a `target`, which may be a jump to a user-defined chain in the same
table.

Sample pillars
==============

Most common rules - allow traffic on localhost, accept related,established and
ping

.. code-block:: yaml

parameters:
iptables:
service:
enabled: True
chain:
INPUT:
rules:
- in_interface: lo
jump: ACCEPT
- connection_state: RELATED,ESTABLISHED
match: state
jump: ACCEPT
- protocol: icmp
jump: ACCEPT

Accept connections on port 22

.. code-block:: yaml

parameters:
iptables:
service:
chain:
INPUT:
rules:
- destination_port: 22
protocol: tcp
jump: ACCEPT

Set drop policy on INPUT chain:

.. code-block:: yaml

parameters:
iptables:
service:
chain:
INPUT:
policy: DROP

Redirect privileged port 443 to 8081

.. code-block:: yaml

parameters:
iptables:
service:
chain:
PREROUTING:
filter: nat
destination_port: 443
to_port: 8081
protocol: tcp
jump: REDIRECT

Allow access from local network
This version of a formula guarantees that manually added rules or rules which
has been added in runtime would be removed.

.. code-block:: yaml

parameters:
iptables:
service:
chain:
INPUT:
rules:
- protocol: tcp
destination_port: 22
source_network: 192.168.1.0/24
jump: ACCEPT
comment: Blah

Support logging with custom prefix and log level

.. code-block:: yaml
In order to ensure architecture, proper epoch value should be specified.
Refer to an example.

parameters:
iptables:
service:
chain:
POSTROUTING:
rules:
- table: nat
protocol: tcp
match: multiport
destination_ports:
- 21
- 80
- 443
- 2220
source_network: '10.20.30.0/24'
log_level: 7
log_prefix: 'iptables-logging: '
jump: LOG


IPv6 is supported as well

.. code-block:: yaml

parameters:
iptables:
service:
enabled: True
ipv6: True
chain:
INPUT:
rules:
- protocol: tcp
family: ipv6
destination_port: 22
source_network: 2001:DB8::/32
jump: ACCEPT


You may set policy for chain in specific table
If 'table' key is omitted, 'filter' table is assumed
Sample pillars
==============

.. code-block:: yaml

parameters:
iptables:
schema:
epoch: 1
service:
enabled: true
chain:
OUTPUT:
policy: ACCEPT

Specify policy directly
v4:
enabled: true
persistent_config: /etc/iptables.v4
modules:
- nf_conntrack_ftp
- nf_conntrack_pptp
v6:
enabled: false
persistent_config: /etc/iptables.v6
modules:
- nf_conntrack_ipv6
defaults:
v4:
metadata_rules: false
policy: ACCEPT
ruleset:
action: ACCEPT
params: ""
rule: ""
v6:
metadata_rules: false
policy: DROP
ruleset:
action: ACCEPT
params: ""
rule: ""
tables:
v4:
filter:
chains:
INPUT:
ruleset:
5:
action: log_drop
10:
rule: -s 192.168.0.0/24 -p tcp
log_drop:
policy: DROP
ruleset:
10:
action: LOG
comment: "Log my packets"
nat:
chains:
OUTPUT:
PREROUTING:
POSTROUTING:
policy: ACCEPT
ruleset:
10:
rule: -s 192.168.0.0/24 -p tcp -o lo
action: SNAT
params: --to-source=127.0.0.1

.. code-block:: yaml

parameters:
iptables:
service:
enabled: true
chain:
FORWARD:
policy:
- table: mangle
policy: DROP

Read more
=========
@@ -181,21 +102,9 @@ formula:

https://github.com/salt-formulas/salt-formula-iptables/issues

For feature requests, bug reports or blueprints affecting entire ecosystem,
use Launchpad salt-formulas project:

https://launchpad.net/salt-formulas

You can also join salt-formulas-users team and subscribe to mailing list:

https://launchpad.net/~salt-formulas-users

Developers wishing to work on the salt-formulas projects should always base
their work on master branch and submit pull request against specific formula.

https://github.com/salt-formulas/salt-formula-iptables

Any questions or feedback is always welcome so feel free to join our IRC
channel:

#salt-formulas @ irc.freenode.net

+ 1
- 1
VERSION Просмотреть файл

@@ -1 +1 @@
0.2
1.0.0

+ 231
- 0
_modules/iptables_extra.py Просмотреть файл

@@ -0,0 +1,231 @@
# -*- coding: utf-8 -*-
from os import chmod,remove
from time import time
from subprocess import Popen,PIPE

def get_tables(family="ipv4"):

''' List iptables tables

:param family: iptables ip family version. type: str

'''

if family == "ipv4":
cmd = 'iptables-save'
elif family == "ipv6":
cmd = 'ip6tables-save'
else:
return "Invalid ip family specified. Use either ipv4 or ipv6"

tables = []
try:
tables_list = Popen(cmd, shell=True, stdout=PIPE)
while True:
line = tables_list.stdout.readline()
if line != '':
if line[0] == "*":
tables.append(line.rstrip()[1:])
else:
break
except:
return "Error getting list of tables"

return tables

def get_chains(family="ipv4", table="filter"):

''' List iptables chains

:param family: iptables ip family version. type: str
:param table: Lookup chains for this table. type: str

'''

if family == "ipv4":
cmd = 'iptables-save'
elif family == "ipv6":
cmd = 'ip6tables-save'
else:
return "Invalid ip family specified. Use either ipv4 or ipv6"

cmd += ' -t ' + table

chains = []
try:
chains_list = Popen(cmd, shell=True, stdout=PIPE)
while True:
line = chains_list.stdout.readline()
if line != '':
if line[0] == ":":
chains.append(line.rstrip()[1:].split(' ')[0])
else:
break
except:
return "Error getting list of chains"

return chains

def get_structure(family="ipv4"):

''' Get structure of all chains in all tables

:param family: iptables ip family version. type: str

'''

if family == "ipv4":
cmd = 'iptables-save'
elif family == "ipv6":
cmd = 'ip6tables-save'
else:
return "Invalid ip family specified. Use either ipv4 or ipv6"

tables = []
tables_list = Popen(cmd, shell=True, stdout=PIPE)
while True:
line = tables_list.stdout.readline()
if line != '':
line = line.rstrip().lstrip()
if line[0] == "*":
elem = {}
table_name = line[1:].split(' ')[0]
elem[table_name] = []
if line[0] == ":":
elem[table_name].append(line[1:].split(' ')[0])
if line == "COMMIT":
tables.append(elem)
else:
break

return tables

def run_script(script):

''' Execute local script

:param script: script to be executed, storad localy: str

'''

chmod(script, 0o700)
process = Popen([script],stdout=PIPE,stderr=PIPE)
process.wait()
code = process.returncode
remove(script)
return code


def flush_all(family="ipv4"):

''' Flush all chains in all tables

:param family: iptables ip family version. type: str

'''

if family == "ipv4":
cmd = 'iptables'
rmmod = 'iptable_'
elif family == "ipv6":
cmd = 'ip6tables'
rmmod = 'ip6table_'
else:
return "Invalid ip family specified. Use either ipv4 or ipv6"

tables = get_structure(family)

f_name = '/tmp/' + cmd + '-flush-' + str(time()).split('.')[0] + '.sh'

with open(f_name, 'w') as f:
f.write('#!/bin/sh\n')
for table in tables:
for var in enumerate(table):
t_name = var[1]
for chain in table[t_name]:
f.write(cmd + ' -t ' + t_name + " -F " + chain + '\n')
if chain not in ['INPUT','FORWARD','OUTPUT','PREROUTING','POSTROUTING']:
f.write(cmd + ' -t ' + t_name + " -X " + chain + '\n')
f.write('rmmod ' + rmmod + t_name + '\n')

return run_script(f_name)

def set_policy_all(family="ipv4", policy="ACCEPT"):

''' Set policy for all chains in all tables

:param family: iptables ip family version. type: str
:param policy: iptables chain policy. type: str

'''

if family == "ipv4":
cmd = 'iptables'
elif family == "ipv6":
cmd = 'ip6tables'
else:
return "Invalid ip family specified. Use either ipv4 or ipv6"

tables = get_structure(family)

f_name = '/tmp/' + cmd + '-policy-' + str(time()).split('.')[0] + '.sh'

with open(f_name, 'w') as f:
f.write('#!/bin/sh\n')
for table in tables:
for var in enumerate(table):
t_name = var[1]
for chain in table[t_name]:
f.write(cmd + ' -t ' + t_name + " -P " + chain + ' ' + policy + '\n')

return run_script(f_name)

def remove_stale_tables(config_file, family="ipv4"):

''' Remove tables which are not in config file
to prevet flushing all the tables

:param family: iptables ip family version. type: str
:param config_file: iptables rules persistent config file. type: str

'''

if family == "ipv4":
cmd = 'iptables'
rmmod = 'iptable_'
elif family == "ipv6":
cmd = 'ip6tables'
rmmod = 'ip6table_'
else:
return "Invalid ip family specified. Use either ipv4 or ipv6"

runtime_tables = get_tables(family)

config_tables = []
for line in open(config_file, 'r'):
if line != '':
if line[0] == "*":
config_tables.append(line.rstrip()[1:])

runtime_tables.sort()
config_tables.sort()
diff = list(set(runtime_tables) - set(config_tables))

if diff != []:
tables = get_structure(family)
f_name = '/tmp/' + cmd + '-flush-' + str(time()).split('.')[0] + '.sh'
with open(f_name, 'w') as f:
f.write('#!/bin/sh\n')
for table in tables:
for var in enumerate(table):
t_name = var[1]
if t_name in diff:
for chain in table[t_name]:
f.write(cmd + ' -t ' + t_name + " -F " + chain + '\n')
if chain not in ['INPUT','FORWARD','OUTPUT','PREROUTING','POSTROUTING']:
f.write(cmd + ' -t ' + t_name + " -X " + chain + '\n')
f.write('rmmod ' + rmmod + t_name + '\n')

return run_script(f_name)
else:
return

+ 2
- 8
debian/changelog Просмотреть файл

@@ -1,11 +1,5 @@
salt-formula-iptables (0.2) trusty; urgency=medium

* First public release

-- Filip Pytloun <filip.pytloun@tcpcloud.eu> Tue, 06 Oct 2015 16:38:43 +0200

salt-formula-iptables (0.1) trusty; urgency=medium
salt-formula-iptables (1.0) xenial; urgency=medium

* Initial release

-- Jan Kaufman <jan.kaufman@tcpcloud.eu> Thu, 13 Aug 2015 23:23:41 +0200
-- Dzmitry Stremkouski <dstremkouski@mirantis.com> Thu, 30 Aug 2018 16:20:23 +0100

+ 6
- 6
debian/control Просмотреть файл

@@ -1,15 +1,15 @@
Source: salt-formula-iptables
Maintainer: Jan Kaufman <jan.kaufman@tcpcloud.eu>
Maintainer: Dzmitry Stremkouski <dstremkouski@mirantis.com>
Section: admin
Priority: optional
Priority: extra
Build-Depends: salt-master, python, python-yaml, debhelper (>= 9)
Standards-Version: 3.9.6
Homepage: http://www.tcpcloud.eu
Vcs-Browser: https://github.com/tcpcloud/salt-formula-iptables
Vcs-Git: https://github.com/tcpcloud/salt-formula-iptables.git
Homepage: https://mirantis.com
Vcs-Browser: https://github.com/Mirantis/salt-formula-iptables
Vcs-Git: https://github.com/Mirantis/salt-formula-iptables.git

Package: salt-formula-iptables
Architecture: all
Depends: ${misc:Depends}
Description: iptables salt formula
Configure iptables rules.
Manages iptables rules.

+ 3
- 3
debian/copyright Просмотреть файл

@@ -1,10 +1,10 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: salt-formula-iptables
Upstream-Contact: Ales Komarek <ales.komarek@tcpcloud.eu>
Source: https://github.com/tcpcloud/salt-formula-iptables
Upstream-Contact: Dzmitry Stremkouski <dstremkouski@mirantis.com>
Source: https://github.com/Mirantis/salt-formula-iptables

Files: *
Copyright: 2014-2015 tcp cloud a.s.
Copyright: 2018 Mirantis a.s.
License: Apache-2.0
Copyright (C) 2014-2015 tcp cloud a.s.
.

+ 0
- 94
iptables/_rule.sls Просмотреть файл

@@ -1,94 +0,0 @@
{%- set table = rule.get('table', 'filter') %}
iptables_{{ table }}_{{ chain_name }}_{{ rule_name }}:
{%- if rule.position is defined %}
iptables.insert:
- position: {{ rule.position }}
{%- else %}
iptables.append:
- require:
{%- if loop.index != 1 %}
- iptables: iptables_{{ table }}_{{ chain_name }}_{% if service_name is defined %}{{ service_name }}_{% endif %}{{ loop.index - 1 }}
{%- else %}
{%- for chain in chains %}
- iptables: iptables_{{ table }}_{{ chain }}
{%- endfor %}
{%- endif %}
{%- endif %}
- table: {{ table }}
- chain: {{ chain_name }}
{%- if rule.family is defined %}
- family: {{ rule.family }}
{%- endif %}
{%- if rule.jump is defined %}
- jump: {{ rule.jump }}
{%- endif %}
{%- if rule.match is defined %}
- match: {{ rule.match }}
{%- endif %}
{%- if rule.comment is defined %}
- comment: {{ rule.comment }}
{%- endif %}
{%- if rule.connection_state is defined %}
- connstate: {{ rule.connection_state }}
{%- endif %}
{%- if rule.protocol is defined %}
- proto: {{ rule.protocol }}
{%- endif %}
{%- if rule.destination_port is defined %}
- dport: {{ rule.destination_port }}
{%- endif %}
{%- if rule.destination_ports is defined %}
- dports:
{%- for port in rule.destination_ports %}
- {{ port }}
{% endfor %}
{%- endif %}
{%- if rule.source_port is defined %}
- sport: {{ rule.source_port }}
{%- endif %}
{%- if rule.in_interface is defined %}
- in-interface: {{ rule.in_interface }}
{%- endif %}
{%- if rule.out_interface is defined %}
- out-interface: {{ rule.out_interface }}
{%- endif %}
{%- if rule.to_destination is defined %}
- to-destination: {{ rule.to_destination }}
{%- endif %}
{%- if rule.to_port is defined %}
- to-port: {{ rule.to_port }}
{%- endif %}
{%- if rule.to_source is defined %}
- to-source: {{ rule.to_source }}
{%- endif %}
{%- if rule.source_network is defined %}
- source: {{ rule.source_network }}
{%- endif %}
{%- if rule.destination_network is defined %}
- destination: {{ rule.destination_network }}
{%- endif %}
{%- if rule.log_prefix is defined %}
- log-prefix: '{{ rule.log_prefix }}'
{%- endif %}
{%- if rule.log_level is defined %}
- log-level: {{ rule.log_level }}
{%- endif %}
{%- if rule.limit is defined %}
- limit: '{{ rule.limit }}'
{%- endif %}
{%- if chain.policy is defined %}
{%- if chain.policy is string %}
- require_in:
- iptables: iptables_filter_{{ chain_name }}_policy
{%- else %}
{%- if table in chain.policy %}
- require_in:
- iptables: iptables_{{ table }}_{{ chain_name }}_policy
{%- endif %}
{%- endif %}
{%- endif %}
{%- if grains.get('virtual_subtype', None) not in ['Docker', 'LXC'] %}
- require:
- iptables: iptables_{{ table}}_{{ chain_name }}{% if rule.family is defined %}_{{ rule.family }}{% endif %}
{%- endif %}
- save: True

+ 20
- 3
iptables/init.sls Просмотреть файл

@@ -1,4 +1,21 @@
{%- from "iptables/map.jinja" import schema with context %}

{%- set include_allowed = true %}
{%- if grains.get('virtual_subtype', None) in ['Docker', 'LXC'] %}
{%- set include_allowed = false %}
echo_usupported_environment:
cmd.run:
- name: echo "You are trying to use iptables inside of docker or lxc. Kernel modules loading are not supported here"
{%- endif %}

{%- if pillar.iptables.service.enabled is defined %}
{%- set include_allowed = false %}
echo_usupported_pillars_schema:
cmd.run:
- name: echo "You are trying to use old style pillars schema. Please update pillars according to the current schema"
{%- endif %}

{%- if include_allowed %}
include:
{%- if pillar.iptables.service is defined %}
- iptables.service
{%- endif %}
- iptables.v{{ schema.epoch }}
{%- endif %}

+ 79
- 9
iptables/map.jinja Просмотреть файл

@@ -1,15 +1,85 @@
{% set schema = salt['grains.filter_by']({
'default': {
},
}, grain='os_family', merge=salt['pillar.get']('iptables:schema')) %}

{% set service = salt['grains.filter_by']({
'RedHat': {
'v4': {
'enabled': true,
'persistent_config': '/etc/sysconfig/iptables',
'pkgs': [' iptables' ],
'service': 'iptables',
'modules': [],
},
'v6': {
'enabled': true,
'persistent_config': '/etc/sysconfig/ip6tables',
'pkgs': [ 'iptables' ],
'service': 'iptables',
'modules': [],
},
},
'Debian': {
'pkgs': ['iptables','iptables-persistent' ],
'service': 'netfilter-persistent',
'v4': {
'enabled': true,
'persistent_config': '/etc/iptables/rules.v4',
'pkgs': [ 'iptables','iptables-persistent' ],
'service': 'netfilter-persistent',
'modules': [ 'iptable_filter', 'ip_tables' ],
},
'v6': {
'enabled': true,
'persistent_config': '/etc/iptables/rules.v6',
'pkgs': [ 'iptables','iptables-persistent' ],
'service': 'netfilter-persistent',
'modules': [ 'ip6table_filter', 'ip6_tables' ],
},
},
'RedHat': {
'pkgs': ['iptables'],
'service': 'iptables',
}, grain='os_family', merge=salt['pillar.get']('iptables:service')) %}

{% set defaults = salt['grains.filter_by']({
'default': {
'v4': {
'metadata_rules': false,
'policy': 'ACCEPT',
'ruleset': {
'action': 'ACCEPT',
'params': '',
'rule': '',
},
},
'v6': {
'metadata_rules': false,
'policy': 'ACCEPT',
'ruleset': {
'action': 'ACCEPT',
'params': '',
'rule': '',
},
},
},
}, merge=salt['grains.filter_by']({
'trusty': {
'service': 'iptables-persistent',
}, grain='os_family', merge=salt['pillar.get']('iptables:defaults')) %}

{% set tables = salt['grains.filter_by']({
'default': {
'v4': {
'filter': {
'chains': {
'INPUT': {},
'OUTPUT': {},
'FORWARD': {},
},
},
},
'v6': {
'filter': {
'chains': {
'INPUT': {},
'OUTPUT': {},
'FORWARD': {},
},
},
},
},
}, grain='oscodename', merge=salt['pillar.get']('iptables:service'))) %}
}, grain='os_family', merge=salt['pillar.get']('iptables:tables')) %}

+ 0
- 117
iptables/rules.sls Просмотреть файл

@@ -1,117 +0,0 @@
{% from "iptables/map.jinja" import service with context %}
{%- if grains.get('virtual_subtype', None) not in ['Docker', 'LXC'] %}

{%- set chains = service.get('chain', {}).keys() %}
{%- for chain_name, chain in service.get('chain', {}).iteritems() %}

{%- set tables = [] %}
{%- for rule in chain.get('rules', []) %}
{%- set table = rule.get('table', 'filter') %}
{%- if table not in tables %}
{%- do tables.append(table) %}
{%- endif %}
{%- endfor %}
{%- if chain.policy is defined %}
{%- if chain.policy is string %}
{%- if 'filter' not in tables %}
{%- do tables.append('filter') %}
{%- endif %}
{%- else %}
{%- for policy in chain.policy %}
{%- if policy.table not in tables %}
{%- do tables.append(policy.table) %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endif %}

{%- for table in tables %}
iptables_{{ table }}_{{ chain_name }}:
iptables.chain_present:
- family: ipv4
- name: {{ chain_name }}
- table: {{ table }}
- require:
- pkg: iptables_packages

{%- if grains.ipv6|default(False) and service.ipv6|default(True) %}
iptables_{{ table }}_{{ chain_name }}_ipv6:
iptables.chain_present:
- family: ipv6
- name: {{ chain_name }}
- table: {{ table }}
- require:
- pkg: iptables_packages
{%- if chain.policy is defined %}
{%- if chain.policy is string %}
- require_in:
- iptables: iptables_filter_{{ chain_name }}_ipv6_policy
{%- else %}
{%- if table in chain.policy %}
- require_in:
- iptables: iptables_filter_{{ chain_name }}_ipv6_policy
{%- endif %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- endfor %}

{%- if chain.policy is defined %}

{%- if chain.policy is string %}
{%- set map = [{'table':'filter', 'policy':chain.policy}] %}
{%- else %}
{%- set map = chain.policy %}
{%- endif %}

{%- for policy in map %}
iptables_{{ policy.table }}_{{ chain_name }}_policy:
iptables.set_policy:
- family: ipv4
- chain: {{ chain_name }}
- policy: {{ policy.policy }}
- table: {{ policy.table }}
- require:
- iptables: iptables_{{ policy.table }}_{{ chain_name }}

{%- if grains.ipv6|default(False) and service.ipv6|default(True) %}
iptables_{{ policy.table }}_{{ chain_name }}_ipv6_policy:
iptables.set_policy:
- family: ipv6
- chain: {{ chain_name }}
- policy: {{ policy.policy }}
- table: {{ policy.table }}
- require:
- iptables: iptables_{{ policy.table }}_{{ chain_name }}_ipv6
{%- endif %}
{%- endfor %}
{%- endif %}

{%- for service_name, service in pillar.items() %}
{%- if service is mapping %}
{%- if service.get('_support', {}).get('iptables', {}).get('enabled', False) %}

{%- set grains_fragment_file = service_name+'/meta/iptables.yml' %}
{%- macro load_grains_file() %}{% include grains_fragment_file %}{% endmacro %}
{%- set grains_yaml = load_grains_file()|load_yaml %}

{%- if grains_yaml is iterable %}
{%- if grains_yaml.get('iptables',{}).rules is defined %}
{%- for rule in grains_yaml.iptables.rules %}
{%- set rule_name = service_name+'_'+loop.index|string %}
{% include "iptables/_rule.sls" %}
{%- endfor %}
{%- endif %}
{%- endif %}

{%- endif %}
{%- endif %}
{%- endfor %}

{%- for rule in chain.get('rules', []) %}
{%- set rule_name = loop.index %}
{% include "iptables/_rule.sls" %}
{%- endfor %}

{%- endfor %}
{%- endif %}

+ 0
- 63
iptables/service.sls Просмотреть файл

@@ -1,63 +0,0 @@
{% from "iptables/map.jinja" import service with context %}

{%- if service.enabled %}

include:
- iptables.rules

iptables_packages:
pkg.installed:
- names: {{ service.pkgs }}

iptables_services:
{%- if grains.init == 'systemd' %}
service.running:
{%- else %}
service.dead:
{%- endif %}
- enable: true
- name: {{ service.service }}
- sig: test -e /etc/iptables/rules.v4
- require:
- pkg: iptables_packages

{%- else %}

iptables_services:
service.dead:
- enable: false
- name: {{ service.service }}

{%- for chain_name in ['INPUT', 'OUTPUT', 'FORWARD'] %}
iptables_{{ chain_name }}_policy:
iptables.set_policy:
- chain: {{ chain_name }}
- policy: ACCEPT
- table: filter
- require_in:
- iptables: iptables_flush

{%- if grains.ipv6|default(False) and service.ipv6|default(True) %}
iptables_{{ chain_name }}_ipv6_policy:
iptables.set_policy:
- chain: {{ chain_name }}
- family: ipv6
- policy: ACCEPT
- table: filter
- require_in:
- iptables: ip6tables_flush
{%- endif %}

{%- endfor %}

iptables_flush:
iptables.flush

{%- if grains.ipv6|default(False) and service.ipv6|default(True) %}
ip6tables_flush:
iptables.flush:
- family: ipv6
{%- endif %}


{%- endif %}

+ 72
- 0
iptables/v1/files/v4_rules Просмотреть файл

@@ -0,0 +1,72 @@
{%- from "iptables/map.jinja" import defaults,service,tables with context %}
{%- if service.v4.enabled -%}
# Generated by salt v{{ grains['saltversion'] }}
{%- if not defaults.v4.metadata_rules %}
{%- for s_name, svc in pillar.items() %}
{%- if svc is mapping %}
{%- if svc.get('_support', {}).get('iptables', {}).get('enabled', False) %}
{%- macro load_grains_file() %}{% include s_name + '/meta/iptables.yml' %}{% endmacro %}
{%- set grains_yaml = load_grains_file()|load_yaml %}
{%- if grains_yaml is iterable %}
{%- set grains_tables = grains_yaml.get('iptables', {}).get('tables', {}).get('v4', {}) %}
{%- if grains_tables is iterable %}
{%- for gt_name, gt in grains_tables.items() %}
{%- if gt_name not in tables.v4 %}
{%- do tables.v4.update( { gt_name: gt } ) %}
{%- else %}
{%- for gc_name, gc in gt.chains.items() %}
{%- set gt_obj = tables.v4.get(gt_name) %}
{%- if gc_name not in gt_obj.chains %}
{%- do gt_obj.chains.update( { gc_name: gc } ) %}
{%- else %}
{%- set gc_obj = gt_obj.chains.get(gc_name) %}
{%- if gc.ruleset is defined %}
{%- if gc_obj.ruleset is not defined %}
{%- do gc_obj.update( { 'ruleset': {} } ) %}
{%- endif %}
{%- for grule_id, gr in gc.ruleset.items()|sort %}
{%- if grule_id not in gc_obj.ruleset %}
{%- do gc_obj.ruleset.update( { grule_id: gr } ) %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- for t_name, t in tables.v4.items() %}
*{{ t_name }}
{%- for c_name, c in t.chains.items() %}
{%- if c_name in ('INPUT','FORWARD','OUTPUT','PREROUTING','POSTROUTING') %}
{%- set policy = c.get('policy', defaults.v4.policy) %}
{%- else %}
{%- set policy = "- [0:0]" %}
{%- endif %}
:{{ c_name }} {{ policy }}
{%- endfor %}
{%- for c_name, c in t.chains.items() %}
{%- for rule_id, r in c.get('ruleset', {}).items()|sort %}
{%- set rule = r.get('rule', defaults.v4.ruleset.rule) %}
{%- set action = r.get('action', defaults.v4.ruleset.action) %}
{%- set params = r.get('params', defaults.v4.ruleset.params) %}
{%- if rule != "" %}
{%- set rule = " " + rule %}
{%- endif %}
{%- if action != "" %}
{%- set action = " -j " + action %}
{%- endif %}
{%- if params != "" %}
{%- set params = " " + params %}
{%- endif %}
-A {{ c_name }}{{ rule }}{{ action }}{{ params }}
{%- endfor %}
{%- endfor %}
COMMIT
{%- endfor %}
{%- endif %}

+ 72
- 0
iptables/v1/files/v6_rules Просмотреть файл

@@ -0,0 +1,72 @@
{%- from "iptables/map.jinja" import defaults,service,tables with context %}
{%- if service.v6.enabled -%}
# Generated by salt v{{ grains['saltversion'] }}
{%- if not defaults.v6.metadata_rules %}
{%- for s_name, svc in pillar.items() %}
{%- if svc is mapping %}
{%- if svc.get('_support', {}).get('iptables', {}).get('enabled', False) %}
{%- macro load_grains_file() %}{% include s_name + '/meta/iptables.yml' %}{% endmacro %}
{%- set grains_yaml = load_grains_file()|load_yaml %}
{%- if grains_yaml is iterable %}
{%- set grains_tables = grains_yaml.get('iptables', {}).get('tables', {}).get('v6', {}) %}
{%- if grains_tables is iterable %}
{%- for gt_name, gt in grains_tables.items() %}
{%- if gt_name not in tables.v6 %}
{%- do tables.v6.update( { gt_name: gt } ) %}
{%- else %}
{%- for gc_name, gc in gt.chains.items() %}
{%- set gt_obj = tables.v6.get(gt_name) %}
{%- if gc_name not in gt_obj.chains %}
{%- do gt_obj.chains.update( { gc_name: gc } ) %}
{%- else %}
{%- set gc_obj = gt_obj.chains.get(gc_name) %}
{%- if gc.ruleset is defined %}
{%- if gc_obj.ruleset is not defined %}
{%- do gc_obj.update( { 'ruleset': {} } ) %}
{%- endif %}
{%- for grule_id, gr in gc.ruleset.items()|sort %}
{%- if grule_id not in gc_obj.ruleset %}
{%- do gc_obj.ruleset.update( { grule_id: gr } ) %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- endif %}
{%- endfor %}
{%- endif %}
{%- for t_name, t in tables.v6.items() %}
*{{ t_name }}
{%- for c_name, c in t.chains.items() %}
{%- if c_name in ('INPUT','FORWARD','OUTPUT','PREROUTING','POSTROUTING') %}
{%- set policy = c.get('policy', defaults.v6.policy) %}
{%- else %}
{%- set policy = "- [0:0]" %}
{%- endif %}
:{{ c_name }} {{ policy }}
{%- endfor %}
{%- for c_name, c in t.chains.items() %}
{%- for rule_id, r in c.get('ruleset', {}).items()|sort %}
{%- set rule = r.get('rule', defaults.v6.ruleset.rule) %}
{%- set action = r.get('action', defaults.v6.ruleset.action) %}
{%- set params = r.get('params', defaults.v6.ruleset.params) %}
{%- if rule != "" %}
{%- set rule = " " + rule %}
{%- endif %}
{%- if action != "" %}
{%- set action = " -j " + action %}
{%- endif %}
{%- if params != "" %}
{%- set params = " " + params %}
{%- endif %}
-A {{ c_name }}{{ rule }}{{ action }}{{ params }}
{%- endfor %}
{%- endfor %}
COMMIT
{%- endfor %}
{%- endif %}

+ 6
- 0
iptables/v1/init.sls Просмотреть файл

@@ -0,0 +1,6 @@
{%- from "iptables/map.jinja" import schema with context %}
{%- if pillar.iptables.service.enabled is not defined %}
include:
- iptables.v{{ schema.epoch }}.v4_service
- iptables.v{{ schema.epoch }}.v6_service
{%- endif %}

iptables/meta/sphinx.yml → iptables/v1/meta/sphinx.yml Просмотреть файл


+ 79
- 0
iptables/v1/v4_service.sls Просмотреть файл

@@ -0,0 +1,79 @@
{% from "iptables/map.jinja" import defaults,schema,service with context %}

{%- if service.v4.enabled %}

iptables_packages_v4:
pkg.installed:
- names: {{ service.v4.pkgs }}

iptables_modules_v4_load:
kmod.present:
- persist: true
- mods: {{ service.v4.modules }}
- require:
- pkg: iptables_packages_v4

{{ service.v4.persistent_config }}:
file.managed:
- user: root
- group: root
- mode: 640
- source: salt://iptables/v{{ schema.epoch }}/files/v4_rules
- template: jinja
- require:
- pkg: iptables_packages_v4

{% if grains['os'] == 'Ubuntu' %}

iptables_services_v4_start:
cmd.run:
- name: find /usr/share/netfilter-persistent/plugins.d/[0-9]*-ip4tables -exec {} start \;
- onlyif: test $(iptables-save | wc -l) -eq 0
- require:
- file: {{ service.v4.persistent_config }}
- kmod: iptables_modules_v4_load

{%- endif %}

{{ service.v4.service }}:
service.running:
- enable: true
- require:
- file: {{ service.v4.persistent_config }}
- kmod: iptables_modules_v4_load
- watch:
- file: {{ service.v4.persistent_config }}

iptables_tables_cleanup_v4:
module.wait:
- name: iptables_extra.remove_stale_tables
- config_file: {{ service.v4.persistent_config }}
- family: ipv4
- require:
- file: {{ service.v4.persistent_config }}
- watch:
- file: {{ service.v4.persistent_config }}
{%- else %}

{% if grains['os'] == 'Ubuntu' %}

iptables_services_v4_stop:
cmd.run:
- name: find /usr/share/netfilter-persistent/plugins.d/[0-9]*-ip4tables -exec {} flush \;
- onlyif: test $(which iptables-save) -eq 0 && test $(iptables-save | wc -l) -ne 0

{{ service.v4.persistent_config }}:
file.absent:
- require:
- cmd: iptables_services_v4_stop

iptables_tables_flush_v4:
module.wait:
- name: iptables_extra.flush_all
- family: ipv4
- watch:
- file: {{ service.v4.persistent_config }}

{%- endif %}

{%- endif %}

+ 79
- 0
iptables/v1/v6_service.sls Просмотреть файл

@@ -0,0 +1,79 @@
{% from "iptables/map.jinja" import defaults,schema,service with context %}

{%- if service.v6.enabled %}

iptables_packages_v6:
pkg.installed:
- names: {{ service.v6.pkgs }}

iptables_modules_v6_load:
kmod.present:
- persist: true
- mods: {{ service.v6.modules }}
- require:
- pkg: iptables_packages_v6

{{ service.v6.persistent_config }}:
file.managed:
- user: root
- group: root
- mode: 640
- source: salt://iptables/v{{ schema.epoch }}/files/v6_rules
- template: jinja
- require:
- pkg: iptables_packages_v6

{% if grains['os'] == 'Ubuntu' %}

iptables_services_v6_start:
cmd.run:
- name: find /usr/share/netfilter-persistent/plugins.d/[0-9]*-ip6tables -exec {} start \;
- onlyif: test $(ip6tables-save | wc -l) -eq 0
- require:
- file: {{ service.v6.persistent_config }}
- kmod: iptables_modules_v6_load

{%- endif %}

{{ service.v6.service }}:
service.running:
- enable: true
- require:
- file: {{ service.v6.persistent_config }}
- kmod: iptables_modules_v6_load
- watch:
- file: {{ service.v6.persistent_config }}

iptables_tables_cleanup_v6:
module.wait:
- name: iptables_extra.remove_stale_tables
- config_file: {{ service.v6.persistent_config }}
- family: ipv6
- require:
- file: {{ service.v6.persistent_config }}
- watch:
- file: {{ service.v6.persistent_config }}
{%- else %}

{% if grains['os'] == 'Ubuntu' %}

iptables_services_v6_stop:
cmd.run:
- name: find /usr/share/netfilter-persistent/plugins.d/[0-9]*-ip6tables -exec {} flush \;
- onlyif: test $(which ip6tables-save) -eq 0 && test $(ip6tables-save | wc -l) -ne 0

{{ service.v6.persistent_config }}:
file.absent:
- require:
- cmd: iptables_services_v6_stop

iptables_tables_flush_v6:
module.wait:
- name: iptables_extra.flush_all
- family: ipv6
- watch:
- file: {{ service.v6.persistent_config }}

{%- endif %}

{%- endif %}

+ 1
- 2
metadata.yml Просмотреть файл

@@ -1,4 +1,3 @@
name: "iptables"
version: "0.2"
version: "1.0.0"
source: "https://github.com/salt-formulas/salt-formula-iptables"


+ 71
- 0
tests/pillar/iptables.sls Просмотреть файл

@@ -0,0 +1,71 @@
iptables:
schema:
epoch: 1
service:
v4:
enabled: true
modules:
- nf_conntrack_ftp
- nf_conntrack_pptp
v6:
enabled: false
modules:
- nf_conntrack_ipv6
defaults:
v4:
metadata_rules: false
policy: ACCEPT
ruleset:
action: ACCEPT
params: ""
rule: ""
v6:
metadata_rules: false
policy: DROP
ruleset:
action: ACCEPT
params: ""
rule: ""
tables:
v4:
filter:
chains:
INPUT:
ruleset:
5:
action: log_drop
10:
rule: -s 192.168.0.0/24 -p tcp
log_drop:
policy: DROP
ruleset:
10:
rule: ""
action: LOG
nat:
chains:
OUTPUT:
PREROUTING:
POSTROUTING:
policy: ACCEPT
ruleset:
10:
rule: -s 192.168.0.0/24 -p tcp -o lo
action: SNAT
params: --to-source=127.0.0.1
config: v4
v6:
filter:
chains:
INPUT:
ruleset:
5:
action: log_drop
10:
rule: -s 200A:0:200C::1/64 -p tcp
log_drop:
policy: DROP
ruleset:
10:
rule: ""
action: LOG

+ 0
- 28
tests/pillar/iptables_server.sls Просмотреть файл

@@ -1,28 +0,0 @@
iptables:
service:
enabled: true
chain:
INPUT:
policy:
- table: nat
policy: ACCEPT
rules:
- position: 1
table: filter
protocol: tcp
destination_port: 8088
source_network: 127.0.0.1
jump: ACCEPT
comment: Blah
OUTPUT:
policy: ACCEPT
FORWARD:
policy:
- table: mangle
policy: DROP
POSTROUTING:
rules:
- jump: MASQUERADE
protocol: icmp
out_interface: ens3
table: nat

Загрузка…
Отмена
Сохранить