Firewalls Virtuais
por: Djames Suhanko
(djames.suhanko@gmail.com)
Para-virtualização e virtualização são dois modos diferentes de atingir um mesmo objetivo - rodar mais de um sistema operacional em uma única máquina. A virtualização implica em emular um hardware para que um dado sistema operacional trabalhe independente da plataforma física em que está hospedado. Com isso, têm-se um custo; o alto consumo de processamento, pois todo um hardware está sendo emulado por um virtualizador, chegando ao esgotamento dos recursos. Cada requisição de hardware feita pelo sistema hospedeiro é entregue ao virtualizador, que se encarrega de fazer a transação com o hardware real. Entre os mais conhecidos, encontra-se o Bochs, Qemu e VMWare. Nesses softwares emuladores de hardware, o sistema operacional deve ser instalado em um arquivo, ou inicializados a partir de um arquivo ISO1.1.
Na para-virtualização, o software trabalha muito mais próximo do hardware real; um sistema operacional usando um kernel modificado gerencia sistemas para-virtualizados, rodando micro-kernels. Com isso, ganha-se em processamento, pois não há uma emulação completa desde a BIOS, possibilitando a execução de muitos sistemas operacionais simultaneamente.
Esse trabalho é feito em Linux pelo Xen, um para-virtualizador com versão free e open. Nesse documento será abordado o uso de Xen rodando em Linux OpenSuSE 10.2, para-virtualizando sistemas instalados em LVM1.2 ,designados à tarefa de firewalls.
Apresentando uma situação real, na multinacional Uranet2.1, onde viveu-se a limitação de espaço físicos de seu data center, pelo método estratégico adotado.
Por ser uma empresa de telefonia e callcenter, cada cliente possui um ou mais tipos de link com a prestadora do serviço, criando assim uma rede local ou remota onde trabalham os atendentes de telemarketing, ou por onde trafegam dados sigilosos. Afim de garantir a segurança e manter a simplicidade de manutenção, impactando ao mínimo no ambiente de produção e isolando qualquer tipo de problema, essas redes são separadas por firewalls independentes, que controlam o acesso entre o cliente e prestadora.
A solução utilizada seria ideal se não fosse a limitação física - consumo demasiado de espaço, racks, servers-select2.2, e principalmente energia (atingindo o limite de seus geradores e no-breaks). Esse é o caso em que se aplicou a solução descrita nesse documento.
Como toda a tecnologia (ou toda a solução), há prós e contras. Citando imediatamente os contras - perde-se nesse momento a segurança do problema físico isolado (apesar de ser o menos comum dos problemas), pois a paralização de um hardware real implicará na paralização de N firewalls. Por fim, ainda é contra a configuração, que não é complexa ao extremo, nem tão simples como poderia ser e, para disolver essa parte do problema, uma estratégia de geração/restauração está contida nesse documento.
Cada hardware real comportará 4 firewalls para-virtualizados. Assim, conta-se como vantagem a redução do parque de máquinas em 75%, além de racks, servers-select e energia. Também as facilitações; a cada uma porta do server-select se acessa de maneira mais ágil o console de 4 firewalls.
Para contar com um ambiente ideal, as máquinas reais são computadores industriais2.3 e as placas ethernet, 2 quad-port2.4. Ainda deve-se contar com 1 porta da rede onboard, afim de criar a rede das máquinas reais.
Cada firewall virtual terá uma reserva de 256MB de memória, ou seja - (4.256)+X para a dom0. A dom0 Não necessita de muita memória, porém para atingir algum valor acima de 1GB será necessário adquirir 3 pentes de 512MB ou 2 de 1GB.
Existem alguns conceitos a seguir que evitarão confusões posteriores. Inicialmente tratando-se dos sistemas operacionais.
Um sistema para-virtualizador é conhecido como Dominio0, Domain0, Dom0, Xen0. Um sistema para-virtualizado é chamado de DominioU, DomainU, DomU, XenU. O ``U'' significa ``Unprivilegied'' ou, sem previlégios - pois esse sistema não terá acesso direto ao hardware.
A configuração necessária é a preparação da dom0 e da domU. A comunicação entre elas acontecerá através de bridges, que isolarão as interfaces de cada firewall. Nos domUs só serão vistas as interfaces que lhe forem atribuidas, ou seja,só poderia ser farejado através da dom0, onde serão enxergadas. As dom0s por sua vez estarão em uma rede separada por um outro firewall, que só será conectado ao mundo no momento em que houver a necessidade de uma manutenção remota. Assim seria algo como:
Internet -> Firewall -> Rede Xen0.
O acesso é feito por ssh, sendo derrubado o daemon assim que a conexão é estabelecida. Concluíndo-se a manutenção, o firewall é desconectado fisicamente da rede. Feita a parte paranóica.
A configuração da Xen0 consiste em uma instalação padrão de um SuSE em modo texto, tendo o hd particionado em 3, onde uma partição menor será swap, uma será a raiz e a terceira, uma partição LVM, que abrigará os domUs.
Após a instalação do sistema, os seguintes daemons foram mantidos:
auditd
cron
dbus
fbset
haldaemon
kbd
microcode
network
nscd
policykitd
powersaved
resmgr
sshd
syslog
xend
xendomain
Para desabilitar os daemons desnecessários, basta rodar o Yast e, em sistema, selecionar ``Serviços do Nível de Execução''.
Os pacotes Xen a serem instalados são:
kernel-xen
xen
xen-libs
xen-tools
Automaticamente será adicionado o pacote bridge-utils, para a configuração da bridge.
O script abaixo ajuda a criar o LVM. Basicamente, é criado com pvcreate, posteriormente o grupo com vgcreate e por fim, os volumes.
Não é necessário conhecimento prévio em LVM para a utilização do script.
A função do script a seguir é criar as partições raiz, swap e uma
pequena partição para backup, como descrito no capítulo 5.
#!/bin/sh
escolhe_particao(){
PARTICAO=`dialog -stdout -inputbox "Digite a particao a criar LVM" 0 0`
[ $? = 1 ] && exit
dialog -stdout -yesno "Voce escolheu $PARTICAO ?" 0 0
if [ $? = 1 ];then
escolhe_particao
fi
echo $PARTICAO >particao
}
criar_grupo(){
NOME_DO_GRUPO=`dialog -stdout -inputbox "Nome para o grupo:" 0 0 vm`
dialog -stdout -yesno "Correto ($NOME_DO_GRUPO)?" 0 0
if [ $? = 1 ];then
criar_grupo
fi
dialog -stdout -yesno "Grupo: $NOME_DO_GRUPO \n Particao: $PARTICAO \n Correto?" 0 0
if [ $? = 1 ];then
exit 0
fi
pvcreate $(cat particao) ||{
dialog -stdout -infobox "Houve algum erro. \n Verifique se a particao existe e se o pacote para LVM esta instalado." 0 0
exit 1
}
vgcreate $NOME_DO_GRUPO $PARTICAO ||{
dialog -stdout -infobox "Houve algum erro. \n Verifique se a particao existe e se o pacote para LVM esta instalado." 0 0
exit 1
}
}
criar_volume(){
if [ "$1" != "" ];then
NOME_DO_GRUPO="$1"
fi
NOME_DO_VOLUME=`dialog -stdout -inputbox "Nome para o volume:" 0 0 vm1`
dialog -stdout -yesno "Correto ($NOME_DO_VOLUME)?" 0 0
if [ $? = 1 ];then
criar_volume
fi
tamanho(){
TAMANHO_RAIZ=`dialog -stdout -inputbox "Tamanho (512M, 5G...)" 0 0 5G`
dialog -stdout -yesno "Correto ($TAMANHO_RAIZ)?" 0 0
if [ $? = 1 ];then
tamanho
fi
TAMANHO_SWAP=`dialog -stdout -inputbox "Tamanho swap (512M, 5G...)" 0 0 512M`
dialog -stdout -yesno "Correto ($TAMANHO_SWAP)?" 0 0
if [ $? = 1 ];then
tamanho
fi
}
tamanho
lvcreate -L$TAMANHO_RAIZ -n $NOME_DO_VOLUME.raiz $NOME_DO_GRUPO
echo "y"|mkreiserfs /dev/$NOME_DO_GRUPO/$NOME_DO_VOLUME.raiz
lvcreate -L$TAMANHO_SWAP -n $NOME_DO_VOLUME.swap $NOME_DO_GRUPO
mkswap /dev/$NOME_DO_GRUPO/$NOME_DO_VOLUME.swap
}
auto_volume(){
NUM=`dialog -stdout -inputbox "Quantas maquinas deseja?" 0 0`
if [ $? = 1 ];then
exit
fi
NOME_DO_VOLUME=`dialog -stdout -inputbox "Nome para o volume:" 0 0 vm`
TAMANHO_RAIZ=`dialog -stdout -inputbox "tamanho da Raiz" 0 0 5G`
TAMANHO_SWAP=`dialog -stdout -inputbox "Tamanho da Swap" 0 0 512M`
for i in `seq 1 $NUM`;do
lvcreate -L$TAMANHO_RAIZ -n $NOME_DO_VOLUME$i.raiz $NOME_DO_GRUPO
echo "y"| mkreiserfs /dev/$NOME_DO_GRUPO/$NOME_DO_VOLUME$i.raiz
lvcreate -L$TAMANHO_SWAP -n $NOME_DO_VOLUME$i.swap $NOME_DO_GRUPO
mkswap /dev/$NOME_DO_GRUPO/$NOME_DO_VOLUME$i.swap
done
dialog -stdout -infobox "Verifique abaixo se foram criadas" 0 0
ls /dev/vm/*
}
dialog -stdout -yesno "Deseja colocar maquinas a um grupo existente?" 0 0
if [ $? = 0 ];then
NOME_DO_GRUPO=`dialog -stdout -inputbox "Nome do grupo existente" 0 0`
criar_volume $NOME_DO_GRUPO
exit 0
fi
escolhe_particao
criar_grupo
dialog -stdout -yesno "Gostaria de criar varios volumes \n passando apenas nome, tamanho raiz e swap?" 0 0
if [ $? = 1 ];then
criar_volume
else
auto_volume
fi
for i in `seq 1 4`;do
ls -l /dev/$NOME_DO_GRUPO/vm$i\.bkp ||{
lvcreate -L64M -n vm$i\.bkp $NOME_DO_GRUPO
echo "y"| mkreiserfs /dev/$NOME_DO_GRUPO/vm$i\.bkp
}
done
A bridge é normalmente configurada em /etc/xen/scripts/network-bridge.
Para esse modelo de configuração, o script foi criado com o seguinte
conteúdo:
#!/bin/sh
#Djames Suhanko
#source /etc/xen/scripts/bridges.so
if [ "$1" = "" ];then
echo "Usage: Stop or Start"
echo " "
exit 0
fi
if [ "$1" = "start" ];then
for i in `seq 0 7`;do
#Cria bridge e adiciona interface
/sbin/brctl addbr br$i 2>/dev/null
/sbin/brctl addif br$i eth$i 2>/dev/null
#Configura interface
/sbin/ifconfig eth$i 0 0.0.0.0 2>/dev/null
#IP na ponte
/sbin/ifconfig br$i 192.168.10.$i netmask 255.255.0.0 2>/dev/null
done
elif [ "$1" = "stop" ];then
for i in `seq 0 7`;do
/sbin/brctl delbr br$i 2>/dev/null
/sbin/brctl delif br$i eth$i 2>/dev/null
/sbin/ifconfig br$i down 2>/dev/null
/sbin/ifconfig eth$i down
done
fi
Desse modo, cada bridge recebe uma interface ethernet, fazendo (a grosso modo) a conexão entre a máquina virtual e a interface ethernet real.
A interface 8, correspondente à placa de rede onboard deverá ser configurada normalmente na dom0, afim de permitir a rede local dom0. Recomenda-se que a configuração dessa interface seja feita em /etc/init.d/after.local (esse arquivo deverá ser criado e ajustado como executável). Algo como:
/sbin/ifconfig eth8 10.0.0.1 netmask 255.255.0.0 up.
Para iniciar uma máquina virtual, pode-se passar com o comando xm todos os parâmetros necessários ou através de um script, como descrito a seguir:
kernel="/boot/vmlinuz-2.6.18.2-34-xen"
ramdisk="/boot/initrd-2.6.18.2.34.xen"
memory=256
root="/dev/hda1 ro"
disk=['phy:/dev/vm/vm1.raiz,hda1,w','phy:/dev/vm/vm1.swap,hda2,w','phy:/dev/vm/vm1.bkp,hda3,w']
vif=['mac=ac:de:48:00:00:01,bridge=br0','mac=ac:de:48:00:00:02,bridge=br1',]
A primeira linha se refere ao kernel, contido no diretório boot
da dom0. Da mesma forma para o initrd, na segunda linha. Seguidamente,
a quantidade de memória reservada para essa máquina. Aí está mais
uma grande vantagem da para-virtualização sobre uma vlan, por exemplo,
pois a domU pode ser atacada ou por algum outro motivo, ter seu desempenho
prejudicado. A domU está limitada à sua porção de recursos; sua quantidade
de CPU e, como especificado aqui, a memória. Com isso, mantém-se isolado
qualquer problema.
A linha seguinte à memória indica a partição raiz da domU. Deve-se notar que, mesmo que o HD da dom0 seja SATA, na domU aparecerá como IDE e nesse primeiro momento, como read-only.
A linha disk informará a raiz, swap e uma partição para o backup, descrito no capítulo 5. O parâmetro phy indica que as partições são físicas. Somente o que for especificado nesse arquivo será visível para a domU.
A linha vif indica as bridges que cada interface ethernet atuará. Especificar o mac de cada interface é opcional, porém para validar o sistema de restauração, é necessário fazê-lo.
O spoofing do MAC deve obedecer a ordem da reserva ac:de:48, podendo modificar todos os demais campos. Também deve-se tomar cuidado para não repetir um MAC ou IP na mesma rede. Caso não seja especificado um MAC, será gerado um aleatoriamente, dentro da reserva do Xen (00:16:3e:...).
Esse arquivo pode receber qualquer nome, porém para validar o backup
é necessário que se chame vmX.nome, onde X representa o número da
máquina virtual (que deverá ter relação com a partição LVM vmX.raiz,
como mostra o script na seção 3.2.3 e deve ser armazenado
preferencialmente em /etc/xen/.
Uma alteração de extrema importância deve ser feita em /boot/grub/menu.lst. Na linha ``module'', adicione o parâmetro dom0_mem=196. Isso evitará travamentos aleatórios nas interfaces de rede.
Para preparar uma XenU, basta uma instalação limpa de um firewall antes de receber rotas e regra. Instalar o sistema nomeando-o como ``generico'' ajudará a não se confundir posteriormente; uma imagem chamada ``generico'' que esteja rodando, certamente não possuirá nenhuma configuração.
Após o sistema devidamente instalado, deve ser feita uma cópia com os parâmetros ``-av'' para um diretório chamado genérico:
mkdir /generico
cd /
ls -l /|egrep -v 'proc|generico|<outro>' |awk '{print $NF}'|while read line; do cp -av $line generico/;done
tar cjvf generico.tbz2 generico
Esse arquivo deve ser transportado para a Xen0 e descomprimido em /, posteriormente criando os diretórios que foram excluídos na geração do pacote genérico:
tar xvjf generico.tbz2
A raiz do sistema agora deve ser a imagem genérica. Para isso, usa-se o comando:
chroot /generico
Monta-se /proc:
mount /proc
A senha deve ser convertida para shadow:
pwconv
O arquivo /etc/udev/rules.d/30-net_persistent_names.rules deve ser editado e a linha contendo os MACs das placas reais do firewall modelo devem ser removidas. As linhas possuirão informações do tipo:
SUBSYSTEM=="net", ACTION=="add", SYSFS{address}=="00:15:c5:35:df:c8", IMPORT="/lib/udev/rename_netiface %k eth0"
É importante remover essa linha, caso contrário, ao iniciar o sistema novas entradas serão criadas para as interfaces virtuais e conseqüentemente as interfaces iniciarão a partir de eth2.
Os serviços desnecessários devem ser removidos, incluindo dessa vez splash e kdb3.1. Basta rodar o Yast, uma vez que a raiz do sistema passou a ser /generico.
Deve-se remover também os arquivos relacionados à configuração da interface no boot. Algo como ``ifcfg-eth-00:0F...''. Estes arquivos estarão em /etc/sysconfig/network/.
O nome de host pode ser mudado através do Yast, na opção ``Serviços de Rede'' -> ``DNS e Nome de Host'', ou editando os arquivos /etc/HOSTNAME e /etc/hosts.
Na máquina real, para se acessar consoles usa-se Alt+[F1-F6]. As domUs também serão acessadas pelo console e esse suporte a múltiplas ttys é conflitante. Deve-se então desabilitar os consoles de 2 a 6, em /etc/inittab (do sistema genérico somente), comentado as linhas:
2:2345:respawn:/sbin/mingetty tty2
3:2345:respawn:/sbin/mingetty tty3
4:2345:respawn:/sbin/mingetty tty4
5:2345:respawn:/sbin/mingetty tty5
6:2345:respawn:/sbin/mingetty tty6
A tabela de sistemas de arquivos deve ser modificada, deixando apenas
as entradas correspondentes a raiz, swap, proc e partição de backup
, que será citado mais adiante. Essa partição existirá apenas na máquina
virtualizada, não sendo necessário criá-la na máquina de geração do
sistema genérico.
Modelo do fstab:
| /dev/hda1 | / | reiserfs | acl,user_xattr | 1 1
/dev/hda2 |
O diretório /bkp deve ser criado no sistema genérico.
Concluídas as configurações, desmonta-se /proc e finaliza-se a jaula:
umount /proc
exit
Para concluir, as libs do Xen devem ser copiadas para o sistema genérico:
cp -av /lib/modules/*xen /generico/lib/modules/
Terminada a configuração, a genérica pode ser copiada para a partição
do firewall que será virtualizado, montando o LVM em /mnt, exemplificando
o primeiro firewall, chamado frwexemplo:
mount /dev/vm/vm1.raiz /mnt
cp -av /generico/* /mnt/
As configurações poderiam ser feitas nesse momento usando-se da jaula,
ou após o primeiro boot, como no exemplo deste documento.
No console da máquina real, facilita-se a inicialização de um sistema virtual estando em /etc/xen, onde ficarão armazenados os scripts inicializadores dos sistemas virtuais, contando com a ajuda de auto-complete, porém todos os comandos podem ser executados de qualquer nível de diretório, indicando o caminho absoluto.
De dentro de /etc/xen:
xm create -c vm1.frwexemplo
A flag ``-c'' diz para iniciar o sistema em primeiro plano. O prefixo ``vm1'' é útil nesse momento, pois indica em que local do LVM se localiza o sistema.
A inicialização deve ocorrer normalmente, apresentando falha apenas no clock do hardware, que em nada influenciará nesse modelo.
Após efetuar o login no sistema, configura-se as interfaces de rede, que apresentarão uma mensagem de ``modulo não encontrado'', bastando ignorar a mensagem.
Para retornar ao console da máquina real, basta usar Ctrl+].
Para retornar a um console, usa-se xm console vmX.nome, exemplificando com o modelo criado:
xm console vm1.frwexemplo
Seguido de Enter.
Para saber quais firewalls estão rodando, usa-se xm list. A lista apresentará o estado das máquinas, ou estado nenhum.
-r: indica processamento
-c: indica crash. A máquina virtual certamente não está rodando.
-b: Se a máquina virtual não estiver processando, entrará em estado de bloqueio até que seja requisitado processamento.
-p: Indica que dado domU foi pausado.
Quando uma domU sofre um crash (por uma configuração que não permitiu
o boot correto, por exemplo), será necessário destruí-la. Para tal,
usa-se o comando:
xm destroy vm1.frwexemplo
Têm-se a possibilidade de pausar um domU em execução. Isso interromperá o processamento, mas não livrará recursos em uso. Para pausar:
xm pause vm1.frwexemplo
E para retomar:
xm unpause vm1.frwexemplo
Pode-se desligar uma domU com:
xm shutdown vmX.nome
Mais detalhes podem ser observados no manual do xm.
Todos os script estão no pacote bkp.tbz2 em www.phantomsystem.com.br, no link superior à esquerda.
Um firewall normalmente roda um pequeno conjunto de serviços; regras de iptables, rotas e dhcp. As informações necessárias estão contidas em um conjunto de arquivos como nome de máquina, interfaces de rede, script pós-boot etc. Se estas informações forem acrescidas a um sistema genérico, tais configurações serão assumidas em um boot posterior, portanto, o script de backup a seguir reunirá os dados necessárias para reconstruir as domUs, caso a máquina real sofra algum dano irrecuperável.
#!/bin/bash
[ -d /bkp ] || mkdir /bkp
if [ -f /bkp/$(date +%Y-%m-%d) ];then
exit
fi
rm -rf /bkp/* 2>/dev/null
DIR=/bkp/`hostname -s`
rm -rfv $DIR
mkdir -p $DIR
cp -rfv -parents /etc/HOSTNAME $DIR
cp -rfv -parents /etc/dhcpd.conf $DIR
cp -rfv -parents /root/* $DIR
cp -rfv -parents /etc/host* $DIR
cp -rfv -parents /etc/resolv.conf $DIR
cp -rfv -parents /etc/rc.d/after.local $DIR
cp -rfv -parents /etc/rc.d/frw* $DIR
cp -rfv -parents /etc/sysconfig/network $DIR
cp -rfv -parents /var/spool/cron/tabs/* $DIR
echo "1" >/bkp/$(echo `date +%Y-%m-%d`)
O script inicia verificando se há o diretório de backup e a data do
backup. Se a data do backup for inferior ao último, ele não será executado.
Se for necessário rodar o backup manualmente, basta remover o conteúdo
de /bkp.
Nesse script, a regra de firewall receberá o mesmo nome do firewall (ambos não devem conter o prefixo vmX). Desse modo, o backup se tornará genérico, dispensando a criação de um script para cada firewall. Se necessário for, basta adicionar ao script outros niveis de arquivos e diretórios.
O script finaliza adicionando a data do último backup. Dessa forma, mesmo que agendado no cron com intervalos curtos, a execução será breve.
O script after.local é apenas um arquivo executável (chmod 755) que, se existir, será executado após o rc - o último a rodar antes do login.
Quando o script roda e os arquivos são copiados, o domU compreende que está armazenando os dados em /dev/hda3, de poucos megas, apenas para armazenar os arquivos de configuração do sistema virtual em execução. Para o Dom0, essa partição é compreendida como um volume do LVM, contido em /dev/vm/vm1.bkp.
Todo esse bkp seria inútil se não pudesse ser armazenado remotamente, porém a máquina virtual não tem acesso à máquina real de forma alguma. A solução é recolher o backup a partir da Dom0, por ser ela a controladora de todo o conjunto.
A partição que corresponde ao bkp estará constantemente montada na
domU em execução, sendo inapropriado acessar uma partição montada
mesmo que a partir da dom0. Para que seja possível copiar os dados
seguramente, o script que recolhe os backups tomará providências -
sincronizará o conteúdo do backup na máquina virtual, enviando um
sinal para sincronísmo dos dados, descarregando o buffer do dispositivo
e posteriormente espelhando o conteúdo do volume LVM para um arquivo.
Finalizará copiando o conteúdo desse arquivo espelhado para o respectivo
diretório de backup, que será /firewalls/vmX.nome, replicando o backup
na rede dom0 através de uma leitura no arquivo defaults.rfs, contido
no diretório /root/bkp. Concluído, o arquivo de imagem é removido
do sistema. Dá-se a esse fato a importância de criar um volume vmX.bkp
de 16 ou 32 megabytes apenas, pois a imagem é gerada bit a bit com
um dump do dispositivo e poderia acarretar em consumo de recursos
excessivos. Não há como evitar o primeiro passo, que é o espelhamento,
mas a data do backup é verificada da mesma forma que é feito na domU.
A replicação na rede é feita por ssh usando-se de troca de chaves,
que dispensará a senha. O script da dom0 que recolhe esse backup:
#!/bin/sh
#Djames Suhanko
#Esse script monta a particao de bkp e copia para /firewalls e rede
source /root/bkp/defaults.rfs
[ ! -f /root/bkp/bkp.lock ] || exit 1
echo "1" >/root/bkp/bkp.lock
roda_bkp(){
[ -d /mnt/bkp ] || mkdir /mnt/bkp
/usr/sbin/flushb /dev/vm/$1\.bkp
dd if=/dev/vm/$1\.bkp of=/mnt/$1\.bkp
mount -o loop /mnt/$1\.bkp /mnt/bkp
MAQUINA_LOCAL="/mnt/bkp"
ARQUIVO=`date +%Y-%m-%d`
[ -f /mnt/bkp/$ARQUIVO ] && {
DIR=`basename $(ls -d /mnt/bkp/*/|sed -e 's/\///')`
cp -r /mnt/bkp/$DIR /mnt/$1\.$DIR
DOMU_BKP=$1\.$DIR
cp -rf /mnt/$DOMU_BKP /firewalls/
cp -f /etc/xen/vm[1-4].* /firewalls/files/
echo $GRUPO|sed -e 's/,/\n/g; s/ //g'|while read line;do
if [ ! "$GRUPO" = "" ];then
ping -c1 $line >/dev/null || ESTADO="no"
if [ ! "$ESTADO" = "no" ];then
scp -r /mnt/$DOMU_BKP root@$line\:/firewalls/
scp /firewalls/files/* root@$line:/firewalls/files/
ESTADO="ok"
fi
fi
if [ ! "$ESTADO" = "ok" ] ;then
echo "$1 $line" >>/root/bkp/nao_copiado_para_rede.err
fi
done
rm -rf /mnt/$DOMU_BKP
umount /mnt/bkp || echo "no umount $1" >>/root/bkp/umount_bkp.err
rm -f /mnt/$1\.bkp
} || umount /mnt/bkp
}
/usr/sbin/xm list|egrep vm|cut -f1 -d.|while read line; do
roda_bkp $line
done
rm -f /root/bkp/bkp.lock
Dessa forma, todas as máquinas da rede dom0 terão em /firewalls uma
cópia dos arquivos dos firewalls virtualizados em sí e nas outras
dom0s. Para restaurar um conjunto de domUs, é necessário saber quais
domUs rodavam em que dom0. Essa informação está no arquivo defaultfs.rfs
em /root/bkp. Por exemplo, as dom0s chamadas de mfXX (mf01, mf02,...),
estariam no defaults.rfs como:
MF01=''vm1.frwexemplo,vm2.frwxxx,vm3.frwxxxxx,vm4.xxxxxxx''
MF02=''...''
Supõe-se que a restauração de um conjunto será necessário no momento
em que um dom0 tiver um problema físico, logo, o hardware deverá ser
substituido. Para tal, o modelo de backup descrito neste documento
sugere que haja uma dom0 de backup em rede, recebendo a replicação
dos arquivos de backup. Assim, se houver a ``morte'' de uma dom0,
a substituição poderá ser feita em alguns poucos minutos, rodando
o script restaura_mf.sh na dom0 de backup:
#!/bin/sh
#Djames Suhanko - djames.suhanko@gmail.com
#Restaurador de grupos
source /root/bkp/defaults.rfs
TODAS=""
if [ "$1" = "remover" ];then
LISTA=`cat /root/bkp/defaults.rfs|egrep MFG|awk -F"=" '{print $1" "$1}'`
REMOVA=`dialog -stdout -title "Remover grupo" -menu "Selecione o grupo" 0 0 0 $LISTA`
if [ $? = 1 ];then
exit
fi
egrep -v "$REMOVA" /root/bkp/defaults.rfs >>/root/bkp/defaults.bkp
mv -f /root/bkp/defaults.bkp /root/bkp/defaults.rfs
exit
fi
if [ "$1" = "adicionar" ];then
NUMERO_DE_MAQUINAS=`dialog -stdout -title "Adicionar Grupo" -inputbox "Entre com o numero de maquinas desejadas" 0 0`
if [ $? = 1 ];then
exit
fi
for i in `seq 1 $NUMERO_DE_MAQUINAS`;do
NOME_DA_MAQUINA=`dialog -stdout -title "Nomes" -inputbox "Entre com o nome da maquina:" 0 0`
if [ $? = 1 ];then
exit
fi
TODAS_VIRGULA=$TODAS_VIRGULA$NOME_DA_MAQUINA","
done
TODAS=`echo $TODAS_VIRGULA|sed -e 's/,$//'`
for i in `seq 1 100`;do
A=`egrep "MFG$i" /root/bkp/defaults.rfs` ||{
echo "MFG$i=\"$TODAS\""
break
}
done
exit
fi
dialog -stdout -title "Maquina Despreparada" -yesno "Deseja selecionar um grupo?" 0 0
if [ $? = 1 ];then
exit
fi
egrep MFG /root/bkp/defaults.rfs >/tmp/grupos
dialog -stdout -textbox /tmp/grupos 0 0
rm -f /tmp/grupos
OPC=$(dialog -stdout -title "Selecione o MF" -menu "Restaurar Grupo" 0 0 0 \
MF01 "MF01" \
MF02 "MF02" \
MF03 "MF03")
[ $? = 1 ] && exit
VMRUNNING=`xm list|egrep vm|wc -l`
if [ $VMRUNNING -gt 0 ];then
dialog -stdout -title "Ops" -msgbox "Maquina virtual rodando. Pare-a primeiro" 0 0
exit
fi
case "$OPC" in
MF01)
[ -d /root/logs ] || mkdir -p /root/logs
GRUPO_SELECIONADO=$MFG1
cp -rf /firewalls/dom0/mf01/* / 2>>/root/logs/copia_dom0
;;
MF02)
[ -d /root/logs ] || mkdir -p /root/logs
GRUPO_SELECIONADO=$MFG2
cp -rf /firewalls/dom0/mf02/* / 2>>/root/logs/copia_dom0
;;
MF03)
exit
#cp -rf /firewalls/dom0/mf03/* / 2>>/root/logs/copia_dom0
#GRUPO_SELECIONADO=$MFG3
;;
esac
echo $GRUPO_SELECIONADO|sed -e 's/,/\n/g; s/\"//g '|while read line; do
mount /dev/vm/$(echo $line|cut -f1 -d.).raiz /mnt
[ -d /mnt/root ] ||{
cp -av /generico/* /mnt
#dialog -stdout -msgbox "Generico copiado para o diretorio" 0 0
}
cp -rv /firewalls/$line/* /mnt/
#servicos
chroot /mnt/ chkconfig -add $(echo $line|cut -f2 -d.)
if [ -f /mnt/etc/dhcpd.conf ];then
chroot /mnt chkconfig -add dhcpd
fi
umount /mnt
ln -sf /etc/xen/$line /etc/xen/auto/$line
done
dialog -stdout -title "Finalizado" -msgbox "Reiniciarei o computador" 0 0
/sbin/reboot
Também é permitido incluir ou remover um grupo no arquivo defaults.rfs, mas novos grupos no menu devem ser incluídos reeditando esse script.
O defaults.rfs deve ser replicado a cada modificação. Como esse é
um arquivo comum em todas as dom0s, a replicação é feita manualmente,
para evitar desatualizações ou sobrescrições inoportunas. O script
que replicará o defaults.rfs contém:
#!/bin/sh
source /root/bkp/defaults.rfs
echo $GRUPO|sed -e 's/^$//g; s/ //g; s/,/\n/g'|while read line;do
scp /root/bkp/defaults.rfs root@$line:/root/bkp/
done
Não apenas os backups das domUs são replicados, mas os da dom0 também,
pois a máquina real possui algumas características especificas como
seu nome, configuração de rede, etc.
O script que faz o backup da dom0:
#!/bin/bash
[ -d /firewalls/dom0 ] || mkdir -p /firewalls/dom0
rm -rf /firewalls/dom0/$(hostname -s) 2>/dev/null
DIR=/firewalls/dom0/`hostname -s`
rm -rfv $DIR
mkdir -p $DIR
cp -rfv -parents /etc/HOSTNAME $DIR
cp -rfv -parents /root/* $DIR
cp -rfv -parents /etc/host* $DIR
cp -rfv -parents /etc/resolv.conf $DIR
cp -rfv -parents /etc/rc.d/after.local $DIR
cp -rfv -parents /etc/sysconfig/network $DIR
cp -rfv -parents /var/spool/cron/tabs/* $DIR
cp -rfv -parents /etc/xen/{vm[1-4]*,scripts/network-bridge} $DIR
source /root/bkp/defaults.rfs
echo $GRUPO|sed -e 's/^$//g; s/ //g; s/,/\n/g'|while read line;do
scp -r /firewalls/dom0/$(hostname -s) root@$line:/firewalls/dom0/
done
Acontecendo o crash, a dom0 de backup substituirá facilmente qualquer
dom0 problemática, porém será necessário preparar uma substituta,
que fará o papel de backup da rede novamente.
Afim de evitar o processo de configuração manual, gerar uma imagem da dom0 genérica sem a construção do LVM é a solução. Para tal, sugere-se o uso do Phantom, disponibilizado livremente em www.phantomsystem.com.br. Tendo uma imagem armazenada em qualquer ponto dessa rede, basta agora restaurá-la para um novo hardware (que desempenhará o papel de dom0 genérica) e reconstruir o LVM.
O ambiente descrito nesse documento foi testado também em desktops Dell Optiplex 740, onde foi possível rodar 2 firewalls simultaneamente.
A solução apresentou alto desempenho e estabilidade, tendo todo o tempo dedicado à configuração.
Foi usado como referência o documento do site www.eriberto.pro.br.
Um canal de consultas no iRC - canal ##xen, no servidor FreeNode, onde pode-se encontrar ajuda (em inglês).
Todas as características de um firewall estão configuradas nas domUs,
tendo a dom0 como única função, gerenciar os sistemas virtualizados.
Esse documento foi editado em LYX, front-end para o LATEX
This document was generated using the LaTeX2HTML translator Version 2002-2-1 (1.70)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /tmp/lyx_tmpdir13143GSP9Hu/lyx_tmpbuf0/xen-final.tex
The translation was initiated by viking on 2007-08-16