
В данной серии статей описан процесс создания первого pet-проекта для начинающего инженера в DevOps:
Глава 1: Введение и подготовка стенда
Глава 2: Настройка центра сертификации и репозитория
Глава 4: Настройка мониторинга
Друзья, хочу ответить на комментарии об отсутствии в данной серии статей инструментов DevOps - Terraform, Ansible, Kubernetes, GitLab CI/CD и прочих инструментов. Полностью согласен с тем, что DevOps без вышеупомянутых инструментов существовать не может.
Данная серия статей является отправной точкой в изучении DevOps и уверен, что именно начинающим инженерам данный материал точно будет полезен. Здесь большой акцент сделан на написании скриптов. Цель данного pet-проекта - практическое ознакомление с Linux перед тем как двигаться дальше в DevOps - именно поэтому название «Проект юного DevOps». В планах написание следующей серии статей уже с углублением в DevOps и его инструменты.
Спасибо за конструктивные комментарии, которые позволяют откорректировать материал и улучшить его качество. Прошу поддержать мое начинание, всем хорошего дня!
Настройка центра сертификации (CA)
Easy-RSA - это набор скриптов для упрощения управления сертификатами в инфраструктуре открытых ключей (PKI). Он широко используется для создания и управления сертификатами в контексте VPN, шифрования и безопасности сетевых соединений. Изначально разработан для работы с OpenVPN, но может использоваться и в других сценариях.
Зайдем на vm «ca» и выполним установку Easy-RSA версии 3.8.0:
sudo apt-get update sudo apt-get install -y easy-rsa=3.0.8-1ubuntu1
Заметка
В других версиях Easy-RSA процесс и особенности настройки могут отличаться от описанных в данной статье.
Скопируем рабочую директорию Easy-RSA в домашнюю директорию нового пользователя и изменим права владения:
sudo cp -r /usr/share/easy-rsa /home/nikolay/ sudo chown -R nikolay:nikolay ~/easy-rsa/ sudo chmod -R 700 easy-rsa/
Настроим Easy-RSA, раскомментировав и изменив следующие строки в конфигурационном файле «~/easy-rsa/vars.example»:
sсt_var EASYRSA_REQ_COUNTRY "RUS" set_var EASYRSA_REQ_PROVINCE "Moscow" set_var EASYRSA_REQ_CITY "Moscow City" set_var EASYRSA_REQ_ORG "Justnikobird" set_var EASYRSA_REQ_EMAIL "justnikobird@yandex.ru" set_var EASYRSA_REQ_OU "LLC" set_var EASYRSA_ALGO ec set_var EASYRSA_DIGEST "sha512"
Применим конфигурацию и создадим инфраструктуру открытых ключей (Public Key Infrastructure):
cd ~/easy-rsa mv vars.example vars ./easyrsa init-pki
Результат выполнения команды
Note: using Easy-RSA configuration from: /home/nikolay/easy-rsa/vars init-pki complete; you may now create a CA or requests. Your newly created PKI dir is: /home/nikolay/easy-rsa/pki
В результате программа создаст директорию «/home/nikolay/easy-rsa/pki», в которой будут храниться все создаваемые в дальнейшем ключи.
Теперь сгенерируем ключи удостоверяющего центра:
./easyrsa build-ca
Система запросит у нас ввести пароль для приватного ключа ca и имя нового ca:
Note: using Easy-RSA configuration from: /home/nikolay/easy-rsa/vars Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022) Enter New CA Key Passphrase: ******* Re-Enter New CA Key Passphrase: ******* read EC key writing EC 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. ----- Common Name (eg: your user, host, or server name) [Easy-RSA CA]: CA creation complete and you may now import and sign cert requests. Your new CA certificate file for publishing is at: /home/nikolay/easy-rsa/pki/ca.crt
В результате программа создаст два фала:
/home/nikolay/easy-rsa/pki/ca.crt - открытый ключ;
/home/nikolay/easy-rsa/pki/private/ca.key - закрытый ключ.
Открытый ключ можно сводобно передавать на другие vm, а закрытый необходимо хранить в строжайшем секрете.
Подробнее о том, что такое сертификаты и какую роль выполняет CA можно изучить в статье «Разбираем TLS по байтам. Кто такой этот HTTPS?»
Выпуск пары ключ-сертификат
Клиентский сертификат и сертификат сервера - это два различных типа сертификатов, используемых в контексте безопасности сети, особенно в протоколе SSL/TLS для шифрования данных.
Технически создание и подписание клиентского и серверного сертификатов схожи: оба включают открытый ключ, метаданные и подпись центра сертификации. Разница между ними сводится к прикрепленным метаданным и их проверке. Возможно использование клиентских сертификатов в роли серверных и наоборот, если отключены проверки подлинности и ограничений в библиотеке TLS. Сертификат сервера проверяется по DNS-имени в поле SAN, а сертификат клиента содержит проверенные атрибуты пользователя, устанавливаемые центром сертификации, и проверяется сервером на соответствие требованиям аутентификации.
Выпуск пары ключ-сертификат для сервера
Для выпуска и подписания новой пары ключ-сертификат для сервера с доменным именем «example.justnikobird.ru», необходимо выполнить следующие действия:
cd ~/easy-rsa ./easyrsa gen-req example.justnikobird.ru nopass ./easyrsa sign-req server example.justnikobird.ru
В результате мы получим два файла:
~/easy-rsa/pki/issued/example.justnikobird.ru.crt - подписанный сертификат;
~/easy-rsa/pki/private/example.justnikobird.ru.key - приватный ключ.
Выпуск пары ключ-сертификат для клиента
Для выпуска и подписания новой клиентской пары ключ-сертификат, необходимо выполнить следующие действия:
cd ~/easy-rsa ./easyrsa gen-req example nopass ./easyrsa sign-req client example
В результате мы получим два файла:
~/easy-rsa/pki/issued/example.crt - подписанный сертификат
~/easy-rsa/pki/private/example.key - приватный ключ
Центр сертификации успешно настроен, теперь соберем развернутую нами программу в deb-пакет, чтобы в дальнейшем процесс установки занял намного меньше времени.
Сборка deb-пакета Easy-RSA
Весь процесс сборки я описал в статье «Работа с DEB-пакетами».
Здесь я только помечу следующие данные для сборки:
Файлы, которые буем хранить в пакете:
/home/nikolay/easy-rsa
install
easy-rsa/ usr/share
control
Source: easy-rsa-lab Section: unknown Priority: optional Maintainer: Nikolay <justnikobird@yandex.ru> Build-Depends: debhelper-compat (= 13) Standards-Version: 4.6.0 Homepage: https://github.com/OpenVPN/easy-rsa #Vcs-Browser: https://salsa.debian.org/debian/just-easy-rsa #Vcs-Git: https://salsa.debian.org/debian/just-easy-rsa.git Rules-Requires-Root: no Package: easy-rsa-lab Architecture: all Depends: easy-rsa Recommends: opensc Description: <insert up to 60 chars description> <insert long description, indented with spaces>
Скриптов нет.
В результате мы собрали пакет «easy-rsa-lab_0.1-1_all.deb».
Далее нам необходимо создать репозиторий, куда мы загрузим наш новый пакет.
Приступим!
Настройка собственного репозитория
Репозитории - это архивы программ. Каждый репозиторий содержит список пакетов, в нём хранящихся, с указанием версий, зависимостей и прочей необходимой информации. В контексте данного лабораторного стенда в настроенном репозитории будут храниться все пакеты, которые мы соберем.
Aptly - это инструмент управления пакетами для Debian-подобных систем, таких как Ubuntu. Он позволяет создавать, обновлять и управлять локальными репозиториями пакетов, облегчая процесс установки и обновления программного обеспечения.
Настройка Aptly
Зайдем на vm «repo» и применим bash-скрипт «vm-start.sh».
Перед работой с Aptly, выполним установку пакета «bzip2»:
sudo apt-get install -y bzip2
Скачаем архив с Aptly версии 1.5.0 с официальной страницы разработчиков на GitHub в домашнюю директорию и распакуем его:
wget -P ~/ https://github.com/aptly-dev/aptly/releases/download/v1.5.0/aptly_1.5.0_linux_amd64.tar.gz tar xvf ~/aptly_1.5.0_linux_amd64.tar.gz
Заметка
В других версиях Aptly процесс и особенности настройки могут отличаться от описанных в данной статье.
Скопируем исполняемый файл программы в директорию «/usr/local/bin»:
sudo cp ~/aptly_1.5.0_linux_amd64/aptly /usr/local/bin/
Создадим конфигурационный файл «/etc/aptly.conf» от имени пользователя «root» и запишем в него следующие строки:
{ "rootDir": "/opt/aptly", "downloadConcurrency": 4, "downloadSpeedLimit": 0, "architectures": ["all"], "dependencyFollowSuggests": false, "dependencyFollowRecommends": false, "dependencyFollowAllVariants": false, "dependencyFollowSource": false, "dependencyVerboseResolve": false, "gpgDisableSign": false, "gpgDisableVerify": false, "gpgProvider": "gpg", "downloadSourcePackages": true, "skipLegacyPool": true, "ppaDistributorID": "ubuntu", "ppaCodename": "", "FileSystemPublishEndpoints": { "lab": { "rootDir": "/var/www/aptly", "linkMethod": "symlink", "verifyMethod": "md5" } }, "enableMetricsEndpoint": false }
Описание конфигурационного файла
rootDir: Определяет корневой каталог, в котором Aptly будет хранить свои данные.
downloadConcurrency: Задает количество одновременных загрузок при скачивании пакетов.
downloadSpeedLimit: Ограничивает скорость загрузки (в байтах в секунду). Установка в 0 отключает ограничение.
architectures: Определяет архитектуры, которые Aptly будет использовать (в данном случае, "all").
dependencyFollowSuggests, dependencyFollowRecommends, dependencyFollowAllVariants, dependencyFollowSource: Управляют тем, следует ли Aptly автоматически добавлять пакеты, зависимые от других пакетов, указанных в полях Suggests, Recommends, Variants и Source.
dependencyVerboseResolve: Активирует запись подробных логов при разрешении зависимостей.
gpgDisableSign, gpgDisableVerify: Опции, позволяющие отключить подпись или верификацию GPG.
gpgProvider: Определяет провайдера GPG, который будет использоваться.
downloadSourcePackages: Определяет, следует ли загружать и хранить исходные пакеты.
skipLegacyPool: Пропускает использование старой файловой системы хранения для пула пакетов.
ppaDistributorID, ppaCodename: Информация о распределении (Distributor ID) и кодовом имени (Codename) для использования при работе с PPA (Personal Package Archive).
FileSystemPublishEndpoints: Определяет конечные точки публикации файловой системы для различных репозиториев. В нашем случае есть одна конечная точка с именем «lab», указывающая на «/var/www/aptly».
enableMetricsEndpoint: Включает или отключает метрический конечный пункт для мониторинга.
Создадим репозиторий с названием «lab»:
sudo aptly repo create -comment="lab repo" -component="main" -distribution="focal" lab
Перенесем пакет «easy-rsa-lab_0.1-1_all.deb» в домашнюю директорию vm «repo» и добавим его в репозиторий:
sudo aptly repo add lab ~/easy-rsa-lab_0.1-1_all.deb
Перенос пакета с помощью SCP (Windows)
В терминале машины, с которой выполняется администрирование всех vm, выполним перенос пакета с vm «ca» на vm «repo».
Скачаем пакет с vm «ca»:
scp -P 1870 nikolay@ca:/home/nikolay/deb/easy-rsa-lab_0.1-1_all.deb .
Загрузим пакет в домашнюю директорию vm «repo»:
scp -P 1870 easy-rsa-lab_0.1-1_all.deb nikolay@repo:/home/nikolay/
Для получения абсолютного пути файла из рабочей директории поможет команда «realpath»:
realpath easy-rsa-lab_0.1-1_all.deb
Вывод:
/home/nikolay/deb/easy-rsa-lab_0.1-1_all.deb
В работе нам могут быть полезны следующие команды:
Посмотреть список репозиториев:
sudo aptly repo list
Посмотреть список опубликованных репозиториев:
sudo aptly publish list
Подробная информация о репозитории на примере «lab»:
sudo aptly repo show -with-packages lab
Подробная информация о пакете на примере «easy-rsa-lab_0.1-1_all.deb»:
sudo aptly package show easy-rsa-lab_0.1-1_all
Удаление репозитория на примере «lab»:
sudo aptly repo drop lab
Снятие репозитория с публикации на примере «lab»:
sudo aptly publish drop focal filesystem:lab:lab
Удаление пакета из репозитория на примере «easy-rsa-lab_0.1-1_all.deb»:
sudo aptly repo remove lab easy-rsa-lab_0.1-1_all
Публикация репозиториев
Для публикации нам потребуется gpg-ключ. Для начала установим набор утилит для генерации случайных чисел в ядре:
sudo apt-get install -y rng-tools
Запустим утилиту:
sudo rngd -r /dev/urandom
Создадим ключ:
sudo gpg --default-new-key-algo rsa4096 --gen-key --keyring pubring
Система запросит ввести имя и email.
После появится окно ввода пароля для закрытого ключа. Придумаем пароль и введем его дважды.
Ключ создан, его можно увидеть с использованием следующей командой:
sudo gpg --list-keys
Теперь сделаем первую публикацию ранее созданного репозитория «lab»:
sudo aptly publish repo lab filesystem:lab:lab
Появится окно для ввода пароля закрытого gpg-ключа.
Для успешного выполнения команды нужно, чтобы в репозиторий был загружен хотя бы один пакет.
Обновление базы пакетов репозитория
В случае внесения изменений в основную базу пакетов, нам необходимо обновлять настройки публикации репозитория. Это приводит к обновлению метаданных и актуализации пакетов в каталогах «pool»:
sudo aptly publish update focal filesystem:lab:lab
После публикации, в каталоге «/var/www/aptly/lab» мы должны увидеть две директории:
ls /var/www/aptly/lab dists pool
В директории «dists» хранятся метаданные для опубликованных дистрибутивов.
В директории «pool» хранятся загруженные пакеты (в нашем случае симлинки на файлы в основном каталоге «/opt/aptly»).
Перенесем в домашнюю директорию vm «repo» сертификат открытого ключа CA.
Для удобства работы с нашим репозиторием в дальнейшем, опубликуем открытый gpg-ключ и сертификат открытого ключа CA в директории «/var/www/aptly/lab» — это необходимы для подключения к репозиторию клиентов:
sudo gpg --export --armor | sudo tee /var/www/aptly/lab/labtest.asc > /dev/null sudo cp ~/ca.crt /var/www/aptly/lab/
Мы вернемся к данным файлам, когда будем настраивать подключение к репозиторию.
Настройка Nginx
Теперь нам необходимо предоставить доступ к нашему репозиторию через интернет, для этого нам понадобится Nginx Web Server.
Выполним установку Nginx:
sudo apt-get update sudo apt-get install -y nginx
Перенесем подписанные на CA ключи для vm «repo» в рабочую директорию Nginx:
sudo cp ~/repo.justnikobird.ru.crt /etc/nginx/ sudo cp ~/repo.justnikobird.ru.key /etc/nginx/
Подготовим хэш пароля для нового пользователя - скачаем необходимый пакет с инструментами и сгенерируем пароль «password» для пользователя «admin»:
sudo apt-get install -y apache2-utils htpasswd -nbB -C 10 admin "password"
В результате выполнения команды мы получим следующую строку, которую запишем в конфигурационный файл «/etc/nginx/conf.d/.htpasswd» для аутентификации на сервере.:
admin:$2y$10$iWOlBiff2IDDovW2wy2SauStp7ahuHpOULM2W7yQ6JpNcbDKeBPYS
Выполним настройку Nginx в конфигурационном файле «/etc/nginx/sites-available/default»:
server { listen 1111 ssl default_server; server_name repo.justnikobird.ru; auth_basic "Restricted Access!"; auth_basic_user_file /etc/nginx/conf.d/.htpasswd; ssl_certificate repo.justnikobird.ru.crt; ssl_certificate_key repo.justnikobird.ru.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; root /var/www/aptly; location / { autoindex on; } } # nginx prometheus exporter server { listen 8080; location /stub_status { stub_status; allow 127.0.0.1; deny all; } }
Заметка
Настройка Nginx на порту 8080 понадобится для подключения системы мониторинга в дальнейшем.
Перезапустим Nginx и активируем автоматический запуск:
sudo systemctl restart nginx.service sudo systemctl enable nginx.service
Проверка исправности работы сервиса
Проверим статус сервиса Nginx:
sudo systemctl status nginx.service
Если сервис работает исправно, то он должен быть в статусе «active (running)»
● nginx.service - A high performance web server and a reverse proxy server Loaded: loaded (/lib/systemd/system/nginx.service; disabled; vendor preset: enabled) Active: active (running) since Tue 2024-01-30 18:37:36 MSK; 2 weeks 0 days ago Docs: man:nginx(8) Main PID: 5562 (nginx) Tasks: 2 (limit: 1013) Memory: 100.8M CPU: 32.199s CGroup: /system.slice/nginx.service ├─5562 "nginx: master process /usr/sbin/nginx -g daemon on; master_process on;" └─5567 "nginx: worker process" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" Jan 30 18:37:36 2454768-justnikobird.twc1.net systemd[1]: nginx.service: Deactivated successfully. Jan 30 18:37:36 2454768-justnikobird.twc1.net systemd[1]: Stopped A high performance web server and a reverse proxy server. Jan 30 18:37:36 2454768-justnikobird.twc1.net systemd[1]: Starting A high performance web server and a reverse proxy server... Jan 30 18:37:36 2454768-justnikobird.twc1.net systemd[1]: Started A high performance web server and a reverse proxy server.
Если сервис в статусе «failed», то необходимо поверить его логи:
sudo journalctl -u nginx.service
Также необходимо проверить какие порты прослушивает запущенный сервис с помощью инструмента «netstat», который входит в пакет «net-tools»:
sudo apt-get install -y net-tools sudo netstat -lptun
В выводе видно, то сервис Nginx прослушивает порты «8080» и «1111»:
Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name tcp 0 0 0.0.0.0:8080 0.0.0.0:* LISTEN 54594/nginx: master tcp 0 0 0.0.0.0:1111 0.0.0.0:* LISTEN 54594/nginx: master
Теперь необходимо проверить настройки iptables на наличие правил, разрешающих доступ к сервису:
sudo iptables -L -v -n | grep 1111 ... Chain INPUT (policy DROP 531K packets, 27M bytes) pkts bytes target prot opt in out source destination 969 56172 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:1111 /* repo_nginx */ ... Chain OUTPUT (policy DROP 214 packets, 76866 bytes) pkts bytes target prot opt in out source destination 631K 2580M ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED
Правила присутствуют, доступ к сервису открыт.
Настройка iptables
sudo iptables -A INPUT -p tcp --dport 1111 -j ACCEPT -m comment --comment repo_nginx
Сохраним конфигурацию iptables с помощью инструмента iptables-persistent:
sudo apt-get install -y iptables-persistent sudo service netfilter-persistent save
Проверка работы репозитория
Проверим исправность работы репозитория, перейдя по ссылке «https://repo.justnikobird.ru:1111»:


