Настройка IPsec с помощью ipsecctl


Настройка хостов

Новая утилита ipsecctl призвана заменить более старую утилиту ipsecadm, а также упростить процедуру установки IPsec соединения "руками" (manual keying), поместив всю настройку в удобный конфигурационный файл /etc/ipsec.conf.

Для примера рассмотрим построение IPsec туннеля между хостами 192.168.10.1 (hostA) и 192.168.11.1 (hostB). Будем использовать Blowfish как алгоритм шифрования нагрузки ESP, а для аутентификации будем использовать HMAC-SHA2-512.

Сгенерируем ключи для аутентификации (512 бит) и шифрования (160 бит). Для других алгоритмов необходима иная длина ключа, например, для AES длина ключа должна быть 128 бит. Примеры можно посмотреть в файлах regress тестов (в директории /usr/src/regress/sbin/ipsecctl/, если у вас установлены исходные коды ОС).

hostA# mkdir -m 700 /etc/ipsec

hostA# openssl rand 64 | hexdump -e '64/1 "%02x"' >/etc/ipsec/akey.local

hostA# openssl rand 20 | hexdump -e '20/1 "%02x"' >/etc/ipsec/ekey

На втором узле создаем ключ для аутентификации:

hostB# mkdir -m 700 /etc/ipsec

hostB# openssl rand 64 | hexdump -e '64/1 "%02x"' >/etc/ipsec/akey.local

Обмениваемся auth ключами и передаем на hostB ключ для шифрования:

hostA# scp /etc/ipsec/ekey 192.168.11.1:/etc/ipsec/ekey

hostA# scp /etc/ipsec/akey.local 192.168.11.1:/etc/ipsec/akey.remote

hostB# scp /etc/ipsec/akey 192.168.10.1:/etc/ipsec/akey.remote

Защищаем файлы от просмотра (на обоих узлах):

# chmod 600 /etc/ipsec.conf /etc/ipsec/{akey*,ekey}

Создадим на узле 192.168.10.1 файл /etc/ipsec.conf. Формат файла описан в man руководстве ipsec.conf(5). Значения SPI (индекс параметра безопасности) выбирается случайным 32-битным значением и уникально идентифицирует ассоциацию безопасности данного хоста.



# Конфигурация IPsec для 192.168.10.1

#

flow esp from 192.168.10.1 to 192.168.11.1

esp from 192.168.10.1 to 192.168.11.1 spi 0x4d9b5ca0:0x832a16bf

auth hmac-sha2-512 enc blowfish

authkey file "/etc/ipsec/akey.local:/etc/ipsec/akey.remote"

enckey file "/etc/ipsec/ekey:/etc/ipsec/ekey"

На узле 192.168.11.1 необходимо создать ответный файл:



# Конфигурация IPsec для 192.168.11.1

#

flow esp from 192.168.11.1 to 192.168.10.1

esp from 192.168.10.1 to 192.168.11.1 spi 0x832a16bf:0x4d9b5ca0

auth hmac-sha2-512 enc blowfish

authkey file "/etc/ipsec/akey.local:/etc/ipsec/akey.remote"

enckey file "/etc/ipsec/ekey:/etc/ipsec/ekey"

Выполняем загрузку конфигурации на обоих хостах:

# ipsecctl -vf /etc/ipsec.conf

flow esp out from 192.168.10.1 to 192.168.11.1 peer 192.168.11.1

type require

flow esp in from 192.168.11.1 to 192.168.10.1 peer 192.168.11.1

type use

esp from 192.168.10.1 to 192.168.11.1 spi 0x4d9b5ca0

auth hmac-sha2-512 enc blowfish

authkey <...>

enckey <...>

esp from 192.168.11.1 to 192.168.10.1 spi 0x832a16bf

auth hmac-sha2-512 enc blowfish

authkey <...>

enckey <...>

Если загрузка успешна, и вы хорошо оттестировали, необходимо добавить загрузку конфигурации в системные инициализационные скрипты (на момент написания статьи скрипт /etc/rc сам еще не обрабатывает наличие ipsec.conf). Добавим в начало /etc/rc.local:



if [ -r /etc/ipsec.conf ]; then

