Gerenciando IPtables de forma eficiente com Saltstack

Gerenciando IPtables de forma eficiente com Saltstack

Estou tentando configurar uma solução flexível de gerenciamento de iptables com SaltStack, mas acho mais difícil do que pensei que seria.

Meu principal requisito: poder ter um pilar onde guardo uma lista de IPs, que deveriam estar na lista de permissões para acesso SSH em todos os minions. É claro que esta lista de IPs mudará de vez em quando: alguns IPs são adicionados, alguns IPs são removidos. O problema que estou enfrentando são os IPs removidos - quando eu os removo do arquivo pilar, o SaltStack não remove a lista de permissões real dos minions.

A única solução alternativa que consegui encontrar foi criar uma nova chave chamada "removed-ips" e sempre que eu quiser remover um IP, eu o adicionaria lá. O segundo loop for irá removê-lo. Claro, esta é uma solução alternativa realmente desagradável. Existe uma maneira melhor de fazer isso?

/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 %}

Responder1

Passei algumas horas descobrindo a melhor maneira de gerenciar várias configurações do iptables com Salt, e a melhor solução parece ser fazer uma combinação de

  1. arquivos de configuração flat iptables (como modelos jinja)
  2. faça com que o salt faça um iptables flush + restaure apenas se o arquivo simples for alterado

é assim que tenho no meu ambiente e funciona muito bem. Eu tentei usar estados salt Iptables, mas fica muito complicado e incontrolável e você tem que fazer isso com força iptables.flushem cada execução de estado alto,

A seguir está uma abordagem mais simples e gerenciável que evita completamente o uso de pilares,


crie um arquivo simples para cada host usando {{grains.id}}.j2 como layout,

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 #}

crie um arquivo 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 }}"

é isso, quando você executa highstate em seus alvos, eles só farão flush+restore sempre que o arquivo simples for modificado. Sua configuração também está no formato iptables nativo, não no formato pilar

agora aplique o estado ou adicione-o ao seu estado mais alto

salt nycweb01 state.sls iptables

Responder2

Para esse tipo de coisa, mantendo uma lista de endereços IP para uso pelo iptables, modelamos o arquivo de configuração "ipset" e usamos regras de iptables que os referenciam para listas de permissão ou negação. Um ipset compensa para conjuntos grandes, e gerenciá-los dessa forma elimina o problema de “remover um endereço”; os conjuntos são completamente recarregados sempre que algo muda.

Estamos gerenciando centralmente redes de milhares de servidores com requisitos rígidos de adesão e acesso, portanto, usar salt e um modelo jinja para renderizar /etc/sysconfig/ipset faz sentido para nós.

informação relacionada