Teste se a alteração do firewall UFW impediria que eu me reconectasse

1

Eu quero gerenciar as regras de firewall do UFW em várias máquinas remotas do Ubuntu 18.04 usando o Ansible. Se uma mudança nas regras do firewall me impedir de se reconectar às máquinas via SSH que seria muito difícil de consertar (vá ao data center com pressa, digite senhas raiz complicadas uma a uma, edite a configuração do firewall manualmente). Existe uma maneira de testar se uma alteração de regra de firewall não me impedirá de se reconectar antes que a alteração seja aplicada?

Como alternativa, existe uma maneira de restaurar automaticamente as regras de firewall se elas forem aplicadas e eu estiver bloqueado? (Eu poderia fazer o meu próprio backup e configurar um cron job para restaurá-lo, em seguida, conectar-se novamente e excluir o cron job, mas talvez algo como isso já existe?)

    
por EM0 03.08.2018 / 15:15

3 respostas

2

Não embutido no módulo ufw. E as alterações que você está fazendo serão aplicadas na próxima reinicialização ou no recarregamento do firewall.

O que você pode fazer é recarregar o firewall e testar uma nova conexão com a porta SSH. Se isso falhar, reinicie o ufw através da conexão persistente ainda aberta.

Eu tenho uma implementação deste chato chamado ansible-role-ufw . Observe, em particular, o uso de wait_for , pois wait_for_connection usará a conexão persistente e não detectará a falha.

Cuidado com o fato de que isso tem uma chance de funcionar. Você ainda precisa de acesso remoto ao console para quando o SSH estiver quebrado.

    
por 05.08.2018 / 22:35
1

Aplique as regras manualmente, sem salvá-las, mas antes disso, agende uma reinicialização ou redefina as regras atuais após alguns minutos. Então, se a nova regra causar algum dano, será apenas por alguns minutos.

    
por 03.08.2018 / 15:41
0

Foi com isso que acabei, estendendo o código do John Mahowald :

roles / set_firewall_rules / tasks / main.yml

# Apply all the requested firewall rules, then try to establish a new SSH connection to the host.
# If that SSH connection fails then reset the firewall, so the user is not locked out of the machine!

# Make sure the SSH connection details figured out by target_ssh_info can actually be used to connect before the change.
# If they're not we'd end up resetting the firewall after ANY change.
- name: Try to SSH before updating firewall
  become: no
  wait_for:
    host: "{{ target_ssh_host }}"
    port: "{{ target_ssh_port }}"
    search_regex: SSH
    timeout: 5
    msg: "Failed to connect to {{ target_ssh_host }}:{{ target_ssh_port }} before firewall rule change"
  connection: local

- name: Set firewall rules
  ufw:
    src: "{{ item.src }}"
    port: "{{ item.port }}"
    proto: "{{ item.proto }}"
    rule: "{{ item.rule }}"
    comment: "{{ item.comment }}"
  register: firewall_rules
  loop: "{{ rules }}"

# Enable/reload the firewall as a separate task, after all rules have been added, so that the order of rules doesn't matter, i.e. we're not locked out
# if a deny rule comes before an allow rule (as it should).
- name: Enable and reload firewall
  ufw:
    state: enabled
  register: firewall_enabled

- name: Try to SSH after updating firewall
  become: no
  # wait_for is key here: it establishes a new connection, while wait_for_connection would re-use the existing one
  wait_for:
    host: "{{ target_ssh_host }}"
    port: "{{ target_ssh_port }}"
    search_regex: SSH
    timeout: 5
    msg: "Failed to connect to {{ target_ssh_host }}:{{ target_ssh_port }} after firewall rule change, trying to reset ufw"
  when: firewall_rules.changed or firewall_enabled.changed
  connection: local
  ignore_errors: yes
  register: ssh_after_ufw_change

# Reset the firewall if the new connection failed above. This works (mostly!), because it uses the existing connection
- name: Reset firewall if unable to SSH
  ufw:
    state: reset
  when:
    - firewall_rules.changed or firewall_enabled.changed
    - ssh_after_ufw_change.failed

# Stop the playbook - the host is now open to the world (firewall is off), which the user really needs to fix ASAP.
# It's probably better than being locked out of it, though!
- name: Fail if unable to SSH after firewall change
  fail:
    msg: "Locked out of SSH after firewall rule changes - firewall was reset"
  when:
    - firewall_rules.changed or firewall_enabled.changed
    - ssh_after_ufw_change.failed

roles / set_firewall_rules / meta / main.yml

---
dependencies:
- { role: target_ssh_info }

roles / target_ssh_info / tasks / main.yml

# Set target_ssh_host and target_ssh_port facts to the real hostname and port SSH uses to connect.

# ansible_host and ansible_port can be set at the host level to define what Ansible passes to ssh, but ssh then looks up ansible_host in ~/.ssh/config.
# This role figure out the real hostname it then connects to - useful for establishing a non-SSH connection to the same host.
# ansible_port is similar, but a little different: if set it overrides the value in ~/.ssh/config.

- name: Get hostname from local SSH config
  shell: "ssh -G '{{ ansible_host | default(inventory_hostname) }}' | awk '/^hostname / { print $2 }'"
  connection: local
  become: no
  register: ssh_host
  changed_when: false

- name: Get port from local SSH config
  shell: "ssh -G '{{ ansible_host | default(inventory_hostname) }}' | awk '/^port / { print $2 }'"
  connection: local
  become: no
  register: ssh_port
  changed_when: false
  when: ansible_port is not defined

# ansible_port overrides whatever is set in .ssh/config
- name: Set target SSH host and port
  set_fact:
    target_ssh_host: "{{ ssh_host.stdout }}"
    target_ssh_port: "{{ ansible_port | default (ssh_port.stdout) }}"

Observe que ssh -G retorna o nome do host e a porta, mesmo que não sejam substituídos em .ssh / config, ou seja, ssh -G arbitrarystring apenas retorna "arbitrarystring" como o nome do host e 22 como a porta.

    
por 10.08.2018 / 11:35