Безопасность на новом уровне: исследование Smallstep CA и его применение

ecf2d96b2788ba86db9ef42eb6e900bd.png

Рассмотрим Smallstep CA, который представляет собой современное и инновационное решение для управления сертификатами. Оно предложить несколько преимуществ по сравнению с OpenSSL.

Развернем FreeIPA с сертификатом, созданным с помощью Smallstep-CA. FreeIPA — открытое программное обеспечение, специализированная служба каталогов. Предназначена для создания в ОС Linux среды, позволяющей централизованно управлять аутентификацией пользователей, устанавливать политики доступа и аудита. Функциональность FreeIPA подобна Active Directory, используемому в Windows.

Цели статьи:

  • Познакомиться с Smallstep-CA (Сокращенное название Step-CA) и его возможностями

  • Установить и настроить Step-CA

  • Развернуть FreeIPA с внешним сертификатом, созданным с помощью Step-CA

Возможности Step-CA

  • Выпуск HTTPS-сертификатов X.509 для работы в браузерах.

  • Выпуск клиентских сертификатов X.509 для включения взаимной аутентификации TLS (mTLS).

  • Выпуск SSH-сертификатов для пользователей при использовании единого идентификатора для входа (SSO ID tokens).

  • Выпуск SSH-сертификатов для хостов в обмен на идентификаторы облачных экземпляров.

  • Автоматизация управления сертификатами с помощью ACME v2.

  • Выдача краткосрочных сертификатов с автоматической регистрацией, обновлением и отзывом.

  • Обеспечение высокой доступности с использованием корневой федерации и/или нескольких промежуточных CA.

  • Работа в качестве промежуточного CA в сети для существующего корневого CA.

  • Выпуск токенов единого входа OAuth OIDC (Okta, GSuite, Azure AD, Auth0, Keycloak или Dex).

  • Идентификация облачных экземпляров для виртуальных машин на AWS, GCP и Azure.

  • Выдача одноразовых краткосрочных токенов JWK вашим инструментам непрерывной поставки (CD) — Puppet, Chef, Ansible, Terraform и др.

  • Выполнение запроса на вызов SCEP (SCEP provisioner).

  • Обновление сертификатов хостов SSH (SSHPOP provisioner).

Часть 1. Step-CA

Действия выполняются на отдельной виртуальной машине со Step-CA по нескольким причинам: конфликт 443 портов, а также возможное расширенное использование Step-CA.

Установка Step-CA

Step-CA является кроссплатформенным, но я тестирую на Ubuntu Linux 20.04 LTS. Инструкции по установке доступны для всех основных операционных систем и различных дистрибутивов Linux. Я установлю систему на выделенную виртуальную машину с именем хоста ca.mydomain.int. При предоставлении сертификатов TLS для внутренних доменов требуется функциональная инфраструктура DNS. Вам придется адаптировать эти инструкции, чтобы они соответствовали вашей собственной структуре DNS.

Установим Step-CA.

wget https://github.com/smallstep/certificates/releases/download/v0.25.2/step-ca_0.25.2_amd64.deb
sudo dpkg -i step-ca_0.25.2_amd64.deb

Это приведет к установке двоичного файла Step-CA в /usr/bin/step-ca и необходимо только для серверной части. Клиентам этот пакет не понадобится. Кроме того, мы установим Step CLI на сервер, чтобы разрешить настройку сервера.

wget https://github.com/smallstep/cli/releases/download/v0.25.2/step-cli_0.25.2_amd64.deb
sudo dpkg -i step-cli_0.25.2_amd64.deb

Step-cli упрощает управление и проверку публикуемого вами центра сертификации.

Инициализация Step-CA

Следующая команда инициализирует центр сертификации с помощью Step CLI:

step-cli ca init

Если вы заменяете или дополняете существующую PKI (инфраструктуру открытых ключей), вы можете передать существующий корневой сертификат и закрытый ключ. Также доступны дополнительные возможности для облачной инфраструктуры (например, системы управления ключами Amazon или Azure).

