Под моим надзором примерно 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)


  1. Hile
    19.03.2018 12:20
    +1

    github.com/itsumma/isolate

    p.s. скоро выкачу новый ssh.py как только у себя протестирую все
    p.s.s. сплю хорошо


    1. artemirk Автор
      19.03.2018 13:17

      Хороший инструмент. Исторически мы свои примерно в одно время с вами сделали. Пока работает и решает задачи, сам понимаешь не трогаем :)


      1. Hile
        19.03.2018 14:20

        У нас давно было, просто в какой то вид оформлено и выложено ток недавно. Основная ветка живет внутри. Баш не страшно юзать в таких местах? шеллшок послужил как раз поводом для написания своего велосипеда )


  1. citius
    19.03.2018 13:29

    Почему не FreeIPA?


    1. Hile
      19.03.2018 14:23

      вся суть подобных решений, в том, что не надо настраивать конечные хосты (вообще никак). А freeipa требует подготовки хоста ( а если там железка не поддерживает то идея вовсе отпадает ).

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


      1. kvaps
        19.03.2018 15:16

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


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


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


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


        1. artemirk Автор
          19.03.2018 15:36

          Я думаю ваш вариант тоже хорошее решение. Мы условно еще привязаны к ISPmanager у него есть возможность «пропихнуть» публичный ключ в лицензию и далее владелец сервера одной кнопкой в панели «пускает» саппорт.
          Этот вариант уже был и он работал. Далее наша действительность развивалась от него.
          Это мои сладкие сны когда у меня будет проект без legacy и я смогу выбрать все технологии и даже ОС на сервере :)


  1. Tatikoma
    19.03.2018 13:42

    ssh hostname "bash --noprofile --norc"
    От этого не забыли закрыть? — В статье не вижу.


    1. artemirk Автор
      19.03.2018 15:32

      В этом варианте все отрабатывает как надо:

      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. myz0ne
      20.03.2018 04:34

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


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


      1. artemirk Автор
        20.03.2018 04:37

        Мне не удалось проникнуть на сервер с .bashrc, возможно мой эксперимент не достаточно чистый.
        Сделал лабораторную VDS. Предлагаю попробовать вместе найти где я не прав. Ключ в конце статьи.


    1. artemirk Автор
      20.03.2018 04:38

      Сделал лабораторную VDS. Вы можете сами попробовать.


  1. MMik
    19.03.2018 14:15

    как защититься от возможности потери ключа пользователем
    Использовать сертификаты и отзывать сертификаты при подозрении на потерю сертификата или при увольнении сотрудника.
    FreeIPA ещё выше предлагают.


    1. artemirk Автор
      19.03.2018 15:24

      Проблема что не все оборудование бывает «мое». Объяснить клиенту что ему сейчас надо настроить свой ssh сервер, сложнее чем дать ему команду cat >authorized_keys. После чего саппорт может помочь клиенту и вырезать ключ или договориться что ключ останется для будущих обращений.

      Подход сертификатов прекрасен если все сервера в личном ведении и ты их сам раскатываешь ансибло-чефом.


  1. vaniacer
    19.03.2018 15:02

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

    И вот такую github.com/vaniacer/sshto создает меню на основе файла ~/.ssh/config


    1. MMik
      19.03.2018 15:20

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

      Опция UserKnownHostsFile=/dev/null — на ваш вкус.


      1. vaniacer
        19.03.2018 15:34

        Слишком радикально на мой вкус)


      1. ValdikSS
        19.03.2018 16:51

        У openssh есть конфигурационный файл ~/.ssh/config, в который и нужно добавлять опции, а не делать алиасы.


        1. MMik
          19.03.2018 21:53

          Алиас многим привычнее.


          1. Crystal_HMR
            20.03.2018 12:40

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


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

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


  1. vaniacer
    19.03.2018 15:10

    А тут вообще через web позволяет фигачить баш скрипты в ssh github.com/vaniacer/up
    И крону можно задачи назначать.


  1. hishnik
    19.03.2018 16:04

    А не проще было поставить какой нибудь УЦ [PKI-CA] (типа xca даже) на изолированной машине и как все нормальные люди настроить доступ к ssh по сертификатам, разместив ключи на «железных» токенах? Надо — отозвал, надо — выписал новый. Я уж молчу о технологии PMI — это круто конечно, но может оказаться слишком громоздким для вас.


    1. artemirk Автор
      19.03.2018 16:08

      Как я уже писал выше не на всех «машинах» куда я хожу я полноправный владелец. Добавить строку authorized_keys меньшее зло для владельца сервера. Наши клиенты не обрадуются если я буду менять им настройки openssh которые они с заботой сделали.

      Все подходы которые решают задачу возможны.


      1. YourChief
        20.03.2018 01:36

        Доверие к CA можно указать через authorized_keys в том числе, разница только в одном ключевом слове вначале строки.

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


  1. ctacka
    19.03.2018 16:35

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


  1. osipov_dv
    19.03.2018 17:26

    а смысл от .bashrc, если можно по scp его поменять?
    Или я что-то не понял?


    1. artemirk Автор
      20.03.2018 04:44

      Попробуйте. Лабораторная VDS предоставлена в конце статьи. У меня не получается.


  1. linjan
    19.03.2018 18:35

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


    Подскажите, чем вы это делаете?


    1. artemirk Автор
      20.03.2018 04:47

      ssh сессия запускается с |tee -a и далее собирается все для дальнейшего поиска.


      1. diver666
        21.03.2018 04:03

        Не могли бы вы более подробно? или пример привести?


        1. artemirk Автор
          21.03.2018 04:07

          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 программа, в файле будут все перерисовки экрана. Дальше или забираем файл или вместо файла сразу пишем в сокет, все на ваше усмотрение.


          1. kt97679
            21.03.2018 06:16

            Как вы защищаетесь от ситуации, когда юзер делает cat /dev/random и переполняет диск?


            1. artemirk Автор
              21.03.2018 11:00

              Ограничением сетевых интерфейсов для начала. Этот дев рандом надо будет по ssh человеку еще вытянуть.

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

              За последний год лог сессий всех сотрудников занимает около 65 гб


          1. diver666
            21.03.2018 10:42

            Хм, я наверно не корректно спросил, вы сами подставляете |tee -a session_log, я почему-то решил что вы логируете сторонних пользователей которые заходят на сервер, те если кто-то войдет ssh -i everebody user@149.154.64.101, лог сессии у вас не сохранится?


            1. artemirk Автор
              21.03.2018 10:58

              На боевые серверы «рядовые» пользователи могут попасть только через сервер авторизации. А на нем ssh подменен на ssh |tee

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


  1. acmnu
    19.03.2018 19:01

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


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


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


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


  1. YourChief
    20.03.2018 01:57

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

    Этот мусор можно сразу убрать. Чтобы обойти эту «защиту» достаточно передать команду по ssh в неинтерактивном сеансе.


    1. artemirk Автор
      20.03.2018 04:48

      Предлагаю попробовать. Я в конце статьи дал ключ от лабораторной VDS. Но во мне так же есть зерно сомнения, но как это сделать я так и не придумал.


  1. saboteur_kiev
    20.03.2018 02:37

    Светить айпишники не боитесь? ботнеты, ddos?

    А вдруг обнаружится уязвимость в ssh, а тут как раз и логины есть и айпишники есть и даже адрес главного сервера с главным ключом в публичном интернете?


    1. artemirk Автор
      20.03.2018 04:50

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


  1. wild_one
    20.03.2018 04:50

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


    1. artemirk Автор
      20.03.2018 05:15

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


    1. Chupaka
      21.03.2018 07:20

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



  1. roswell
    20.03.2018 04:51

    1. Hile
      21.03.2018 16:09

      на сколько я понимаю, эта либа через гугл работает или я ошибаюсь?


      1. roswell
        21.03.2018 20:54

        Нет, ей сервисы Гугла для работы не нужны.


        1. Hile
          22.03.2018 14:28

          я там пониже другой тулкит еще постил, а так хорошо да, а то встречал аутентификатор который через гугл вворачивался (странная поделка )


  1. datacompboy
    20.03.2018 10:38

    Лабу, похоже, раздраконили уже, всё?


  1. bfuvx
    20.03.2018 10:46

    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 клиента. Вручную тоже очень быстро ловится нужный момент.


    1. lexore
      20.03.2018 11:28

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


      1. artemirk Автор
        20.03.2018 11:42

        Отрабатывает как положено и не пускает.


      1. bfuvx
        20.03.2018 11:51

        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.


        1. datacompboy
          20.03.2018 11:53

          На всех, это четко описано в его мане.


    1. datacompboy
      20.03.2018 11:53

      Интересно. А ~/.ssh/rc так обойти можно?


      1. bfuvx
        20.03.2018 12:11

        Да, такой же принцип:

        execve("/bin/sh", ["sh", "-c", "/bin/bash -c '/bin/sh .ssh/rc'"]...

        Никто не мешает послать sigint в нужный момент. Легко проверить на чем-нибудь типа «sleep 10;echo hello».


    1. artemirk Автор
      21.03.2018 04:01

      Первым решение было просто написать срипт/программу который или пускает bash или выходит. /bin/maybelogin, но потом попробовал bashrc остановились на нем как на более простом. Если у пользователя в passwd прописан /bin/maybelogin и кинуть sigint что будет запуcкать ssh?


      1. bfuvx
        21.03.2018 13:01

        что будет запуcкать ssh?

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


  1. lexore
    20.03.2018 11:36
    +1

    SSH у людей не достаточно безопасен.

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


  1. Hile
    20.03.2018 11:45

    www.nongnu.org/oath-toolkit

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

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


    1. Hile
      20.03.2018 11:52

      ну и вот удобняшка (консольный генератор QR кодов и secret )

      github.com/mcepl/gen-oath-safe


  1. datacompboy
    20.03.2018 21:16

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


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


    1. kt97679
      21.03.2018 01:29

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