Вместо раздачи открытых ключей в authorized_keys на каждом сервере серверы доверяют одному CA в Stronghold. Пользователь входит в Stronghold через OIDC, подписывает свой открытый ключ и получает сертификат на 30 минут. Отзывать доступ на серверах не нужно: сертификат истекает сам.
Цель
Настроить SSH CA в Stronghold, роль, которая разрешает пользователю входить только под своим именем, доверие к CA на серверах и получение сертификата после входа через OIDC.
Предварительные требования
Перед началом подготовьте:
- Токен Stronghold с правами на настройку механизмов секретов, политик и Identity.
- Настроенный метод аутентификации OIDC, который передаёт группы пользователя (в DP — метод
oidc_deckhouse). - Серверы с OpenSSH, на которых вы можете менять
sshd_config. - Имя учётной записи каждого пользователя на серверах. В примере оно хранится в метаданных сущности (шаг 3).
Шаг 1. Настройте SSH CA
Включите механизм секретов SSH и сгенерируйте ключ CA.
Включите механизм секретов SSH:
d8 stronghold secrets enable -path=ssh-client-signer sshСгенерируйте ключ CA:
d8 stronghold write ssh-client-signer/config/ca generate_signing_key=true
Шаг 2. Настройте доверие на серверах
На каждом сервере настройте sshd на доверие сертификатам, подписанным CA Stronghold.
Сохраните открытый ключ CA на каждом сервере. Эндпоинт
public_keyне требует аутентификации:curl -o /etc/ssh/trusted-user-ca-keys.pem https://stronghold.example.com/v1/ssh-client-signer/public_keyДобавьте в
/etc/ssh/sshd_config:TrustedUserCAKeys /etc/ssh/trusted-user-ca-keys.pemПерезапустите
sshd:sudo systemctl restart sshd
Распространяйте ключ и настройку через систему управления конфигурацией (Ansible, Puppet, Salt).
Шаг 3. Создайте роль с шаблонным именем пользователя
Роль разрешает подписывать ключ только для principal, совпадающего с именем учётной записи пользователя на серверах. Имя учётной записи подставляет шаблон Identity.
Для метода oidc_deckhouse в DP имя псевдонима сущности — это email пользователя: модуль задаёт user_claim равным email в роли deckhouse_dex_authenticated. Email не совпадает с именем учётной записи на сервере, поэтому в примере имя учётной записи хранится в ключе ssh_user метаданных сущности. Менять метаданные сущности может только токен с правами на identity/entity/*, поэтому пользователь не может сменить свой principal.
Получите accessor метода аутентификации:
OIDC_ACCESSOR=$(d8 stronghold read -field=accessor sys/auth/oidc_deckhouse)Задайте имя учётной записи на серверах для каждого пользователя. Сущность пользователя создаётся при первом входе в Stronghold:
ENTITY_ID=$(d8 stronghold write -field=id identity/lookup/entity alias_name="<USER_EMAIL>" alias_mount_accessor="$OIDC_ACCESSOR") d8 stronghold write identity/entity/id/$ENTITY_ID metadata=ssh_user=<SSH_USER>Плейсхолдеры:
<USER_EMAIL>— email пользователя, он же имя псевдонима в методеoidc_deckhouse;<SSH_USER>— имя учётной записи пользователя на серверах.
Параметр
metadataзаменяет все метаданные сущности. Если у сущности уже есть метаданные, передайте все ключи в той же команде.Создайте роль:
d8 stronghold write ssh-client-signer/roles/ops - <<EOF { "key_type": "ca", "algorithm_signer": "rsa-sha2-256", "allow_user_certificates": true, "allowed_users_template": true, "allowed_users": "{{identity.entity.metadata.ssh_user}}", "default_user_template": true, "default_user": "{{identity.entity.metadata.ssh_user}}", "allowed_extensions": "permit-pty,permit-port-forwarding", "default_extensions": { "permit-pty": "" }, "ttl": "30m", "max_ttl": "1h" } EOFЕсли имя псевдонима уже совпадает с именем учётной записи на сервере, используйте вместо метаданных шаблон
{{identity.entity.aliases.<OIDC_ACCESSOR>.name}}, где<OIDC_ACCESSOR>— accessor метода. Например, это подходит для отдельного подключения OIDC сuser_claim, равнымpreferred_username.
Шаг 4. Выдайте права на подпись
Разрешите членам группы IdP подписывать ключи по роли.
Создайте политику:
d8 stronghold policy write ssh-ops - <<'POLICY' path "ssh-client-signer/sign/ops" { capabilities = ["update"] } POLICYПривяжите политику к группе IdP через внешнюю группу Identity:
GROUP_ID=$(d8 stronghold write -field=id identity/group name=ops type=external policies=ssh-ops) d8 stronghold write identity/group-alias name=ops mount_accessor="$OIDC_ACCESSOR" canonical_id="$GROUP_ID"Здесь
name=opsвgroup-alias— имя группы, которое IdP передаёт в claim групп.
Шаг 5. Получите сертификат и войдите на сервер
Эти действия выполняет пользователь на своей рабочей станции.
Войдите в Stronghold:
d8 stronghold login -method=oidc -path=oidc_deckhouseЕсли SSH-ключа нет, создайте его:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519Подпишите открытый ключ и сохраните сертификат рядом с ключом:
d8 stronghold write -field=signed_key ssh-client-signer/sign/ops public_key=@$HOME/.ssh/id_ed25519.pub > ~/.ssh/id_ed25519-cert.pubПодключитесь к серверу. OpenSSH автоматически использует файл
*-cert.pub:ssh <SSH_USER>@server.example.com<SSH_USER>— ваше имя учётной записи на серверах из шага 3.
Повторяйте шаги 1 и 3 после истечения сертификата.
Проверка
Проверьте результат:
Просмотрите содержимое сертификата:
ssh-keygen -Lf ~/.ssh/id_ed25519-cert.pubВ поле
Principalsдолжно быть ваше имя учётной записи на серверах, в полеValid— интервал не длиннее 30 минут.Попробуйте подписать ключ для чужого principal — запрос должен быть отклонён:
d8 stronghold write ssh-client-signer/sign/ops public_key=@$HOME/.ssh/id_ed25519.pub valid_principals=rootЧерез 30 минут убедитесь, что вход с тем же сертификатом отклоняется сервером.
При ошибках входа смотрите раздел «Устранение неполадок».
Очистка
Удалите объекты, созданные в этом руководстве.
Удалите внешнюю группу и её псевдоним:
d8 stronghold delete identity/group/name/ops.Удалите политику и роль:
d8 stronghold policy delete ssh-ops d8 stronghold delete ssh-client-signer/roles/opsДля тестового стенда отключите mount:
d8 stronghold secrets disable ssh-client-signer. После этого удалите строкуTrustedUserCAKeysна серверах.