TL;DR В этот статье мы установим single sign-on для SSH от Google. За кулисами мы воспользуемся OpenID Connect (OICD), краткосрочными SSH сертификатами, несколькими хитростями конфигурации SSH, и опенсорсными пакетами step-ca и step от Smallstep. Мы настроим SSH Certificate Authority и воспользуемся им, чтобы загрузить в нашей системе нового пользователя и новый хост. Этот метод привносит много преимуществ помимо single sign-on, так как отпадает нужда в сборе, передаче и контроле файлов authorized_keys, хоть и требует больше подготовительной работы по сравнению с настройкой типичной пары открытого/секретного SSH ключей.

Как не следует пользоваться SSH


Еще в далеком 2004 году кто-то научил меня копипастить открытый ключ в файл authorized_keys. С тех пор я продолжал невинно копировать один и тот же старый публичный ключ на каждый сервер, с которым мне приходилось работать, и у меня постоянно не получалось сделать это с первого раза, потому что я забывал корректно настраивать chmod.

Лишь однажды, когда в 2015 году OpenSSH объявил мой тип ключа устаревшим, я с неохотой заменил свой ключ. Теперь, за давностью лет, остается только гадать, на каких серверах мой открытый ключ все еще лежит. Может, у старых стартапов, с которыми я когда-то работал? У клиентов с фриланса? На криптоферме моей племянницы?

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

Большинство организаций обычно создают сценарий (playbook) для автоматизации управления файлами authorized_keys, однако их сбор, выгрузка и обслуживание остаются месивом вне зависимости от продуманности исполнения.

Single Sign-On с OpenID Connect и SSH сертификатами


Вместо использования файлов authorized_keys мы настроим SSH Certificate Authority и осуществим доступ по SSH через краткосрочные сертификаты, а для поддержки single sign-on мы добавим OpenID Connect (OICD). Как только у нас все получится, результат будет отменный, поэтому прошу вашего терпения, так как нам понадобится чуть больше подготовительных настроек, чем при типичной SSH-конфигурации «из коробки».

Что такое SSH сертификат? SSH сертификат — это альтернатива, которая превосходит пару открытого/секретного SSH ключей. Пользователь и хост обмениваются сертификатами в ходе SSH-соединения (handshake), своего рода урезанной версии сертификата TLX X.509, в той же манере что и пара SSH ключей. Для более глубоко анализа рекомендуем ознакомиться со следующей статьей.

Ниже можно увидеть расшифрованный SSH сертификат:

-:
        Type: ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate
        Public key: ECDSA-CERT SHA256:N7ErGTPjhmruRS/4OiwyRi6Iyr59z0Ur1ifkHIHu4V8
        Signing CA: ECDSA SHA256:E0GH/kZ/CGUIe8mMzzpujIiEYGC2IHDHafYBnye1WSU
        Key ID: "carl@smallstep.com"
        Serial: 16253962425132258867
        Valid: from 2020-03-23T16:01:39 to 2020-03-24T08:01:39
        Principals:
                carl
                carl@smallstep.com
        Critical Options: (none)
        Extensions:
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

Пользовательские сертификаты, как на примере выше, позволяют хостам опознавать пользователей, а сертификаты хостов помогают пользователям опознавать хосты. Ключевым различием является поле Principals.

По умолчанию, в ходе SSH соединения SSHD позволит войти в хост под именем пользователя из поля
Principals пользовательского сертификата. Аналогично, SSH ожидает увидеть искомое имя хоста в поле Principals сертификата хоста.

Кроме того, у сертификатов могут быть расширения, которые допускают привелегированные SSH функции (например, agent forwarding и port forwarding) или форсируют директивы конфигураций.


Чтобы у нас все заработало, мы настроим SSH Certificate Authority (CA), а именно — step-ca сервер от Smallstep. При наличии у них соответствующих полномочий, пользователи и хосты буду получать SSH сертификаты от нашего CA.

Ниже представлена схема того, как Алиса получает свой пользовательский сертификат и заходит в хост:



Мы проведем настройку CA через работающий совместно с нашим инструментом командной строки step блоком конфигурации OpenSSH.

