Новый датацентр. Сервер.

Долго ли, коротко, но дошел я до того, что мне стало уж очень дорого пользоваться услугами Amazon. Оно удобно, но дорого. Значит, мне опять дорога назад, к выделенному серверу.

Но терять кучку удобных штук типа докера нет желания, поэтому буду строить сразу и с запасом. Итак, что мне охота

1. Централизованное управление аккаунтами. Для всяких ssh, git и прочим
2. KVM и докер.
3. Чистый, не засранный хост. Не хочу видеть по интерфейсу и 10 правил на каждый контейнер.
4. Разное.

Итак, стадия номер 1 или “подготовка”. Все использованное мной можно найти тут: https://github.com/kiltum/newdc Ну и я подозреваю, что вы уже имеете опыт администрирования linux, поэтому буду только намечать путь.

Арендую новый сервер. Hetzner, leaseweb – их много. И ставлю туда пустую и голую CentOS 7. Никаких панелей, рюшечек и прочего. Из моих уже личных требований – поставить все на raid1.

Бутстраплю ее с помощью ansible и роли centos-bootstrap.yml. Там снос selinux, firewalld, установка ntp и прочих пакетиков и обновление системы. Самый необходимый минимум.

Ставлю KVM. Эта операция одноразовая, поэтому можно и руками.

yum install qemu-kvm libvirt libvirt-python libguestfs-tools virt-install

Сношу дефаултную сеть от KVM. Это автоматически избавляет меня от кучки правил в iptables.

virsh net-autostart --disable default
virsh net-destroy default

Создаю тупой интерфейс, куда буду цеплять с помощью бриджа виртуалки

modprobe dummy numdummies=1
echo "dummy" > /etc/modules-load.d/dummy.conf
echo "options dummy numdummies=1" >> /etc/modprobe.d/dummy.conf

Генерирую для него мак-адресс (в принципе можно от балды, но лучше что бы с первыми октетами от KVM – так симпатичней)

hexdump -vn3 -e '/3 "52:54:00"' -e '/1 ":%02x"' -e '"\n"' /dev/urandom

И делаю конфиг-фаил для этого интерфейса

cat > /etc/sysconfig/network-scripts/ifcfg-dummy0
DEVICE=dummy0
MACADDR=52:54:00:1b:e1:80
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Ethernet
IPV6INIT=no
BRIDGE=virbr100

и описываю бридж

cat > /etc/sysconfig/network-scripts/ifcfg-virbr100
DEVICE=virbr100
NAME=virbr100
NM_CONTROLLED=no
ONBOOT=yes
TYPE=Bridge
DELAY=2
STP=on
IPADDR=172.16.100.1
NETMASK=255.255.255.0
IPV6INIT=no

Поднимаю созданное

ifup virbr100

В результате я получил следующее

2: dummy0: mtu 1500 qdisc noqueue master virbr100 state UNKNOWN qlen 1000
link/ether 52:54:00:1b:e1:80 brd ff:ff:ff:ff:ff:ff
inet6 fe80::5054:ff:fe1b:e180/64 scope link
valid_lft forever preferred_lft forever
...
5: virbr100: mtu 1500 qdisc noqueue state UP qlen 1000
link/ether 52:54:00:1b:e1:80 brd ff:ff:ff:ff:ff:ff
inet 172.16.100.1/24 brd 172.16.100.255 scope global virbr100
valid_lft forever preferred_lft forever
inet6 fe80::5054:ff:fe1b:e180/64 scope link
valid_lft forever preferred_lft forever

Разрешаю форвардинг пакетиков между интерфейсами

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p

Для полноценной работы виртуалок я добавляю в стандартный набор правил еще одно, которое обеспечивает виртуалкам выход в интернет. Вместо иксиков подставьте свой внешний ipшник

-A POSTROUTING -o eth0 -j SNAT --to-source x.x.x.x

И в принципе все, я готов создать первую виртуалку.

virt-install --name head.ka12.ko --network bridge=virbr100 --memory 1024 --disk path=head.ka12.co.img,size=30 --cdrom ../iso/CentOS-7-x86_64-Minimal-1708.iso --graphics vnc,listen=172.16.100.1 --noautoconsole

И получаю к ней доступ по VNC

virsh vncdisplay head.ka12.co

Так как пока нету ничего даже похожего на нормальный доступ, пробрасываю VNC порт на локальную машину

ssh -L 5901:172.16.100.1:5900 kiltum@ka12.co

Дальше открываю VNC клиент и по адресу localhost:5901 получаю консоль виртуалки. Дальше как обычно “Далее-далее-подождать и перезагрузить”. Опять же можно было заморочиться и использовать автостарты, но мне лень такое делать на редких и одноразовых операциях.

У этой новой виртуалки будет совершенно ожидаемый адрес 172.16.100.2. После “ребута” инсталлятора снова запускаем и ставим в автозапуск

virsh start head.ka12.co
virsh autostart head.ka12.co

Первым делом надо решить вопрос с доступом в мою “инфраструктуру”. Тут пока ничего лучше не придумали, как openvpn. Запихиваю в /etc/resolv.conf временный адрес DNS сервера и начинаю

yum -y install epel-release mc
yum -y install openvpn easy-rsa

Меняю конфиги openvpn

cat server.conf
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh2048.pem
server 172.16.101.0 255.255.255.0
ifconfig-pool-persist ipp.txt
push "route 172.16.0.0 255.255.0.0"
;push "redirect-gateway def1 bypass-dhcp"
;push "dhcp-option DNS 172.16.100.2"
;push "dhcp-option DOMAIN ka12.co"
duplicate-cn
keepalive 10 120
comp-lzo
user nobody
group nobody
persist-key
persist-tun
verb 3

Обратите внимание, специально закомментировал некоторые строки, которые понадобятся в будущем. Теперь генерирую ключи

mkdir -p /etc/openvpn/easy-rsa/keys
cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa
mcedit /etc/openvpn/easy-rsa/vars
cp /etc/openvpn/easy-rsa/openssl-1.0.0.cnf /etc/openvpn/easy-rsa/openssl.cnf
cd /etc/openvpn/easy-rsa
source ./vars
./clean-all
./build-ca
./build-key-server server
./build-dh
cd /etc/openvpn/easy-rsa/keys
cp dh2048.pem ca.crt server.crt server.key /etc/openvpn
cd /etc/openvpn/easy-rsa
./build-key client

Разрешаю форвардинг

echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
echo "net.ipv4.conf.all.forwarding=1" >> /etc/sysctl.conf
sysctl -p

и запускаю openvpn

systemctl enable openvpn@server.service
systemctl start openvpn@server.service

так как там все по умолчанию, очищаю правила фаерволла на виртуалке

iptables -F

Все, теперь на хосте надо открыть порт 1194/udp и пробросить его на виртуалку

-A PREROUTING -d x.x.x.x/32 -i eth0 -p udp --dport 1194 -j DNAT --to-destination 172.16.100.2
-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT

Добавляю роутинг до подсети vpn

ip route add 172.16.101.0/24 via 172.16.100.2

cat > /etc/sysconfig/network-scripts/route-virbr100
172.16.101.0/24 via 172.16.100.2 dev virbr100

Делаю темплейт клиентского конфига

cat client.template
client
dev tun
proto udp
remote vpn.ka12.co 1194
resolv-retry infinite
nobind
persist-key
persist-tun
comp-lzo
verb 3
key-direction 1
remote-cert-tls server
mssfix
<ca>
ca.crt
</ca>
<cert>
client.crt
</cert>
<key>
client.key
</key>
<tls-auth>
ta.key
</tls-auth>

И заполняю его (в дальнейшем я сделал маленький скрипт gen_config.sh)

sed -e '/ca.crt/rca.crt' -e '/client.crt/reasy-rsa/keys/client.crt' -e '/client.key/reasy-rsa/keys/client.key' -e '/ta.key/rta.key' -e '/crt/d' -e '/\.key/d' client.template | sed -e 's/#.*$//' -e '/^$/d' > cl.ovpn

Цепляюсь и проверяю доступность хоста через vpn

traceroute 172.16.100.1
traceroute to 172.16.100.1 (172.16.100.1), 64 hops max, 52 byte packets
1 172.16.101.1 (172.16.101.1) 53.941 ms 48.797 ms 47.938 ms
2 172.16.100.1 (172.16.100.1) 49.186 ms !Z 48.813 ms !Z 49.865 ms !Z

Пробрасываю ключ, бутстраплю виртуалку и ставлю в ней FreeIPA
ssh-copy-id root@172.16.100.2

ansible-playbook -i inventory -l head.ka12.co centos-bootstrap.yml

yum -y install ipa-server bind bind-dyndb-ldap ipa-server-dns

ipa-server-install --setup-dns --mkhomedir --allow-zone-overlap

Меняю шелл по умолчанию

kinit admin
ipa config-mod --defaultshell=/bin/bash

Внезапно оказалось, что FreeIPA с 1 гигом памяти стартует очень тяжко. Добавляю памяти

virsh setmaxmem head.ka12.co 4G --config
virsh setmem head.ka12.co 2G --config

И включаю VPN на полную

push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 172.16.100.2"
push "dhcp-option DOMAIN ka12.co"

Добавляю pam сервис

cd /etc/pam.d/
ln -s system-auth openvpn

Добавляю группу openvpn и sshd и заношу в нее меня. В принципе все тоже самое можно сделать через веб-интерфес FreeIPA.

ipa hbacsvc-add openvpn
ipa hbacrule-add allow_openvpn
ipa hbacrule-add-service allow_openvpn --hbacsvcs=openvpn
ipa hbacrule-add-user allow_openvpn --user=kiltum
ipa hbacrule-add-service allow_sshd --hbacsvcs=sshd
ipa hbacrule-add-user allow_sshd --user=kiltum
ipa hbacrule-add-host allow_sshd --hosts=head.ka12.co
ipa hbactest --user=kiltum --host=head.ka12.co --service=sshd

Теперь остался последний шаг. Добавляю в конфиг сервера

plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn

а в конфиг клиента

auth-user-pass

И всё.

В случае проблем проверить работу авторизации можно и прямо на стороне сервера:

pamtester openvpn kiltum authenticate

Что же получил на данном этапе?

1. Хост, на котором крутится только KVM и больше ничего. А значит: ошибиться негде, ломать тоже особо нечего.
2. OpenVPN, доступ до которого защищен сразу двумя методами: клиентским сертификатом и логином-паролем.
3. Внутренний DNS, который снаружи никак не виден.
4. Управление пользователями/группами/сервисами. Располагается исключительно во внутренней сети.
5. Даже если опустить везде фаирволлы, то ничего нового не будет доступно снаружи.