echo -n ' ipsec'; /sbin/ipsecctl -f /etc/ipsec.conf

fi

Тут еще надо сделать замечание, что поскольку IPsec устанавливает дополнительные маршруты, то правильнее всего добавлять такой скрипт не в rc.local, а сразу в /etc/rc после загрузки isakmpd.

Тестирование

Проверяем. На хосте 192.168.10.1:

hostA# ipsecctl -sa

FLOWS:

flow esp in from from 192.168.10.1 to 192.168.11.1

peer 192.168.11.1

flow esp out from from 192.168.11.1 to 192.168.10.1

peer 192.168.11.1



SADB:

esp from 192.168.10.1 to 192.168.11.1 spi 0x4d9b5ca0

enc blowfish auth hmac-sha2-512

esp from 192.168.11.1 to 192.168.10.1 spi 0x832a16bf

enc blowfish auth hmac-sha2-512

Видно, что на втором хосте (192.168.11.1) часть, отвечающая за базу SA, та же самая, а описания IPsec потоков противоположные.

hostB# ipsecctl -sa

FLOWS:

flow esp in from from 192.168.11.1 to 192.168.10.1

peer 192.168.10.1

flow esp out from from 192.168.10.1 to 192.168.11.1

peer 192.168.10.1



SADB:

esp from 192.168.10.1 to 192.168.11.1 spi 0x4d9b5ca0

enc blowfish auth hmac-sha2-512

esp from 192.168.11.1 to 192.168.10.1 spi 0x832a16bf

enc blowfish auth hmac-sha2-512

Проверим, что творится в канале. Запускаем дампер сетевого трафика на 192.168.11.1:

hostB# tcpdump -nvi fxp0 host 192.168.10.1 and 192.168.11.1

Пытаемся присоединиться к порту 22 с машины 192.168.10.1:

hostA# telnet 192.168.11.1 ssh

Trying 192.168.11.1...

Connected to 192.168.11.1.

Escape character is '^]'.

SSH-1.99-OpenSSH_4.1

На 192.168.11.1 видим только пакеты ESP:

18:51:59.624908 esp 192.168.10.1 > 192.168.11.1 spi 0x4D9B5CA0

seq 559 len 68 [tos 0x10] (ttl 64, id 44596, len 88)

18:51:59.625505 esp 192.168.11.1 > 192.168.10.1 spi 0x832A16BF

seq 436 len 68 (DF) (ttl 64, id 29087, len 88)

...

Стоит также обратить внимание на появившиеся маршруты в таблице маршрутизации:

hostA# netstat -rnf encap

Routing tables



Encap:

Source Port Destination Port Proto SA(Address/Proto/Type/Direction)

192.168.11.1/32 0 192.168.10.1/32 0 0 192.168.11.1/50/use/in

192.168.10.1/32 0 192.168.11.1/32 0 0 192.168.11.1/50/require/out

Замечания по настройке pf

Перейдем к настройке фильтра пакетов (pf). Основные идееи тут должны быть такими:

Необходимо разрешить входящий трафик по протоколу ESP от необходимых узлов.
Запретить не ESP трафик от этих узлов (если, конечно, не требуется обратное...)
Фильтрация по расшифрованной нагрузке (протоколы/порты) должна производиться на интерфейсе enc0.
Примерный вид правил для узла (hostA) может выглядеть так:

# Определение внешнего интерфейса

#

ext_if = "fxp0"



# Удаленный IPsec хост

#

hostB = "192.168.11.1"



# Не фильтровать на loopback

#

set skip on lo



# Политика блокирования по умолчанию

#

block

block return-rst proto tcp



# Разрешить исходящие пакеты (к hostB будет явно разрешен только ESP)

#

pass out to ! $hostB keep state



# Разрешить входящие и исходящие соединения от/к hostB только по протоколу ESP

#

pass in on $ext_if proto esp from $hostB to ($ext_if) keep state

pass out on $ext_if proto esp from ($ext_if) to $hostB keep state



# Разрешить входящие соединения от hostB на необходимые порты

#

pass in on enc0 proto tcp from $hostB to ($ext_if) port { 80 8080 }

keep state

Обновлено: 13.03.2015