Re: Mutual authentication средствами nginx

Gena Makhomed gmm at csdoc.com
Wed Jan 22 20:49:21 UTC 2014


On 22.01.2014 16:18, Илья Шипицин wrote:

> очевидно, если пользователь предъявляет вам сертификат,
> то у него есть закрытый ключ.
 >
> чтобы nginx смог дальше предъявить этот же сертификат, получается надо
> дубликаты всех пользовательских закрытых ключей держать на nginx ?
>
> или вы какой-то другой сценарий имели в виду ?

Другой сценарий.

Есть два сервера. На каждом из этих двух серверов работает
веб-сервис, который отвечает на запросы пользователей по протоколу
http и https. Кроме того, этим двум сервисам надо время от времени
обмениваться между собой информацией. Причем канал связи между ними
надо сделать максимально защищенным, так чтобы никто посторонний
не мог отправлять пакеты одному сервису от имени другого сервиса.

Самый надежный вариант, что я смог придумать - это сделать
свой собственный Certificate authority (с помощью easy-rsa)
создать в нем сертификаты для каждого сервера и каждого клиента,
и настроить проверку всех клиентских и серверных сертификатов
на уровне nginx.

Каждый из этих двух веб-сервисов выступает одновременно
и в роли клиента и в роли сервера при связи друг с другом.

Все что связано с сертификатами и TLS/SSL хотелось бы оставить
на уровне nginx, чтобы веб-сервисам приходил plain http,
и разработчикам этих веб-сервисов не приходилось бы потом
заморачиваться с https-запросами и клиентскими сертификатами.

Если веб-приложение работает как сервер - ему запрос приходит
на http://127.0.0.1:80/ а если веб-приложение работает как клиент
и хочет связаться с другим веб-сервисом - то оно просто отправляет
plain http запрос на http://127.0.0.1:8080/ - здесь слушает nginx
и проксирует этот запрос через https с mutual auth на удаленный сервер.

Если nginx работает в роли сервера - тогда без проблем можно
настроить проверку валидности клиентского сертификата.
Приблизительно вот так:

server {
     listen 11.22.33.44:555 ssl;
     ...
     ssl_client_certificate /etc/tls/api.example.com/ca.crt;
     ssl_verify_client on;

     # allow connection only for client with certificate with serial "01"
     if ($ssl_client_serial != "01") { return 403; }

Но если nginx работает в роли клиента и проксирует запросы от сервиса
к другому серверу через proxy_pass https:// - тут не получается
настроить его, чтобы он предъявлял свой клиентский сертификат
и чтобы проверял валидность серверного сертификата.

Скорее всего - такой функциональности сейчас в nginx таки нет.
Только не понятно - ее "еще нет" или же "вообще нет и не будет".

Подозреваю, что такая функциональность в nginx будет полезной
не только мне, но и большому количеству других пользователей.

И возможно это даже будет killer feature, которая позволит
еще больше увеличить % использование nginx в современном
web 2.0 и будущем web 3.0. Если это кому-то интересно.

Альтернативные варианты - это разве что OpenVPN.
Но nginx надежнее и удобнее в эксплуатации.

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

Может быть я ошибаюсь, но с моей точки зрения идеальным
вариантом решения этой и многих других подобных задач -
было бы научить nginx работать в таком proxy_pass режиме.

Самому писать такой патч - я полгода наверное буду вспоминать
все нюансы работы С/С++ и разбираться с устройством OpenSSL.
Тем более, что еще не факт, что его примут в основную ветку.

Если бы существовала в природе Nginx Foundation и можно было
бы пожертвовать некоторое количество денег, обозначив свой интерес
в том чтобы в nginx появилась такая feature - я бы не задумываясь
часть своей зарплаты потратил бы на то, чтобы "проголосовать" за нее.
Возможно, если это надо не только мне, но и другим людям - тогда
эта задача поднялась бы повыше в списке приоритетов на разработку.

Могу даже попробовать пойти к начальству и предложить вариант
чтобы компания единолично спонсировала появление такой feature
в nginx, которая была бы полезной для реализации этой задачи.

Но прежде чем куда-то идти и о чем-то просить - вот сначала
попытался узнать в списке рассылки - может быть я какой-то
неправильный вариант решения для этой задачи придумал
и ее все обычно решают другим, более простым способом?

Или же по каким-то техническим или идеологическим причинам
такая feature никогда не может быть добавлена в nginx,
и поэтому мне надо искать какие-то другие варианты
решения для этой нашей задачи?



>> Как сделать Mutual authentication
>> между двумя сервисами с помощью nginx?
>>
>> На двух разных серверах nginx слушает на порту 443
>> и проксирует клиентские запросы на порт 80 backend`а.
>>
>> "На вход" проверка клиентского сертификата работает отлично.
>> А когда backend делает клиентский запрос на 127.0.0.1:8080 -
>> nginx проксирует этот запрос на 443 порт удаленного сервера
>> по https. Но как сделать так, чтобы при proxy_pass nginx
>> еще и предьявлял клиентский сертификат удаленному сервису?
>>
>> Или какой софт можно использовать здесь вместо nginx,
>> если nginx это делать не умеет и такая функциональность
>> в нем никогда не будет реализована по каким-то причинам?
>> Хотя, это наверное была бы killer feature, полезная многим.
>>
>> Если только принимать https-запросы на уровне nginx,
>> а отправлять https-запросы через само приложение
>> - тогда будет layering violation и клиентскому
>> приложению придется давать доступ к файлу ключа.
>>
>> Может быть кто-то уже решал такую или похожую задачу?

-- 
Best regards,
  Gena



Подробная информация о списке рассылки nginx-ru