Ansible ile Firewall Kural Yönetimi: iptables ve firewalld Otomasyonu

Firewall kurallarını elle yönetmek, onlarca sunucu olduğunda kabusa dönüşür. Bir kural eklemeyi unutursun, test ortamıyla production arasında farklılıklar oluşur, değişiklikleri kim yaptı bilemezsin. Ansible bu karmaşayı ortadan kaldırıyor. Hem iptables hem de firewalld için güçlü modüller sunuyor ve tüm kural yönetimini kod olarak ifade etmeni sağlıyor. Bu yazıda gerçek dünya senaryolarıyla Ansible’ın firewall otomasyon yeteneklerini derinlemesine inceleyeceğiz.

Neden Ansible ile Firewall Yönetimi?

Manuel firewall yönetiminin sorunları saymakla bitmez. Sunucu sayısı arttıkça tutarsızlıklar kaçınılmaz hale gelir. Bir sysadmin SSH erişimini açık bırakır, diğeri unutur. Audit loglarına bakarsın, kim ne zaman hangi kuralı ekledi belli değildir.

Ansible bu sürecin önüne geçiyor:

  • İdempotent yapı: Playbook’u kaç kez çalıştırsan da sonuç aynı olur, kural zaten varsa tekrar eklenmez
  • Version control entegrasyonu: Tüm firewall kuralların Git’te, değişiklik geçmişi şeffaf
  • Merkezi yönetim: Yüzlerce sunucuya aynı anda kural uygulayabilirsin
  • Test edilebilirlik: Staging ortamında önce test et, sonra production’a taşı
  • Hata azaltma: Yazım hataları ve unutulan adımlar tarihe karışır

iptables Yönetimi

Temel iptables Modülü

Ansible’ın ansible.builtin.iptables modülü, doğrudan iptables kurallarını yönetmeni sağlar. CentOS 7 öncesi sistemlerde ve iptables’ı tercih eden ortamlarda sıklıkla kullanılır.

Basit bir HTTP/HTTPS erişim kuralı ekleyelim:

---
- name: Temel Web Sunucusu Firewall Kuralları
  hosts: webservers
  become: yes
  tasks:
    - name: HTTP trafiğine izin ver
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        destination_port: 80
        jump: ACCEPT
        comment: "Ansible tarafından yönetilir - HTTP"

    - name: HTTPS trafiğine izin ver
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        destination_port: 443
        jump: ACCEPT
        comment: "Ansible tarafından yönetilir - HTTPS"

    - name: SSH erişimine izin ver
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        destination_port: 22
        jump: ACCEPT
        comment: "Ansible tarafından yönetilir - SSH"

    - name: Loopback trafiğine izin ver
      ansible.builtin.iptables:
        chain: INPUT
        in_interface: lo
        jump: ACCEPT

    - name: Kurulu bağlantılara izin ver
      ansible.builtin.iptables:
        chain: INPUT
        ctstate: ESTABLISHED,RELATED
        jump: ACCEPT

IP Bazlı Kısıtlamalar

Gerçek dünyada genellikle belirli IP adreslerinden belirli portlara erişimi kısıtlaman gerekir. Örneğin, veritabanı sunucusuna sadece uygulama sunucularından erişim:

---
- name: Veritabanı Sunucusu Güvenlik Kuralları
  hosts: database_servers
  become: yes
  vars:
    app_servers:
      - "10.0.1.10"
      - "10.0.1.11"
      - "10.0.1.12"
    admin_network: "10.0.100.0/24"

  tasks:
    - name: Uygulama sunucularından MySQL erişimine izin ver
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        source: "{{ item }}"
        destination_port: 3306
        jump: ACCEPT
        comment: "App server DB erişimi"
      loop: "{{ app_servers }}"

    - name: Admin ağından SSH erişimine izin ver
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        source: "{{ admin_network }}"
        destination_port: 22
        jump: ACCEPT
        comment: "Admin SSH erişimi"

    - name: Diğer tüm gelen trafiği engelle
      ansible.builtin.iptables:
        chain: INPUT
        policy: DROP

iptables Kurallarını Kalıcı Hale Getirmek

iptables kurallarının en büyük sorunu, sistem yeniden başladığında kaybolmasıdır. Bunu çözmek için iptables-save kullanmalısın:

