Шифрование Ethernet на скорости 1Gbps на Linux


Введение

В одном из проектов встала задача прозрачного шифрования трафика на Ethernet уровне. Стоимость “аппаратных” шифраторов для такой скорости зашкаливала и было решено посмотреть на возможность программной реализации.

В статье рассматривается решение по “преодолению” рубежа 1Gbps пропускной способности зашифрованного канального уровня и имеющее низкие временные задержки.

Решение не требует навыков программирования, только дистрибутив GNU/Linux системы со свободным программным обеспечением, доступным в большинстве стандартных репозиториев.

Отдельной задачей решаемой в рамках статьи была плохая распараллеливаемость криптографических алгоритмов. Не смотря на большую суммарную производительность многоядерных процессоров, одиночный VPN-туннель имеет производительность 300-600 Mbps.


Тестовый стенд

Стенд состоит их двух серверов ETegro Hyperion RS160 G3. Каждый содержит:
два сетевых интерфейса. Скорость каждого — 1Gbps;
eth0 — подключённый к “офисной” сети;
eth1 — через который напрямую соединены патч-кордом два тестовых компьютера.
свободную операционную систему Debian GNU/Linux 6.0.2 amd64;
процессор Quad-Core AMD Opteron™ Processor 2386 SE (четыре ядра, тактовая частота 2800 Mhz).

Сервисом виртуальной криптографически защищённой частной сети является свободный пакет OpenVPN. Данная программа имеет важную возможность создания виртуального сетевого TAP-интерфейса способного инкапсулировать Ethernet-фреймы, а не только более высокоуровневые IP-пакеты.

Тестирование производительности сетевого подключения производится программой Netperf 2.4.4. Измеряется как потоковый трафик, так и его задержки (путём пересчёта измерений *RR тестов, выдающих количество транзакций (request/response) произведённых в секунду).

Между eth1 устройствами поднята IPv4 сеть: 172.16.10.0/24.

На устройстве eth0 никаких IP адресов не устанавливается. Для “офисного” оборудования eth0 является прозрачным и безопасным мостом второго уровня.
Схема высокоскоростного шифрования трафика

зелёным цветом обозначаются не зашифрованные данные;
красным цветом обозначаются зашифрованные данные;


Один туннель OpenVPN

Сетевой TAP интерфейс объединяется с физическим eth0 в т.н. мост. Этим достигается прозрачная пересылка Ethernet-фреймов с физического интерфейса в инкапсулирующий туннель, на противоположном конце которого также имеется связанный мостом физический интерфейс.


Несколько туннелей OpenVPN

Распараллеливание процесса шифрования трафика осуществляется запуском нескольких OpenVPN-демонов. Распределение трафика между демонами (потока атомарных Ethernet-фреймов) производится за счёт объединения TAP-интерфейсов в виртуальный bond-интерфейс. “Bonding” — процесс объединения сетевых интерфейсов в один общий виртуальный, с целью увеличения либо суммарной пропускной способности, либо надёжности соединения. Несложный алгоритм планирования распределяет поступающие Ethernet-фреймы по интерфейсам bond-а. Bond-интерфейс, в свою очередь, объединяется в мост с Ethernet интерфейсом eth0.


Схематичное представление работы OpenVPN

зелёным цветом обозначаются не зашифрованные данные;
красным цветом обозначаются зашифрованные данные;
жёлтым цветом обозначаются динамически меняющиеся от входного трафика данные;
фиолетовым цветом обозначены вызовы системных функций;
ETH0 — сетевой интерфейс подключённый к сети офиса;
ETH1 — сетевой интерфейс подключённый к ETH1 противолежащего офиса;
CMPRS — сжатие Ethernet-фрейма без потерь;
PAD — дополнение (padding) сжатого фрейма до размера шифроблока;
INCR — инкрементирующийся счётчик;
SEQ — порядковый номер OpenVPN-пакета;
DATA — сжатый дополненный фрейм;
ENC — шифрование данных, используя вектор инициализации IV;
EDATA — зашифрованный DATA фрейм;
PRNG — генератор криптографически стойких псевдослучайных чисел;
IV — вектор инициализации, передаваемый в открытом виде;
HMAC — функция и результат хэш-кода аутентичности сообщения;
UDP — UDP-пакет инкапсулирующий OpenVPN-пакет;
IP — IP-пакет инкапсулирующий UDP-пакет.
Особенности OpenVPN-решения
Во время шифрования используется режим сцепления блоков шифротекста (Cipher Block Chaining (CBC)). Для этого режима необходимо использование постоянно меняющегося вектора инициализации.
Вектор инициализации передаётся в открытом виде, однако из-за использования PRNG его сложно (невозможно) предсказать.
Для предотвращения атак повторного воспроизведения (replay attack) используется код аутентичности сообщения (Message Authentication Code (MAC)) основанный на использовании хэш-функции (HMAC).
Сжатие данных необходимо с точки зрения криптографии для уменьшения возможного большого количества корреляций во входящем трафике.
Для увеличения энтропии псевдослучайного шума чисел для PRNG имеется возможность двухстороннего обмена ею между OpenVPN-демонами.
Смена ключей шифрования (время от времени) происходит без каких-либо задержек для транзитного трафика, так как есть возможность работы одновременно имея пару параллельно действующих ключей.
Процесс обмена ключами может происходить используя TLS-соединение (Transport Layer Security).
Гарантированная доставка пакетов данных обеспечивается на уровне OpenVPN, а не более низлежащих транспортов, используя SEQ.


