使用 Ansible 添加 iptables 规则

许多系统和应用程序需要对某些端口和协议进行某些访问。使用 Ansible 安装这些系统时,还需要打开所需的端口,以便系统能够正常运行。由于 Ansible 中没有 iptables 模块,因此需要 shell 命令来添加 iptables 规则。

例如,这里有一个任务,它添加一个 iptables 规则以允许 Apache 在端口 80 上进行通信。

- name: Apache | add apache iptable rule
  command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache"
  sudo: true

一旦到位,您可能需要保存和/或重新启动 iptables 以便永久保存规则。下面两条规则会保存iptables规则并重启iptables服务。请注意,这些命令特定于 Ubuntu,因此可能不适用于您的系统设置。

- name: save iptables
  command: iptables-save
  sudo: true
 
- name: restart iptables
  service: name=ufw state=restarted
  sudo: true

这允许 Apache 进行通信,但问题是当 Ansible 任务第二次运行时,将添加第二个 iptables 规则。这可能会导致问题,尤其是当 Ansible 一遍又一遍地运行以维护服务器的配置时。为此,必须添加另一个步骤以在添加规则之前检测规则的存在。这是通过使用 shell 模块打印可用的 iptables 规则并将它们存储到变量中来完成的。Ansible 关键字“register”允许将当前任务的任何返回值保存为变量,在这种情况下,注册的变量称为“iptablesrules”。

- name: Apache | get iptables rules
  shell: iptables -L
  register: iptablesrules
  sudo: true

有了这个,我们现在可以运行 iptables 插入命令,只有当我们找不到与我们想要添加的规则匹配的规则时。对iptablesrules.stdout参数运行 find 函数以在内容中查找单词“Apache”。这与在 iptables 规则创建中使用的注释相匹配。这是修改后的任务。

- name: Apache | add apache iptable rule
  command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache"
  sudo: true
  when: iptablesrules.stdout.find("Apache") == -1

现在唯一的问题是,当检查 Ansible playbook 是否会按预期执行时(通过使用 --check 标志),添加的条件将失败。这是因为在这种情况下生成的 iptablesrules 变量没有完成,因此 Ansible 会出错并抱怨缺少变量。解决这个问题的方法是强制 iptables 规则变量注册表任务始终运行,即使我们处于检查模式。为此,我们将 always_run 标志添加到任务中。

- name: Apache | get iptables rules
  shell: iptables -L
  register: iptablesrules
  always_run: yes
  sudo: true

这是完整的整个剧本。请注意,更好的做法是使用 create iptables save 和 restart 任务作为处理程序,并从需要的任务中通知它们。这允许在为其他服务生成 iptables 规则时重用它们。

---
- name: Apache | get iptables rules
  shell: iptables -L
  register: iptablesrules
  always_run: yes
  sudo: true
 
- name: Apache | add apache iptable rule
  command: /sbin/iptables -I INPUT 1 -p tcp --dport http -j ACCEPT -m comment --comment "Apache"
  sudo: true
  when: iptablesrules.stdout.find("Apache") == -1
 
- name: save iptables
  command: iptables-save
  sudo: true
 
- name: restart iptables
  service: name= ufw state=restarted
  sudo: true