---
- name: iptables Kurallarını Kalıcı Hale Getir
  hosts: all
  become: yes
  tasks:
    - name: iptables-persistent paketini kur (Debian/Ubuntu)
      ansible.builtin.apt:
        name: iptables-persistent
        state: present
      when: ansible_os_family == "Debian"

    - name: iptables-services paketini kur (RHEL/CentOS)
      ansible.builtin.yum:
        name: iptables-services
        state: present
      when: ansible_os_family == "RedHat"

    - name: Kuralları kaydet (Debian/Ubuntu)
      ansible.builtin.shell: |
        iptables-save > /etc/iptables/rules.v4
        ip6tables-save > /etc/iptables/rules.v6
      when: ansible_os_family == "Debian"
      changed_when: true

    - name: iptables servisini etkinleştir (RHEL/CentOS)
      ansible.builtin.service:
        name: iptables
        enabled: yes
        state: started
      when: ansible_os_family == "RedHat"

    - name: Kuralları kaydet (RHEL/CentOS)
      ansible.builtin.shell: service iptables save
      when: ansible_os_family == "RedHat"
      changed_when: true

firewalld Yönetimi

firewalld Temelleri

firewalld, RHEL/CentOS 7 ve sonrası ile modern Linux dağıtımlarında varsayılan firewall çözümüdür. Zone kavramıyla çalışır ve dinamik kural değişikliğini destekler. Ansible’ın ansible.posix.firewalld modülü bu sistemi son derece temiz bir şekilde yönetmeni sağlar.

---
- name: firewalld Temel Yapılandırması
  hosts: rhel_servers
  become: yes
  tasks:
    - name: firewalld'ı kur
      ansible.builtin.yum:
        name: firewalld
        state: present

    - name: firewalld'ı başlat ve etkinleştir
      ansible.builtin.service:
        name: firewalld
        state: started
        enabled: yes

    - name: HTTP servisine izin ver
      ansible.posix.firewalld:
        service: http
        permanent: yes
        state: enabled
        zone: public

    - name: HTTPS servisine izin ver
      ansible.posix.firewalld:
        service: https
        permanent: yes
        state: enabled
        zone: public

    - name: SSH servisine izin ver
      ansible.posix.firewalld:
        service: ssh
        permanent: yes
        state: enabled
        zone: public

    - name: Kuralları yeniden yükle
      ansible.builtin.command: firewall-cmd --reload
      changed_when: true

Zone Bazlı Yapılandırma

firewalld’ın en güçlü özelliği zone yönetimidir. Farklı ağ segmentleri için farklı güvenlik politikaları tanımlayabilirsin:

---
- name: firewalld Zone Yapılandırması
  hosts: edge_servers
  become: yes
  vars:
    internal_zone: "internal"
    dmz_zone: "dmz"
    internal_interface: "eth1"
    dmz_interface: "eth2"

  tasks:
    - name: Internal zone'a interface ata
      ansible.posix.firewalld:
        zone: "{{ internal_zone }}"
        interface: "{{ internal_interface }}"
        permanent: yes
        state: enabled

    - name: DMZ zone'a interface ata
      ansible.posix.firewalld:
        zone: "{{ dmz_zone }}"
        interface: "{{ dmz_interface }}"
        permanent: yes
        state: enabled

    - name: Internal zone'da yönetim portlarına izin ver
      ansible.posix.firewalld:
        zone: "{{ internal_zone }}"
        port: "{{ item }}/tcp"
        permanent: yes
        state: enabled
      loop:
        - "22"
        - "9090"
        - "8080"

    - name: DMZ zone'da sadece web portlarına izin ver
      ansible.posix.firewalld:
        zone: "{{ dmz_zone }}"
        port: "{{ item }}/tcp"
        permanent: yes
        state: enabled
      loop:
        - "80"
        - "443"

    - name: DMZ'den internal'a geçişi engelle
      ansible.posix.firewalld:
        zone: "{{ dmz_zone }}"
        rich_rule: "rule family='ipv4' source address='172.16.0.0/24' reject"
        permanent: yes
        state: enabled

    - name: Yapılandırmayı yeniden yükle
      ansible.builtin.command: firewall-cmd --reload
      changed_when: true

Rich Rules Kullanımı

firewalld’ın rich rules özelliği, iptables’a benzer detaylı kural tanımlamanı sağlar:

---
- name: firewalld Rich Rules Yapılandırması
  hosts: application_servers
  become: yes
  vars:
    monitoring_server: "10.0.200.50"
    backup_server: "10.0.200.60"
    allowed_admin_ips:
      - "192.168.1.100"
      - "192.168.1.101"

  tasks:
    - name: Monitoring sunucusundan SNMP erişimine izin ver
      ansible.posix.firewalld:
        rich_rule: >
          rule family='ipv4'
          source address='{{ monitoring_server }}/32'
          port port='161' protocol='udp'
          accept
        permanent: yes
        state: enabled
        zone: public

    - name: Backup sunucusundan rsync erişimine izin ver
      ansible.posix.firewalld:
        rich_rule: >
          rule family='ipv4'
          source address='{{ backup_server }}/32'
          port port='873' protocol='tcp'
          accept
        permanent: yes
        state: enabled
        zone: public

    - name: Admin IP'lerinden SSH'a izin ver
      ansible.posix.firewalld:
        rich_rule: >
          rule family='ipv4'
          source address='{{ item }}/32'
          service name='ssh'
          accept
        permanent: yes
        state: enabled
        zone: public
      loop: "{{ allowed_admin_ips }}"

    - name: Brute force koruması için rate limiting uygula
      ansible.posix.firewalld:
        rich_rule: >
          rule family='ipv4'
          service name='ssh'
          limit value='3/m'
          accept
        permanent: yes
        state: enabled
        zone: public

Gerçek Dünya Senaryosu: Çok Katmanlı Uygulama Güvenliği

Diyelim ki üç katmanlı bir uygulaman var: web sunucuları, uygulama sunucuları ve veritabanı sunucuları. Her katmanın farklı güvenlik kurallarına ihtiyacı var.

Inventory Yapısı

# inventory/production/hosts.ini
[webservers]
web01 ansible_host=10.0.1.10
web02 ansible_host=10.0.1.11

[appservers]
app01 ansible_host=10.0.2.10
app02 ansible_host=10.0.2.11

[dbservers]
db01 ansible_host=10.0.3.10

[production:children]
webservers
appservers
dbservers

Grup Değişkenleri ile Esnek Kural Yönetimi

# group_vars/webservers.yml
firewall_type: firewalld
allowed_services:
  - http
  - https
allowed_ports:
  - port: "8080"
    proto: tcp
blocked_ips:
  - "185.220.101.0/24"  # Bilinen kötü amaçlı blok
  - "45.155.205.0/24"

# group_vars/appservers.yml
firewall_type: firewalld
allowed_services:
  - ssh
allowed_ports:
  - port: "8443"
    proto: tcp
  - port: "9000"
    proto: tcp
allowed_sources:
  - "10.0.1.0/24"  # Sadece web sunucu ağından erişim

# group_vars/dbservers.yml
firewall_type: iptables
db_port: 3306
allowed_db_sources:
  - "10.0.2.10"
  - "10.0.2.11"

Ana Playbook

---
- name: Çok Katmanlı Uygulama Firewall Yönetimi
  hosts: production
  become: yes

  pre_tasks:
    - name: Mevcut firewall durumunu kontrol et
      ansible.builtin.command: systemctl is-active firewalld
      register: firewalld_status
      changed_when: false
      failed_when: false

  roles:
    - role: firewall_common
    - role: firewall_webserver
      when: inventory_hostname in groups['webservers']
    - role: firewall_appserver
      when: inventory_hostname in groups['appservers']
    - role: firewall_dbserver
      when: inventory_hostname in groups['dbservers']

  post_tasks:
    - name: Firewall durumunu doğrula
      ansible.builtin.command: firewall-cmd --list-all
      register: firewall_status
      changed_when: false
      when: ansible_os_family == "RedHat"

    - name: Firewall durumunu göster
      ansible.builtin.debug:
        var: firewall_status.stdout_lines
      when: ansible_os_family == "RedHat"

Firewall Kurallarını Test Etmek

Kural uyguladıktan sonra doğrulama yapmak kritik önem taşır. Ansible ile bu süreci de otomatize edebilirsin:

---
- name: Firewall Kurallarını Doğrula
  hosts: all
  become: yes
  tasks:
    - name: Açık portları listele (ss komutu ile)
      ansible.builtin.command: ss -tlnp
      register: open_ports
      changed_when: false

    - name: firewalld aktif kurallarını kontrol et
      ansible.builtin.command: firewall-cmd --list-all-zones
      register: fw_zones
      changed_when: false
      when: ansible_os_family == "RedHat"

    - name: iptables kurallarını kontrol et
      ansible.builtin.command: iptables -L -n -v
      register: ipt_rules
      changed_when: false
      when: ansible_os_family == "Debian"

    - name: Kritik portların açık olduğunu doğrula
      ansible.builtin.wait_for:
        host: "{{ ansible_default_ipv4.address }}"
        port: "{{ item }}"
        timeout: 5
        state: started
      loop:
        - 22
        - 80
        - 443
      ignore_errors: yes
      register: port_check

    - name: Port kontrol sonuçlarını göster
      ansible.builtin.debug:
        msg: "Port {{ item.item }}: {{ 'AÇIK' if not item.failed else 'KAPALI' }}"
      loop: "{{ port_check.results }}"