Преимущества


  • Больше никакого управления открытыми ключами. У вас больше не будет ситуации, когда по вашей инфраструктуре раскидано бессчетное (на самом деле равное users * hosts) количество файлов authorized_keys. Пользователям на ваших хостах вообще больше не потребуется раздел .ssh.
  • Легкие предоставление и отзыв доступа на всех хостах. Стандартные пары SSH ключей никогда не устаревают, в то время как SSH сертификаты позволяют нам проводить пассивную ревокацию, так как доступ по SSH истекает в тот же день, когда пользователь удаляется из раздела OAuth.
  • Используйте собственные политики безопасности. Выдача SSH сертификатов потоком OAuth OICD будет вестись с применением ваших политик безопасности Google (включая 2FA и ключи безопасности). Вы сможете самостоятельно настраивать сроки истечения сертификатов.
  • Сертификаты подтвержденных хостов. Мы воспользуемся EC2 Instance Identity Documents (IIDs), благодаря чему сертификаты будут выдаваться только хостам на вашем AWS аккаунте.
  • Пользовательские сертификаты хранятся в памяти. Пары ключей зачастую хранятся на диске — и никогда не истекают.
  • Больше никакого Trust On First Use (TOFU). Пользуясь сертификатами хостов, вы больше не увидите это сообщение:

    The authenticity of host 'ec2-3-15-28-130.us-east-2.compute.amazonaws.com (3.15.28.130)' can`t be established.
    
    ECDSA key fingerprint is SHA256:HYDAjwFL/qEmTuKm903tIk0fbPNk1CSRqH/usavToLw.
    Are you sure you want to continue connecting (yes/no/[fingerprint])?
    	

Чего в этой статье нет


  • Более тесной интеграции с поставщиками идентификации (например, синхронизации с директориями SCIM или LDAP).
  • Добавления поддержки использования сертификатов для sudo.
  • Расширенных списков управления доступом (access control lists, ACLs) для определения доступа между пользователями и группами хостов.
  • Резервного копирования базы данных CA.
  • Немедленного отзыва пользовательского сертификата, еще до его истечения.

Обязательные условия перед началом


  • Ваши хосты находятся на EC2.
  • Ваши пользователи находятся на одном домене GSuite.
  • У вас есть локально установленный инструментарий step
    • Для macOS вы можете запустить brew install step.
    • Для Linux вы можете воспользоваться пакетами Debian.

Но я не хочу пользоваться Certificate Authority!


Возможно, вы думаете, что это сложно и страшно. Такую репутацию Certificate Authorities заработали из-за загадочных подробностей сертификатов TLS X.509, одного только числа акронимов в мире ИОК (инфраструктуры открытых ключей, PKI), и сложности таких инструментов, как openssl.

Кроме того, у больших CA, например Let's Encrypt, есть огромное число ответственностей по обеспечению безопасности интернета.

Мы не будем пользоваться Let’s Encrypt.

SSH сертификаты проще, чем TLS сертификаты. SSH CA попросту позволяет нам делегировать часть ответственностей в области аутентификации и авторизации множества хостов одному централизованному сервису.

В этом проекте мы настроим CA с тремя поставщиками — тремя методами выдачи сертификатов:

  • Для пользовательских сертификатов мы воспользуемся поставщиком OAuth OIDC, соответствующим нашему Google OAuth приложению. Мы доверяем Google в надежном доступе людей и выдаче только корректных, подписанных Google токенов идентификации OAuth аутентифицированным пользователям. CA проверит токен открытым ключом Google.
  • Для новых EC2 хостов нам потребуется поставщик AWS, соответствующий нашему AWS аккаунту. Новые хосты будут запрашивать SSH сертификаты хостов через этого поставщика. Мы доверяем AWS в предоставлении подписанных Amazon IIDs, и CA проверит их открытым ключом Amazon.
  • И наконец, для еженедельного обновления сертификатов хостов мы воспользуемся поставщиком SSHPOP.

Приступим?

1. Создайте учетные данные Google OAuth


В этом проекте вам потребуются учетные данные Google 2.0 OAuth, их создание займет пару минут.

  • Если у вас его еще нет, создайте Google Cloud Console Project

    • Создайте его в том GSuite Organization, в котором вы будете пользоваться single sign-on.
  • Настройте OAuth 2.0 consent screen под Внутренний (Internal) проект
  • Создайте учетные данные OAuth 2.0
    • При выборе вида приложения (Application Type) выберите Прочее (Other)

Запишите Client ID и Client Secret, они понадобятся в следующем шаге!
Заметка: Ваш CA будет выдавать пользовательские сертификаты только тем пользователям, которые авторизованы в GSuite Organization, соответствующем вашему аккаунту Google Cloud project.

2. Запустите ваш Certificate Authority


Мы установим step-ca на Ubuntu 18.04 LTS в инстансе AWS. Нам должно хватить бесплатного уровня инстанса AWS (t2.micro/t3.micro).

Возьмите этот скрипт запуска CA и вставьте сверху требуемые значения:

  • ID OICD клиента
  • OICD client secret
  • Доменное имя вашего GSuite
  • Имя вашего CA
  • Пароль корневого ключа
  • Вашу почту

Загрузите его в виде EC2 User Data скрипта, чтобы затем использовать на шаге 3 (настройка инстансов), когда вы запустите ваш EC2 инстанс.

Для взаимосвязанности вашему VPC потребуется прикрепленный интернет шлюз, и ваш инстанс должен быть в группе безопасности, доступной всем вашим хостам и пользователям на портах 22 (SSH) и 443 (HTTPS).

Полезно отметить, что
step-ca принимает HTTPS соединения только через mTLS — так он лучше защищен от атак по сравнению с типичным web-сервером.

Воспользуйтесь своим PEM ключом, чтобы подключиться к вашему CA инстансу.

Результат User Data скрипта находится в /var/log/cloud-init-output.log. Проверьте его и убедитесь, что все инициализировано корректно и step-ca работает.

CA должен создать следующие ключи и сертификаты:

  • /etc/step-ca/certs/root_ca.crt — корневой TLS сертификат вашего CA (самоподписаный).
  • /etc/step-ca/certs/ssh_host_ca_key.pub — CA SSH ключ хоста дает пользователям верифицировать сертификаты хостов.
  • /etc/step-ca/certs/ssh_user_ca_key.pub — CA SSH ключ пользователя дает хостам верифицировать сертификаты пользователей.
  • У вас также будут секретные ключи подписи CA (в /etc/step-ca/secrets) для указанных выше сертификатов и ключей. Для дешифровки этих ключей CA при загрузке прочитывает их пароли из файла /etc/step-ca/password.txt.

Под рутом уберите User Data скрипт с вашим root паролем CA:

# rm /var/lib/cloud/instances/i-**/user-data.txt**

От вашего CA вам потребуется немного информации:

  • Публичное имя хоста, чтобы мы могли его снова найти.
  • Отпечаток корневого сертификата — для установки общего TLS соединения с этим хостом.

Запустите под рутом следующее:

# step certificate fingerprint $(step path)/certs/root_ca.crt
5bc2b4779ad1562f6ed0809857fbed7925d2432eb25083f41a468532495ca658

Не забудьте записать это. Ваш CA заработал!

Загрузите новый хост


Давайте загрузим инстанс Ubuntu, который станет нашим первым ssh target хостом.

Заметка: Ваш CA будет выдавать сертификаты хоста только инстансам на его аккаунте AWS.

В этот раз для запуска нового инстанса воспользуйтесь User Data скриптом хоста и заполните следующие значения:

  • Адрес вашего CA (https://[CA hostname]).
  • Отпечаток корневого сертификата вашего CA.

Ниже можно видеть, что должен сделать User Data скрипт:



Таким образом, мы получаем сертификат хоста в обмен на Instance Identity Document (IID) и его подпись.

Кстати об IID… В случае если вы раньше никогда с ними не работали, вот так выглядит один из них:

$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"` && curl -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/dynamic/instance-identity/document
{
  "accountId" : "8072125551212",
  "architecture" : "x86_64",
  "availabilityZone" : "us-east-2c",
  "billingProducts" : null,
  "devpayProductCodes" : null,
  "marketplaceProductCodes" : null,
  "imageId" : "ami-0fc20dd1da406780b",
  "instanceId" : "i-01bd292377d6d8fec",
  "instanceType" : "t2.micro",
  "kernelId" : null,
  "pendingTime" : "2020-03-11T23:18:12Z",
  "privateIp" : "172.31.46.150",
  "ramdiskId" : null,
  "region" : "us-east-2",
  "version" : "2017-09-30"
}

