SSH у людей не достаточно безопасен. Как я борюсь с паранойей

    Под моим надзором примерно 1000 железных серверов, VPS даже не начинаю считать. Пару десятков из них обладают весьма критичными данными. И банальный ssh с ключами в стандартной ситуации не достаточно безопасен. Не все «кожаные люди» берегут ключи, поговорим как защититься от возможности потери ключа пользователем.

    Кого защищаем


    «Стандартная» хостинг компания. Наибольшее количество персонала в службе заботы клиентов и поддержке. Честный SSH доступ к серверам есть только у поддержки 3 линии, порядка 12 человек. Завершает набор технический авангард компании — «отдел обслуживания» человек на 8.

    Массовый пользователь


    Для отдела поддержки и частично отдела обслуживания настроен сервер авторизации SSH. Это сервер который имеет ключ для авторизации почти куда угодно. Всемогущий ключ одна из самых ценных информаций, которую нельзя упустить. Напрямую читать его могут 4 человека в конторе. Резервная копия на бумаге лежит в сейфе. Так же на этот сервер получают временный доступ разработчики которым надо воочию увидеть где и как сломалось.

    Сотрудник может через сервер авторизации получить ssh доступ с использованием всемогущего ключа. Технически эти сотрудники могут позвать только одну команду — ssh, ssh в свою очередь использует приватный ключ для подключения к удаленному серверу. Как правило сотрудники используют локальный скрипт для быстрого использования сервера авторизации. Исторически сложилось что он называется go. Вот его содержимое:

    image

    Еще один плюс общего сервера авторизации это возможность логировать и считать статистику для всех сотрудников. Мы знаем какой сотрудник сколько времени провел на каком сервере. На случае внештатных ситуаций знаем что сотрудник там вводил и что ему отвечало, так как копируется весь ввод и вывод ssh-сессии.

    Полубоги


    Второй серьезной уязвимостью являются всемогущие ключи нескольких сотрудников. Такие ключи разрешается прописывать на сервера только с параметром from=””. В authorized_keys это выглядит вот так:

    image

    Указанные всемогущие 4 человека осознают свою значимость и шифруют диск ноутбука не забывая о пароле на приватную часть ключа.
    Работа вне офиса возможна только с использованием VPN до офиса. Если в офисе нет электричества у нас есть резервный VPN сервер который так же умеет анонсировать нашу офисную сеть.

    Всемогущий сервер


    Последним серьезным пунктом является большой служебный сервер. Сервер осуществляет мониторинг почти всего и знает обо всех железяках и зачем они нужны, кроме этого на нем запускаются все ansible задачи. На сервере лежит свой приватный ключ под паролем. После входа на сервер магия с ssh-agent в bashrc предлагает ввести пароль от ключа. Дальше можно работать в полную силу. Прямого ssh на этот сервер нет, «два притопа, три прихлопа» и ты на сервере.

    Эти правила не отменяют нормальную настройку файрвола на серверах. Но файрвол как правило настраивается чуть шире и пускает ssh из офисной сети, далее через sshd_config прижимаем список ip которые могут стать root:

    image

    А если все это не сработает


    Последним бастионом проверки на каждом сервере выступает .bashrc файл, при инициализации shell по ssh стартует bash, и он проверяет источник подключения:

    image

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

    Планы на доделку


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

    P.s: Сообщение от bfuvx как обойти bashrc
    ssh -vvv -i everebody root@149.154.64.101

    Ловим что-нибудь типа «debug2: shell request accepted on channel 0» и посылаем в этот момент «Ctrl+c»:

    Last failed login: Tue Mar 20 02:41:12 EDT 2018 from 58.242.83.24 on ssh:notty
    There were 23 failed login attempts since the last successful login.
    Last login: Tue Mar 20 02:40:14 2018 from 95.154.75.23
    ^C-bash-4.2#
    Поделиться публикацией
    Ой, у вас баннер убежал!

    Ну. И что?
    Реклама
    Комментарии 63
    • +3
      github.com/itsumma/isolate

      p.s. скоро выкачу новый ssh.py как только у себя протестирую все
      p.s.s. сплю хорошо
      • +1
        Хороший инструмент. Исторически мы свои примерно в одно время с вами сделали. Пока работает и решает задачи, сам понимаешь не трогаем :)
        • +1
          У нас давно было, просто в какой то вид оформлено и выложено ток недавно. Основная ветка живет внутри. Баш не страшно юзать в таких местах? шеллшок послужил как раз поводом для написания своего велосипеда )
      • +2
        Почему не FreeIPA?
        • +1
          вся суть подобных решений, в том, что не надо настраивать конечные хосты (вообще никак). А freeipa требует подготовки хоста ( а если там железка не поддерживает то идея вовсе отпадает ).

          Если много разного приходится админить, то только такие велосипеды и спасают.
          • +1

            Поддерживаю, FreeIPA + Linux-виртуалка с одим мастер-ключем ко всему.
            Через правила sudo можно разрешить запуск определенных команд и только с конкретными аргументами, если есть такая необходимость.


            Например: пользователь vasya может запускать sudo ssh только с аргументом server1, server2 и switchB


            Так же настроить sudoreplay для логирования, после чего каждая ssh сессия будет сохранена и сможет быть проиграна в интерактивном режиме.


            Как бонус отсутствие необходимости устанавливать ipa-client на каждом сервере и общий сервер аутентификации с LDAP и удобной web-мордой — что тоже безусловно большой плюс.

            • +2
              Я думаю ваш вариант тоже хорошее решение. Мы условно еще привязаны к ISPmanager у него есть возможность «пропихнуть» публичный ключ в лицензию и далее владелец сервера одной кнопкой в панели «пускает» саппорт.
              Этот вариант уже был и он работал. Далее наша действительность развивалась от него.
              Это мои сладкие сны когда у меня будет проект без legacy и я смогу выбрать все технологии и даже ОС на сервере :)
        • +3
          ssh hostname "bash --noprofile --norc"
          От этого не забыли закрыть? — В статье не вижу.
          • 0
            В этом варианте все отрабатывает как надо:

            artem:~ artem$ssh root@149.154.64.101
            Last failed login: Mon Mar 19 08:31:53 EDT 2018 from 58.242.83.24 on ssh:notty
            There were 23 failed login attempts since the last successful login.
            Last login: Mon Mar 19 08:31:04 2018 from 188.120.252.193
            bashrc Connection DENY
            Connection to 149.154.64.101 closed.
            artem:~ artem$ssh root@149.154.64.101 «bash --noprofile --norc»
            bashrc Connection DENY
            • +1

              А так? ssh hostname -T /bin/sh
              Почему bashrc? Такие вещи лучше делать через pam
              Я делал примерно так
              https://github.com/dmitriy-myz/pam_alerter


              В идеале, ключ вообще не должен храниться на сервере, куда пускают сотрудников.
              Можно попробовать использовать ssh-agent на отдельном сервере, который логинится на гейт с пробросом агента. Пользователям задавать переменную SSH_AUTH_SOCK.

              • 0
                Мне не удалось проникнуть на сервер с .bashrc, возможно мой эксперимент не достаточно чистый.
                Сделал лабораторную VDS. Предлагаю попробовать вместе найти где я не прав. Ключ в конце статьи.
              • 0
                Сделал лабораторную VDS. Вы можете сами попробовать.
              • +2
                как защититься от возможности потери ключа пользователем
                Использовать сертификаты и отзывать сертификаты при подозрении на потерю сертификата или при увольнении сотрудника.
                FreeIPA ещё выше предлагают.
                • 0
                  Проблема что не все оборудование бывает «мое». Объяснить клиенту что ему сейчас надо настроить свой ssh сервер, сложнее чем дать ему команду cat >authorized_keys. После чего саппорт может помочь клиенту и вырезать ключ или договориться что ключ останется для будущих обращений.

                  Подход сертификатов прекрасен если все сервера в личном ведении и ты их сам раскатываешь ансибло-чефом.
                • 0
                  Вот такую штуку сделал, к безопасности отношения не имеет скорей наоборот) Автоматизирует ответ 'yes' при первом подключении к очередному серверу github.com/vaniacer/ssh_yes

                  И вот такую github.com/vaniacer/sshto создает меню на основе файла ~/.ssh/config
                  • 0
                    Автоматизирует ответ 'yes' при первом подключении к очередному серверу
                    echo "alias ssh='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'" >> ~/.bash_profile; source ~/.bash_profile

                    Опция UserKnownHostsFile=/dev/null — на ваш вкус.
                    • 0
                      Слишком радикально на мой вкус)
                      • +5
                        У openssh есть конфигурационный файл ~/.ssh/config, в который и нужно добавлять опции, а не делать алиасы.
                        • –1
                          Алиас многим привычнее.
                          • 0

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


                            1. если использовать кроме ssh еще инструменты типо sshfs и scp — конфигурация через ~/.ssh/config позволяет использовать host во всех этих командах; а в случае alias'ов нужен алиас на каждую.
                            2. Если нужно добавить/поменять какой-то дефолтный параметр — нужно либо разворачивать alias и делать руками, либо писать команду полностью заново. А ssh_config позволяет использовать всё как и раньше, просто передав необходимый ключ.

                            И многое другое :)

                    • 0
                      А тут вообще через web позволяет фигачить баш скрипты в ssh github.com/vaniacer/up
                      И крону можно задачи назначать.
                      • +3
                        А не проще было поставить какой нибудь УЦ [PKI-CA] (типа xca даже) на изолированной машине и как все нормальные люди настроить доступ к ssh по сертификатам, разместив ключи на «железных» токенах? Надо — отозвал, надо — выписал новый. Я уж молчу о технологии PMI — это круто конечно, но может оказаться слишком громоздким для вас.
                        • 0
                          Как я уже писал выше не на всех «машинах» куда я хожу я полноправный владелец. Добавить строку authorized_keys меньшее зло для владельца сервера. Наши клиенты не обрадуются если я буду менять им настройки openssh которые они с заботой сделали.

                          Все подходы которые решают задачу возможны.
                          • 0
                            Доверие к CA можно указать через authorized_keys в том числе, разница только в одном ключевом слове вначале строки.

                            Соответственно, любой, кто должен получить доступ куда-либо, должен просто-напросто получить временную подпись на свой ключ со стороны ключа CA. Сам ключ CA при этом может располагаться на каком-либо HSM. Согласитесь, это решение гораздо лучше, чем колхоз со «всемогущим ключом» и сервером-прокси для SSH.
                        • +2

                          А может поставит что-то типа vault-а и отказаться от единого всемогущего ключа?

                          • +1
                            а смысл от .bashrc, если можно по scp его поменять?
                            Или я что-то не понял?
                            • 0
                              Попробуйте. Лабораторная VDS предоставлена в конце статьи. У меня не получается.
                            • 0
                              Мы знаем какой сотрудник сколько времени провел на каком сервере. На случае внештатных ситуаций знаем что сотрудник там вводил и что ему отвечало, так как копируется весь ввод и вывод ssh-сессии.


                              Подскажите, чем вы это делаете?
                              • 0
                                ssh сессия запускается с |tee -a и далее собирается все для дальнейшего поиска.
                                • 0
                                  Не могли бы вы более подробно? или пример привести?
                                  • 0
                                    artem:~ artem$ssh -i everebody user@149.154.64.101 |tee -a session_log
                                    Last login: Tue Mar 20 21:01:55 2018 from 188.120.252.193
                                    [user@login ~]$ cat /etc/host
                                    cat: /etc/host: No such file or directory
                                    [user@login ~]$ logout
                                    Connection to 149.154.64.101 closed.

                                    artem:~ artem$cat session_log
                                    Last login: Tue Mar 20 21:01:55 2018 from 188.120.252.193
                                    [user@login ~]$ cat /etc/host
                                    cat: /etc/host: No such file or directory
                                    [user@login ~]$ logout

                                    В файле session_log будут все что происходило по ssh, из минусов это когда mc или другая ncurses программа, в файле будут все перерисовки экрана. Дальше или забираем файл или вместо файла сразу пишем в сокет, все на ваше усмотрение.
                                    • 0
                                      Как вы защищаетесь от ситуации, когда юзер делает cat /dev/random и переполняет диск?
                                      • 0
                                        Ограничением сетевых интерфейсов для начала. Этот дев рандом надо будет по ssh человеку еще вытянуть.

                                        Ну и в целом если мы решили сохранять сессии то согласны потратить на них место на диске. Винты в 8 тб у нас не редкость.

                                        За последний год лог сессий всех сотрудников занимает около 65 гб
                                      • 0
                                        Хм, я наверно не корректно спросил, вы сами подставляете |tee -a session_log, я почему-то решил что вы логируете сторонних пользователей которые заходят на сервер, те если кто-то войдет ssh -i everebody user@149.154.64.101, лог сессии у вас не сохранится?
                                        • 0
                                          На боевые серверы «рядовые» пользователи могут попасть только через сервер авторизации. А на нем ssh подменен на ssh |tee

                                          Обычные ssh сеансы не логируем. Люди которые у нас могут рутом попасть на сервер могут рассказать что делали и они в состояние отключить логирование если им надо :)
                                • 0

                                  Я как-то организовывал доступ к клиентам по ssh для большого количества людей разом. Ситуацию упрощало, что ходить они могли с одного бокса. Т.е. сначал шли на некий ssh_box, а потом оттуда к клиенту.


                                  Идея была в том, чтоб у сотрудника не было возможности прочитать приватный ключ, а значит и законнектится с другого хоста (authorized на целевых хостах строго мониторился). Для этого использовался SshAgent поднятый под левым пользователем (скажем master). Приватные ключи принадлежали этому пользователю, а конечный пользователь, скажем vasya использует socket от ssh agent для коннекта.


                                  Разумеется в такой структуре были разные уровни доступа. Например на root у клиентов могли пойти только три человека (два админа и тех.дир), а на пользователя приложения человек 15. Достигалось это запусков нескольких ssh agent, сокеты, которых был доступны разным unix группам.


                                  Единственное, что для такого варианта пришлось пачить ssh agent. Он по дефолту не позволяет коннектится к себе другому пользователю. Вторая засада была в том, что для того, чтоб явно сказать с каким приватным ключом коннектится к хосту надо сформировать список пар host:public_key и положить его в config. На тот момент это было тайное знание, которое я прояснял у разработчиков.

                                  • 0
                                    Последним бастионом проверки на каждом сервере выступает .bashrc файл, при инициализации shell по ssh стартует bash, и он проверяет источник подключения

                                    Этот мусор можно сразу убрать. Чтобы обойти эту «защиту» достаточно передать команду по ssh в неинтерактивном сеансе.
                                    • 0
                                      Предлагаю попробовать. Я в конце статьи дал ключ от лабораторной VDS. Но во мне так же есть зерно сомнения, но как это сделать я так и не придумал.
                                    • 0
                                      Светить айпишники не боитесь? ботнеты, ddos?

                                      А вдруг обнаружится уязвимость в ssh, а тут как раз и логины есть и айпишники есть и даже адрес главного сервера с главным ключом в публичном интернете?
                                      • 0
                                        Я очень аккуратен в выборе ip которые свечу. Но в целом все наши сети легко можно выяснить по автономной системе, так как мы является «лиром» и все наши ip по честному наши во whois.
                                      • 0

                                        Еще очень советую "ключи на бумаге" хранить с помощью схемы разделения секретов Шамира.

                                        • 0
                                          Я оцениваю возможность взлома сейфа ради ssh ключа как событие с крайне малой вероятностью.
                                          • 0

                                            А практическая её реализация с помощью какого софта возможна?

                                          • 0
                                            на сколько я понимаю, эта либа через гугл работает или я ошибаюсь?
                                            • +1
                                              Нет, ей сервисы Гугла для работы не нужны.
                                              • 0
                                                я там пониже другой тулкит еще постил, а так хорошо да, а то встречал аутентификатор который через гугл вворачивался (странная поделка )
                                          • 0
                                            Лабу, похоже, раздраконили уже, всё?
                                            • +2
                                              ssh -vvv -i everebody root@149.154.64.101

                                              Ловим что-нибудь типа «debug2: shell request accepted on channel 0» и посылаем в этот момент «Ctrl+c»:
                                              
                                              Last failed login: Tue Mar 20 02:41:12 EDT 2018 from 58.242.83.24 on ssh:notty
                                              There were 23 failed login attempts since the last successful login.
                                              Last login: Tue Mar 20 02:40:14 2018 from 95.154.75.23
                                              ^C-bash-4.2# cat /root/README
                                              Привет всемогущий инжинер. Пароль. 
                                              
                                              "Другой жизни не будет"

                                              Можно автоматизировать с помощью expect или правкой ssh клиента. Вручную тоже очень быстро ловится нужный момент.

                                              Пример для expect:
                                              
                                              spawn ssh -vv -i everebody root@149.154.64.101
                                              expect "debug2: shell request accepted on channel 0" { send "\x03" }
                                              interact
                                              
                                              • 0

                                                К чему такие сложности.
                                                ssh root@149.154.64.101 /bin/sh

                                                • 0
                                                  Отрабатывает как положено и не пускает.
                                                  • 0
                                                    ssh root@149.154.64.101 /bin/sh
                                                    выльется в "$SHELL" -c "$command", strace:

                                                    strace -e execve -f -p $server_sshd_pid
                                                    execve("/bin/bash", ["bash", "-c", "/bin/sh"], [/* 8 vars */]) = 0
                                                    

                                                    Возможно не на всех версиях openssh.
                                                    • 0
                                                      На всех, это четко описано в его мане.
                                                  • 0
                                                    Интересно. А ~/.ssh/rc так обойти можно?
                                                    • 0
                                                      Да, такой же принцип:
                                                      execve("/bin/sh", ["sh", "-c", "/bin/bash -c '/bin/sh .ssh/rc'"]...

                                                      Никто не мешает послать sigint в нужный момент. Легко проверить на чем-нибудь типа «sleep 10;echo hello».
                                                    • 0
                                                      Первым решение было просто написать срипт/программу который или пускает bash или выходит. /bin/maybelogin, но потом попробовал bashrc остановились на нем как на более простом. Если у пользователя в passwd прописан /bin/maybelogin и кинуть sigint что будет запуcкать ssh?
                                                      • 0
                                                        что будет запуcкать ssh?

                                                        Ничего, сессия завершится. Но как уже обращали внимание выше, для этого случая есть специально разработанный механизм — pam, его и нужно использовать. Можно как свой модуль написать так и использовать pam_exec для запуска срипта/программы.
                                                    • +1
                                                      SSH у людей не достаточно безопасен.

                                                      Вообще заголовок не раскрыт.
                                                      Как я понял из статьи, все риски сводятся к тому, что кто-то может иметь ключ без пароля и потерять его.

                                                      • 0
                                                        www.nongnu.org/oath-toolkit

                                                        есть в EPEL позволяет юзать Google Authenticator или Yubikey брелки

                                                        настройка вот тут github.com/itsumma/isolate#otp
                                                      • +1

                                                        Чуть не забыл, ещё один момент в защите через башрц:
                                                        ssh -L 2222:22.22.22.22:22 -N root@host &
                                                        ssh localhost -p 2222


                                                        Позволит зайти на удалённый 22.22.22.22 с айпишником "защищённого".
                                                        Так как при -N вообще не запускается шелл.
                                                        То есть важно проброс портов выключать

                                                        • 0
                                                          Я как раз долбился по списку разрешенных адресов когда ссш сервер был погашен. Справедливости ради надо уточнить, что мы не знаем был ли у машины, которую мы ломали, адрес в разрешенном диапазоне, так что эта атака вполне могла не получится. Но замечание совершенно правильное, порт форвардинг надо отключать.

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

                                                        Самое читаемое