Application: Nginx + SSL.
Примем меры к защите трафика между клиентом и сервером с помощью OpenSSL. Учитывая то, что "front-end" у нас для всех запросов - Nginx, нам достаточно настроить работу с SSL только для него, а "back-end", в роли которого будет работать Apache2 даже знать об этом не будет.
Было бы красиво для каждого сайта, нуждающегося в шифровании трафика, создать или приобрести свой сертификат. Ограничения (или особенности, если вдаваться в терминологию) протокола HTTPS требуют закреплять за каждым виртуальным хостом по выделенному IP. Но, в данном конкретном случае, мы не так богаты, чтобы закупать для каждого ресурса по выделенному IP адресу. Потому придётся создать для всего набора сервисов один сертификат и использовать его применительно к сервисам, нуждающимся в защите (до тех пор, пока не разживемся полноценным заверенным сертификатом).
Установим пакеты приложений работы с сертификатами и шифрованием трафика (скорее всего, они уже установлены):
# aptitude install openssl ssl-cert
Пройдем этапы создания необходимых ключевых файлов.
Создадим себе временную директорию для работы:
# mkdir /tmp/work
# cd /tmp/work
# cd /tmp/work
Создаем приватный ключ:
# openssl genrsa -des3 -out domain.name.key 2048
Генерация ключа сопровождается требованием ввести "парольную фразу" для доступа к ключу (её обязательно нужно будет запомнить на время проведения манипуляций с созданием ключевых файлов):
Generating RSA private key, 2048 bit long modulus
........+++
................+++
e is 65537 (0x10001)
Enter pass phrase for domain.name.key:
Verifying - Enter pass phrase for domain.name.key:
........+++
................+++
e is 65537 (0x10001)
Enter pass phrase for domain.name.key:
Verifying - Enter pass phrase for domain.name.key:
Вторым этапом создаем запрос на "самоподписанный" сертификат подлинности (никто его подтвердить не сможет, но шифровать трафик это не помешает):
# openssl req -new -key domain.name.key -out doamin.name.csr
В процессе создания запроса нам понадобится запомненная ранее "парольная фраза". Так же, нас попросят ответить на ряд вопросов о данных, включаемых в сертификат; желательно отвечать на них правдиво, хотя бы и затем, чтобы не запутаться в дальнейшем в своём положении в этом мире. Предложение защитить запрос паролем проще всего проигнорировать:
Enter pass phrase for domain.name.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KZ
State or Province Name (full name) [Some-State]:State
Locality Name (eg, city) []:City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Any
Organizational Unit Name (eg, section) []:Section
Common Name (eg, YOUR name) []:domain.name
Email Address []:support@domain.name
....
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:Company
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:KZ
State or Province Name (full name) [Some-State]:State
Locality Name (eg, city) []:City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Any
Organizational Unit Name (eg, section) []:Section
Common Name (eg, YOUR name) []:domain.name
Email Address []:support@domain.name
....
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:Company
Следующий финт, даже не этап, состоит в удалении из приватного ключа "парольной фразы", чтобы избежать запроса этой самой фразы при каждом обращении к приватному ключу:
# cp domain.name.key domain.name.key.orig
# openssl rsa -in domain.name.key.orig -out domain.name.key
# openssl rsa -in domain.name.key.orig -out domain.name.key
Enter pass phrase for domain.name.key.orig:
writing RSA key
writing RSA key
Последний этап - создание SSL сертификата как такового:
# openssl x509 -req -days 3650 -in domain.name.csr -signkey domain.name.key -out domain.name.crt
Signature ok
subject=/C=KZ/ST=State/L=City/O=ITS/OU=Any/CN=domain.name/emailAddress=support@domain.name
Getting Private key
subject=/C=KZ/ST=State/L=City/O=ITS/OU=Any/CN=domain.name/emailAddress=support@domain.name
Getting Private key
Раскладываем ключ и сертификат по надлежащим им местам и удаляем все, что было нами для их создания сотворено:
# mkdir -p /var/www/ssl/certs
# mkdir -p /var/www/ssl/private
# cp domain.name.crt /var/www/ssl/certs/
# cp domain.name.key /var/www/ssl/private/
# rm -R /tmp/work
# mkdir -p /var/www/ssl/private
# cp domain.name.crt /var/www/ssl/certs/
# cp domain.name.key /var/www/ssl/private/
# rm -R /tmp/work
Nginx работает с правами специально созданного для этого пользователя. Соответсвенно ограничиваем доступ к сертификатам:
# chown -R root:www-nginx /var/www/ssl
# chmod -R g-w /var/www/ssl
# chmod -R o-rwx /var/www/ssl
# chmod -R g-w /var/www/ssl
# chmod -R o-rwx /var/www/ssl
Описание конфигурации виртуального хоста с поддержкой SSL в Nginx отличается от описания обычного наличием следующих директив:
server {
# описываем виртуальный хост исключительно для отслеживания подключений к порту 80 (http) и перенаправления их на 443 (https)
listen *:80;
server_name u000.local;
rewrite ^/(.*)$ https://$host/$1 permanent;
}
#
server {
# указываем серверу прослушивать соответствующий порт
listen *:443;
....
# включаем механизм SSL и, следуя рекомендациям разработчиков сервера, устанавливаем следующие параметры
ssl on;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /var/www/ssl/certs/domain.name.crt;
ssl_certificate_key /var/www/ssl/private/domain.name.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
....
# Перенаправление на сервер "back-end"
location / {
proxy_pass http://127.0.0.1:8080/;
include /etc/nginx/proxy.conf;
}
....
}
# описываем виртуальный хост исключительно для отслеживания подключений к порту 80 (http) и перенаправления их на 443 (https)
listen *:80;
server_name u000.local;
rewrite ^/(.*)$ https://$host/$1 permanent;
}
#
server {
# указываем серверу прослушивать соответствующий порт
listen *:443;
....
# включаем механизм SSL и, следуя рекомендациям разработчиков сервера, устанавливаем следующие параметры
ssl on;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers AES128-SHA:AES256-SHA:RC4-SHA:DES-CBC3-SHA:RC4-MD5;
ssl_certificate /var/www/ssl/certs/domain.name.crt;
ssl_certificate_key /var/www/ssl/private/domain.name.key;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
....
# Перенаправление на сервер "back-end"
location / {
proxy_pass http://127.0.0.1:8080/;
include /etc/nginx/proxy.conf;
}
....
}
Удостоверимся в том, что Nginx работает, дополнительно прослушивая ещё и заданный 443 (https) порт:
# netstat -apn | grep tcp | grep nginx
tcp 0 0 0.0.0.0:80 *:* LISTEN 3573/nginx
tcp 0 0 0.0.0.0:443 *:* LISTEN 3573/nginx
tcp 0 0 0.0.0.0:443 *:* LISTEN 3573/nginx
Попробуем подключится к порту с помощью специального SSL-клиента, проверяя, действительно ли там защищённое соединение:
# openssl s_client -connect domain.name:443
Вывод, если он будет - "говорящий".