Этот сегмент JSON подписан Amazon, так выглядит подпись:

$ TOKEN=`curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`     && curl -H "X-aws-ec2-metadata-token: $TOKEN" –v http://169.254.169.254/latest/dynamic/instance-identity/signature
c0p6ygyFNFxyjs/73QGCQN+7khkZBr6H5cP/gefBgAwe80GmSTNlQy68LBSQQYrQczv2aHTXj3xa
CFkaGE4GPYiAogCkywcnt5VAp3t176GQwVxqfmawTliPMs31dY7ZeZvixN/1uoe8x1pt0EXAMPLE

Авторизируйтесь с вашим PEM ключом и проверьте, что все запустилось корректно. Результат вашего User Data скрипта должен быть в /var/log/cloud-init-output.log.

Создайте себе на хосте пользователя


Логин нового пользователя, которого вы создадите, обязательно должен совпадать с именем почты, через которую вы авторизовались в Google, например:

$ sudo adduser --quiet --disabled-password --gecos '' carl

Вот мы и закончили настройку со стороны хоста!

4. На борту нового аккаунта


Давайте настроим ваш первый пользовательский аккаунт. Запустите на вашем локальном устройстве следующее:

$ CA_URL=https://[YOUR CA].compute.amazonaws.com
$ CA_FINGERPRINT=[CA FINGERPRINT]
$ step ca bootstrap        --ca-url $CA_URL        --fingerprint $CA_FINGERPRINT