Handler Kullanımı ile Akıllı Yeniden Yükleme

Firewall kuralları değiştiğinde servisi yeniden yüklemek gerekir. Bu işlemi handler’larla şöyle düzenleyebilirsin:

---
- name: Handler Tabanlı Firewall Yönetimi
  hosts: all
  become: yes
  handlers:
    - name: Reload firewalld
      ansible.builtin.command: firewall-cmd --reload
      changed_when: true

    - name: Save iptables rules
      ansible.builtin.shell: |
        if command -v iptables-save > /dev/null 2>&1; then
          iptables-save > /etc/iptables/rules.v4
        fi
      changed_when: true

  tasks:
    - name: Web servisi kuralı ekle
      ansible.posix.firewalld:
        service: http
        permanent: yes
        state: enabled
        zone: public
      notify: Reload firewalld

    - name: Özel port kuralı ekle
      ansible.posix.firewalld:
        port: "8080/tcp"
        permanent: yes
        state: enabled
        zone: public
      notify: Reload firewalld

    - name: iptables kuralı ekle
      ansible.builtin.iptables:
        chain: INPUT
        protocol: tcp
        destination_port: 9000
        jump: ACCEPT
      notify: Save iptables rules
      when: ansible_os_family == "Debian"

İpuçları ve Dikkat Edilmesi Gerekenler

SSH bağlantısını kesmemek: Firewall kurallarını uygularken ilk olarak SSH kuralını ekle, en sona da varsayılan politikayı sıkılaştır. Aksi halde Ansible’ın sunucuya erişimi kesilir.

Kalıcılık kontrolü: firewalld’da permanent: yes ile birlikte immediate etkisi için ayrıca --reload yapmayı unutma. Sadece permanent: yes koymak kuralı dosyaya yazar ama hemen aktif etmez.

Idempotency testi: Playbook’u iki kez çalıştır, ikinci çalışmada hiçbir görev “changed” durumuna geçmemeli.

Rol ayırımı: Web sunucusu, uygulama sunucusu ve veritabanı sunucusu kurallarını ayrı role’lere yaz. Hem okunabilirliği artırır hem de bakımı kolaylaştırır.

Değişken hassasiyeti: İzin verilen IP listelerini group_vars veya Ansible Vault’ta tut. Kod içine gömmekten kaçın.

Önce test ortamı: Her yeni firewall politikasını mutlaka staging’de dene. Production’da bir kural hatası ciddi kesintiye yol açabilir.

Mevcut kuralları temizlemek: Bazen sıfırdan başlamak gerekir. flush parametresiyle tüm zincirleri temizleyebilirsin ama bu işlemi yaparken çok dikkatli ol.

Log kuralları ekle: Engellenen trafiği loglayan kurallar eklemek, sorun giderme sürecini büyük ölçüde kolaylaştırır. firewalld’da rich rules içinde log aksiyonunu kullanabilirsin.

Sonuç

Ansible ile firewall yönetimi, güvenlik politikalarını kod olarak ifade etmenin en temiz yollarından biri. iptables’ın esnekliği ile firewalld’ın zone bazlı yaklaşımı arasındaki farkı anlayıp her iki sistemi de Ansible ile yönetebilmek, sysadmin olarak güvenlik otomasyonunda ciddi bir olgunluk seviyesi demek.

Burada anlattığımız yapıyı kurduğunda, yeni bir sunucu eklediğinde tek yapman gereken inventory’ye ekleyip playbook’u çalıştırmak. Tüm güvenlik kuralları otomatik olarak uygulanıyor, version history Git’te, değişiklikler denetlenebilir. Onlarca sunucuya aynı anda kural uygulamak, bireysel sunucularda hata riskini ortadan kaldırmak ve firewall politikalarını yazılım geliştirme sürecine dahil etmek artık çok daha kolay.

Bir sonraki adımda bu playbook’ları CI/CD pipeline’ına entegre edip her değişiklikte otomatik test çalıştırmayı hedefleyebilirsin. Güvenlik konfigürasyonlarının da kod gibi test edilmesi gerektiğini hiç unutma.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir