Com a instalação e configuração dos serviços de email e agenda concluídos, o momento de colocar nosso servidor em produção se aproxima.

Os últimos passos antes disso são os arremates de uns detalhezinhos que ficaram para o final. Isso não significa que eles não são importantes e devam ser negligenciados. Au contraire! Eles são essenciais! São eles: o firewall, a rotação de logs e a inicialização automática de todos os serviços que instalamos e configuramos.

Partiu?

Firewall local

Lá na parte IV eu disse que:

Nosso servidor terá um firewall local, via iptables, que não depende dos security groups (SG), e também os SGs. Isso é efetivamente uma camada dupla de firewall.

É agora que faremos isso. Primeiro vamos compor a primeira camada de firewall, a que roda localmente no próprio servidor.

O firewall iptables do Linux é um assunto muito particular, tipo nariz e orifício retrofuricular. Existe uma imensidão de formas de implementar firewalls iptables. Cada um tem o seu modo preferido de fazer isso. Não sou eu que vou dizer para você como isso deve ser feito. Fique a vontade para usar o seu próprio modo.

Mas para quem nunca criou um script de firewall, vou mostrar um jeito, o mais simples que eu consegui produzir. Ele é tão simples justamente porque isso pode ser estendido à exaustão e eu só quero mostrar o que é absolutamente essencial para ser exposto ou protegido em nosso contexto de uso: um servidor de emails e agendas. É por essa razão que eu chamo o meu script de 'Firewall Fodidamente Estúpido e Simples', ou FSSF na sigla em inglês.

Isto posto, deixo o aviso:

Nunca, jamais, em hipótese alguma e pelo tempo que a humanidade existir use o FSSF em produção! Crie o seu próprio script para substituí-lo!

Combinado? Ótimo!

Crie o arquivo /etc/rc.d/rc.firewall e coloque isso dentro dele. Esse conteúdo é o meu FSSF em si.

#! /bin/bash
iptables -F
iptables -X
echo FSSF - Fucking Simple and Stupid Firewall is loading...
echo "  !!!BE VERY WARNED!!!"
echo "  !!!THIS IS NOT MEANT FOR PRODUCTION USE!!!"

echo "    [Ruleset 1] Allowing loopback..."
iptables -A INPUT -s 127.0.0.1 -j ACCEPT
echo "                  (so localhost can talk to itself)"

echo "    [Ruleset 2] Allowing ICMP packets..."
iptables -A INPUT -p icmp -j ACCEPT
echo "                  (good for ping)"

echo "    [Ruleset 3] Allowing SSH service..."
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
echo "                  (remote terminal sessions)"

echo "    [Ruleset 4] Allowing email related services..."
iptables -A INPUT -p tcp --dport 25 -j ACCEPT
iptables -A INPUT -p tcp --dport 587 -j ACCEPT
iptables -A INPUT -p tcp --dport 993 -j ACCEPT
iptables -A INPUT -p tcp --dport 4190 -j ACCEPT
echo "                  (SMTP, submission, IMAPS and sieve)"

echo "    [Ruleset 5] Allowing HTTPS services..."
iptables -A INPUT -p tcp --dport 3443 -j ACCEPT
iptables -A INPUT -p tcp --dport 8443 -j ACCEPT
echo "                  (ViMbAdmin and Horde)"

echo "    [Ruleset 6] Allowing established connections..."
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
echo "                  (keep valid connections alive)"

echo "    [Ruleset 7] Rejecting all remaining traffic..."
iptables -A INPUT -j REJECT
iptables -A FORWARD -j REJECT
echo "                  (kick all that bastard asses)"

echo "  !!!BE VERY WARNED!!!"
echo "  !!!THIS IS NOT MEANT FOR PRODUCTION USE!!!"
echo FSSF - Fucking Simple and Stupid Firewall loading is DONE.