Эта команда установит и настроит на вашем устройстве корневой сертификат CA. У вас появятся два новых файла: ~/.step/config/defaults.json (файл конфигурации step) и ~/.step/certs/root_ca.crt (TSL сертификат вашей корневой CA).

После этого мы можем выдать себе пользовательский сертификат:

$ step ssh login [your email address] --provisioner "Google"

Что делает эта команда?

  1. Запускает ваш системный браузер и запускает процесс авторизации Google OICD.
  2. После авторизации полученный от Google токен ID отправляется вашему CA.
  3. Ваш CA подтверждает токен и выдает соответствующий вашей почте SSH сертификат.
  4. Сертификат добавляется к вашему SSH агенту. Чтобы взглянуть на него, воспользуйтесь step ssh list, а чтобы разобрать и изучить — step ssh list --raw | step ssh inspect.

Наконец, давайте настроим SSH пользоваться нашим CA:

$ step ssh config

Эта команда делает следующее:

  1. Сначала она достает открытый ключ хоста CA — он используется для верификации сертификатов хоста — и устанавливает этот ключ в вашу конфигурацию SSH со следующим результатом (хранящимся в ~/.step/known_hosts):

    @cert-authority * ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHyWTo9TLDwhyLlHq2ANkjtSGLyJ3xPtfL+7faiV+YA0k4kLUc8cJ5rWFHdUShbwtkOsLhkqeDDXoFnH/C5BG+4=
  2. Затем она импортирует в вашу SSH конфигурацию (в .step/ssh/config) вот такой ненавязчивый блок:

    Match exec "step ssh check-host %h"
    		ForwardAgent yes
    		User carl
    		UserKnownHostsFile "/Users/carl/.step/ssh/known_hosts"
    		ProxyCommand step ssh proxycommand %r %h %p --provisioner "Google"

Блок Match exec рассматривается, только когда команда выше вернет true.

Команда обращается к вашему CA и спрашивает, есть ли у имени хоста, к которому вы пытаетесь соединиться через SSH, соответствующий сертификат. Если он есть, команда возвращает true. Мы не хотим, чтобы управляемые CA хосты вмешивались в ваш sconfig каких-либо других хостов.

Директива ProxyCommand осуществляет всю магию процесса Single Sign-On. Прежде чем инициировать подключение, step ssh proxycommand проверит ваш SSH сертификат, и если он отсутствует или истек, она проведет вас через процесс OAuth OIDC и запросит новый сертификат от вашего CA.

Заметка: Блок конфигурации вашего CA определяется шаблоном, который хранится в <code>/etc/step-ca/templates/ssh, и при желании что-либо поменять, например, убрать директиву ForwardAgent, достаточно обратиться к этому шаблону.

Время попробовать!


Мы готовы соединиться по SSH с настроенным вами хостом. Вы можете запустить SSH командой -v чтобы пронаблюдать handshake. В частности, вы должны увидеть что-то такое:

