Вопрос или проблема
Я хотел бы настроить Git-хостинг, обеспечивающий:
- доступ по SSH только для чтения для анонимных пользователей, и
- доступ по SSH для чтения и записи, аутентифицированный известными открытыми ключами SSH.
В идеале, OpenSSH должен информировать мое приложение о публичном ключе клиента и позволять приложению самостоятельно решать, предоставить ли доступ к службам.
Я могу контролировать все на сервере, но клиент — это обычный upstream Git-клиент, и я не могу им управлять.
Попытка 1: AuthorizedKeysCommand
/etc/ssh/sshd_config
Match User forge
AuthorizedKeysFile none
AuthorizedKeysCommand /usr/libexec/lindenii/forge/ssh_authorized_keys_command %C %D %f %h %k %t %U %u
AuthorizedKeysCommandUser root
PasswordAuthentication no
PermitEmptyPasswords no
DisableForwarding yes
PermitTTY no
/usr/libexec/lindenii/forge/ssh_authorized_keys_command
#!/bin/sh
# Позволяет авторизоваться с любым ключом
# Прототип, поэтому не заботимся о гонках и других проблемах с логированием
printf 'Endpoints: %s\n' "$1" > /var/log/lindenii/authkeys.last
printf 'Routing domain: %s\n' "$2" >> /var/log/lindenii/authkeys.last
printf 'Fingerprint: %s\n' "$3" >> /var/log/lindenii/authkeys.last
printf 'Home: %s\n' "$4" >> /var/log/lindenii/authkeys.last
printf 'Key/cert base64: %s\n' "$5" >> /var/log/lindenii/authkeys.last
printf 'Key/cert type: %s\n' "$6" >> /var/log/lindenii/authkeys.last
printf 'UID: %s\n' "$7" >> /var/log/lindenii/authkeys.last
printf 'Username: %s\n' "$8" >> /var/log/lindenii/authkeys.last
[ "$8" != "forge" ] && exit
# TODO: убедитесь, что тип и base64 ключа/сертификата безопасны и не приводят к инъекциям
# В любом случае, эта строка выводит строку, схожую с форматом authorized_keys, и
# фактически позволяет любому публичному ключу войти в систему, передавая в forge/ssh_shell
# тип ключа и ключа base64.
printf 'command="/usr/libexec/lindenii/forge/ssh_shell --ssh-key-type %s --ssh-key-base64 %s" %s %s\n' "$6" "$5" "$6" "$5"
Это позволяет любому клиенту с публичным ключем SSH войти в систему. Приложение может затем выбрать, как его обрабатывать. Если я хочу сразу отклонить соединение, я также могу выполнить аутентификацию в ssh_authorized_keys_command
и ничего не выводить в случае неудачной аутентификации.
Но это не работает для пользователей, у которых вовсе нет публичного ключа.
Попытка 2: Пользователь с пустым паролем и ForceCommand
Проблемы:
AuthorizedKeysCommand
не запускается, когда доступна аутентификация с пустым паролем, даже если у клиента есть публичный ключ.ForceCommand
берет верх надcommand=
, предоставляемойAuthorizedKeysCommand
в любом случае.
Попытка 3: ExposeAuthInfo
Проблемы:
- Файл
$SSH_USER_AUTH
всегдаnone
, когда доступна аутентификация с пустым паролем, даже если у клиента есть публичный ключ.
Вопросы
- Есть ли способ настроить OpenSSH в соответствии с моими нуждами? (Возможно, с помощью особой настройки PAM?)
- Если нет, существуют ли альтернативные реализации SSH, которые могли бы это сделать?
- Если нет, может ли OpenSSH передать соединение на кастомный SSH-сервер (возможно, через проксирование или
SCM_RIGHTS
), как только он узнает, что входящее соединение направлено пользователюforge
? - Если нет, существуют ли альтернативные реализации SSH, которые могли бы это сделать?
Ответ или решение
Настройка доступа к Git-хостингу с использованием OpenSSH, позволяющего анонимный доступ и доступ с проверкой подлинности через известные SSH-ключи, представляет собой интересную задачу с множеством технических нюансов. Чтобы внедрить эту систему, необходимо чётко сформулировать требования и пошагово рассмотреть каждую компоненту конфигурации.
Теория
Основная идея состоит в том, чтобы предоставить пользователям возможность подключаться к серверу двумя способами:
- Чтение и анонимный доступ через SSH без какой-либо аутентификации. Это можно реализовать путем разрешения подключения с пустым паролем, однако этот подход небезопасен и обычно не рекомендуется в производственных средах.
- Запись и доступ с аутентификацией через известные SSH-публичные ключи, где сервер проверяет, у кого есть разрешение на запись. Этот метод основывается на проверке подлинности через файлы
authorized_keys
.
Пример
Рассмотрим предложенные попытки:
-
AuthorizedKeysCommand
. Этот подход использует сценарий для динамического предоставления ключей аутентификации при подключении пользователя. Он позволяет выполнять проверку и управление доступом на уровне приложения. Хотя он хорош для аутентифицированных пользователей, он не покрывает сценарий анонимного доступа, где у клиентов нет публичных ключей. -
Пользователь с пустым паролем и
ForceCommand
. Этот метод предполагает, что для анонимных пользователей будет создана учетная запись с пустым паролем. Однако в этом случаеAuthorizedKeysCommand
не запускается даже если у клиента есть публичный ключ. К тому же,ForceCommand
имеет приоритет над любымcommand=
, переданнымAuthorizedKeysCommand
. -
ExposeAuthInfo
. Этот подход позволяет получать более подробную информацию о процессе аутентификации. Тем не менее, в случае доступности пустого пароля содержимое$SSH_USER_AUTH
будетnone
, что не разрешает различать анонимный и публично аутентифицированный доступ.
Применение
Теперь перейдем к анализу и решению задачи:
-
Настройка PAM (Pluggable Authentication Module): Возможно, стоит обратить внимание на возможность настройки PAM для реализации более гибкой схемы аутентификации. PAM позволяет настраивать модульную систему проверки подлинности, которая может сыграть ключевую роль в различении пользователей по типу входа.
-
Альтернативные реализации SSH: Рассмотрите использование альтернативных SSH-серверов, которые могут предлагать более гибкие механизмы аутентификации. Такие серверы, как LSH или Dropbear, могут предоставлять функциональные возможности, которых нет в OpenSSH.
-
Проксирование или передача подключения: Если OpenSSH не предоставляет требуемую функциональность, рассмотрите возможность проксирования или использования
SCM_RIGHTS
для передачи контролируемых соединений на ваш пользовательский SSH-сервер. Это возможно, но может потребовать значительных усилий по разработке и тестированию.
Заключение
Ваша задача объединяет требования безопасности, гибкости доступа и управляемости подключений, что делает её технически сложной. OpenSSH изначально не проектировался для одновременного поддержания анонимного и аутентифицированного доступов в рамках одного протокола. Таким образом, может потребоваться привлечение дополнительных решений, таких как настройка PAM или использование других SSH-реализаций, для достижения ваших целей.
В конечном счете, выбор подхода должен базироваться на оценке рисков безопасности, простоте в интеграции с существующей инфраструктурой и управляемости системы в будущем. Соблюдая эти принципы, вы сможете обеспечить баланс между доступностью и безопасностью вашего Git-хостинга.