Установка серверной части
1Распаковать дистрибутив в D:\Rubezh или другой выбранный каталог. Проверить наличие docker-compose.yml, .env.example, каталогов backend, frontend и infra. Не подменять файл Compose конфигурацией другого программного продукта.
2Создать .env из .env.example только при новой установке. Указать уникальные пароли владельца PostgreSQL и прикладной роли, а также учётные данные файлового хранилища. Значения change_me и другие демонстрационные секреты заменить.
3Сохранить предусмотренные внутренние адреса postgres, object-storage и certificate-manager. Прикладную роль PostgreSQL оставить отдельной от владельца базы. Не предоставлять ей права SUPERUSER или BYPASSRLS.
4Для рабочей установки с HTTPS задать RUBEZH_ENVIRONMENT=production и RUBEZH_SESSION_COOKIE_SECURE=true. При включённом Secure вход выполняется по HTTPS, а не по HTTP.
5Проверить конфигурацию без вывода содержимого секретов и собрать контейнеры.
if (-not (Test-Path '.env')) {
Copy-Item '.env.example' '.env'
}
docker compose @composeArgs config --quiet
docker compose @composeArgs build
Первичная подготовка HTTPS
До первого запуска Nginx должны существовать локальный удостоверяющий сертификат, его закрытый ключ и сертификат сервера. Если для экземпляра уже подготовлены действующие сертификаты, сохранить их и перейти к запуску сервисов. Для нового экземпляра без сертификатов выполнить приведённую ниже одноразовую процедуру. Она создаёт отдельный локальный удостоверяющий центр и вызывает существующий механизм выпуска сертификата сервера. Повторно создавать удостоверяющий центр при обновлениях нельзя.
Указать фактический IPv4-адрес сервера. В примере имя образа rubezh-certificate-manager соответствует имени проекта rubezh, заданному выше.
$serverIp = '192.168.1.10'
New-Item -ItemType Directory -Force '.\infra\nginx\certs' | Out-Null
New-Item -ItemType Directory -Force '.\infra\nginx\runtime-certs' | Out-Null
$pkiPath = (Resolve-Path '.\infra\nginx\certs').Path
$certPath = (Resolve-Path '.\infra\nginx\runtime-certs').Path
$certificateBootstrap = @'
import os
from datetime import datetime, timedelta, timezone
from pathlib import Path
from cryptography import x509
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.x509.oid import NameOID
import app
cert_path = Path('/pki/rubezh-local-ca.crt')
key_path = Path('/pki/rubezh-local-ca.key')
server_files = [
Path('/runtime/rubezh-server.crt'),
Path('/runtime/rubezh-server.key'),
]
if any(p.exists() for p in [cert_path, key_path, *server_files]):
raise SystemExit('Existing certificates found; bootstrap stopped')
key = rsa.generate_private_key(public_exponent=65537, key_size=3072)
name = x509.Name([
x509.NameAttribute(NameOID.COMMON_NAME, 'Rubezh Local CA')
])
now = datetime.now(timezone.utc)
cert = (
x509.CertificateBuilder()
.subject_name(name).issuer_name(name)
.public_key(key.public_key())
.serial_number(x509.random_serial_number())
.not_valid_before(now - timedelta(minutes=5))
.not_valid_after(now + timedelta(days=3650))
.add_extension(x509.BasicConstraints(ca=True, path_length=0), True)
.add_extension(x509.KeyUsage(
digital_signature=True, content_commitment=False,
key_encipherment=False, data_encipherment=False,
key_agreement=False, key_cert_sign=True, crl_sign=True,
encipher_only=False, decipher_only=False,
), True)
.sign(key, hashes.SHA256())
)
key_path.write_bytes(key.private_bytes(
serialization.Encoding.PEM,
serialization.PrivateFormat.PKCS8,
serialization.NoEncryption(),
))
cert_path.write_bytes(cert.public_bytes(serialization.Encoding.PEM))
app.CA_CERT_PATH = cert_path
app.CA_KEY_PATH = key_path
app.rotate_certificate(app.RotateRequest(
ip_address=os.environ['RUBEZH_INSTALL_IP']
))
print('CA and server certificates created')
'@
$certificateBootstrap | docker run --rm -i `
--mount "type=bind,source=$pkiPath,target=/pki" `
--mount "type=bind,source=$certPath,target=/runtime" `
-e "RUBEZH_INSTALL_IP=$serverIp" `
--entrypoint python rubezh-certificate-manager -
Полученные закрытые ключи остаются только на сервере и в защищённой резервной копии. На рабочие места передают исключительно файл rubezh-local-ca.crt. Закрытый ключ удостоверяющего центра и файл rubezh-server.key клиентам не передают.
Подготовка Offline ключей и запуск
Для новой установки сгенерировать серверные Offline-ключи штатной командой. Две строки RUBEZH_OFFLINE_… из результата перенести в соответствующие параметры .env. Вывод содержит закрытые ключи: хранить его как секрет и не публиковать. При наличии ключей работающей установки использовать существующие значения.
docker compose @composeArgs run --rm --no-deps backend python -m app.cli.generate_offline_keys
Запустить хранилища, создать прикладную роль PostgreSQL и применить миграции. Команда db-bootstrap должна завершиться успешно до запуска миграций.
docker compose @composeArgs up -d postgres object-storage
docker compose @composeArgs run --rm db-bootstrap
docker compose @composeArgs run --rm --no-deps backend alembic upgrade head
docker compose @composeArgs up -d
docker compose @composeArgs ps -a
docker compose @composeArgs exec backend alembic current
Проверка результата. Миграции завершились без ошибок. Долгоживущие сервисы запущены; для сервисов с проверкой здоровья отображается healthy. Завершение db-bootstrap с кодом 0 является штатным. Файлы сертификатов существуют, адрес сервера соответствует сертификату.