В этом руководстве я буду настраивать центр сертификации со следующими настройками:

  • Deployment Type: Standalone — Автономные облачные сервисы и средства мониторинга доступны, но могут потребовать дополнительных затрат при более масштабном развертывании.

  • PKI Name: MyPrivateCA — Для более крупных развертываний вам следует сделать это название описательным, чтобы различать тестовую среду, среду разработки и производственную среду.

  • DNS names or IP addresses: ca.mydomain.int — Эти DNS-имена и IP-адреса будут включены в сертификат CA. Добавьте здесь свои собственные DNS-имена и IP-адреса.

  • IP and port to bind to :443 — Это приведет к привязке ко всем IP-адресам на порту 443. Если для доступа будет использоваться промежуточный сервер, Nginx или другой балансировщик нагрузки, вы можете привязаться к внутреннему IP 127.0.0.1 и/или использовать другой порт.

  • First provisioner: pki@mydomain.int — Это эквивалент суперпользователя или пользователя root сервера PKI. mydomain.int построен на моей личной инфраструктуре DNS. Пожалуйста, настройте его в соответствии с вашими требованиями.

  • Password: Оставьте пустым — это автоматически сгенерирует пароль, который вы должны сохранить.

Сделаем возможным запустить сервер Step-CA от имени обычного пользователя (не от имени root):

sudo setcap CAP_NET_BIND_SERVICE=+eip $(which step-ca)
step-ca

При этом будет запрошен случайный пароль, который мы сгенерировали выше, чтобы разблокировать корневые ключи. Должно получиться что-то вроде этого:

2023/12/19 09:25:44 Starting Smallstep CA/0.25.2 (linux/arm64)
…
2023/12/19 09:25:44 X.509 Root Fingerprint: …
2023/12/19 09:25:44 Serving HTTPS on :443 ...

Теперь ваш центр сертификации запущен. Остановим его для настройки.

Если вы не получаете последнюю строку, что-то мешает вам запустить это приложение на порту 443. Нажмите CTRL+C, чтобы выйти из программы и прочитать, почему не удалось выполнить привязку, из сообщений журнала, которые на данный момент должны быть в выводе терминала. Если вы используете Linux, обычным пользователям, как правило, не разрешается работать с портами ниже 1024. Чтобы решить проблему, вы можете либо использовать команду setcap, либо запустить приложение от имени root с помощью sudo, либо поместить его в контейнер в Docker.

Иногда у вас может быть веб-сервер, уже запущенный на этом порту. Если SELinux включен, вы должны разрешить приложению Step-CA запускаться на привилегированном порту. Во время установки или в файле конфигурации укажите альтернативный порт (например, 8443) и используйте запущенный веб-сервер в качестве прокси.

Если все в порядке, теперь у вас есть работающая система PKI! Для запуска центра сертификации потребуется ваш пароль для расшифровки сертификата. Лучше всего хранить пароль в безопасном месте, таком как хранилище (например, Hashicorp Vault) или чип TPM. Скомпрометированный корневой ключ может привести к компрометации всей вашей PKI.

Автоматический запуск вашего PKI при перезагрузке вашей системы:

На данный момент у нас есть служба, работающая на порту 443. Однако мы не хотим делать это вручную при каждой перезагрузке сервера. Нажмите CTRL+C в терминале, где вы запустили процесс, чтобы завершить процесс Step-CA. Хорошая практика запускать подобные службы под учетной записью службы с ограниченным доступом. Создадим такую учетную запись:

sudo useradd --system --home /etc/step-ca --shell /bin/false step

Создайте и переместите конфигурацию вашего центра сертификации в домашний каталог пользователя step:

