Как стать автором
Обновить

dynDNS для Amazon EC2 или как автоматизировать автообновление IP на хостинге с динамическим публичным IP

Время на прочтение 6 мин
Количество просмотров 6.3K
Недавно встала задача развернуть виртуальный сервер Ubuntu 12.04 на Amazon EC2 для некоего сервиса и присвоить ему доменное имя в существующей доменной зоне, но как известно Amazon меняет публичный и локальный адреса после перезагрузки или выключения машины, поэтому было решено использовать bash (для *nix) и bat (для Windows) для автоматизации обновления динамического адреса для хостинга.


Такой скрипт на bash уже существует Marius Ducea Jun 1st, 2009 года. Он был немного неактуальным в плане которых команд API от Amazon, но в большинстве своём остался практически неизменным.
Всё же повторюсь как настроить работающий BIND для получения команды на синхронизацию, хотя на хабре уже есть несколько статей описывающих данный метод:
habrahabr.ru/post/101380
habrahabr.ru/post/45921
и много других.

Я лишь исправил некоторые команды, засунул его в автозагрузку с системой и сделал аналогичный bat-скрипт для Windows, использовав cURL и некоторые файлы от BIND.

Долго мучился почему не получается обновить зону (master и slave были на другом хостинге, работающим на Ubuntu 10.04 с установленным BIND), пришлось включить на нём логирование:

В файле /etc/bind/named.conf прописал правила для создания логов, которые будут записаны в папку в /var/log/named/
logging {
    channel bind_log {
    file "/var/log/named/named.log";
    print-time yes;
    print-category yes;
    print-severity yes;
    };
    channel update_debug {
    file "/var/log/named/update-debug.log";
    severity debug 3;
    print-time yes;
    print-category yes;
    print-severity yes;
    };
    channel security_info {
    file "/var/log/named/security-info.log";
    severity info;
    print-time yes;
    print-category yes;
    print-severity yes;
    };
    category default { bind_log;};
    category xfer-in { bind_log;};
    category xfer-out { bind_log;};
    category update { update_debug;};
    category security { security_info;};
};


После
/etc/init.d/bind9 restart

логи появились и можно было попробовать обновить зону скриптом, который был немного модифицирован, но вначале надо было создать ключи, я использовал 512 бит:
dnssec-keygen -a HMAC-MD5 -b 512 -r /dev/urandom -n USER example.com

Получили 2 файла:
Kexample.com.+157+10000.key
Kexample.com.+157+10000.private

В скрипте необходимо указать путь к полученному private — ключу:
#!/bin/bash

#Путь к приватному ключевому файлу
DNS_KEY="/etc/bind/key/Kexample.com.+157+10000.private"
#Имя домена
DOMAIN=example.com

#Имя поддомена статически
HOSTNAME=site1
#Раскомментировать нижние 2 строки, если надо использовать динамическое имя (возможны ошибки при внесении записи в DNS)
#USER_DATA=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/local-hostname`
#HOSTNAME=`echo $USER_DATA`
#Установить имя до следующей перезагрузки
hostname $HOSTNAME.$DOMAIN
echo Поддомен и домен: $HOSTNAME.$DOMAIN

PUBIP=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/public-ipv4`
echo Публичный адрес: $PUBIP
cat<<EOF | /usr/bin/nsupdate -k $DNS_KEY -v
server ns1.$DOMAIN
zone $DOMAIN
update delete $HOSTNAME.$DOMAIN A
update add $HOSTNAME.$DOMAIN 60 A $PUBIP
send
EOF

LOCIP=`/usr/bin/curl -s http://169.254.169.254/latest/meta-data/local-ipv4`
echo Локальный адрес: $LOCIP
cat<<EOF | /usr/bin/nsupdate -k $DNS_KEY -v
server ns1.$DOMAIN
zone $DOMAIN
update delete local.$HOSTNAME.$DOMAIN A
update add local.$HOSTNAME.$DOMAIN 60 A $LOCIP
send
EOF

, а в DNS сервере указать содержимое публичного ключа в файле подгружаемых зон (у меня это named.conf.local):
key example.com. {
        algorithm HMAC-MD5;
        secret "ynl7o+JFPekH4iUaptw7z12xLhkUBJTmqbmTYa1xe+Gpt26HVaff+qQW hlmWcvAUeYdg19B+M4YeFrfhAvlcLQ==";
};
zone "example.com" {
        type master;
        file "/etc/bind/master/example.com";
        allow-update { key example.com.; };
        allow-query { any; };

};

Содержимое публичного ключа:
example.com. IN KEY 0 3 157 ynl7o+JFPekH4iUaptw7z12xLhkUBJTmqbmTYa1xe+Gpt26HVaff+qQW hlmWcvAUeYdg19B+M4YeFrfhAvlcLQ==


Перезагружаем на хостинге с master/slave–записьсью DNS сервер и смотрим логи при попытке обновить зону полученным скриптом на хостинге Amazon.

Был получен отлуп:
named.log
26-Jan-2013 22:53:27.780 update-security: info: client 192.168.254.1#58180: signer "example.com" approved
26-Jan-2013 22:53:27.782 general: error: /etc/bind/master/example.com.jnl: create: permission denied
26-Jan-2013 22:53:27.881 update-security: info: client 192.168.254.1#52062: signer "example.com" approved
26-Jan-2013 22:53:27.883 general: error: /etc/bind/master/example.com.jnl: create: permission denied