Репозиторий успешно настроен.
Как подружить браузер с новой web-страницей?
Чтобы браузер не ругался на наш сертификат, необходимо загрузить файл сертификата с открытым ключом CA в библиотеку «Trusted Root Certificate Authorities» в настройках браузера.
Подключение к Repo
В системе, где планируем подключиться к репозиторию, создадим файл «/etc/apt/sources.list.d/own_repo.list» и запишем в него данные для подключения к repo:
echo "deb https://repo.justnikobird.ru:1111/lab focal main" | sudo tee -a /etc/apt/sources.list.d/own_repo.list > /dev/null
Настроим https аутентификацию в файле «/etc/apt/auth.conf» для пользователя «admin» с паролем «password»:
machine repo.justnikobird.ru:1111 login admin password password
Добавим правило в iptables и сохраним конфигурацию с помощью инструмента iptables-persistent:
sudo iptables -A OUTPUT -p tcp --dport 1111 -j ACCEPT -m comment --comment repo.justnikobird.ru sudo apt-get install -y iptables-persistent sudo service netfilter-persistent save
Импортируем в систему ключ, который опубликовали ранее:
wget --no-check-certificate -P ~/ https://admin:password@repo.justnikobird.ru:1111/lab/labtest.asc sudo apt-key add ~/labtest.asc
Импортирует в систему сертификат от CA чтобы новый репозиторий считался доверенным:
wget --no-check-certificate -P ~/ https://admin:password@repo.justnikobird.ru:1111/lab/ca.crt sudo cp ~/ca.crt /usr/local/share/ca-certificates/ca.crt sudo update-ca-certificates
Обновим список пакетов:
sudo apt-get update
Проверим наличие пакета «easy-rsa-lab» в подключенном репозитории:
sudo apt search easy-rsa-lab
В результате мы должны получить следующий вывод:
Sorting... Done Full Text Search... Done easy-rsa-lab/focal 0.1-1 all <insert up to 60 chars description>
Репозиторий успешно подключен к системе!
Bash-скрипт для Repo
Настало время написать bash-скрипт, который сможет выполнить настройку Repo автоматически:
repo.sh
#!/bin/bash # проверим, запущен ли скрипт от пользователя root if [[ "${UID}" -ne 0 ]]; then echo "You need to run this script as root!" exit 1 fi # функция, которая проверяет наличие пакета в системе и в случае его отсутствия выполняет установку command_check() { if ! command -v "$1" &>/dev/null; then echo -e "\n====================\n$2 could not be found!\nInstalling...\n====================\n" apt-get install -y "$3" echo -e "\nDONE\n" fi } # функция, которая запрашивает путь до файла и проверяет его валидность path_request() { while true; do read -r -e -p $'\n'"Please input full valid path to ${1}: " path if [ -f "$path" ]; then echo "$path" break fi done } # функция, которая проверяет наличие правила в iptables и в случае отсутствия применяет его iptables_add() { if ! iptables -C "$@" &>/dev/null; then iptables -A "$@" fi } # установим все необходимые пакеты используя функцию command_check systemctl restart systemd-timesyncd.service apt-get update command_check wget "Wget" wget command_check iptables "Iptables" iptables command_check netfilter-persistent "Netfilter-persistent" iptables-persistent command_check rngd "Rng-tools" rng-tools command_check nginx "Nginx" nginx command_check htpasswd "Htpasswd" apache2-utils command_check basename "Basename" coreutils command_check bzip2 "Bzip2" bzip2 # настроим aptly echo -e "\n====================\nAptly Configuration...\n====================\n" # проверим на наличие старых файлов aptly (полезно при переустановке) if [ -f /tmp/aptly_1.5.0_linux_amd64.tar.gz ] || [ -d /tmp/aptly_1.5.0_linux_amd64 ]; then rm -rf /tmp/aptly_1.5.0_linux_amd64* fi # скачаем исходники aptly с распакуем их if wget -P /tmp/ https://github.com/aptly-dev/aptly/releases/download/v1.5.0/aptly_1.5.0_linux_amd64.tar.gz; then tar -xvf /tmp/aptly_1.5.0_linux_amd64.tar.gz -C /tmp/ mv -f /tmp/aptly_1.5.0_linux_amd64/aptly /usr/local/bin/ else exit 1 fi rm -rf /opt/aptly rm -rf /var/www/aptly # создадим конфигурационный файл aptly echo '{ "rootDir": "/opt/aptly", "downloadConcurrency": 4, "downloadSpeedLimit": 0, "architectures": ["all","amd64"], "dependencyFollowSuggests": false, "dependencyFollowRecommends": false, "dependencyFollowAllVariants": false, "dependencyFollowSource": false, "dependencyVerboseResolve": false, "gpgDisableSign": false, "gpgDisableVerify": false, "gpgProvider": "gpg", "downloadSourcePackages": true, "skipLegacyPool": true, "ppaDistributorID": "ubuntu", "ppaCodename": "", "FileSystemPublishEndpoints": { "lab": { "rootDir": "/var/www/aptly", "linkMethod": "symlink", "verifyMethod": "md5" } }, "enableMetricsEndpoint": false }' >/etc/aptly.conf # создадим репозиторий lab if aptly repo create -comment="lab repo" -component="main" -distribution="focal" lab; then # запросим путь до первого deb-пакета package_path=$(path_request "first package (architecture is all or amd64)") # загрузим пакет в новый репозиторий if ! aptly repo add lab "$package_path"; then exit 1 fi else exit 1 fi echo -e "\n====================\nLab Repo Successfully Created\n====================\n" # сгенерируем gpg-ключи echo -e "\n====================\nGPG Key Generating...\n====================\n" rngd -r /dev/urandom rngd_check=$? if [ $rngd_check -eq 0 ] || [ $rngd_check -eq 10 ]; then gpg --default-new-key-algo rsa4096 --gen-key --keyring pubring gen_key_check=$? if [ $gen_key_check -eq 0 ] || [ $gen_key_check -eq 2 ]; then gpg --list-keys fi else exit 1 fi echo -e "\nDONE\n" # опубликуем репозиторий aptly publish repo lab filesystem:lab:lab # экспортируем открытый gpg-ключ на web-страницу репозитория gpg --export --armor | tee /var/www/aptly/lab/labtest.asc >/dev/null # экспортируем открытый ключ ca на web-страницу репозитория cp "$(path_request "ca certificate")" /var/www/aptly/lab/ca.crt echo -e "\n====================\nLab Repo Successfully Published\n====================\n" # настроим nginx echo -e "\n====================\nNginx Configuration...\n====================\n" # запросим доменное имя репозитория read -r -p $'\n'"repo domain name (example repo.justnikobird.ru): " repo_name # запросим путь до сертификата с помощью функции path_request и перенес файл в рабочую директорию nginx server_crt=$(path_request certificate) cp "$server_crt" /etc/nginx/ cert_file=$(basename "$server_crt") # запросим путь до приватного ключа с помощью функции path_request и перенес файл в рабочую директорию nginx server_key=$(path_request key) cp "$server_key" /etc/nginx/ key_file=$(basename "$server_key") # запросим логин и пароль для нового репозитория read -r -p $'\n\n'"login for ${repo_name}: " repo_login read -r -p "password for ${repo_name}: " -s repo_pass # сгенерируем хэш пароля htpasswd -nbB -C 10 "$repo_login" "$repo_pass" >>/etc/nginx/conf.d/.htpasswd # создадим конфигурационный файл nginx echo ' server { listen 1111 ssl default_server; server_name '"$repo_name"'; auth_basic "Restricted Access!"; auth_basic_user_file /etc/nginx/conf.d/.htpasswd; ssl_certificate '"$cert_file"'; ssl_certificate_key '"$key_file"'; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; root /var/www/aptly; location / { autoindex on; } } # nginx prometheus exporter server { listen 8080; location /stub_status { stub_status; allow 127.0.0.1; deny all; } }' >/etc/nginx/sites-available/default echo -e "\nDONE\n" # настроим iptables echo -e "\n====================\nIptables configuration\n====================\n" iptables_add INPUT -p tcp --dport 1111 -j ACCEPT -m comment --comment repo_nginx echo -e "\n====================\nSaving iptables config...\n====================\n" service netfilter-persistent save echo -e "\nDONE\n" # перезагрузим nginx-сервис systemctl restart nginx.service systemctl enable nginx.service echo -e "\n====================\nRepo listening on port 1111\n====================\n" echo -e "\nOK\n" exit 0
Обновление bash-скрипта для vm
После успешной настройки Repo, добавим в скрипт первичной настройки vm процесс подключения к новому Repo и правило в iptables:
vm-start.sh
#!/bin/bash # активируем опцию, которая прерывает выполнение скрипта, если любая команда завершается с ненулевым статусом set -e # проверим, запущен ли скрипт от пользователя root if [[ "${UID}" -ne 0 ]]; then echo -e "You need to run this script as root!\nPlease apply 'sudo su root' and add your host-key to /root/.ssh/authorized_keys before run this script!" exit 1 fi # проверим, загружены ли открытые ssh-ключи у пользователя root if [ ! -f /root/.ssh/authorized_keys ]; then echo -e "\n====================\nFile /root/.ssh/authorized_keys not found!\n====================\n" exit 1 else if [ ! -s /root/.ssh/authorized_keys ]; then echo -e "\n====================\nFile /root/.ssh/authorized_keys is empty!\n====================\n" exit 1 fi fi # функция, которая проверяет наличие пакета в системе и в случае его отсутствия выполняет установку command_check() { if ! command -v "$1" &>/dev/null; then echo -e "\n====================\n$2 could not be found!\nInstalling...\n====================\n" apt-get install -y "$3" echo -e "\nDONE\n" fi } # функция, которая запрашивает имя нового пользователя и проверяет его на наличие в системе username_request() { while true; do read -r -p $'\n'"new username: " username if id "$username" >/dev/null 2>&1; then echo -e "\nUser $username exists!\n" else break fi done } # функция, которая проверяет наличие правила в iptables и в случае отсутствия применяет его iptables_add() { if ! iptables -C "$@" &>/dev/null; then iptables -A "$@" fi } # функция, которая выполняет backup файла путем копирования его и модификации названия bkp() { if [ -f "$1" ]; then cp "$1" "$1".bkp fi } # функция, которая восстанавливает файл из backup restore_bkp() { if [ -f "$1".bkp ]; then if [ -f "$1" ]; then rm "$1" && mv "$1".bkp "$1" else mv "$1".bkp "$1" fi else echo -e "\nCan't find backup file!\n" fi } # настроим часовой пояс echo -e "\n====================\nSetting timezone\n====================" timedatectl set-timezone Europe/Moscow systemctl restart systemd-timesyncd.service timedatectl echo -e "\nDONE\n" # установим все необходимые пакеты используя функцию command_check apt-get update command_check wget "Wget" wget command_check iptables "Iptables" iptables command_check netfilter-persistent "Netfilter-persistent" iptables-persistent command_check openssl "Openssl" openssl command_check update-ca-certificates "Ca-certificates" ca-certificates command_check tee "Tee" coreutils # проверим наличие конфигурационного файла ssh if [ ! -f /etc/ssh/sshd_config ]; then echo -e "\n====================\nFile /etc/ssh/sshd_config not found!\n====================\n" exit 1 fi # проверим наличие конфигурационного файла grub if [ ! -f /etc/default/grub ]; then echo -e "\n====================\nFile /etc/default/grub not found!\n====================\n" exit 1 fi # создадим нового пользователя echo -e "\n====================\nNew user config\n====================" while true; do read -r -n 1 -p "Continue or Skip? (c|s) " cs case $cs in [Cc]*) # запросим имя пользователя используя функцию username_request (функция создаст глобальную переменную "username") username_request # запросим пароль для нового пользователя read -r -p "new password: " -s password # создадим нового пользователя и перенесем ssh-ключи useradd -p "$(openssl passwd -1 "$password")" "$username" -s /bin/bash -m -G sudo cp -r /root/.ssh/ /home/"$username"/ && chown -R "$username":"$username" /home/"$username"/.ssh/ echo -e "\n\nDONE\n" # выполним корректировку prompt statement echo -e "\n====================\nEdit prompt statement for this user?\n====================" while true; do read -r -n 1 -p "Continue or Skip? (c|s) " cs case $cs in [Cc]*) # запросим имя vm read -r -p $'\n'"vm name: " vm_name # выполним корректировку prompt statement echo "PS1='\${debian_chroot:+(\$debian_chroot)}\\u@$vm_name:\\w\\\$ '" >>/home/"$username"/.bashrc echo -e "\n\nDONE\n" break ;; [Ss]*) echo -e "\n" break ;; *) echo -e "\nPlease answer C or S!\n" ;; esac done break ;; [Ss]*) echo -e "\n" break ;; *) echo -e "\nPlease answer C or S!\n" ;; esac done # настроим ssh echo -e "\n====================\nEdit sshd_config file\n====================" while true; do read -r -n 1 -p "Continue or Skip? (c|s) " cs case $cs in [Cc]*) sed -i 's/#\?\(Port\s*\).*$/\1 1870/' /etc/ssh/sshd_config sed -i 's/#\?\(PermitRootLogin\s*\).*$/\1 no/' /etc/ssh/sshd_config sed -i 's/#\?\(PubkeyAuthentication\s*\).*$/\1 yes/' /etc/ssh/sshd_config sed -i 's/#\?\(PermitEmptyPasswords\s*\).*$/\1 no/' /etc/ssh/sshd_config sed -i 's/#\?\(PasswordAuthentication\s*\).*$/\1 no/' /etc/ssh/sshd_config echo -e "\n\n" /etc/init.d/ssh restart echo -e "\nDONE\n" break ;; [Ss]*) echo -e "\n" break ;; *) echo -e "\nPlease answer C or S!\n" ;; esac done # выключим ipv6 echo -e "\n====================\nDisabling ipv6\n====================" while true; do read -r -n 1 -p "Continue or Skip? (c|s) " cs case $cs in [Cc]*) echo -e "\n\n" sed -i 's/^GRUB_CMDLINE_LINUX_DEFAULT="/&ipv6.disable=1 /' /etc/default/grub sed -i 's/^GRUB_CMDLINE_LINUX="/&ipv6.disable=1 /' /etc/default/grub update-grub echo -e "\nDONE\n" break ;; [Ss]*) echo -e "\n" break ;; *) echo -e "\nPlease answer C or S!\n" ;; esac done # подключим репозиторий echo -e "\n====================\nRepo config\n====================" while true; do read -r -n 1 -p "Continue or Skip? (c|s) " cs echo -e "\n" case $cs in [Cc]*) # выполним backup файлов с помощью функции bkp bkp /etc/apt/sources.list.d/own_repo.list bkp /etc/apt/auth.conf # запросим логин и пароль для подключения к репозиторию read -r -p $'\n\n'"login for repo.justnikobird.ru: " repo_login read -r -p "password for repo.justnikobird.ru: " -s repo_pass # проверим файл /etc/apt/sources.list.d/own_repo.list на наличие записи о репозитории, и в случае ее отсутствия добавим if ! grep -Fxq "deb https://repo.justnikobird.ru:1111/lab focal main" /etc/apt/sources.list.d/own_repo.list &>/dev/null; then echo "deb https://repo.justnikobird.ru:1111/lab focal main" | tee -a /etc/apt/sources.list.d/own_repo.list >/dev/null fi # проверим файл /etc/apt/auth.conf на наличие записей о репозитории, и в случае их отсутствия добавим if ! grep -Fxq "machine repo.justnikobird.ru:1111" /etc/apt/auth.conf &>/dev/null; then echo -e "machine repo.justnikobird.ru:1111\nlogin $repo_login\npassword $repo_pass" | tee -a /etc/apt/auth.conf >/dev/null else # если в файле /etc/apt/auth.conf записи обнаружены, то попросим пользователя удалить их echo -e "\n\nrepo.justnikobird.ru has been configured in /etc/apt/auth.conf!\nPlease manually clean configuration or skip this stage." restore_bkp /etc/apt/sources.list.d/own_repo.list restore_bkp /etc/apt/auth.conf exit 1 fi # скачаем и установим gpg-ключ от репозитория if ! wget --no-check-certificate -P ~/ https://"$repo_login":"$repo_pass"@repo.justnikobird.ru:1111/lab/labtest.asc; then restore_bkp /etc/apt/sources.list.d/own_repo.list restore_bkp /etc/apt/auth.conf exit 1 else apt-key add ~/labtest.asc fi # скачаем и установим открытый ключ ca-сертификата от репозитория if ! wget --no-check-certificate -P /usr/local/share/ca-certificates/ https://"$repo_login":"$repo_pass"@repo.justnikobird.ru:1111/lab/ca.crt; then restore_bkp /etc/apt/sources.list.d/own_repo.list restore_bkp /etc/apt/auth.conf exit 1 else update-ca-certificates fi # выполним синхронизацию списков пакетов в системе if ! apt update; then restore_bkp /etc/apt/sources.list.d/own_repo.list restore_bkp /etc/apt/auth.conf exit 1 fi echo -e "\nDONE\n" break ;; [Ss]*) echo -e "\n" break ;; *) echo -e "\nPlease answer C or S!\n" ;; esac done # настроим iptables echo -e "\n====================\nIptables config\n====================" while true; do read -r -n 1 -p "Current ssh session may drop! To continue you have to relogin to this host via 1870 ssh-port and run this script again. Are you ready? (y|n) " yn case $yn in [Yy]*) #---DNS--- iptables_add OUTPUT -p tcp --dport 53 -j ACCEPT -m comment --comment dns iptables_add OUTPUT -p udp --dport 53 -j ACCEPT -m comment --comment dns #---NTP--- iptables_add OUTPUT -p udp --dport 123 -j ACCEPT -m comment --comment ntp #---REPO--- iptables_add OUTPUT -p tcp --dport 1111 -j ACCEPT -m comment --comment repo.justnikobird.ru #---ICMP--- iptables_add OUTPUT -p icmp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT iptables_add INPUT -p icmp -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT #---loopback--- iptables_add OUTPUT -o lo -j ACCEPT iptables_add INPUT -i lo -j ACCEPT #---Input-SSH--- iptables_add INPUT -p tcp --dport 1870 -j ACCEPT -m comment --comment ssh #---Output-HTTP--- iptables_add OUTPUT -p tcp -m multiport --dports 443,80 -j ACCEPT #---ESTABLISHED--- iptables_add INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT iptables_add OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT #---INVALID--- iptables_add OUTPUT -m state --state INVALID -j DROP iptables_add INPUT -m state --state INVALID -j DROP #---Defaul-Drop--- iptables -P OUTPUT DROP iptables -P INPUT DROP iptables -P FORWARD DROP # save iptables config echo -e "\n====================\nSaving iptables config\n====================\n" service netfilter-persistent save echo -e "DONE\n" break ;; [Nn]*) echo -e "\n" exit ;; *) echo -e "\nPlease answer Y or N!\n" ;; esac done echo -e "\nOK\n" exit 0
Bash-скрипт для Easy-RSA
Настало время написать bash-скрипт, который сможет выполнить настройку Easy-RSA автоматически:
easy-rsa.sh
#!/bin/bash # активируем опцию, которая прерывает выполнение скрипта, если любая команда завершается с ненулевым статусом set -e # проверим, запущен ли скрипт от пользователя root if [[ "${UID}" -ne 0 ]]; then echo "You need to run this script as root!" exit 1 fi # проверим подключен ли репозиторий if [[ ! $(grep -rhE ^deb /etc/apt/sources.list*) == *"deb https://repo.justnikobird.ru:1111/lab focal main"* ]]; then echo -e "Lab repo not connected!\nPlease run vm_start.sh script!\n" exit 1 fi # запросим путь будущего расположения рабочей директории easy-rsa while true; do read -r -e -p $'\n'"Path for easy-rsa location (format: /home/nikolay): " dest_dir if [[ "$dest_dir" == */ ]]; then echo -e "\nWrong path format!\n" else if [ ! -d "$dest_dir" ]; then echo -e "\nDirectory $dest_dir doesn't exist!\n" else break fi fi done # проверим установлена ли программа Easy-RSA if [ ! -d /usr/share/easy-rsa/ ]; then echo -e "\n====================\nEasy-rsa could not be found\nInstalling...\n====================\n" systemctl restart systemd-timesyncd.service apt-get update apt-get install -y easy-rsa-lab echo -e "\nDONE\n" else while true; do read -r -n 1 -p $'\n'"Are you ready to reinstall easy-rsa? (y|n) " yn case $yn in [Yy]*) apt-get purge -y easy-rsa apt-get install -y easy-rsa-lab echo -e "\nDONE\n" break ;; [Nn]*) exit ;; *) echo -e "\nPlease answer Y or N!\n" ;; esac done fi # запросим username у администратора Easy-RSA и скопируем рабочую директорию Easy-RSA в рабочую директорию введенного пользователя while true; do read -r -p $'\n'"Easy-rsa owner username: " username if id "$username" >/dev/null 2>&1; then cp -r /usr/share/easy-rsa "$dest_dir"/easy-rsa chmod -R 700 "$dest_dir"/easy-rsa/ chown -R "$username":"$username" "$dest_dir"/easy-rsa/ break else echo -e "\nUser $username doesn't exists!\n" fi done # создадим пару CA-ключей while true; do read -r -n 1 -p $'\n'"Are you ready to create pair of CA keys? (y|n) " yn case $yn in [Yy]*) cd "$dest_dir"/easy-rsa sudo -u "$username" ./easyrsa build-ca echo -e "\nDONE\n" break ;; [Nn]*) exit ;; *) echo -e "\nPlease answer Y or N!\n" ;; esac done echo -e "\nOK\n" exit 0
Также если вам интересна работа с генераторами трафика, то предлагаю ознакомиться с моей статьей «Cisco TRex на практике».