sudo mkdir /etc/step-ca
sudo mv $(step path)/* /etc/step-ca

В директории /etc/step-ca будет такая структура

certs  config  db  secrets  templates

Сохраните пароль PKI в /etc/step-ca/password.txt, чтобы его можно было прочитать при запуске сервера. Ограничьте доступ к этому файлу для других пользователей.

sudo touch /etc/step-ca/password.txt
sudo chmod 600 /etc/step-ca/password.txt
sudo nano /etc/step-ca/password.txt

Обратите внимание, что вам придется редактировать эти файлы от имени root, поэтому убедитесь, что вы указали sudo vi или sudo nano для редактирования этих файлов.

Теперь отредактируйте файл /etc/step-ca/config/defaults.json и /etc/step-ca/config/ca.json, чтобы отразить новый путь. В моем случае мне пришлось изменить различные ключи в конфигурации с /home/ubuntu/.step на /etc/step-ca, воспользуйтесь функцией поиска и замены в вашем редакторе. ubuntu — текущий пользователь на виртуальной машине.

sudo nano /etc/step-ca/config/defaults.json
sudo nano /etc/step-ca/config/ca.json

Установите пользователя step владельцем каталога конфигурации вашего CA:

sudo chown -R step:step /etc/step-ca

Создайте файл модуля systemd в вашем любимом редакторе. Еще раз, вы можете использовать vi или nano:

sudo nano /etc/systemd/system/step-ca.service

Добавьте следующее содержимое:

[Unit]
Description=Step-CA service
Documentation=https://smallstep.com/docs/step-ca
Documentation=https://smallstep.com/docs/step-ca/certificate-authority-server-production
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=30
StartLimitBurst=3
ConditionFileNotEmpty=/etc/step-ca/config/ca.json
ConditionFileNotEmpty=/etc/step-ca/password.txt
[Service]
Type=simple
User=step
Group=step
Environment=STEPPATH=/etc/step-ca
WorkingDirectory=/etc/step-ca
ExecStart=/usr/bin/step-ca config/ca.json --password-file password.txt
ExecReload=/bin/kill --signal HUP $MAINPID
Restart=on-failure
TimeoutStopSec=30
StartLimitInterval=30
StartLimitBurst=3
; Process capabilities & privileges
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
SecureBits=keep-caps
NoNewPrivileges=yes
; Sandboxing
ProtectSystem=full
ProtectHome=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
PrivateTmp=true
PrivateDevices=true
ProtectClock=true
ProtectControlGroups=true
ProtectKernelTunables=true
ProtectKernelLogs=true
ProtectKernelModules=true
LockPersonality=true
RestrictSUIDSGID=true
RemoveIPC=true
RestrictRealtime=true
SystemCallFilter=@system-service
SystemCallArchitectures=native
MemoryDenyWriteExecute=true
ReadWriteDirectories=/etc/step-ca/db
[Install]
WantedBy=multi-user.target

Этот файл также размещен на GitHub.

Вот несколько примечаний о свойствах в этом файле, созданных для изолирования приложения:

  • Пользователь и группа заставляют Step-CA запускаться от имени пользователя службы, которого мы создали ранее.

  • Использование AmbientCapabilities и CapabilityBoundingSet предназначено для ограничения диапазона возможностей, которые может получить процесс. В этом случае мы можем привязываться только к портам, которые меньше 1024, как обсуждалось ранее.

  • SecureBits позволяет службе сохранять свои возможности даже после переключения на пользователя step. NoNewPrivileges гарантирует, что после запуска процесса он не сможет повысить свой уровень для получения новых привилегий.

  • ProtectSystem, ProtectHome и RestrictNamespaces изолируют процесс.

  • RestrictAddressFamilies не позволяет службе выделять сокеты, отличные от IP или Unix.

  • PrivateTmp и PrivateDevices предоставляют службе закрытый каталог временных файлов и доступ к закрытому набору ключевых псевдоустройств (например, генератору случайных чисел), но не дают доступа к реальному оборудованию.

  • Строфы Protect* ограничивают доступ к системным ресурсам, поэтому процесс не может их изменять.

  • Блокировка личности гарантирует, что процесс не сможет сменить личность после запуска. Это включает в себя отключение поддержки ASMR и возможностей виртуальной памяти или переключение с 64-разрядного на 32-разрядный режим, что может быть признаком компрометации.

  • RestrictSUIDSGID ограничивает создание файлов setuid/setgid (файлы, запускаемые от имени root).

  • RemoveIPC удаляет все объекты межпроцессного взаимодействия, которые служба создает при остановке.

  • RestrictRealtime ограничивает доступ к планированию в реальном времени.

  • SystemCallFilter и SystemCallArchitectures определяют список системных вызовов, которые может использовать служба.

  • MemoryDenyWriteExecute предотвращает создание службой сопоставлений памяти, доступных для записи и исполняемых файлов.

  • ReadWriteDirectories гарантирует, что процесс может выполнять запись в свой каталог состояния.

Теперь нам нужно убедиться, что система распознает изменение, затем включить и запустить процесс Step-CA, это также позволит ему запуститься при загрузке вашей системы Linux:

sudo systemctl daemon-reload
sudo systemctl enable --now step-ca
sudo systemctl status step-ca

Команда status должна возвращать значение Active: активный (запущен) и часть выходных данных процесса Step-CA. Если произошла ошибка или вы хотите просмотреть журналы, вы можете использовать следующую команду:

sudo journalctl -u step-ca

Отныне, если вы хотите настроить свой сервер step-ca в этом новом расположении, обязательно укажите путь к конфигурации в качестве переменной окружения:

export STEPPATH=/etc/step-ca

Теперь вы можете убедиться, что он находится в папке /etc/step-ca:

sudo step certificate fingerprint $(step path)/certs/root_ca.crt

Часть 2. FreeIPA.

Действия выполняются на виртуальной машине с FreeIPA.

Использую Ubuntu Linux 20.04 LTS для FreeIPA из-за этого бага https://github.com/freeipa/freeipa-container/issues/429.

Устанавливаем docker.

sudo apt install docker.io docker-compose-v2 mc

Добавляем текущего пользователя в группу docker и перелогинимся на сервер.

sudo usermod -aG docker $USER

Создаем директорию и меняем ее владельца /etc/docker-compose.
ubuntu — текущий пользователь на виртуальной машине.

sudo mkdir -p /etc/docker-compose
sudo chown -R ubuntu:ubuntu /etc/docker-compose

Запускаем FreeIPA для генерации CSR c параметром --external-ca

cat <

Запустим Docker Compose и ждем, когда FreeIPA создаст ipa.csr и завершится.

cd /etc/docker-compose/
docker compose up

CSR FreeIPA

CSR FreeIPA сохранится по пути /etc/docker-compose/freeipa-data/ipa.csr.

Просмотр CSR.

openssl req -text -noout -verify -in /etc/docker-compose/freeipa-data/ipa.csr

Копируем /etc/docker-compose/freeipa-data/ipa.csr c FreeIPA сервера в /etc/step-ca/certs/ipa.csr на сервер Step-CA.

Подпишем зашифрованный запрос на выпуск сертификата (csr) FreeIPA корневым сертификатом CA, так как в FreeIPA csr указано поле CA:True и только корневой сертификат может его подписать. Потребуется пароль из файла /etc/step-ca/password.txt.

sudo step certificate sign --profile intermediate-ca /etc/step-ca/certs/ipa.csr /etc/step-ca/certs/root_ca.crt /etc/step-ca/secrets/root_ca_key | sudo tee -a /etc/step-ca/certs/ipa.crt

Просмотр crt.

openssl x509 -noout -text -in /etc/step-ca/certs/ipa.crt

Копируем /etc/step-ca/certs/root_ca.crt c сервера Step-CA в /etc/docker-compose/ca/root_ca.crt на сервер FreeIPA.

Копируем /etc/step-ca/certs/ipa.crt c сервера step-ca в /etc/docker-compose/freeipa-certificate/ipa.crt на сервер FreeIPA.

Обновляем /etc/docker-compose/docker-compose.yaml.

services:
  freeipa:
    image: freeipa/freeipa-server:fedora-39-4.11.1
    container_name: freeipa
    restart: unless-stopped
    hostname: freeipa.mydomain.int
    ports:
      - 123:123/udp
      - 389:389
      - 443:443
      - 464:464
      - 464:464/udp
      - 636:636
      - 80:80
      - 88:88
      - 88:88/udp
    tty: true
    stdin_open: true
    environment:
      IPA_SERVER_HOSTNAME: freeipa.mydomain.int
      TZ: "Europe/Moscow"
    command:
      - --no-ntp
      - --no-host-dns
      - --admin-password=youpassword
      - --dirsrv-pin=youpassword
      - --ds-password=youpassword
      - --external-cert-file=/freeipa-certificate/ipa.crt
      - --external-cert-file=/ca/root_ca.crt
      - --http-pin=youpassword
      - --realm=MYDOMAIN.INT
      - --unattended
      - -v
    cap_add:
      - SYS_TIME
      - NET_ADMIN
    volumes:
      - /etc/docker-compose/ca:/ca
      - /etc/docker-compose/freeipa-certificate:/freeipa-certificate
      - /etc/docker-compose/freeipa-data:/data
      - /etc/localtime:/etc/localtime:ro
      - /sys/fs/cgroup:/sys/fs/cgroup:ro
    sysctls:
      - net.ipv6.conf.all.disable_ipv6=0
      - net.ipv6.conf.lo.disable_ipv6=0
    security_opt:
      - "seccomp:unconfined"
    tmpfs:
    - /run
    - /tmp

Запускаем FreeIPA. Смотрим ошибки.

docker compose up

FreeIPA конфигурируется минут 10. Если ошибок нет, добавляем Docker Compose в systemd unit.

sudo nano /etc/systemd/system/freeipa.service

Содержимое:

[Unit]
Description=%i service with docker compose
Requires=docker.service
After=docker.service

[Service]
Type=oneshot
RemainAfterExit=true
WorkingDirectory=/etc/docker-compose/
ExecStart=/usr/bin/docker compose up -d --remove-orphans
ExecStop=/usr/bin/docker compose down

[Install]
WantedBy=multi-user.target

Запускаем FreeIPA через systemd.

sudo systemctl daemon-reload
sudo systemctl enable --now freeipa
sudo systemctl status freeipa

Команда systemctl status должна возвращать значение Active: активный (запущен) и часть выходных данных процесса Step-CA. Если произошла ошибка или вы хотите просмотреть журналы, вы можете использовать следующую команду:

sudo journalctl -u freeipa

Установка корневых сертификатов Step-CA

Прописываем ca.mydomain.int и freeipa.mydomain.int либо в DNS либо в /etc/hosts.

sudo nano /etc/hosts

Получение отпечатка корневого сертификата.

export STEPPATH=/etc/step-ca
step certificate fingerprint $(step path)/certs/root_ca.crt

Запустите следующую команду на клиенте, чтобы загрузить корневой сертификат, заменив DNS или IP-адрес и отпечаток вашего CA-сервера отпечатком пальца из приведенной выше команды:

step ca bootstrap --ca-url https://ca.mydomain.int --fingerprint ce3f9c4ef123bf7ddf2a527a35e80100080992a17d13c79d7f7a049eed923079

Скачайте корневой сертификат в файл ~/.step/certs/root_ca.crt.

step certificate install --all ~/.step/certs/root_ca.crt

В chrome видим, что сертификат валидный.

Автоматизация

Для автоматизации процесса установки, настройки Step-CA и выписывания сертификатов, необходимо решение следующих issue:
https://github.com/smallstep/cli/issues/674
https://github.com/maxhoesel-ansible/ansible-collection-smallstep/issues/340
https://github.com/maxhoesel-ansible/ansible-collection-smallstep/issues/408
https://github.com/maxhoesel-ansible/ansible-collection-smallstep/issues/407

Заключение

В этой статье я рассказал о том, как быстро создать свой собственный центр сертификации. Этот пример удобен для демонстрации и тестирования; однако для производственного использования и в более крупных средах вам следует обязательно ознакомиться с обширной документацией Step-CA и убедиться, что закрытые корневые ключи, операционная система сервера CA, программное обеспечение и любые пароли, связанные с вашим PKI, защищены надлежащим образом. Следует также рассмотреть такие меры предосторожности, как шифрование диска, многофакторная аутентификация, безопасная загрузка и аттестация оборудования.

© Habrahabr.ru