This commit is contained in:
Bellord
2026-10-01 01:49:21 +03:00
commit 6806881e8e
9 changed files with 380 additions and 0 deletions
+19
View File
@@ -0,0 +1,19 @@
# Общие данные
CERT_COUNTRY="EU"
CERT_LOCALITY="Local Network"
CERT_ORG="Ixrs"
# Корневой сертификат (Root CA)
ROOT_CN="Ixrs Root CA"
CERT_DAYS=3650
ROOT_EXT_SECTION="v3_ca" # Секция внутри root_ca.ini
# Промежуточный сертификат (Intermediate CA)
INT_CN="Ixrs Intermediate CA"
INT_DAYS=1825
INT_EXT_SECTION="v3_intermediate" # Секция внутри intermediate_ca.ini
# Выпускающий сертификат (Доменный / Конечный)
DOMAIN_CN="ixrs.ru"
ISSUING_DAYS=365
ISSUING_EXT_SECTION="v3_cert" # Секция внутри issuing_san.ini
+20
View File
@@ -0,0 +1,20 @@
# Конфигурационные файлы (рабочие копии)
.env
root_ca.ini
intermediate_ca.ini
issuing_san.ini
# Любые приватные ключи (главный секрет!)
*.key
privkey.pem
# Любые запросы на сертификат и файлы индексов OpenSSL
*.csr
*.srl
# Любые сгенерированные сертификаты и цепочки
*.crt
*.pem
# Папка с конечными сертификатами
certs/
+105
View File
@@ -0,0 +1,105 @@
# Локальная инфраструктура сертификатов (Local PKI)
Набор bash-скриптов и конфигурационных файлов для автоматического создания собственного доверенного центра сертификации (Root CA), промежуточного центра (Intermediate CA) и выпуска универсальных мультидоменных SSL-сертификатов (для Nginx, Nginx Proxy Manager, Docker-сервисов и любых других веб-серверов).
---
## 📋 Описание полей сертификата (Subject)
При настройке метаданных сертификатов в файле конфигурации используются следующие стандартные атрибуты:
* **CN** (*Common Name*) — Имя создаваемого объекта. Для Root/Intermediate CA указывается понятное название центра (например, `Ixrs Root CA`), а для конечных сертификатов — базовый домен организации.
* **O** (*Organization*) — Название компании или организации (например, `Ixrs`).
* **L** (*Locality*) — Город, населенный пункт или описание сети (например, `Local Network`).
* **C** (*Country*) — Двухбуквенный код страны в формате ISO (например, `RU`, `EU`, `US`).
* **ST** (*State*) — Регион, область, штат или край.
* **emailAddress** — Электронная почта администратора для связи.
---
## 📂 Структура проекта и генерируемые файлы
После успешного выполнения всех скриптов структура директории будет выглядеть следующим образом:
```text
.
├── .env # Активный файл конфигурации (копия из .env.example)
│
├── root_ca.ini # Конфигурация OpenSSL для Root CA
├── intermediate_ca.ini # Конфигурация OpenSSL для Intermediate CA
├── issuing_san.ini # Список доменов, поддоменов и IP для конечного сертификата
│
├── build-root-cert.sh # Скрипт сборки Root CA
├── build-intermediate-cert.sh # Скрипт сборки Intermediate CA
├── build-issuing-cert.sh # Скрипт сборки универсального мультидоменного сертификата
│
# ── Сгенерированные файлы (Артефакты) ──────────────────────────────────────────
│
├── root_ca.key # [🔒 SECRET] Приватный ключ Корневого ЦС
├── root_ca.crt # Публичный сертификат Корневого ЦС
├── root_ca.pem # Корневой сертификат в формате PEM (для совместимости)
├── root_ca.srl # Файл серийных номеров для отслеживания Root CA
│
├── intermediate_ca.key # [🔒 SECRET] Приватный ключ Промежуточного ЦС
├── intermediate_ca.csr # Запрос на подпись (CSR) Промежуточного ЦС
├── intermediate_ca.crt # Публичный сертификат Промежуточного ЦС
├── intermediate_ca.srl # Файл серийных номеров для отслеживания Intermediate CA
│
├── issuing.key # [🔒 SECRET] Исходный приватный ключ доменов
├── issuing.csr # Запрос на подпись (CSR) для конечных доменов
├── issuing.crt # Исходный конечный сертификат (только домены)
│
# ── Готовые контейнеры для веб-серверов (Nginx / NPM / Apache) ─────────────────
│
├── privkey.pem # [🔒 SECRET] Универсальный приватный ключ для веб-сервера
└── fullchain.pem # Полная цепочка (Конечный серт + Промежуточный серт)
```
---
## ⚙️ Настройка окружения
Для конфигурации скриптов используются файлы `.env` и `.ini`. Создайте их на основе шаблонов (команда безопасно пропустит копирование, если файлы уже созданы и настроены):
```bash
cp -n .env.example .env
cp -n root_ca.ini.example root_ca.ini
cp -n intermediate_ca.ini.example intermediate_ca.ini
cp -n issuing_san.ini.example issuing_san.ini
```
---
## 🚀 Порядок запуска и использования
Перед запуском сделайте скрипты исполняемыми:
```bash
chmod +x build-root-cert.sh build-intermediate-cert.sh build-issuing-cert.sh
```
### Шаг 1. Создание Корневого ЦС
Запустите скрипт создания главного сертификата. Если файлы уже существуют, скрипт выведет предупреждение для предотвращения случайной перезаписи.
```bash
./build-root-cert.sh
```
* Скрипт интерактивно спросит, хотите ли вы установить корневой сертификат в системное хранилище доверенных сертификатов ОС (Debian/Ubuntu). В случае согласия он сам запросит права `sudo` в нужный момент.
### Шаг 2. Создание Промежуточного ЦС
Запустите скрипт создания промежуточного центра, который будет использоваться непосредственно для подписи конечных адресов. Он защищен флагами ограничения области видимости доменов (`nameConstraints`) и запретом создания цепочек ниже уровнем (`pathlen:0`).
```bash
./build-intermediate-cert.sh
```
### Шаг 3. Выпуск мультидоменного сертификата
Запустите скрипт генерации универсального сертификата. Он подпишет ключ, строго опираясь на правила и список альтернативных имен (DNS и IP) из файла `issuing_san.ini`.
```bash
./build-issuing-cert.sh
```
* В конце процесса скрипт предложит автоматически собрать универсальные PEM-контейнеры `privkey.pem` (приватный ключ) и `fullchain.pem` (полная цепочка сертификатов), которые готовы к копированию в Nginx, Nginx Proxy Manager, Apache или бэкенд-приложения.
---
## 🛡️ Безопасность
* **Конфиденциальность ключей:** Приватные файлы ключей (`*.key` и `privkey.pem`) дают полный контроль над вашей локальной безопасностью. Никогда не передавайте их третьим лицам и ограничьте к ним доступ на машине (`chmod 400`).
* **Игнорирование в Git:** Обязательно добавьте секретные файлы в `.gitignore`, чтобы случайно не отправить личные ключи и доступы в публичный репозиторий.
+75
View File
@@ -0,0 +1,75 @@
#!/bin/bash
# Определяем путь к файлу .env (в той же папке, что и скрипт)
ENV_FILE="$(dirname "$0")/.env"
# Проверяем, существует ли файл .env, и загружаем его
if [ -f "$ENV_FILE" ]; then
source "$ENV_FILE"
else
echo "Ошибка: Файл конфигурации $ENV_FILE не найден!"
exit 1
fi
# 1. Проверяем, существуют ли файлы Root CA, необходимые для подписи
if [ ! -f "root_ca.crt" ] || [ ! -f "root_ca.key" ]; then
echo "Ошибка: Не найдены файлы root_ca.crt или root_ca.key!"
echo "Сначала запустите скрипт build-root-cert.sh"
exit 1
fi
# 2. ПРОВЕРКА НАЛИЧИЯ УЖЕ ГОТОВОГО ПРОМЕЖУТОЧНОГО СЕРТИФИКАТА
if [ -f "intermediate_ca.key" ] || [ -f "intermediate_ca.crt" ]; then
echo "Внимание: Файлы промежуточного сертификата (intermediate_ca.key/crt) УЖЕ СУЩЕСТВУЮТ!"
echo "⚠️ ПЕРЕЗАПИСЬ ЭТИХ ФАЙЛОВ ПРИВЕДЕТ К ТОМУ, ЧТО ВСЕ ВЫПУЩЕННЫЕ РАНЕЕ СЕРТИФИКАТЫ САЙТОВ ПЕРЕСТАНУТ РАБОТАТЬ!"
echo ""
read -p "Вы уверены, что хотите перевыпустить Промежуточный ЦС? [y/N]: " overwrite_response
overwrite_response=$(echo "$overwrite_response" | tr '[:upper:]' '[:lower:]')
# По умолчанию (если просто нажат Enter) или если ответ не "y"/"yes" — отменяем выполнение
if [[ ! "$overwrite_response" =~ ^(y|yes)$ ]]; then
echo "Генерация отменена во избежание порчи действующих сертификатов."
exit 0
fi
echo "Продолжаем генерацию и перезапись файлов..."
fi
echo "Генерация ключа и CSR для Промежуточного ЦС..."
# Создаем ключ и запрос (CSR) для промежуточного ЦС
openssl req -new -nodes -newkey rsa:4096 \
-keyout intermediate_ca.key -out intermediate_ca.csr \
-subj "/C=${CERT_COUNTRY}/L=${CERT_LOCALITY}/O=${CERT_ORG}/CN=${INT_CN}"
echo "Подпись промежуточного сертификата с помощью Root CA..."
# Подписываем промежуточный сертификат с помощью Root CA
openssl x509 -req -sha512 -days "$INT_DAYS" \
-extfile intermediate_ca.ini -extensions "$INT_EXT_SECTION" \
-CA root_ca.crt -CAkey root_ca.key -CAcreateserial \
-in intermediate_ca.csr \
-out intermediate_ca.crt
echo ""
# Запрашиваем подтверждение у пользователя (Y - да, n - нет)
read -p "Хотите установить промежуточный сертификат в систему как доверенный? [Y/n]: " response
# Переводим ответ в нижний регистр
response=$(echo "$response" | tr '[:upper:]' '[:lower:]')
# Если пользователь нажал Enter или ввел y/yes
if [[ -z "$response" || "$response" =~ ^(y|yes)$ ]]; then
echo "Установка промежуточного сертификата..."
if [ "$EUID" -ne 0 ]; then
sudo cp intermediate_ca.crt /usr/local/share/ca-certificates/intermediate_ca.crt
sudo update-ca-certificates
else
cp intermediate_ca.crt /usr/local/share/ca-certificates/intermediate_ca.crt
update-ca-certificates
fi
echo "Промежуточный сертификат успешно установлен!"
else
echo "Установка отменена."
fi
+62
View File
@@ -0,0 +1,62 @@
#!/bin/bash
# Определяем путь к файлу .env и загружаем его
ENV_FILE="$(dirname "$0")/.env"
if [ -f "$ENV_FILE" ]; then
source "$ENV_FILE"
else
echo "Ошибка: Файл конфигурации $ENV_FILE не найден!"
exit 1
fi
# Проверяем наличие Промежуточного ЦС для подписи
if [ ! -f "intermediate_ca.crt" ] || [ ! -f "intermediate_ca.key" ]; then
echo "Ошибка: Не найдены файлы intermediate_ca.crt или intermediate_ca.key!"
echo "Сначала запустите скрипт build-intermediate-cert.sh"
exit 1
fi
# Проверяем наличие файла конфигурации SAN
if [ ! -f "issuing_san.ini" ]; then
echo "Ошибка: Файл конфигурации issuing_san.ini не найден!"
exit 1
fi
echo "Генерация универсального ключа и запроса (CSR) по файлу конфигурации..."
# Создаем один общий запрос. В CN подставляем базовый домен из .env
openssl req -new -nodes -newkey rsa:4096 \
-keyout issuing.key -out issuing.csr \
-subj "/C=${CERT_COUNTRY}/L=${CERT_LOCALITY}/O=${CERT_ORG}/CN=${DOMAIN_CN}"
echo "Подпись мультидоменного сертификата через Intermediate CA (на $ISSUING_DAYS дн)..."
# Подписываем, строго используя расширения SAN из файла issuing_san.ini
openssl x509 -req -sha512 -days "$ISSUING_DAYS" \
-extfile issuing_san.ini -extensions "$ISSUING_EXT_SECTION" \
-CA intermediate_ca.crt -CAkey intermediate_ca.key -CAserial intermediate_ca.srl -CAcreateserial \
-in issuing.csr \
-out issuing.crt
echo ""
# Запрашиваем подтверждение сборки пакета для NPM
read -p "Хотите собрать файлы privkey.pem и fullchain.pem? [Y/n]: " npm_response
# Переводим ответ в нижний регистр
npm_response=$(echo "$npm_response" | tr '[:upper:]' '[:lower:]')
# Если пользователь нажал Enter или ввел y/yes
if [[ -z "$npm_response" || "$npm_response" =~ ^(y|yes)$ ]]; then
echo "Сборка универсальных файлов privkey.pem и fullchain.pem..."
# Копируем приватный ключ
cat issuing.key > privkey.pem
# Объединяем доменный и промежуточный сертификаты в единую цепочку (Full Chain)
cat issuing.crt > fullchain.pem
cat intermediate_ca.crt >> fullchain.pem
echo "Файлы сертификата (PEM-контейнеры) готовы в текущей папке:"
echo " -> Приватный ключ: privkey.pem"
echo " -> Цепочка сертификатов: fullchain.pem"
fi
echo ""
echo "✅ Процесс выпуска сертификата успешно завершен!"
+61
View File
@@ -0,0 +1,61 @@
#!/bin/bash
# Определяем путь к файлу .env (в той же папке, что и скрипт)
ENV_FILE="$(dirname "$0")/.env"
# Проверяем, существует ли файл .env, и загружаем его
if [ -f "$ENV_FILE" ]; then
source "$ENV_FILE"
else
echo "Ошибка: Файл конфигурации $ENV_FILE не найден!"
exit 1
fi
# ПРОВЕРКА НАЛИЧИЯ УЖЕ ГОТОВОГО КОРНЕВОГО СЕРТИФИКАТА
if [ -f "root_ca.key" ] || [ -f "root_ca.crt" ]; then
echo "Внимание: Файлы Корневого сертификата (root_ca.key/crt) УЖЕ СУЩЕСТВУЮТ!"
echo "⚠️ ПЕРЕЗАПИСЬ КОРНЯ СЛОМАЕТ ДОВЕРИЕ КО ВСЕМ ВЫПУЩЕННЫМ РАНЕЕ ПРОМЕЖУТОЧНЫМ И ДОМЕННЫМ СЕРТИФИКАТАМ!"
echo ""
read -p "Вы абсолютно уверены, что хотите перевыпустить Корневой ЦС? [y/N]: " overwrite_response
overwrite_response=$(echo "$overwrite_response" | tr '[:upper:]' '[:lower:]')
# По умолчанию (Enter) или при любом ответе, кроме y/yes — выходим
if [[ ! "$overwrite_response" =~ ^(y|yes)$ ]]; then
echo "Генерация отменена. Текущий корневой сертификат сохранен."
exit 0
fi
echo "Продолжаем генерацию и перезапись Корневого ЦС..."
fi
# Root certificate (Root CA)
openssl req -x509 -nodes -new -sha512 -days "$CERT_DAYS" \
-newkey rsa:4096 -keyout root_ca.key -out root_ca.crt \
-extfile root_ca.ini -extensions "$ROOT_EXT_SECTION" \
-subj "/C=${CERT_COUNTRY}/L=${CERT_LOCALITY}/O=${CERT_ORG}/CN=${ROOT_CN}"
echo ""
# Запрашиваем подтверждение у пользователя (Y - да, n - нет)
read -p "Хотите установить сертификат в систему как доверенный? [Y/n]: " response
# Переводим ответ в нижний регистр для надежности
response=$(echo "$response" | tr '[:upper:]' '[:lower:]')
# Если пользователь нажал Enter или ввел y/yes
if [[ -z "$response" || "$response" =~ ^(y|yes)$ ]]; then
echo "Установка сертификата..."
if [ "$EUID" -ne 0 ]; then
sudo cp root_ca.crt /usr/local/share/ca-certificates/root_ca.crt
sudo update-ca-certificates
else
cp root_ca.crt /usr/local/share/ca-certificates/root_ca.crt
update-ca-certificates
fi
echo "Сертификат успешно установлен!"
else
echo "Установка отменена."
fi
+9
View File
@@ -0,0 +1,9 @@
[ v3_intermediate ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
nameConstraints = critical, permit;DNS:ixrs.ru, permit;DNS:.ixrs.ru
# Разрешает домен ixrs.ru, localhost и локальные IP-адреса
nameConstraints = critical, permit;DNS:ixrs.ru, permit;DNS:.ixrs.ru, permit;DNS:localhost, permit;IP:127.0.0.1/255.255.255.255, permit;IP:0:0:0:0:0:0:0:1/128
+24
View File
@@ -0,0 +1,24 @@
[ v3_cert ]
subjectKeyIdentifier = hash
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
nsComment = "IXRS Local Certificate"
subjectAltName = @alt_names
[alt_names]
# IP-адреса
IP.1 = 127.0.0.1
IP.2 = ::1
# Доменные имена
DNS.1 = localhost
DNS.2 = ixrs.ru
DNS.3 = *.ixrs.ru
DNS.4 = nova.ixrs.ru
DNS.5 = *.nova.ixrs.ru
DNS.6 = mini.ixrs.ru
DNS.7 = *.mini.ixrs.ru
DNS.8 = *.s3.mini.ixrs.ru
DNS.9 = *.bellord.ixrs.ru
+5
View File
@@ -0,0 +1,5 @@
[ v3_ca ]
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign