Вопрос или проблема
Текущая ситуация:
У меня есть установка OpenStack Triple-O (Liberty), где даже “публичная” сеть находится в частной среде (сеть 10.24.7.0/24). Единственный способ получить доступ к этой сети – через шлюз. Я хотел бы сделать Horizon доступным из интернета с помощью обратного прокси. Из-за соображений безопасности вся внешняя связь должна быть зашифрована с помощью HTTPS. Обратный прокси должен использоваться в качестве хоста для завершения SSL, а весь внутренний трафик должен быть нешифрованным.
Установка OpenStack не была настроена для использования SSL/TLS и не знает, что “публичная” сеть на самом деле не публичная.
В настоящее время я пытаюсь использовать Nginx в качестве обратного прокси, но использование другого программного обеспечения обратного прокси также возможно, если они предоставят решение моей проблемы.
Шлюз работает на RHEL 7.2, Nginx установлен из официального репозитория Nginx версии 1.11.1 (основная линия).
gateway.example.com – это FQDN, используемый в примерах,
1.2.3.4 – внешний IP-адрес шлюза, используемый в примерах
10.24.7.9 – “публичная” конечная точка установки Triple-O
Работа на данный момент:
http://gateway.example.com
загружает index.html, где можно скачать сертификат ЦА, используемой для подписания серверного сертификата.- Из-за того, что установка OpenStack не знает, что она находится за точкой завершения SSL, мне приходится изменять ссылки в содержимом. Это делается с помощью двух директив sub_filter, одна общая (
sub_filter 'http://$host' 'https://$host';
) и одна, которая заменяет IP конечной точки OpenStack (sub_filter 'http://10.24.7.9' 'https://$host';
) - Функция
console
Horizon позволяет пользователю подключаться к последовательной консоли экземпляра через NoVNC, встроенный в Horizon. NoVNC использует веб-сокеты для установки двухстороннего TCP-соединения между браузером и физическим хостом, на котором работает экземпляр. Чтобы поддержать это, мне пришлось настроить Nginx для разрешения обновлений HTTP-соединений и прослушивания порта 6080. iptables
разрешает трафик на портах 80, 443 и 6080.
Проблемы:
- На странице Horizon, показывающей детали экземпляра, вместо отображения тела вкладки (обзор, журнал, консоль, журнал действий), строка вкладок повторяется, и отображается только содержимое вкладки обзора.
- Подключения к консоли экземпляра заканчиваются с ошибкой 1006. (Необходимый URL для отображения консоли в отдельной вкладке браузера был получен с помощью
nova get-vnc-console <ID> novnc
с заменой IP конечной точки на FQDN.) Я подозреваю, что эта ошибка вызвана тем, что соединение, которое было обновлено с HTTP1.1 до стандарта websocket, содержит информацию о “публичном” интерфейсе, к которому нельзя получить прямой доступ из браузера, ИЛИ что соединение отклонено программным обеспечением NoVNC из-за несоответствия между настроенным адресом сервера/имя хоста (“публичный”) и адресом в запросе (имя/IP прокси). Оба этих случая – предположение.
Конфигурационный файл Nginx
ssl_certificate /etc/nginx/certs/gateway.example.com.crt;
ssl_certificate_key /etc/nginx/certs/gateway.example.com.key;
ssl_dhparam /etc/nginx/certs/dh.pem;
ssl_protocols TLSv1.2 TLSv1.1;
ssl_ciphers AES256+EECDH:AES128+EECDH:!aNULL:!eNULL:!ECDSA:!SHA:!DSS;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server { # http
server_name gateway.example.com localhost 1.2.3.4;
listen *:80;
root /usr/share/nginx/html;
location / {
index index.html;
}
location ~ ^/dashboard {
return 302 `https://$host$request_uri`;
}
location ~ ^/console {
return 302 `https://$host:6080$request_uri`;
}
location ~ ^/websockify {
return 302 `https://$host:6080$request_uri`;
}
}
server { # https
server_name gateway.example.com localhost 1.2.3.4;
listen *:443;
ssl on;
location / {
sub_filter '`http://10.24.7.9`' '`https://$host`';
sub_filter '`http://$host`' '`https://$host`';
sub_filter_last_modified on;
sub_filter_once off;
sub_filter_types *;
proxy_pass `http://10.24.7.9/$uri`;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Accept-Encoding "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
server { # https на порту 6080 для novnc
server_name gateway.example.com localhost 1.2.3.4;
listen *:6080;
ssl on;
location / {
proxy_pass `http://10.24.7.9:6080/$uri`;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_connect_timeout 90;
# proxy_send_timeout 90;
# proxy_read_timeout 90;
}
}
У кого-нибудь есть рабочая конфигурация для этой настройки? Я хотел бы остаться с Nginx, но могу переключиться на Apache или любое другое программное обеспечение, которое может предоставить решение.
Правка: уточнил использование ЦА, добавил подозрения по поводу ошибки подключения NoVNC
Я также смог решить первую проблему. Причина этого странного поведения заключалась в том, что обратный прокси отбрасывал часть запроса с параметрами (все, что за ?). Это снова было вызвано неправильно настроенными строками proxy_pass.
Решение заключалось в удалении /$uri
из обеих строк proxy_pass в конфигурационном файле (подробности см. http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_pass).
Это рабочее решение:
ssl_certificate /etc/nginx/certs/gateway.example.com.crt;
ssl_certificate_key /etc/nginx/certs/gateway.example.com.key;
ssl_dhparam /etc/nginx/certs/dh.pem;
ssl_protocols TLSv1.2 TLSv1.1;
ssl_ciphers AES256+EECDH:AES128+EECDH:!aNULL:!eNULL:!ECDSA:!SHA:!DSS;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server { # http
server_name gateway.example.com localhost 1.2.3.4;
listen *:80;
root /usr/share/nginx/html;
location / {
index index.html;
}
location ~ ^/dashboard {
return 302 `https://$host$request_uri`;
}
location ~ ^/console {
return 302 `https://$host:6080$request_uri`;
}
location ~ ^/websockify {
return 302 `https://$host:6080$request_uri`;
}
}
server { # https
server_name gateway.example.com localhost 1.2.3.4;
listen *:443;
ssl on;
location / {
sub_filter '`http://10.24.7.9`' '`https://$host`';
sub_filter '`http://$host`' '`https://$host`';
sub_filter_last_modified on;
sub_filter_once off;
sub_filter_types *;
proxy_pass `http://10.24.7.9`;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Origin `http://$host`;
proxy_set_header Accept-Encoding "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
server { # https на порту 6080 для novnc
server_name gateway.example.com localhost 1.2.3.4;
listen *:6080;
ssl on;
location / {
proxy_pass `http://10.24.7.9:6080`;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Origin `http://$host`;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_connect_timeout 90;
# proxy_send_timeout 90;
# proxy_read_timeout 90;
}
}
Я смог решить вторую из проблем (ошибка 1006), изменив некоторые параметры конфигурации. Поскольку другая проблема все еще сохраняется, я не могу подтвердить, что консоль NoVNC работает из интерфейса Horizon, но когда я напрямую вызываю URL NoVNC, я получаю соединение и могу взаимодействовать с экземпляром.
Это рабочее решение на данный момент:
ssl_certificate /etc/nginx/certs/gateway.example.com.crt;
ssl_certificate_key /etc/nginx/certs/gateway.example.com.key;
ssl_dhparam /etc/nginx/certs/dh.pem;
ssl_protocols TLSv1.2 TLSv1.1;
ssl_ciphers AES256+EECDH:AES128+EECDH:!aNULL:!eNULL:!ECDSA:!SHA:!DSS;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
server { # http
server_name gateway.example.com localhost 1.2.3.4;
listen *:80;
root /usr/share/nginx/html;
location / {
index index.html;
}
location ~ ^/dashboard {
return 302 `https://$host$request_uri`;
}
location ~ ^/console {
return 302 `https://$host:6080$request_uri`;
}
location ~ ^/websockify {
return 302 `https://$host:6080$request_uri`;
}
}
server { # https
server_name gateway.example.com localhost 1.2.3.4;
listen *:443;
ssl on;
location / {
sub_filter '`http://10.24.7.9`' '`https://$host`';
sub_filter '`http://$host`' '`https://$host`';
sub_filter_last_modified on;
sub_filter_once off;
sub_filter_types *;
proxy_pass `http://10.24.7.9/$uri`;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Origin `http://$host`;
proxy_set_header Accept-Encoding "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
server { # https на порту 6080 для novnc
server_name gateway.example.com localhost 1.2.3.4;
listen *:6080;
ssl on;
location / {
proxy_pass `http://10.24.7.9:6080/$uri`;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Origin `http://$host`;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_connect_timeout 90;
# proxy_send_timeout 90;
# proxy_read_timeout 90;
}
}
коротко
Изменения:
В обоих серверных блоках для портов 443 и 6080 я добавил proxy_set_header Origin http://$host;
. Не знаю точно, что это делает, но это решило мою проблему.
Это все еще оставляет меня с первой проблемой.
Я наткнулся на это, когда тоже долго мучился с этой проблемой. И это действительно мне помогло. Однако nginx не любит кавычки ` вокруг http://$host и т.д. Если вы их удалите, все будет работать. Вот рабочая конфигурация для меня, например:
ssl_certificate /etc/ssl/cert.pem;
ssl_certificate_key /etc/ssl/cert.key;
ssl_ciphers HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
server { # http
server_name openstack.example.com;
listen *:80;
location / {
return 302 https://$host$request_uri;
}
location ~ ^/console {
return 302 https://$host:6080$request_uri;
}
location ~ ^/websockify {
return 302 https://$host:6080$request_uri;
}
}
server { # https
server_name openstack.example.com;
listen *:443;
ssl on;
location / {
sub_filter 'http://192.168.0.200:6080' 'https://$host:6080';
sub_filter 'http://$host:6080' 'https://$host:6080';
sub_filter_last_modified on;
sub_filter_once off;
sub_filter_types *;
proxy_pass http://192.168.0.200;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Origin http://$host;
proxy_set_header Accept-Encoding "";
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
server { # https на порту 6080 для novnc
server_name openstack.example.com;
listen *:6080;
ssl on;
location / {
proxy_pass http://192.168.0.200:6080;
proxy_request_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header Origin http://$host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
}
}
Я публикую это, потому что, возможно, кто-то ищет обновленный ответ.
Ответ или решение
Как настроить OpenStack Horizon за обратным прокси (предпочтительно Nginx)
Введение
В связи с ростом киберугроз и требованиями безопасности, организациям важно обеспечить безопасный доступ к своим приложениям и услугам. Для инфраструктуры OpenStack это становится ещё более значимым, особенно в случае установки Turbo OpenStack (Triple-O), где корректная настройка доступа к интерфейсу Horizon через обратный прокси (reverse proxy) может оказаться необходимой мерой. В этом руководстве мы рассмотрим, как настроить Nginx как обратный прокси для OpenStack Horizon, обеспечивая при этом безопасный доступ через HTTPS.
Анализ текущей ситуации
У вас уже есть развернутая установка OpenStack с использованием Triple-O, однако она располагается в частной сети. Цель состоит в том, чтобы сделать Horizon доступным извне, используя обратный прокси, при этом все внешние соединения должны быть зашифрованы. Решение включает в себя настройку SSL-терминации на Nginx и дальнейшую маршрутизацию нешифрованного трафика внутри вашей сети.
Настройка обратного прокси Nginx
-
Установка и конфигурация Nginx:
Убедитесь, что Nginx установлен на вашем шлюзовом сервере:sudo yum install nginx
-
Конвертация конфигурации Nginx:
Откройте конфигурационный файл Nginx (обычно расположенный по пути/etc/nginx/nginx.conf
) и добавьте следующую конфигурацию. Важно помнить, что использование правильных заголовков и перенаправлений имеет критическое значение для корректной работы OpenStack Horizon.ssl_certificate /etc/nginx/certs/gateway.example.com.crt; ssl_certificate_key /etc/nginx/certs/gateway.example.com.key; ssl_protocols TLSv1.2 TLSv1.1; ssl_ciphers HIGH:!RC4:!MD5:!aNULL:!eNULL:!EXP:!LOW:!MEDIUM; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; server { # HTTP listen *:80; server_name gateway.example.com; location / { return 302 https://$host$request_uri; } } server { # HTTPS listen *:443 ssl; server_name gateway.example.com; location / { proxy_pass http://10.24.7.9; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
-
Решение проблем с отображением и соединением:
-
Если наблюдается проблема с дублированием вкладок или отсутствием контента, проверьте использование
sub_filter
. Обновленная версия должна выглядеть следующим образом:location / { sub_filter 'http://10.24.7.9' 'https://$host'; sub_filter_once off; proxy_pass http://10.24.7.9; ... }
-
Для подключения к NoVNC (веб-консоль через Horizon) убедитесь, что вы направляете трафик на соответствующий порт (6080). В конфигурации добавьте:
server { # NoVNC listen *:6080 ssl; server_name gateway.example.com; location / { proxy_pass http://10.24.7.9:6080; ... } }
-
-
Перезапустите Nginx для применения изменений:
sudo systemctl restart nginx
Заключение
Настройка OpenStack Horizon за обратным прокси, таким как Nginx, может существенно повысить безопасность и удобство доступа к вашей инфраструктуре. Eigen конфигурация, особое внимание к заголовкам и корректные правила перенаправления — важные аспекты успешной настройки. Как видно из приведённого выше, небольшие изменения в конфигурации могут эффективно решать проблемы с дублированием контента и обеспечивать корректную работу NoVNC.
С последними изменениями вы можете убедиться, что Horizon будет доступен безопасно и эффективно для ваших пользователей за пределами локальной сети, что создаёт более безопасные и удобные условия использования облачных ресурсов.