update-debug.log
26-Jan-2013 22:53:27.780 update: info: client 192.168.254.1#58180: updating zone 'example.com/IN': deleting rrset at 'flussonic.example.com' A
26-Jan-2013 22:53:27.781 update: info: client 192.168.254.1#58180: updating zone 'example.com/IN': adding an RR at 'flussonic.example.com' A
26-Jan-2013 22:53:27.781 update: debug 3: client 192.168.254.1#58180: updating zone 'example.com/IN': checking for NSEC3PARAM changes
26-Jan-2013 22:53:27.782 update: info: client 192.168.254.1#58180: updating zone 'example.com/IN': error: journal open failed: unexpected error
26-Jan-2013 22:53:27.882 update: info: client 192.168.254.1#52062: updating zone 'example.com/IN': deleting rrset at 'local.flussonic.example.com' A
26-Jan-2013 22:53:27.882 update: info: client 192.168.254.1#52062: updating zone 'example.com/IN': adding an RR at 'local.flussonic.example.com' A
26-Jan-2013 22:53:27.882 update: debug 3: client 192.168.254.1#52062: updating zone 'example.com/IN': checking for NSEC3PARAM changes
26-Jan-2013 22:53:27.883 update: info: client 192.168.254.1#52062: updating zone 'example.com/IN': error: journal open failed: unexpected error


в логах было написано что нет разрешения за запись, хотя на файлах и папках стояло разрешение записи для пользователя и группы bind.
Поиски в интернете гласили что надо поправить строчку в /etc/apparmor.d/usr.sbin.named
c
/etc/bind/** r,

на
/etc/bind/** rw,

, но это означает уменьшить безопасть зон, расположенных в этой директории, но я как обычно полагаюсь на авось.
Далее надо перезагрузить разрешения и сам BIND
/etc/init.d/apparmor restart
/etc/init.d/bind9 restart


После очередного рестарта сервиса на DNS хостинге ошибка исчезла и зона благополучно обновилась, но все закомментированные в ней данные были утеряны, т.к. bind «навёл порядок» в записях и поудалял лишнее, поэтому следует сделать копию всех зон.

Так же следовало данный скрипт сделать автозапускаемым, т.к. после включения виртуалки неудобно заходить через ssh на ужасное имя ec2-55-240-2-74.compute-1.amazonaws.com (постоянно меняется) и руками его запускать что бы обновить зону.
Для этого я сделал его исполняемым и скопировал в /etc/init.d/
chmod +x ec2-hostname.sh
cp ec2-hostname.sh /etc/init.d/
update-rc.d ec2-hostname.sh defaults


Для Windows оказалось всё намного проще:
@echo off
Setlocal enabledelayedexpansion
rem Путь к приватному ключевому файлу
set DNS_KEY="Kexample.com.+157+10000.private"
rem Имя домена
set DOMAIN=example.com
rem Имя поддомена
set HOSTNAME=site1
echo Поддомен и домен: %HOSTNAME%.%DOMAIN%

for /F "Delims=" %%P In ('curl -s http://169.254.169.254/latest/meta-data/public-ipv4') Do Set PUBIP=%%~P
echo Публичный адрес: %PUBIP%
(
@echo server ns1.%DOMAIN%
@echo zone %DOMAIN%
@echo update delete %HOSTNAME%.%DOMAIN% A
@echo update add %HOSTNAME%.%DOMAIN% 60 A %PUBIP%
@echo send
) | nsupdate -k %DNS_KEY% -v 

for /F "Delims=" %%L In ('curl -s http://169.254.169.254/latest/meta-data/local-ipv4') Do Set LOCIP=%%~L
echo Локальный адрес: %LOCIP%
(
@echo server ns1.%DOMAIN%
@echo zone %DOMAIN%
@echo update delete local.%HOSTNAME%.%DOMAIN% A
@echo update add local.%HOSTNAME%.%DOMAIN% 60 A %LOCIP%
@echo send
) | nsupdate -k %DNS_KEY% -v 

:eof


И поместить его в шедулер с запуском при старте системы.
Последнюю версию cURL брал здесь: www.paehl.com/open_source
BIND: www.isc.org/software/bind
От BIND нужны только файлы:
libisc.dll
liblwres.dll
libisccfg.dll
libbind9.dll
libeay32.dll
libdns.dll
libxml2.dll
nsupdate.exe

Их можно положить рядом со скриптом или же закинуть в %WINDIR%\system32

Вывод из всего этого:
Хоть я и выполнил данное задание, безопасть DNS сервера стала ещё меньше, т.к. добавилась ещё одна уязвимость и риск потерять правильно настроенную зону.
Прежде чем повторять написанное здесь, следует чётко понимать что же надо получить, сделать копию всех критически важных и изменяемых объектов, надо быть уверенным что в случае какого-либо сбоя можно получить доступ к машине и исправить ситуацию.
За последствия я не отвечаю, т.к. сам не уверен в её правильности.

P.S.
Прошу прощения за такой сумбурный текст, и возможные ошибки.

Теги:
Хабы:
+1
Комментарии 11
Комментарии Комментарии 11

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн
PG Bootcamp 2024
Дата 16 апреля
Время 09:30 – 21:00
Место
Минск Онлайн
EvaConf 2024
Дата 16 апреля
Время 11:00 – 16:00
Место
Москва Онлайн