# ДЗ к занятию "Nginx - Описание, Настройка, Безопасность"
::: success
Для выполнения задания необходимо использовать настроенные приложения и виртуальные машины из прошлого урока.
:::
:::info
Практика требует наличия:
1. Хотя бы одной виртуальной машины Linux
2. Установленный Vagrant
3. Установленный Ansible
:::
Результат выполнения дз можно выкладывать на свой github, либо загружать архив с проектом в lms.
## Задача №1
## Vagrant
Для простого поднятия виртуальных машин можно воспользоваться вот таким конфигом:
```ruby=
Vagrant.configure("2") do |config|
config.vm.base_mac = nil
config.ssh.username = "labs"
config.ssh.private_key_path = "labs_private"
config.ssh.forward_agent = true
# config.vm.synced_folder ".", "/vagrant", disabled: true
config.vm.provider "virtualbox" do |vb|
vb.gui = false
vb.memory = "1024"
vb.cpus = 1
# vb.linked_clone = true
end
N = 3
(1..N).each do |machine_id|
config.vm.define "nginx-#{machine_id}" do |n|
#n.vm.hostname = "nginx-#{machine_id}"
n.vm.network "private_network", ip: "192.168.56.#{20+machine_id}"
n.vm.network "forwarded_port", guest: 80, host: "#{8080+machine_id}"
n.vm.network "forwarded_port", guest: 443, host: "#{8442+machine_id}"
n.vm.box = "ubuntuServer"
end
end
end
```
Команда vagrant up будет стартовать последовательно 3 машины. Если этого не происходит - пользователю внутри системы нехватает привилегий для настройки системы. Нужно прописать его учетку в sudoers без пароля.
## Простая установка
# Simple nginx setup role
::: warning
Нужно поставить приложение на 2 сервера.
Перед приложениями настроить балансировщик, который будет распределять доступ и проводить авторизацию с использованием сертификатов пользователей.
:::
::: danger
Все ip адреса заполнять нужно по конфигурации вашей сети
:::
### Поднимаем приложение
1. Создать файл index.html, содержимое файла должно говорить на котором сервере мы оказались. Для этого лучше сделать отдельную task.
2. Создать простой конфиг для nginx. Документацию можно найти [тут](https://docs.nginx.com/nginx/admin-guide/).
Содержимое конфига помещаем в переменную `nginx_configs`. Переменная может храниться в `myproject/host_vars/nginx-(1,2).yml`. Дальше роль nginx будет создавать файл конфигурации `mywebsite.conf` по пути в директории `/etc/nginx/conf.d`:
```yaml
nginx_configs:
- name: mywebsite.conf
value: |
server {
listen 80;
location / {
access_log off;
root /var/www/mywebsite;
}
}
```
Данный конфиг нужно располагать на 2х серверах с приложением `nginx-2` и `nginx-3`.
3. Создаем конфиг для балансировщика. Возможный путь - `myproject/host_vars/nginx-1.yml`
```yaml
nginx_configs:
- name: mywebsite.conf
value: |
upstream backend {
server 192.168.56.22:80;
server 192.168.56.23:80;
}
server {
listen 80;
server_name nginx-1.local;
location / {
proxy_pass http://backend;
}
}
```
4. Запускаем тестовый запрос ```curl 127.0.0.1:8081``` несколько раз правильная настройка выдаст нам ответы от всех серверов по очереди.
## Задача №2
### Цель - написать 2 роли, которые будут выполнять следующие операции:
1. Создать сертификаты для сервера и клиента, добавить их для работы сервера
2. Создать сертификаты для клиентов.
В результате настройки сервер балансировки должен открывать страницу только по предоставленному сертификату.
Набор полезных команд, которые могут понадобиться для описание роли.
- Создание сертификатов УЦ
```bash
openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt
```
- Создание сертификата сервера. Для этого нужно создать конфиг server.cnf
```bash
cat >server.cnf <<EOF
[req]
prompt = no
distinguished_name = dn
req_extensions = ext
[dn]
CN = nginx-1.local
emailAddress = my.email@example.com
O = Private person
OU = Alter ego dept
L = Korolyov
C = RU
[ext]
subjectAltName = DNS:nginx-1.local,IP:127.0.0.1
EOF
```
- Создание запроса на сертификат для сервера:
```bash
openssl req -new -utf8 -nameopt multiline,utf8 -config server.cnf -newkey rsa:2048 -keyout server.key -nodes -out server.csr
```
- Создание сертификата по запросу
```bash
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt -extfile server.cnf -extensions ext
```
- Создание сертификата клиента (Обязательно указываем уникальные Organization Name, Organizational Unit Name,
Common Name для каждого клиента и они не должны совпадать с указанными для сервера или корневого УЦ)
```bash
openssl req -new -utf8 -nameopt multiline,utf8 -newkey rsa:2048 -nodes -keyout client.key -out client.csr
openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt
```
В результате вы должны получить следующий набор файлов:
- Корневые сертификат и ключ (ca.crt, ca.key)
- Сертификат, ключ и запрос для клиента (client.crt, client.csr, client.key)
- Сертификат, ключ и запрос для сервера (server.key, server.crt, server.csr)
- Конфиг для генерирования сертификатов (server.cnf)
- Созданные файлы можно так же хранить в переменных:
```yaml
nginx_ssl_certs:
- name: ca.crt
value: |
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
- name: server.crt
value: |
-----BEGIN CERTIFICATE-----
....
-----END CERTIFICATE-----
- name: server.key
value: |
-----BEGIN PRIVATE KEY-----
....
-----END PRIVATE KEY-----
```
- подготовка конфига с настройкой `https`:
```yaml
nginx_configs:
- name: mywebsite.conf
value: |
upstream backend {
server 192.168.56.22:80;
server 192.168.56.23:80;
}
server {
listen 80;
server_name nginx-1.local;
return 301 https://$host:8443$request_uri;
}
server {
listen 443 ssl http2;
server_name nginx-1.local;
access_log /var/log/nginx/nginx-1.local.access.log main;
error_log /var/log/nginx/nginx-1.local.error.log debug;
ssl_certificate ssl/server.crt;
ssl_certificate_key ssl/server.key;
ssl_client_certificate ssl/ca.crt;
ssl_verify_client on;
location / {
proxy_pass http://backend;
}
}
```
- после предоставления данных на балансировщик, можно проверить результат:
```curl -Lk 127.0.0.1:8081```. где -L - follow redirect (http->https), k - игнорировать что сертификат не доверенный
- прверка доступа к ресурсу:
```bash
curl --cacert ssl/ca.crt --cert ssl/client.crt --key ssl/client.key -L 127.0.0.1:8081
```
- ограничения только для выбранных сертификатов. nginx умеет работать с серийным номером, поэтому можно использовать следующие команды:
```bash
cert=filename.crt serial=$(openssl x509 -in ${cert} -text -noout | grep -A1 Serial | grep -v Serial | tr -d ' ') && \
echo classic serial: $serial && \
echo \$ssl_client_serial: $(echo $serial | tr -d ":" | tr '[:lower:]' '[:upper:]')
```
- вид конфига при добавлении серийника:
-
```text
map $ssl_client_serial $reject {
default 1;
..........C5CE16 0; #client1
..........635A2D60 0; # client2
}
server {
...
location / {
if ($reject) { return 403; }
proxy_pass http://backend;
}
....
```
### Полезные проекты для проверки безопасности конфига
- https://github.com/stark0de/nginxpwner
- https://github.com/yandex/gixy