Infisical - это самостоятельный менеджер по секретам. Он хранит учетные данные, необходимые вашим приложениям, и передает их в процесс во время выполнения, поэтому ничего чувствительного не должно сидеть в файле на коробке. Причина запуска одного - это счет: ваш пароль производственной базы данных находится в .env на сервере приложения, в переменной CI, в потоке Slack с того дня, как сломался сервис, и в чьей-то истории оболочки. Никто не вращает его, потому что никто не может найти каждый экземпляр.

В этом руководстве показано, как установить Inficial на собственном сервере. Ставим перед ним Nginx и сертификат Let’s Encrypt, а затем проходит полный путь, который выполняет настоящий секрет: создать проект, хранить секрет, дать приложению свою собственную личность машины и введите значение в системный сервис, который никогда не записывает его на диск. Каждая команда ниже была запущена на Ubuntu 26.04 LTS

Предпосылки

  • Сервер под управлением Ubuntu 26.04
  • Права пользователя: пользователь root или обычный пользователь с привилегиями sudo.

Конвенции

1
2
# - данные команды должны выполняться с правами root либо непосредственно от имени пользователя root, либо с помощью команды sudo.
$ - данные команды должны выполняться от имени обычного пользователя.

Шаг 1. Обновите систему

Свежая установка Ubuntu 26.04 LTS требует обновления пакетов до последних доступных версий.

1
sudo apt update -y && sudo apt upgrade -y

Система может нуждаться в перезагрузке после обновления.

1
sudo reboot -f

Шаг 2. Установка Infisical

Теперь нам нужно загрузить последнюю соответствующую версию Infisical добавим репозиторий:

1
2
3
4
curl -1sLf 'https://artifacts-infisical-core.infisical.com/setup.deb.sh' | sudo -E bash

# Install
sudo apt update && sudo apt install infisical-core

Шаг 3. Установка PostgreSQL

Установите пакет Postgres.

1
2
3
sudo apt install postgresql postgresql-contrib redis-server

sudo systemctl enable --now postgresql redis-server

Шаг 4. Создание базы данных

Нам нужно создать базу данных для Infisical.

1
2
3
sudo -u postgres psql -c "CREATE USER infisical WITH PASSWORD 'YourStrongPassword';"
sudo -u postgres psql -c "CREATE DATABASE infisical_db OWNER infisical;"
sudo -u postgres psql -c "GRANT ALL PRIVILEGES ON DATABASE infisical_db TO infisical;"

Шаг 5. Создайте файл конфигурации

Сначала создайте два секрета:

1
2
openssl rand -hex 16      # ENCRYPTION_KEY
openssl rand -base64 32   # AUTH_SECRET

Пакет считывает конфигурационный файл в стиле Ruby, а не переменные среды.

Затем создайте каталог конфигурации и откройте файл. Этот файл содержит строки подключения к базе данных и другие настройки времени выполнения.

1
2
sudo mkdir -p /etc/infisical
sudo nano /etc/infisical/infisical.rb

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

1
2
3
4
5
6
7
8
9
# Important: Replace with secure values in production
infisical_core['ENCRYPTION_KEY'] = '6c1fe4e407b8911c104518103505b218'
infisical_core['AUTH_SECRET'] = '5lrMXKKWCVocS/uerPsl7V+TX/aaUaI7iDkgl3tSmLE='

# Example database connection strings
infisical_core['DB_CONNECTION_URI'] = 'postgres://infisical:YourStrongPassword@127.0.0.1:5432/infisical_db'
infisical_core['REDIS_URL'] = ''redis://127.0.0.1:6379'
infisical_core['SITE_URL'] = 'https://secrets.example.org'
infisical_core['PORT'] = 8080

Этот файл - драгоценности короны экземпляра, так что заприте его, прежде чем идти дальше:

1
sudo chmod 600 /etc/infisical/infisical.rb

Применяйте конфигурацию. Шаг перенастройки запускает миграцию и запускает контролируемую службу:

1
sudo infisical-ctl reconfigure

Сервер работает на порту 8080 по умолчанию (настраиваемый в infisical.rb).

Проверьте сервис и подтвердите ответы API. Обратите внимание, что хвост infisical-ctl следует за журналом и не выходит, поэтому используйте статус для скриптов:

1
2
sudo infisical-ctl status
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/api/status

Здоровая установка печатает контролируемый процесс и HTTP 200:

1
2
run: infisical_core: (pid 5269) 43791s; run: log: (pid 5267) 43792s
200

Шаг 6. Настройте Nginx в качестве обратного прокси

1
sudo apt install nginx

Создайте обратный конфигурацию прокси-сервера для infisical.