debug1: Server host certificate: ecdsa-sha2-nistp256-cert-v01@openssh.com SHA256:KUwZbRewusotBbO4Wbrj1EpPexMqKEj0ZUr1Fvf41+g, serial 782
1790606781444805 ID "i-0fa7218db55ac0536" CA ecdsa-sha2-nistp256 SHA256:VIwnVtTJJwdUsjGaPyOS5yT1O/uxyxj0CQJd+Ce/w0M valid from 2020-03-2
3T16:23:32 to 2020-04-22T16:24:32
debug1: Host 'ec2-3-135-235-172.us-east-2.compute.amazonaws.com' is known and matches the ECDSA-CERT host certificate.
debug1: Found CA key in /Users/carl/.step/ssh/known_hosts:1
...
debug1: Offering public key: carl@smallstep.com ECDSA-CERT SHA256:mBQXA0znZvd+21hhvViUVEybzrO4x190xZftFXAYCFY agent
debug1: Server accepts key: carl@smallstep.com ECDSA-CERT SHA256:mBQXA0znZvd+21hhvViUVEybzrO4x190xZftFXAYCFY agent

Вуаля! У вас получилось.

Совет: Вы можете запросить у CA список всех хостов, которым были выданы сертификаты, через команду step ssh hosts.

Q&A


Как мне зарегистрировать в CA уже существующий хост?


Для хостов Ubuntu 18.04 LTS этот процесс аналогичен загрузке нового хоста, достаточно запустить скрипт запуска хоста под рутом. Для других платформ вам потребуется портировать скрипт под ваши нужды.

После того как вы запустите и настроите все ваши хосты, у вас может возникнуть желание подправить настройки instanceAge вашего поставщика AWS для CA. Эти настройки хранятся в /etc/step-ca/config/ca.json. Инстанс любого возраста может запустить сам себя по умолчанию. Установка настроек, например, в 5m, создаст дополнительную меру предосторожности, эффективно заставив CA принимать IID токены только от инстансов моложе пяти минут.

Заметка: Созданный скриптом Instance Identity токен — это одноразовый токен. Вы не можете перерегистрировать хост, вы можете лишь обновить его сертификат. Почему? Потому что любой пользователь на хосте может в любой момент получить доступ к IID, и мы не хотим, чтобы пользователи могли получить сертификат хоста от CA.

Могу я пользоваться другим поставщиком OAuth OIDC?


Конечно! Для этого достаточно поменять сетевой адрес сервера конфигурации OAuth и поменять имя поставщика OIDC в User Data скрипте для CA.

Могу я пользоваться GCP или Azure вместо AWS?


Да! У step-ca есть поставщики для всех трех, вам только нужно будет внести правки в конфигурацию CA и скрипт загрузки хоста. Более подробно об этом можно почитать в документации поставщиков step-ca.

Могу я использовать хост-бастион (инсталляционный сервер)?


Можете. Сначала выдайте всем своим хостам сертификаты, а затем добавьте в known_hosts на вашем бастионе CA ключ хоста:

$ CA_URL=https://[YOUR CA].compute.amazonaws.com
$ CA_FINGERPRINT=[CA FINGERPRINT]
$ step ca bootstrap       --ca-url $CA_URL       --fingerprint $CA_FINGERPRINT
$ mkdir -p ~/.ssh && echo "@cert-authority * $(step ssh config --host --roots)" > ~/.ssh/known_hosts

После этого достаточно будет ssh к бастиону, и затем ssh к внутреннему хосту.

Могу я изменить срок действия SSH сертификата?


Да. По умолчанию они действительны 16 часов, и в файле конфигурации CA (ca.json) под объектом claims, у вашего поставщика OIDC, вы можете внести изменения в соответствующих строчках, например:

"defaultUserSSHCertDuration": "720h",
"maxUserSSHCertDuration": "720h"

Буду ли я отрезан от всех своих хостов при отключении моей CA?


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

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

Могу я использовать хосты на нескольких AWS аккаунтах?


Конечно. Для этого достаточно добавить ID аккаунта в файл конфигурации CA (/etc/step-ca/config/ca.json) и перезапустить сервер CA.

Как мне добавить поддержку sudo?


Воспользуйтесь agent forwarding и подключаемым модулем аутентификации pam_ussh.

Что еще я могу сделать со своей CA?


Многое! Теперь, когда у вас есть свой личный CA, вы можете настроить TSL сертификаты для шифрования всего своего внутреннего трафика через общие TLS. Если вы хотите узнать побольше о CA, поставщиках, вариантах конфигурации и прочем, прочтите Step Certificates Documentation.

Подведение итогов


С нашим базовым сетапом любой пользователь вашей Google-организации сможет получить сертификат. Также он получит доступ только к тем хостам, на которых у него есть аккаунты.