
Estoy intentando configurar una solución de administración de iptables flexible con SaltStack, pero lo encuentro más difícil de lo que pensaba.
Mi principal requisito: poder tener un pilar donde guarde una lista de IP, que deberían estar en la lista blanca para el acceso SSH en todos los minions. Esta lista de IP, por supuesto, cambiará de vez en cuando: algunas IP se agregan, otras se eliminan. El problema al que me enfrento es con las IP eliminadas: cuando las elimino del archivo pilar, SaltStack no elimina la lista blanca real de los minions.
La única solución que pude encontrar fue crear una nueva clave llamada "ips eliminadas" y cada vez que quisiera eliminar una IP, la agregaría allí. El segundo bucle for lo eliminará. Por supuesto, esta es una solución realmente desagradable, ¿existe una mejor manera de hacerlo?
/srv/pillar/iptables-default.sls:
iptables-default:
whitelisted-ips:
- '55.55.55.55'
- '66.66.66.66'
- '77.77.77.77'
removed-ips:
- '88.88.88.88'
/srv/salt/iptables-default.sls:
{% for ip in salt['pillar.get']('iptables-default:whitelisted-ips') %}
Whitelist OSF IP {{ip}} for SSH access:
iptables.append:
- table: filter
- family: ipv4
- chain: INPUT
- jump: ACCEPT
- match: state
- connstate: NEW
- source: '{{ ip }}'
- dport: 22
- proto: tcp
- save: True
{% endfor %}
{% for ip in salt['pillar.get']('iptables-default:removed-ips') %}
Remove old IPs that are not needed anymore:
iptables.delete:
- table: filter
- family: ipv4
- chain: INPUT
- jump: ACCEPT
- match: state
- connstate: NEW
- source: {{ ip }}
- dport: 22
- proto: tcp
- save: True
{% endfor %}
Respuesta1
Pasé algunas horas descubriendo la mejor manera de administrar varias configuraciones de iptables con Salt, y la mejor solución parece ser hacer una combinación de
- archivos de configuración planos de iptables (como plantillas jinja)
- haga que salt haga un lavado de iptables + restauración solo si el archivo plano cambia
así lo tengo en mi env y funciona muy bien. Intenté usar estados salt de Iptables, pero se vuelve muy engorroso e inmanejable y hay que hacerlo con fuerza iptables.flush
en cada ejecución de estado alto.
El siguiente es un enfoque más simple y manejable que evita por completo el uso de pilares.
cree un archivo plano para cada host usando {{ grains.id }}.j2 como diseño,
cat /srv/salt/state/iptables/files/nycweb1.j2
##############################################################
## This file is managed by SALTSTACK - Do not modify manually
##############################################################
*filter
:INPUT ACCEPT
:FORWARD ACCEPT
:OUTPUT ACCEPT
## Allow all loopback (lo0) traffic
-A INPUT -i lo -j ACCEPT
## Drop all traffic to 127/8 that doesn't use lo0
-A INPUT ! -i lo -d 127.0.0.0/8 -j DROP
## Accept inbound traffic for already established connections.
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
## Effectively allow all outbound traffic.
-A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
## Allow ping
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
## Blacklist
-A INPUT -s 0.0.0.0/32 -p tcp -m tcp --dport 22 -j REJECT --reject-with icmp-port-unreachable
## Whitelist
-A INPUT -s 121.236.129.235/32 -p tcp -m tcp --dport 22 -j ACCEPT {# NY office pub #}
-A INPUT -s 192.168.10.0/24 -p tcp -m tcp --dport 22 -j ACCEPT {# NY office priv #}
COMMIT
*nat
:PREROUTING ACCEPT
:INPUT ACCEPT
:OUTPUT ACCEPT
:POSTROUTING ACCEPT
-A PREROUTING -p tcp -m tcp --dport 27015 -j DNAT --to-destination 192.168.38.20
-A OUTPUT -p tcp -m addrtype --src-type LOCAL --dst-type LOCAL -m tcp --dport 1266 -j DNAT --to-destination 169.254.1.1:443
-A POSTROUTING -s 192.168.1.2/32 -d 10.3.4.65/32 -p tcp -m tcp --dport 48854 -j MASQUERADE
-A POSTROUTING -d 10.0.2.15/24 -p tcp -m tcp --dport 27045 -j SNAT --to-source 192.168.99.11 {# description #}
COMMIT
{# EOF #}
crear un archivo de estado,
cat /srv/salt/state/iptables/init.sls
# STATE - IPTABLES
{% set iptables_file = '/etc/sysconfig/iptables' %}
iptables_pkg:
pkg.installed:
- name: iptables
{{ iptables_file }}:
file.managed:
- user: root
- group: root
- mode: 644
- source: salt://{{ slspath }}/files/{{ grains.id }}.j2
- template: jinja
flush_tables:
iptables.flush:
- table: filter
- family: ipv4
- onchanges:
- file: "{{ iptables_file }}"
restore_tables:
cmd.run:
- name: "/usr/sbin/iptables-restore < {{ iptables_file }}"
- onchanges:
- file: "{{ iptables_file }}"
Eso es todo, cuando ejecuta highstate en sus objetivos, solo realizarán vaciado+restauración cada vez que se modifique el archivo plano. Su configuración también está en formato iptables nativo, no en formato pilar
ahora aplique el estado o agréguelo a su estado alto
salt nycweb01 state.sls iptables
Respuesta2
Para este tipo de cosas, manteniendo una lista de direcciones IP para uso de iptables, creamos una plantilla para el archivo de configuración "ipset" y usamos reglas de iptables que hacen referencia a ellas para listas de permitidos o denegados. Un ipset vale la pena para conjuntos grandes y administrarlos de esta manera elimina el problema de "eliminar una dirección"; Los sets se recargan por completo cada vez que algo cambia.
Gestionamos de forma centralizada redes de miles de servidores con estrictos requisitos de membresía y acceso, por lo que usar salt y una plantilla jinja para representar /etc/sysconfig/ipset tiene sentido para nosotros.