Проект юного DevOps Глава 2: Настройка центра сертификации и репозитория
В данной серии статей описан процесс создания первого pet-проекта для начинающего инженера в DevOps:
Глава 1: Введение и подготовка стенда
Глава 2: Настройка центра сертификации и репозитория
Глава 3: Настройка OpenVPN
Глава 4: Настройка мониторинга
Настройка центра сертификации (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
В результате программа создаст два фала:
Открытый ключ можно сводобно передавать на другие 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
В результате мы получим два файла:
Выпуск пары ключ-сертификат для клиента
Для выпуска и подписания новой клиентской пары ключ-сертификат, необходимо выполнить следующие действия:
cd ~/easy-rsa
./easyrsa gen-req example nopass
./easyrsa sign-req client example
В результате мы получим два файла:
Центр сертификации успешно настроен, теперь соберем развернутую нами программу в 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
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:
Скриптов нет.
В результате мы собрали пакет »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
sudo aptly repo show -with-packages lab
sudo aptly package show easy-rsa-lab_0.1-1_all
sudo aptly repo drop lab
Снятие репозитория с публикации на примере «lab»:
sudo aptly publish drop focal filesystem:lab:lab
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
Репозиторий успешно подключен к системе!
Bash-скрипт для Repo
Настало время написать bush-скрипт, который сможет выполнить настройку Repo автоматически:
repo.sh
Версия на GitHub
#!/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
Версия на GitHub
#!/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
Настало время написать bush-скрипт, который сможет выполнить настройку Easy-RSA автоматически:
easy-rsa.sh
Версия на GitHub
#!/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