O que o FSSF faz e que o seu script de firewall também deverá fazer? Vamos por partes:

  1. A primeira regra (Ruleset 1) permite todo o tráfego do localhost para ele mesmo. Isso é essencial para os nossos serviços que respondem no IP 127.0.0.1.
  2. A segunda regra permite tráfego de coisas que possibilitam, por exemplo, que você faça ping no servidor. Se quiser deixar essa regra de fora, fique a vontade.
  3. A terceira regra permite conexões ao servidor SSH (porta 22). Queremos administrar o servidor, certo?
  4. A quarta regra permite conexões a todos os serviços relacionados ao email (SMTP: 25, submission: 587, IMAPS: 993 and sieve: 4190).
  5. A quinta regra permite conexões via web ao ViMbAdmin (3443) e Horde (serviços Cal/CardDAV e interface web, 8443).
  6. A sexta regra faz com que as conexões já estabelecidas em qualquer um dos serviços anteriores sejam mantidas.
  7. A sétima regra rejeita todo o resto de conexões possíveis.

Todas as regras têm um comportamento comum: elas permitem conexões vindas de qualquer lugar na internet. Se você tem IP dinâmico, não terá pra onde correr a não ser deixar assim. Se você usar o script de firewall para permitir acesso SSH somente a partir do seu IP atual e depois de alguns dias ele mudar, você perderá o acesso ao seu servidor via SSH e o novo dono do IP é quem terá esse acesso. O iptables só entende IP, não dá para colocar aquele DNS dinâmico maroto nele.

Mas se seu IP é fixo, poderá melhorar isso permitindo conexões apenas a partir do seu IP em alguns serviços. Na verdade, apenas o serviço SMTP na porta 25 precisa estar aberto a toda a internet. Afinal como você vai receber emails de fora se ninguém consegue conectar no seu SMTP?

Agora vamos rodar o FSSF.

# chmod 755 /etc/rc.d/rc.firewall
# /etc/rc.d/rc.firewall
FSSF - Fucking Simple and Stupid Firewall is loading...
!!!BE VERY WARNED!!!
!!!THIS IS NOT MEANT FOR PRODUCTION USE!!!
  [Ruleset 1] Allowing loopback...
                (so localhost can talk to itself)
  [Ruleset 2] Allowing ICMP packets...
                (good for ping)
  [Ruleset 3] Allowing SSH service...
                (remote terminal sessions)
  [Ruleset 4] Allowing email related services...
                (SMTP, submission, IMAPS and sieve)
  [Ruleset 5] Allowing HTTPS services...
                (ViMbAdmin and Horde)
  [Ruleset 6] Allowing established connections...
                (keep valid connections alive)
  [Ruleset 7] Rejecting all remaining traffic...
                (kick all that bastard asses)
!!!BE VERY WARNED!!!
!!!THIS IS NOT MEANT FOR PRODUCTION USE!!!
FSSF - Fucking Simple and Stupid Firewall loading is DONE.

Se você viu isso, o FSSF rodou direito. Quer conferir?

# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  localhost            anywhere
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:smtp
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:submission
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:imaps
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:sieve
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:8443
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:22443
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
REJECT     all  --  anywhere             anywhere             reject-with icmp-port-unreachable

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             state NEW,RELATED,ESTABLISHED

Isso prova que as regras do FSSF foram carregadas adequadamente. Você pode testar isso a partir de qualquer servidor externo. Tente fazer uma conexão da sua máquina local via telnet em qualquer uma das portas que não esteja aberta. Outro teste: comente a regra 2 (icmp), rode o script novamente e tente fazer um ping para o servidor. Se não houver resposta, seu firewall está ok.

Como você deve ter notado, o FSSF é estúpido e fodido porque ele não tem métodos para inciar (start) ou parar (stop). Ele carrega as regras e foda-se. Se você quiser remover todas as regras do iptables, use os comandos:

# iptables -F
# iptables -X
# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Os dois primeiros comandos (-F e -X) limpam o iptables e o terceiro (-L) lista. Se a saída for semelhante, seu firewall foi desativado. Agora é só rodar o FSSF novamente para carregar as regras.

Quando você reinicializar o servidor, o FSSF será executado automaticamente. Ele foi colocado em /etc/rc.d/rc.firewall justamente para que isso aconteça, uma vez que é nesse local que a inicialização do Slackware espera que o script de firewall esteja. O script que o carrega automaticamente é o /etc/rc.d/rc.inet2.

Nossa primeira camada de proteção está pronta e o servidorzinho está minimante protegido. Agora vamos a segunda camada, a que fica no AWS.

Firewall na nuvem

O AWS implementa um recurso que eles chamam de Security Groups. Isso é um nome comercial para o bom e velho firewall. Há poucos detalhes sobre como o AWS implementa isso internamente. Esse software é fechado. Portanto não podemos confiar nele sozinho para ser o nosso firewall. Daí a necessidade do firewall local que implementamos acima.

Mas já que dispomos do firewall na nuvem, por que não usá-lo? Ele tem lá a sua utilidade.

Acesse o seu console do AWS e vá direto em VPC. No menu lateral, clique em Security Groups. Vamos criar quatro Security Groups distintos: acesso ao email, acesso às agendas, acesso administrativo e emergências.

Clique no botão 'Create Security Group'. O primeiro grupo conterá essas configurações:

  • Name tag: vpc.sg.mail
  • Group name: vpc.sg.mail
  • Description: allow secure email
  • VPC: selecione o VPC onde a instância do seu servidor está.

Clique em 'Yes, Create'. O novo Security Group vai aparecer na lista. Clique nele. Na parte debaixo da tela você verá as propriedades do Security Group selecionado e quatro abas. Clique na aba 'Inbound Rules' e no botão 'Edit' dentro dela.

Você deve definir as regras abaixo. Para adicionar novas regras, basta clicar no botão 'Add another rule'.

Type            | Protocol | Port Range | Source
----------------+----------+------------+----------
SMTP (25)       | TCP (6)  | 25         | 0.0.0.0/0
Custom TCP Rule | TCP (6)  | 587        | 0.0.0.0/0
IMAPS (993)     | TCP (6)  | 993        | 0.0.0.0/0
Custom TCP Rule | TCP (6)  | 4190       | 0.0.0.0/0

Note que essa regra é idêntica à regra quatro do FSSF. Ela permite o acesso proveniente de toda a internet (0.0.0.0/0) aos serviços de email (SMTP, submission, IMAPS e sieve).

Do mesmo modo que no firewall local, se você tem IP fixo e quer limitar o acesso a esse IP em alguns desses serviços, coloque o seu IP fixo em 'Source' (por exemplo, 200.0.0.1/32). Se você quer dar acesso aos IPs de toda uma rede, use a máscara CIDR apropriada. Mas se seu IP é dinâmico, há pouco o que fazer a não ser liberar a internet inteira.

Agora o segundo grupo. O mesmo caminho que fizemos acima, mas com os seguintes dados:

  • Name tag: vpc.sg.http-s
  • Group name: vpc.sg.http-s
  • Description: allow http-s

Esse Security Group só tem uma regra:

Type            | Protocol | Port Range | Source
----------------+----------+------------+----------
HTTPS* (8443)   | TCP (6)  | 8443       | 0.0.0.0/0

Ué! Cadê a porta do ViMbAdmin? Calma, pequeno gafanhoto!

Terceiro grupo.

  • Name tag: vpc.sg.adm
  • Group name: vpc.sg.adm
  • Description: allow full adm access

Regra do terceiro grupo:

Type            | Protocol | Port Range | Source
----------------+----------+------------+-------------
ALL Traffic     | ALL      | ALL        | 200.0.0.1/32

Finalmente, o quarto grupo.

  • Name tag: vpc.sg.tmp-adm
  • Group name: vpc.sg.tmp-adm
  • Description: temporary full adm access

Regra desse grupo (idêntica a do terceiro):

Type            | Protocol | Port Range | Source
----------------+----------+------------+-------------
ALL Traffic     | ALL      | ALL        | 200.0.0.1/32

Só para fins de exemplo, vamos supor que 200.0.0.1/32 é IP dinâmico que sua conexão à internet local possui agora, certo? Mas e se seu IP mudar? Você fica sem acesso, lógico! Vai ter que entrar no console do AWS para alterar o IP na munheca. Chato isso, né?

IP Dinâmico dominado {#ip-dinâmico-dominado}

Contra a chatice, apresento o GRANDE MACETE FODÃO: como atualizar automaticamente a troca de IPs dinâmicos em Security Groups do AWS. Lembra que lá nos pré-requisitos dessa série eu pedi o awscli? É para usar aqui.

Para isso funcionar, eu parto da presunção que você já tem um serviço de DNS dinâmico configurado em seu computador ou roteador. Esse serviço detecta a mudança do seu IP e atualiza um serviço de DNS. Vamos usar como exemplo o endereço minhacasa.duckdns.org.

Primeiro, vamos ver se o seu awscli funciona direitinho. Para isso, volte ao console do AWS e pegue o 'Group ID' do security group vpc.sg.adm. Para fins de exemplo, vamos supor que o 'Group ID' é sg-1a2b3c4d.

Agora rode isso no seu servidor de email:

# aws ec2 describe-security-groups --group-ids sg-1a2b3c4d --output text
SECURITYGROUPS  allow full adm access   sg-1a2b3c4d     vpc.sg.adm      999999999999    vpc-9f8e7d6c
IPPERMISSIONS   -1
IPRANGES        200.0.0.1/32
IPPERMISSIONSEGRESS     -1
IPRANGES        0.0.0.0/0
TAGS    Name    vpc.sg.adm

Se a sua saída é semelhante, o awscli está funcionando bem. Podemos continuar.

Agora crie o arquivo /usr/local/bin/ec2sgddns com o conteúdo abaixo. NÃO ESQUEÇA de ajustar os valores das variáveis sgid e rdns para algo que funcione para você. Se você preferir, o script está neste gist.

#!/bin/bash
#title           :ec2sgddns
#description     :Verify and compare DDNS IPs to AWS EC2 Security Groups allowed
#                 IP rules and updated them if the first were changed.
#author          :Deny Dias (deny [at] macpress [dot] com [dot] br)
#date            :2015.05.26
#version         :0.3
#usage           :Put this script somewhere in the host, chmod +x, run in cron.
#                 It requires AWS CLI, an account with key and permissions and
#                 an empty Security Group ID (which one could apply to instances
#                 later.) Use with care and at your own risk!
#                 Configure runtime variables accordingly before runtime.
#license         :CC0
#==============================================================================

# SET THESE RUNTIME VARIABLES to fit your needs.
# $sgid is the EC2 Security Group ID (single value)
# $rdns is the DDNS entries, which need to be changed when adding/removing someone
#   ($rnds could be a single dig command or and array of them.)
sgid=sg-1a2b3c4d
rdns=$(dig +short minhacasa.duckdns.org 2> /dev/null)

# NO USER CHANGES REQUIRED BELLOW THIS LINE

# Function to validade IPs
# Courtesy of Mitch Frazier
# http://www.linuxjournal.com/content/validating-ip-address-bash-script
function valid_ip()
{
    local  ip=$1
    local  stat=1

    if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
        OIFS=$IFS
        IFS='.'
        ip=($ip)
        IFS=$OIFS
        [[ ${ip[0]} -le 255 && ${ip[1]} -le 255 \
            && ${ip[2]} -le 255 && ${ip[3]} -le 255 ]]
        stat=$?
    fi
    return $stat
}

# Set EC2 SG command and store it in an array
sgip=(`aws ec2 describe-security-groups --group-ids $sgid --query SecurityGroups[*].IpPermissions[*].IpRanges --output text | awk -F '/' {'print $1'}`)

# Begin runtime, log IPs
echo [`date -Iseconds`] Verifying EC2 Security Group ID $sgid rules and updating it if necessary.
echo [`date -Iseconds`] Discovered DDNS IPs: ${rdns[@]}
echo [`date -Iseconds`] Validating DDNS IPs...

# Initialize DDNS array
ddns=()

# Sanitize DDNS resolution
for ip in ${rdns[@]}
do
  if valid_ip $ip; then
    stat="is"
    ddns+=("$ip")
  else
    stat="IS NOT"
  fi
  printf "[`date -Iseconds`] Validation result: %-15s %s a valid IP address.\n" "$ip" "$stat"
done

# Log current IPs]
echo [`date -Iseconds`] EC2 SG IPs set: ${sgip[@]}
echo [`date -Iseconds`] DDNS IPs found: ${ddns[@]}

# Discover if the EC2 SG is empty and populates it with DDNS entries, then exit
if [ -z ${sgip[0]} ];then
  i=0
  echo [`date -Iseconds`] EC2 SG $sgid is empty. Populating with DDNS IPs entries...
  for pg in ${ddns[@]};do
    authorizecmd="aws ec2 authorize-security-group-ingress --group-id $sgid \
                  --ip-permissions '{\"IpProtocol\": \"-1\", \"IpRanges\": [{\"CidrIp\": \"${ddns[$i]}/32\"}]}' --output text"
    echo [`date -Iseconds`] Authorizing DDNS IP: ${ddns[$i]}...
    #echo [`date -Iseconds`] Command: $authorizecmd
    eval $authorizecmd
    echo [`date -Iseconds`] Authorized DDNS IP: ${ddns[$i]}
    ((i++))
  done
  # Finishes runtime
  echo [`date -Iseconds`] Authorized IPs on EC2 SG ID $sgid are now: ${ddns[@]}
  echo [`date -Iseconds`] No more DDNS IP entries to authorize. EC2 SG $sgid is now populated.
  exit 0
fi

# If EC2 SG returns entries, set one flag for each entry to test against later
# This set the complete fail parameter
for tf in ${sgip[@]};do
  testfalse+=1
done

# Iterates on each array pair, set true/false for each match
echo [`date -Iseconds`] Verifying if EC2 SG and DDNS IPs match...
for ia in ${sgip[@]};do
  for ib in ${ddns[@]};do
    if [[ $ia = $ib ]];then
      match+=0
    else
      match+=1
    fi
  done
done;
echo "[`date -Iseconds`] EC2 SG/DDNS IPs matching done."

# If any of the DDNS IPs has changed, revoke all rules and authorize again
echo [`date -Iseconds`] Verifying if EC2 SG rules update is necessary...
sgtest=(`echo ${match[@]} | sed -e 's/.\{'"${#sgip[@]}"'\}/&\n/g'`)
i=0
for it in ${sgtest[@]};do
  testmatch=${sgtest[$i]}
  if [ $testmatch -eq $testfalse ];then
    echo [`date -Iseconds`] At least one DDNS IP has changed EC2 SG. Updating rules...
    d=0
    for r in ${sgip[@]};do
      revokecmd="aws ec2 revoke-security-group-ingress --group-id $sgid \
                --ip-permissions '{\"IpProtocol\": \"-1\", \"IpRanges\": [{\"CidrIp\": \"${sgip[$d]}/32\"}]}' --output text"
      echo [`date -Iseconds`] Revoking EC2 SG IP: ${sgip[$d]}...
      #echo [`date -Iseconds`] Command: $revokecmd
      eval $revokecmd
      echo [`date -Iseconds`] Revoked EC2 SG IP: ${sgip[$d]}
      ((d++))
    done
    g=0
    for a in ${ddns[@]};do
      authorizecmd="aws ec2 authorize-security-group-ingress --group-id $sgid \
                    --ip-permissions '{\"IpProtocol\": \"-1\", \"IpRanges\": [{\"CidrIp\": \"${ddns[$g]}/32\"}]}' --output text"
      echo [`date -Iseconds`] Authorizing DDNS IP: ${ddns[$g]}...
      #echo [`date -Iseconds`] Command: $authorizecmd
      eval $authorizecmd
      echo [`date -Iseconds`] Authorized DDNS IP: ${ddns[$g]}
      ((g++))
    done
    describecheck=`eval $describecmd | tr '\n' ' '`
    echo [`date -Iseconds`] Authorized IPs on EC2 SG ID $sgid are now: ${ddns[@]}
    echo [`date -Iseconds`] EC2 SG ID $sgid rules were updated.
    exit 0
  fi
  ((i++))
done
# Finishes runtime
echo [`date -Iseconds`] No DDNS IP has changed. EC2 SG ${sgip[$i]} rules are updated.

Se você tem mais de um DNS dinâmico e quer o script atualize o IP de todos, basta configurar a variável rdns como um array, como mostro a seguir:

rdns=(`dig +short minhacasa.duckdns.org 2> /dev/null` `dig +short trabalho.noip.com 2> /dev/null` `dig +short vovo.dyndns.org 2> /dev/null`)

Uma vez que o script contenha os valores que você quer para o Security Group e seus DNSs dinâmicos, altere as permissões para executá-lo e rode-o.

# chmod 755 /usr/local/bin/ec2sgddns
# ec2sgddns
[2015-05-26T19:11:59-0300] Verifying EC2 Security Group ID sg-1a2b3c4d rules and updating it if necessary.
[2015-05-26T19:11:59-0300] Discovered DDNS IPs: 200.0.0.1
[2015-05-26T19:11:59-0300] Validating DDNS IPs...
[2015-05-26T19:11:59-0300] Validation result: 200.0.0.1 is a valid IP address.
[2015-05-26T19:11:59-0300] EC2 SG IPs set: 200.0.0.1
[2015-05-26T19:11:59-0300] DDNS IPs found: 200.0.0.1
[2015-05-26T19:11:59-0300] Verifying if EC2 SG and DDNS IPs match...
[2015-05-26T19:11:59-0300] EC2 SG/DDNS IPs matching done.
[2015-05-26T19:11:59-0300] Verifying if EC2 SG rules update is necessary...
[2015-05-26T19:11:59-0300] No DDNS IP has changed. EC2 SG rules are updated.

Se você viu uma saída parecida, está tudo certo como seu script. Note que ele não atualizou nada porque o valores no security group (EC2 SG IPs) e no DNS dinâmico (DDNS IPs) são os mesmos.

Não acredita que ele funciona? Zuzo bem... eu também não acreditaria.

Volte lá no console do AWS e edite o grupo vpc.sg.adm para trocar o seu IP para qualquer outro, ou mesmo apagar a regra (só a regra, não o grupo). Fique tranquilo, você não vai perder o acesso ao servidor porque os grupos que criamos ainda não foram associados à instância.

Rode o script novamente. Dessa vez a saída será assim (supondo que você tenha alterado o IP para outro qualquer):

# ec2sgddns
[2015-05-26T19:31:57-0300] Verifying EC2 Security Group ID sg-1a2b3c4d rules and updating it if necessary.
[2015-05-26T19:31:57-0300] Discovered DDNS IPs: 200.0.0.1
[2015-05-26T19:31:57-0300] Validating DDNS IPs...
[2015-05-26T19:31:57-0300] Validation result: 200.0.0.1 is a valid IP address.
[2015-05-26T19:31:57-0300] EC2 SG IPs set: 200.0.0.55
[2015-05-26T19:31:57-0300] DDNS IPs found: 200.0.0.1
[2015-05-26T19:31:57-0300] Verifying if EC2 SG and DDNS IPs match...
[2015-05-26T19:31:57-0300] EC2 SG/DDNS IPs matching done.
[2015-05-26T19:31:57-0300] Verifying if EC2 SG rules update is necessary...
[2015-05-26T19:31:57-0300] At least one DDNS IP has changed EC2 SG. Updating rules...
[2015-05-26T19:31:57-0300] Revoking EC2 SG IP: 200.0.0.55...
[2015-05-26T19:31:58-0300] Revoked EC2 SG IP: 200.0.0.55
[2015-05-26T19:31:58-0300] Authorizing DDNS IP: 200.0.0.1...
[2015-05-26T19:31:58-0300] Authorized DDNS IP: 200.0.0.1
[2015-05-26T19:31:58-0300] Authorized IPs on EC2 SG ID sg-1a2b3c4d are now: 200.0.0.1
[2015-05-26T19:31:58-0300] EC2 SG ID sg-1a2b3c4d rules were updated.

Viu! Funciona!!! Uso esse esquema há mais de um ano e meio e nunca fiquei na mão.

Agora volte no console e apague a regra que existe no grupo vpc.sg.tmp-adm. Esse grupo é um seguro contra a falha do script. Se ele falhar e você não tiver acesso à instância, entre no console, preencha o IP manualmente e associe-o a instância.

Falando em associar grupos a instância, precisamos fazer isso. Ainda no console do AWS, vá em EC2, selecione a instância que roda o seu servidor e clique com o botão direito nela. Selecione a opção 'Networking' > 'Change Security Groups'. Marque os grupos vpc.sg.mail, vpc.sg.http-s e vpc.sg.adm. Conforme dito acima, não marque o grupo vpc.sg.tmp-adm. Clique no botão 'Assign Security Groups' para efetivar os grupos.

Pronto! A partir de agora a segunda camada de firewall está em vigor. Se você alterar o IP no grupo vpc.sg.adm novamente perderá o acesso ao SSH e ao ViMbAdmin do seu servidor. Um bom teste a fazer é colocar o seu IP no grupo vpc.sg.tmp-adm e associá-lo à instância para ver se a contingência funciona.

Mas porque não mudar o seu IP direto no grupo vpc.sg.adm, você deve estar se perguntando? Por causa do último passo para esse esquema todo funcionar automaticamente.

No seu servidor, edite o cron do root com crontab -e e coloque isso no final dele:

#
# Update AWS vpc.sg.adm security group
*/5 * * * * /usr/local/bin/ec2sgddns >> /var/log/ec2sgddns

A cada cinco minutos, o script de atualização de IPs dinâmicos no AWS vai rodar. Se nada mudou, ele não faz nada. Se seu IP dinâmico foi alterado, ele atualiza. Independente do caso, ele registra tudo no log /var/log/ec2sgddns.

E isso responde a pergunta anterior. Como o script roda a cada cinco minutos, se houver um problema persistente com o seu serviço de DNS dinâmico (IP que não atualiza, serviço fora do ar ou coisa do gênero), o problema será refletido na regra do grupo vpc.sg.adm. Se você altera o seu IP manualmente nesse grupo pelo console do AWS, perderá novamente o seu acesso quando o script rodar.

Eis o momento em que você usa o grupo vpc.sg.tmp-adm. Esse grupo não possui atualização automática. Só não deixe ele associado a nada e nem com regras. Deixe ele vazio, sem regra alguma. Crie a regra quando precisar e associe-o a uma instância apenas quando o método automático falhar.

Contingência é isso, mais conhecida como 'plano B' ou 'Ih, fodeu'!

Outra coisa que dá pra fazer com esse esquema é ser menos permissivo com os serviços do email ou agenda. O SMTP tem que ficar aberto pra internet inteira, não tem jeito. Mas suponha que você queria permitir o acesso ao IMAPS, ao submission e ao Horde somente dentro da sua casa ou empresa. Simples, basta apagar as regras das portas desses serviços nos grupos específicos. O grupo vpc.sg.adm e o nosso script vão continuar liberando o acesso a esses serviços, mas só para quem estiver dentro dos IPs liberados. Elegante, não?

Nosso firewall dupla camada, dinâmico e automático está pronto. Na próxima parte vamos tratar da rotação de logs e da inicialização automática dos serviços de email e agendas.