Customer-Found Prod-Related: CEEMCP-19 Prod-Related: PROD-22620 Change-Id: Ib14838becc409c2f735d93b5fa8a8ead6ea1a5ecmaster^2
@@ -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 |
@@ -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 |
@@ -1,7 +1,6 @@ | |||
iptables-salt-formula | |||
===================== | |||
iptables-formula | |||
================ | |||
1.0.0 | |||
0.0.1 (2015-08-03) | |||
- Initial formula setup | |||
- Initial setup |
@@ -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. |
@@ -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 @@ | |||
0.2 | |||
1.0.0 |
@@ -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 |
@@ -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 |
@@ -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. |
@@ -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. | |||
. |
@@ -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 |
@@ -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 %} |
@@ -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')) %} |
@@ -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 %} |
@@ -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 %} |
@@ -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 %} |
@@ -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 %} |
@@ -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 %} |
@@ -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 %} |
@@ -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,4 +1,3 @@ | |||
name: "iptables" | |||
version: "0.2" | |||
version: "1.0.0" | |||
source: "https://github.com/salt-formulas/salt-formula-iptables" | |||
@@ -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 |
@@ -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 |