Однопоточное шифрование

Результаты измерения производительности TCP соединения напрямую по сети между eth1 интерфейсами:

Запуск OpenVPN

Используются заранее подготовленные (pre-shared) ключи шифрования, которые находятся на обоих концах соединения:
% openvpn --genkey --secret key.asc

Запуск OpenVPN на каждом из компьютеров производится следующим образом:
alpha# openvpn --remote 172.16.10.2 --dev tap0 --secret key.txt
beta# openvpn --remote 172.16.10.1 --dev tap0 --secret key.txt

Задержки увеличились в четыре раза. Относительно начального значения этот рост может показаться существенным, однако абсолютные значения его равняются накладным расходам любого активного сетевого оборудования — поэтому этим фактом можно пренебречь.


Попытки увеличения производительности


Смена алгоритма шифрования. По-умолчанию OpenVPN использует алгоритм Blowfish с 128-битным ключом шифрования. Данный алгоритм отличается своей открытостью, свободой использования, патентной чистотой. На момент создания он также являлся одним из самых быстрых, но до сих пор его криптографическая стойкость высока (гарантируется стойкость “честного” 128-ого ключа). Однако современные реализации более криптостойкого алгоритма AES (Advanced Encryption Standard, также известного как Rijndael) на практике имеют большую производительность:
# openvpn ... --cipher AES-128-CBC

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


Многопоточное шифрование

Казалось бы, достаточно будет запустить 2-3 OpenVPN туннеля и они дадут необходимую полосу пропускания в 1Gbps.


Распределение канального трафика


Запуск нескольких OpenVPN-демонов на разных портах:
# openvpn ... --port 5001
# openvpn ... --port 5002
# openvpn ... --port 5003
Создание bond-интерфейса (по умолчанию его конфигурация установлена в режим повышения производительности):
# modprobe bonding
# ifenslave bond0 tap0
# ifenslave bond0 tap1
# ifenslave bond0 tap2
Объединение bond-интерфейса с физическим интерфейсом eth0:
# brctl addbr br0
# brctl addif br0 bond0

Однако показатели производительности стали не намного лучше:

Было замечено, что процессы openvpn постоянно перемещаются между ядрами процессора и пиковая нагрузка каждого ядра редко достигает даже 90 процентов.


Привязка процессов OpenVPN к процессору

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

Серверы тестового стенда имеют архитектуру NUMA (Non-Uniform Memory Access). Для жёсткой привязки процессов к ядрам и как следствие к т.н. нодам используется утилита numactl. Можно указать, что определённые процессы должны запускаться на конкретном ядре:
# numactl --physcpubind=1 openvpn ... --port 5001
# numactl --physcpubind=2 openvpn ... --port 5002
# numactl --physcpubind=3 openvpn ... --port 5003

После этого, ситуация с производительностью заметно улучшилась:

Такая завышенная скорость, в сравнение с вариантом без шифрования вообще, получается за счёт применения сжатия трафика. В реальности это значение может быть как меньше, так и существенно больше. Это будет зависеть от передаваемых данных.

Запуск производился с настройками максимальной производительности, то есть с отключённой аутентификацией пакетов. После включения получаются следующие результаты:

Также можно установить размеры ключей шифрования равными 256-бит (AES-256-CBC), что обеспечивает гораздо более высокую криптостойкость и весьма незначительное понижение пропускной способности:

Зачастую, в реальности полное пиковое использование канала далеко не всегда происходит. Было произведено измерение производительности всего с двумя OpenVPN-туннелями, но с привязкой к процессору:

Выводы

Имея современный многоядерный процессор, можно небольшими трудозатратами добиться прозрачного криптостойкого шифрования трафика канального уровня (например между подразделениями организации, связанной выделенным каналом связи). Стоимость такого решения будет существенно ниже специализированных аппаратных шифраторов.

Распараллеливание нагрузки производится за счёт распределения Ethernet-фреймов, поступающих с физического сетевого интерфейса на виртуальный bonding-интерфейс, объединяющий TAP-устройства формируемые процессами OpenVPN.

Если в процессоре есть возможность выполнения таких алгоритмов/функций как AES и SHA1, то можно существенно увеличить пропускную способность шифрованного канала. Эмпирически было замечено, что около половины всех вычислительных ресурсов затрачивается на процесс сжатия данных.

Сергей Матвеев (руководитель отдела исследования и разработки <sergey.matveev@etegro.com>)

Отдельное спасибо за помощь в написании статьи:
Андрею Сапронову (технический директор <andrey.sapronov@etegro.com>)

http://www.etegro.com/articles/encrypted-gigabit

Обновлено: 13.03.2015