1
sudo nano /etc/nginx/sites-available/infisical.conf

Заполните файл следующей конфигурацией.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
server {
    server_name     secrets.example.org;
    listen          80;

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_redirect off;
        proxy_buffering off;
        client_max_body_size 50M;
    }
}

Включите конфигурацию обратной прокси-сервера Infisical Nginx.

1
sudo ln -s /etc/nginx/sites-available/infisical.conf /etc/nginx/sites-enabled/infisical.conf

Проверка конфигурации и перезагрузите службу Nginx.

1
2
sudo nginx -t
sudo systemctl restart nginx.service

Затем посетите веб-сайт по адресу http://secrets.example.org для доступа.

Шаг 7. Получите сертификат TLS от Let’s Encrypt

Мы будем использовать Let’s Encrypt для получения SSL-сертификата бесплатно. Пожалуйста, убедитесь, что вы указали свой поддомен на IP-адрес сервера. Шаги, приведенные ниже, будут работать только в том случае, если вы обслуживаете интерфейс управления с помощью Nginx.

1
sudo apt install certbot  python3-certbot-nginx

Запрос на Let’s Encrypt SSL.

1
sudo certbot certonly --nginx -d secrets.example.org

Проверьте SSL

Откройте следующую ссылку в вашем веб-браузере для проверки.

1
https://secrets.example.org

Следующая команда гарантирует, что Certbot может проверить ваш поддомен с помощью вашей конфигурации.

1
sudo certbot renew --dry-run

Если пробный запуск прошел без ошибок, все готово. Теперь процесс продления будет автоматизирован.

Он автоматически настраивает /etc/nginx/sites-available/infisical.conf для включения SSL.

Шаг 8. Создайте учетную запись администратора

Просмотрите свой домен и Infisical отправит вас на /admin/signup. Первая созданная учетная запись становится супер-администратором экземпляра, что означает, что тот, кто впервые попадает на эту страницу, владеет вашими секретами. Создайте его сразу после начала службы, а не завтра.

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

Не читайте поле inviteOnlySignup на конечной точке статуса в качестве подтверждения. Он отражает внутренний флаг разрешительной подписи, а не описывает политику, которую предлагает его название, поэтому плохо быть начеку. Вместо этого проверьте настройку в консоли сервера и подтвердите ее, открыв страницу регистрации в частном окне.

Шаг 9. Создайте проект и храните первый секрет

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

Создайте один из страниц продукта Secrets Management, назовите его в честь сервиса, который будет его потреблять, а затем добавьте секреты с панелью «Добавить секретность». Значения маскируются в списке до тех пор, пока вы не нажмете «Откровите значения», что является правильным по умолчанию для экрана, которым кто-то может поделиться:

Шаг 10. Дайте приложению собственную идентификацию машины

Приложения никогда не должны входить в систему как личность. Нечеловеческие модели нечеловеческих клиентов в качестве машинных идентичностей, и метод аутентификации по умолчанию для них - Universal Auth: идентификатор клиента и секрет клиента, которые обменивают на недолговечный токен доступа. Идентификатору предоставляется роль в конкретных проектах, поэтому она читается только то, к чему вы ее прикрепили.

Создайте один под контролем доступа, машинные идентификаторы. Дайте ему название рабочей нагрузки, а не человека, который его сделал, выберите роль члена организации, а затем добавьте его в проект с ролью зрителя, если ему нужно только читать. Доступными ролями проекта являются Admin, Member, Viewer и No Access.

Откройте метод Universal Auth на личность, чтобы найти идентификатор клиента и создать секрет клиента. Внимательно прочитайте настройки токенов на этой панели, потому что по умолчанию щедры:

Токен доступа TTL и max TTL по умолчанию до 2592000 секунд, что составляет тридцать дней. Притч, который живет в течение месяца, едва ли короче, чем полномочия, которые он должен был защищать. Отредактируйте метод и установите TTL на длину разворачивания, измеренную за считанные минуты, и max TTL до чего-то часа или меньше. Доверенные полевые поля IP по умолчанию 0.0.0.0/0 и ::/0 таким образом, сужение только входа IPv4 оставляет дверь открытой на IPv6, и оба могут быть ограничены вашим диапазоном выхода CI. Локаут включен по умолчанию при трех неудачных попытках с пятиминутным локаутом.

Секрет клиента раскрывается ровно один раз. Храните его там, где рабочая нагрузка может прочитать его и нигде больше.

Шаг 11. Введите секреты в реальный сервис

Установите CLI на машину, которая выполняет рабочую нагрузку. Это отдельный пакет от сервера, опубликованный в собственном репозитории:

