Проксирование POP/IMAP через NGINX c помощью Django

Одной из не так часто используемых возможностей nginx является возможность проксировать POP/IMAP. Когда это может быть полезно? Ну например для распределения нагрузки в высоконагруженной почтовой службе. Второй вариант — для прозрачной для пользователей переадресации на стороннюю почтовую службу.

Передо мной стояла следующая задача: в компании было принято решение использовать вместо своих серверов в качестве почтовой службы Яндекс.Почту для Домена. В основном решение было продиктовано огромным потоком спама, с которым не справлялся SpamAssassin, да и с самим объёмом почты сервер справлялся не без труда (на нём было множество других служб). При этом требовалось перенести почту без изменения паролей пользователей. Пароли, естественно, хранились в виде хэшей, поэтому автоматически установить пользователям на Яндексе такие же пароли было невозможно.

Поэтому я принял решение оставить авторизацию пользователей на своих серверах. Как раз с помощью nginx. А для упрощения администрирования этой системы, я написал два Django-приложения: одно для управления пользователями и авторизацией в nginx, а второе для синхронизации первого приложения с Яндекс.Почтой для домена.

Итак,

1. Настройка nginx как POP/IMAP прокси

Конфигурация достаточно простая:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
mail {
 auth_http 127.0.0.1:8080/auth/auth; # адрес авторизационного приложения (см. ниже)
 auth_http_header X-NGX-Auth-Key "SOME_SECRET_KEY"; # HTTP-заголовок, который nginx
                                                    # будет устанавливать, чтобы
                                             # показать авторизационному приложению,
                                             # что это действительно он
 proxy on; # включаем pop/imap прокси
 
 xclient off; # отключаем передачу в SMTP информации о пользователе (команду XCLIENT)
 
# дальше вроде всё понятно
 imap_capabilities "IMAP4rev1" "UIDPLUS";
 server {
 listen 143;
 protocol imap;
 starttls only;
 }
 
 server {
 listen 993;
 protocol imap;
 ssl on;
 }
 
 smtp_auth "plain";
 smtp_capabilities "8BITMIME" "SIZE 42991616" "ENHANCEDSTATUSCODES";
 
 server {
 listen 25;
 listen 587;
 protocol smtp;
 starttls only;
 }
 
 server {
 listen 465;
 protocol smtp;
 ssl on;
 }
 
 pop3_capabilities "TOP" "USER";
 server {
 listen 110;
 protocol pop3;
 starttls only;
 }
 
 server {
 listen 995;
 protocol pop3;
 ssl on;
 }
}

А что с SMTP?

Nginx почему-то не умеет передавать в SMTP авторизацию иначе как через команду XCLIENT (которую, например, яндексовский SMTP не поддерживает). Самый простой выход из такой ситуации — запустить свой SMTP на том же сервере, где nginx, и просто принимать от nginx с локалхоста любую почту без авторизации.

2. Авторизационное приложение

Nginx работает с авторизационным приложением по следующему протоколу:

Он отправляет HTTP-запрос со следующими заголовками:

Auth-Method: plain
Auth-User: user
Auth-Pass: password
Auth-Protocol: imap
Auth-Login-Attempt: 1
X-NGX-Auth-Key: SOME_SECRET_KEY
Client-IP: 192.168.1.1

И ждёт либо положительный ответ (вся информация — в HTTP-заголовках):

Auth-Status: OK
Auth-Server: 192.168.1.10 # адрес почтового сервера
Auth-Port: 110
Auth-User: newname # логин в почтовый сервер
Auth-Pass: password # пароль в почтовый сервер (plaintext)

Либо отрицательный:

Auth-Status: Invalid login or password
Auth-Wait: 3 # таймаут перед следующей попыткой входа

Методы аутентификации

Моё Django-приложение рассчитано на работу с простым методом PLAIN. Мне кажется при работе по SSL/STARTTLS это достаточно безопасно. Особенности работы с nginx остальных методов я сейчас, честно говоря, не вспомню, хотя в своё время это смотрел.

3. Django-приложение для аутентификации

1. Установка

Лежит на гитхабе и битбакете (там же по соседству можно найти и второе приложение, для Яндекс.Почты, но про него я подробнее напишу позже). Установка:

1
2
3
pip install git+https://V-Alexeev@github.com/V-Alexeev/nginxmailauth.git
или
pip install hg+https://bitbucket.org/v_alexeev/nginxmailauth

Дальше добавляем nginxmailauth в INSTALLED_APPS, urls.py, а также устанавливаем две собственных опции:

1
2
3
NGX_AUTH_KEY = "SOME_SECRET_KEY" # Тот ключ, который мы установили в конфиге nginx
ALLOWED_NGINX_IPS = ("127.0.0.1", "192.168.1.5") # Дополнительная проверка: только
                 # с этих IP-адресов будут разрешаться запросы

Запускаем сервер с нашим приложением и направляем на него nginx. Оно вполне может быть запущено на общедоступном адресе, поскольку в нём есть одна служба для пользователей — смена пароля (по адресу /change_password), а авторизационные запросы фильтруются по IP-адресу и X-NGX-Auth-Key.

2. Что включено

  1. Методы проверки пароля:
    1. Простым текстом
    2. Сравнение с md5-хэшем пароля
    3. Сравнение с md5-хэшем от строки «логин:сервер:пароль».
    4. Чтобы добавить свой метод проверки, достаточно отнаследоваться от класса BaseAuthenticationMethod и переопределить метод get_password (см. докстринги в methods.py).
    5. В планах — добавить проверку пароля через Kerberos.
  2. Управление пользователями через стандартную админку Django.
  3. Страница смены своего пароля самими пользователями (по адресу /change_password).

  1. Dobrii Deni
    Kak startovati prilozenie ?

    Vasja

Оставить комментарий


Примечание - Вы можете использовать эти HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>