1
2
3
4
curl -1sLf 'https://artifacts-cli.infisical.com/setup.deb.sh' | sudo -E bash

# Install
sudo apt update && sudo apt install infisical

Направьте CLI на свой собственный пример и обменивайте учетные данные личности на токен. Использовать INFISICAL_DOMAIN, который имеет приоритет над старшим INFISICAL_API_URL когда оба установлены. Суффикс /api является необязательным в любом случае, потому что CLI добавляет его, когда он отсутствует:

1
2
3
4
5
export INFISICAL_DOMAIN="https://secrets.example.org"
export INFISICAL_TOKEN=$(infisical login --method=universal-auth \
  --client-id="your-client-id" \
  --client-secret="your-client-secret" \
  --plain --silent)

Прочтите секреты, которые позволяет увидеть личность. Идентификатор проекта поступает из URL-адреса проекта или страницы его настроек:

1
infisical secrets --projectId="your-project-id" --env=dev

CLI печатает таблицу всего по объему и ничего, что не выходит за рамки:

1
2
3
4
5
6
7
┌─────────────────┬──────────────────────────────────────────────────┬─────────────┐
│ SECRET NAME     │ SECRET VALUE                                     │ SECRET TYPE │
├─────────────────┼──────────────────────────────────────────────────┼─────────────┤
│ DATABASE_URL    │ postgres://billing:127.0.0.1:5432/billing        │ shared      │
│ JWT_SIGNING_KEY │ dGhpcy1pcy1hLWxhYi1zaWduaW5nLWtleQ==             │ shared      │
│ STRIPE_API_KEY  │ sk_test_51LabExampleKeyNotReal0000               │ shared      │
└─────────────────┴──────────────────────────────────────────────────┴─────────────┘

Теперь запустите приложение через infisical run, который извлекает секреты и передает их в детский процесс в качестве переменных среды:

1
infisical run --projectId="your-project-id" --env=dev -- python3 app.py

То же приложение, запущенное без обертки, ничего не находит, и на диске в любом случае нет .env:

1
2
3
4
5
INF Injecting 3 Infisical secrets into your application process
app reading its config
  DATABASE_URL = postgres://billing:127.0.0.1:54...
  STRIPE_API_KEY set: True
  .env on disk: False

Это счастливый путь, и именно здесь останавливается большинство записей. Следующая часть - почему они не должны.

Шаг 12. Накопление личности не охватывает процесс

Вот часть скипа swiftстартов. Обертка, которая испрашивает файл учетных данных, а затем звонит в CLI, оставляет идентификатор клиента и клиент секретом в среде приложения, которое она запускает. Все, что может запустить оболочку внутри вашего приложения, может читать их, отчеканить свежие жетоны навсегда, и ваш тщательно сокращенный TTL ничего не значит.

Проверка детской процессной среды показывает, какие именно утечки:

1
2
infisical run --projectId="$PROJECT_ID" --env=dev -- \
  bash -c 'printenv | grep -oE "^INFISICAL_[A-Z_]+" | sort'

Три из этих четырех строк являются учетными данными, а не конфигурацией:

1
2
3
4
INFISICAL_DOMAIN
INFISICAL_TOKEN
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET

Исправление стоит одной команды. Удалите учетные переменные в течение последнего времени, чтобы приложение унаследовало значения, а не учетные данные, которые их принесли:

1
2
3
infisical run --projectId="$PROJECT_ID" --env=dev -- \
  env -u INFISICAL_TOKEN -u INFISICAL_UNIVERSAL_AUTH_CLIENT_ID -u INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET \
  bash -c 'printenv | grep -oE "^INFISICAL_[A-Z_]+" | sort'

Та же проверка теперь возвращает одну безвредную линию, адрес конечной точки:

1
INFISICAL_DOMAIN

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

Шаг 13. Системный блок, который объединяет

Настройка INFISICAL_UNIVERSAL_AUTH_CLIENT_ID и INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET Недостаточно само по себе, что является первым, что большинство людей пробует. CLI игнорирует их для run и попадает в интерактивный логин, который выходит из строя в условиях системы. Крошечная обертка обрабатывает обмен. Создать его:

1
sudo nano /usr/local/bin/infisical-exec

Он входит в систему, заменяет себя CLI и удаляет учетные данные из того, что будет дальше:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash
set -euo pipefail

token=$(infisical login --method=universal-auth \
  --client-id="${INFISICAL_UNIVERSAL_AUTH_CLIENT_ID}" \
  --client-secret="${INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET}" \
  --plain --silent)

exec env INFISICAL_TOKEN="${token}" \
  infisical run --projectId="${INFISICAL_PROJECT_ID}" --env="${INFISICAL_ENV}" --silent -- \
  env -u INFISICAL_TOKEN -u INFISICAL_UNIVERSAL_AUTH_CLIENT_ID -u INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET "$@"

Сделайте его исполняемым, затем создайте файл учетных данных, который будет считываться:

1
2
3
sudo chmod 755 /usr/local/bin/infisical-exec
sudo mkdir -p /etc/billing-api
sudo nano /etc/billing-api/infisical.env

Шесть строк, и только две из них являются секретными. Проверка обновления отключена, поэтому CLI не обращается к GitHub каждый раз, когда устройство перезапускается:

1
2
3
4
5
6
INFISICAL_DOMAIN=https://secrets.example.org
INFISICAL_PROJECT_ID=your-project-id
INFISICAL_ENV=prod
INFISICAL_DISABLE_UPDATE_CHECK=true
INFISICAL_UNIVERSAL_AUTH_CLIENT_ID=your-client-id
INFISICAL_UNIVERSAL_AUTH_CLIENT_SECRET=your-client-secret

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

1
2
sudo chown root:billing /etc/billing-api/infisical.env
sudo chmod 640 /etc/billing-api/infisical.env

Теперь о самом подразделении.

1
sudo nano /etc/systemd/system/billing-api.service

Полномочия прибывают через EnvironmentFile и никогда не появляться в подразделении или в ps выходной:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[Unit]
Description=billing-api with secrets injected by Infisical
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=billing
EnvironmentFile=/etc/billing-api/infisical.env
ExecStart=/usr/local/bin/infisical-exec /usr/local/bin/billing-api
Restart=on-failure
RestartSec=5
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes

[Install]
WantedBy=multi-user.target

Теперь вы можете перезагрузить систему и запустить billing-api.

1
2
3
sudo systemctl daemon-reload
sudo systemctl enable --now billing-api
sudo journalctl -u billing-api -n 20 --no-pager

Сервис придумывает свою конфигурацию уже в памяти:

1
2
3
4
5
systemd[1]: Started billing-api.service - billing-api with secrets injected by Infisical.
infisical-exec[10865]: INF Injecting 3 Infisical secrets into your application process
infisical-exec[10881]: billing-api starting
infisical-exec[10881]:   DATABASE_URL present: yes
infisical-exec[10881]:   STRIPE_API_KEY present: yes

Проверьте затвердевание, прочитав рабочую среду процесса напрямую, что является единственной проверкой, которая фактически доказывает это. Основной PID устройства - обертка CLI; приложение - его ребенок:

1
2
3
4
5
6
7
MAIN=$(systemctl show -p MainPID --value billing-api)
APP=$(pgrep -P ${MAIN} | head -1)
for P in ${MAIN} ${APP}; do
  echo "pid ${P} ($(ps -o comm= -p ${P}))"
  echo "  credentials: $(sudo cat /proc/${P}/environ | tr '\0' '\n' | grep -cE '^INFISICAL_(TOKEN|UNIVERSAL_AUTH_CLIENT_ID|UNIVERSAL_AUTH_CLIENT_SECRET)=')"
  echo "  secrets:     $(sudo cat /proc/${P}/environ | tr '\0' '\n' | grep -cE '^(DATABASE_URL|STRIPE_API_KEY|JWT_SIGNING_KEY)=')"
done

Раскол - это весь смысл. Обертка содержит учетные данные и никаких секретов; приложение содержит секреты и никаких учетных данных. Рабочая нагрузка в этой лаборатории была заглушкой раковины, которая заканчивается sleep, поэтому детский процесс сообщает, что имя:

1
2
3
4
5
6
pid 11720 (infisical)
  credentials: 3
  secrets:     0
pid 11737 (sleep)
  credentials: 0
  secrets:     3

Теперь ротация работает так, как и предполагалось. Измените значение в пользовательском интерфейсе, перезапустите службу, и новое значение будет жить без развертывания, перестроенного изображения или запуска управления конфигурацией. Рабочие нагрузки Kubernetes получают такое же поведение через оператора, а не через CLI, и оператор внешних секретов является нейтральным для поставщика способом подключения к нему, если вы уже используете его.

Завершение

В настоящее время на Ubuntu 26.04 LTS установлена корректная установка Infisical с правильным TLS-шифрованием и CLI и веб-доступом. Ваш сервер Infisical готов надежно хранить и управлять секретами для вашей инфраструктуры.

Вы можете поделиться статьей со своими друзьями в социальных сетях, которым может быть интересна эта статья или просто оставить комментарий ниже. Спасибо.