Как Ваш компьютер может дать доступ к себе через туннель средствами ssh, autossh, autosshd

Материал из ALT Linux Wiki

Здесь будет подробно рассказано, как дать кому-то доступ на ваш (мобильный) компьютер через туннель.

Туннель нужен, если у вашего компьютера нет постоянного адреса в Интернете. Это будет удобно, если вы ездите с ним и подключаетесь к Интернету по-разному.

(Иногда в подобных ситуациях люди используют проприетарный TeamViewer. Можно обойтись без него и иметь всё под своим контролем.)

Туннель (на самом деле, проброс одного порта) будет создаваться средствами ssh (openssh-client), autossh, autosshd. Это основная задача, описанию решения которой посвящён этот рассказ.

  • кому-то в этом руководстве будет названо я для простоты.
  • ssh в этом рассказе появится ещё и в другой роли: как средство входа для меня на ваш компьютер (с вашей стороны это обеспечивает openssh-server). Но эти две роли независимы друг от друга.
  • Считается, что я имею больше опыта администрирования, поэтому указания для вас подробные, а для меня -- краткие, схематичные.

Туннель

Конфигурация туннеля

вы и я: ваше имя

  • Договоримся об имени для вашего компьютера (по которому я буду вести у себя учёт). Обозначим его NAME; дальше вместо NAME будем подставлять это выбранное ваше имя.

вы: ваш ключ, которому я позволю делать туннель у меня

(делает обычный пользователь, не root)

  • ssh-keygen -f ~/.ssh/id_for_tun_NAME -C 'tunnel wanted by NAME'
  • Сообщите мне его открытую (т.н. "публичную") часть: cat ~/.ssh/id_for_tun_NAME.pub

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

(делает администратор)

  • useradd -m tun_NAME
  • Позволяю входить по вашему ключу: cat >> ~tun_NAME/.ssh/authorized_keys (Заготовка файла ~tun_NAME/.ssh/authorized_keys уже будет после useradd.)
  • TODO: Хорошо бы ещё запретить этому специальному пользователю (для обслуживания туннеля с моей стороны) выполнять любые команды из-под ssh, запускать командную оболочку, входить для иных целей, помимо туннеля.
  • Выбираю у себя номер порта и сообщаю его вам. (Пусть он обозначается PORT_NAME.) Возможна конфигурация, когда порт выбирается автоматически (как в конфигурации ниже); тогда заранее договариваться о номере порта не надо.

вы: сохраняете конфигурацию

(делает тот же обычный пользователь, не root)

  • Впишите в ~/.ssh/config конфигурацию (например, cat >> ~/.ssh/config -- дописывает в конец файла; потом Ctrl-D), о которой мы договорились:
 Host {{{MY_NAME}}}_tunnel
      Hostname {{{MY_HOST}}}
      Port {{{MY_HOST_SSHPORT}}}
      User tun_NAME
      IdentityFile ~/.ssh/id_for_tun_NAME
      ForwardX11 no
      Compression yes
      CompressionLevel 9
      RemoteForward 0 localhost:22

0 в качестве номера порта значит, что порт будет подобран автоматически (и напечатается ssh-клиентом -- см. команду ниже). В таком случае о номере порта можно заранее не договариваться.

(NAME нужно заменить на имя, выделенное для вас.)

(Вместо {{{MY_NAME}}}_tunnel можете придумать любое другое удобное для вас обозначение того, к кому вы пробрасываете туннель, и использовать его в командах ниже.)

Отредактировать ~/.ssh/config можно каким-нибудь текстовым редактором[1].

мы: виден ли выделенный для вас порт снаружи

Напомню себе и вам о ещё одном варианте строчки из этой конфигурации:

      RemoteForward *:0 localhost:22

или (при ручном выборе номера порта)

      RemoteForward *:PORT_NAME localhost:22

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

Я должен, чтобы слушание на всех интерфейсах работало, включить следующую опцию в /etc/openssh/sshd_config[2]:

   GatewayPorts yes

Запуск туннеля

вы: инициируете туннель (каждый раз, когда нужно)

(делает тот же обычный пользователь, не root)

  • ssh {{{MY_NAME}}}_tunnel

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

На самом деле, в нашем деле "правильнее" было бы дать команду с опцией:

  • ssh -N {{{MY_NAME}}}_tunnel

-- опция -N указывает ssh-клиенту, чтобы он только перенаправлял порты (т.е. создавал "туннель"), но не давал вам командную оболочку другого компьютера (моего, к которому вы подключаетесь). Я мог бы как раз и запретить специальному пользователю, под которым с моей стороны обслуживается туннель, работать с командной оболочкой (потому что исполнять команды на моём компьютере -- не наша цель).

С вашей стороны: вход для меня

(делается root)

(Ниже описаны самые обыкновенные действия для заведения пользователя для кого-то.)

пользователь для меня и ключ

(Вы можете узнать, какое имя пользователя я предпочитаю; здесь: {{{ME}}}.)

  • useradd -G wheel -m {{{ME}}} (группа wheel нужна, если я должен быть администратором)
  • Сообщайте мне пароль root, когда мне нужно администрировать, или добавьте меня в /etc/sudoers.[3]
  • cat >> ~{{{ME}}}/.ssh/authorized_keys
   {{{MY_PUBLIC_KEY}}}

ssh-сервер у вас работает?

  • service sshd status
  • Если нет, включите: service sshd start
  • Если не стоит этот пакет, поставьте: apt-get install openssh-server
  • Включите навсегда: chkconfig sshd on
  • Посмотрите, будет ли он запускаться теперь всегда: chkconfig sshd[4]

Замечание: ssh-сервер у вас безопасен?

Вообще-то, если мы договоримся, что на порт, выделенный для Вас с моей стороны, надо пускать всех с Интернета, то стоит обеспокоиться тем, чтобы нельзя было Вас атаковать подбором паролей к Вашим пользователям, т.е. в настройках ssh-сервера запретить вход по паролю (останется вход по ключу). (TODO: написать конкретно!)

Сессия удалённой работы/администрирования

я: иду

(обычный пользователь)

  • ssh 0 -l {{{ME}}} -p PORT_NAME -v
  • su - или sudo su - (использую, соответственно, ваш пароль root-а или пароль пользователя {{{ME}}}, который вы установили -- их вы мне должны сообщить)

Автоматический туннель

Для большего удобства давайте позаботимся об автоматическом поддержании туннеля (средствами autossh и "обёрктой" вокруг него -- autosshd).

Преимущество команды autossh перед ssh в том, что такая команда будет перезапускать ssh с туннелем в случае всяких проблем. (Вам не нужно будет вручную заново давать эту команду.)

Преимущество же autosshd в том, что туннель будет запускаться системным сервисом, т.е. каждый раз при загрузке вашей системы, и вам не нужно будет об этом заботиться и давать самим команду. Это может также быть удобно, если я удалённо буду экспериментировать с перезагрузкой вашей системы. (Системный сервис, конечно, можно будет при желании отключить потом.)

Вот несколько всё более сложных усовершенствований:

вы: делайте autossh вместо ssh

(делает ваш обычный пользователь)

(Пакет autossh должен быть у вас установлен администратором, например, так: apt-get install autossh.)

Для запуска туннеля вместо

  • ssh -N {{{MY_NAME}}}_tunnel

попробуйте:

  • autossh -M 0 -N {{{MY_NAME}}}_tunnel

У autossh обязательна опция -M, которая даёт порт для мониторинга соединения, но документация /usr/share/doc/autossh-1.4c/README говорит, что современные ssh могут сами это делать (см. опции ServerAliveInterval, ServerAliveInterval). -M 0 как раз отключает этот мониторинг.

вы: пусть специальный пользователь _autossh занимается туннелем

(делается root)

  • предварительно поставьте autosshd (версия пакета в репозитории пакетов Sisyphus могла уже измениться, конечно -- см. ссылки для скачивания):

apt-get install ftp://ftp.altlinux.org/pub/distributions/ALTLinux/Sisyphus/files/noarch/RPMS/autosshd-0.0.2-alt8.noarch.rpm

(Лучше поставьте из архива именно ту версию, которую я "одобрил", т.е. с которой я проверял эту инструкцию: apt-get install ftp://ftp.altlinux.org/pub/distributions/archive/sisyphus/date/2014/01/31/noarch/RPMS.classic/autosshd-0.0.2-alt8.noarch.rpm! Чтобы не перезаписать конкретную версию при обновлении, можно добавить строчку RPM::Hold { "^autosshd"; }; в конфигурацию APT, например, в отдельный новый файл /etc/apt/apt.conf.d/autosshd-tested.conf.)

Будет создан специальный пользователь _autossh с домашней директорией /var/lib/autosshd/.[5]

  • перенесите настройки ssh-туннеля к этому специальному пользователю (YOU -- имя вашего обычного пользователя):
    • cp -v ~YOU/.ssh/id_for_tun_NAME* ~_autossh/.ssh/
    • cat ~YOU/.ssh/config >> ~_autossh/.ssh/config
    • chown _autossh:_autossh -R ~_autossh/.ssh

Теперь вашу обычную команду инициации туннеля (ssh -N {{{MY_NAME}}}_tunnel) можно исполнять от имени нового специального пользователя; так вы будете в большей безопасности от атак из сети и от ошибок в ssh (ваши личные данные, с которыми вы работаете от имени своего обычного пользователя, а также вся система в случае, если вы можете переключаться в администратора -- если вы в группе wheel). Однако специальный пользователь _autossh настроен так, что под ним "зайти" в систему нельзя, поэтому просто самому проверить и запустить ssh -N {{{MY_NAME}}}_tunnel, сделав, скажем, su - _autossh, не получится. Можно рассматривать сделанные нами настройки ssh для пользователя _autossh как задел для работы autosshd (или как пример того, что эти настройки можно сделать под каким-то другим пользователем и от этого может быть польза).

вы: настройка autosshd

  • настройки в файле /etc/autossh.d/{{{MY_NAME}}}_tunnel.conf (нужен какой-нибудь ненулевой AUTOSSH_PORT![6] и в опциях (auto)ssh должна быть -N!):
   #usage: autossh [-V] [-M monitor_port[:echo_port]] [-f] [SSH_OPTIONS]
   #
   #    -M specifies monitor port. May be overridden by environment
   #       variable AUTOSSH_PORT. 0 turns monitoring loop off.
   #       Alternatively, a port for an echo service on the remote
   #       machine may be specified. (Normally port 7.)
   #    -f run in background (autossh handles this, and does not  pass it to ssh.)
   #    -V print autossh version and exit.
   #
   #Environment variables are:
   #    AUTOSSH_LOGLEVEL    - level of log verbosity
   AUTOSSH_LOGLEVEL=4
   
   #    AUTOSSH_MESSAGE     - message to append to echo string (max 64 bytes)
   #    AUTOSSH_PIDFILE     - write pid to this file
   #    AUTOSSH_FIRST_POLL  - time before first connection check (seconds)
   #
   
   #    AUTOSSH_POLL        - how often to check the connection (seconds)
   #AUTOSSH_POLL=600
   #    AUTOSSH_PORT        - port to use for monitor connection
   #AUTOSSH_PORT=20000
   #    AUTOSSH_GATETIME    - how long must an ssh session be established
   #                          before we decide it really was established
   #                          (in seconds). Default is 30 seconds; use of -f
   #                          flag sets this to 0.
   #AUTOSSH_GATETIME=30
   #    AUTOSSH_LOGFILE     - file to log to (default is to use the syslog facility)
   #AUTOSSH_LOGFILE=$HOST.log
   
   #    AUTOSSH_DEBUG       - turn logging to maximum verbosity and log to stderr
   AUTOSSH_DEBUG=yes 
   
   #    AUTOSSH_PATH        - path to ssh if not default
   #AUTOSSH_PATH=/usr/local/bin/ssh
   
   #    AUTOSSH_MAXSTART    - max times to restart (default is no limit)
   #AUTOSSH_MAXSTART=100
   
   #    AUTOSSH_MAXLIFETIME - set the maximum time to live (seconds)
   
   AUTOSSH_PIDFILE=/var/run/autosshd/{{{MY_NAME}}}_tunnel.pid
   AUTOSSH_LOCKFILE={{{MY_NAME}}}_tunnel.lck
   AUTOSSH_LOGFILE=/var/lib/autosshd/{{{MY_NAME}}}_tunnel.log
   
   HOST={{{MY_NAME}}}_tunnel
   USER=_autossh
   
   #AUTOSSH_PORT parameter must be unique for each connection and can not be 0
   AUTOSSH_PORT=6666
   
   MANUAL=no
   
   AUTOSSH_OPTIONS=" -M ${AUTOSSH_PORT} -f -N ${HOST}"


  • для удобства в /var/lib/autosshd/.ssh/config предлагается назначить фиксированный порт на моей стороне -- PORT_NAME, о котором мы договорились (т.е. который я вам выделил и сообщил); вместо
     RemoteForward 0 localhost:22

сделайте:

     RemoteForward PORT_NAME localhost:22

например, что-нибудь вроде (Предупреждение: это совсем не тот порт, что AUTOSSH_PORT, который появлялся просто как часть внутренней кухни, несовершенной):

     RemoteForward 6060 localhost:22
  • проверка, запускается ли настроенный сервис -- как обычно:
    • вы запускаете: service autosshd start
    • вы смотрите о его состоянии: service autosshd status
    • я проверяю: ssh 0 -p PORT_NAME -l {{{ME}}} (могу также вписать эти параметры в раздел вроде "Host NAME" в свой ~/.ssh/config)
  • включаем сервис на каждый запуск системы -- как обычно:
    • включен ли уже: chkconfig --list autosshd
    • пусть будет включён: chkconfig autosshd on
    • включен ли теперь: chkconfig --list autosshd

Примечания (о частных особенностях систем)

  1. Какой-нибудь текстовый редактор: например, medit в Simply Linux: medit ~/.ssh/config; или, например, emacs -- пакет с ним можно поставить, если он не стоит.
  2. man ssh_config:

    If the bind_address is not specified, the default is to only bind to loopback addresses. If the bind_address is ‘*’ or an empty string, then the forwarding is requested to listen on all interfaces. Specifying a remote bind_address will only succeed if the server's GatewayPorts option is enabled (see sshd_config(5)).

  3. На самом деле, например, в ALT Linux p7 пользователи из группы wheel и так уже могут пользоваться sudo. Но чтобы пользоваться sudo, нужно иметь свой пароль. Его можете установить вы: passwd {{{ME}}}; или дать это сделать мне, когда я войду и стану администратором через su -, узнав от вас ваш пароль root-а.
  4. Для систем со старым-добрым SysV init можно использовать и команду chkconfig --list sshd; а для новомодного systemd (например, в ALT Linux p7) эта команда даст информацию так:
    # chkconfig sshd
    Внимание: Отправляется запрос 'systemctl is-enabled sshd.service'.
    disabled
    # 
    
  5. После установки autosshd-0.0.2-alt3 видим:
    # fgrep ssh /etc/passwd
    sshd:x:484:465::/var/empty:/dev/null
    _autossh:x:480:458:Autossh daemon:/var/lib/autosshd:/dev/null
    # rpm -qf /var/lib/autosshd --scripts 
    preinstall scriptlet (through /bin/sh):
    # Add the "_autossh" user
    /usr/sbin/groupadd -r -f _autossh 2>/dev/null ||:
    /usr/sbin/useradd  -r -g _autossh -c 'Autossh daemon' \
    	-s /dev/null -d /var/lib/autosshd _autossh 2>/dev/null ||:
    /usr/sbin/usermod -p `pwgen -s 24 1` _autossh
    postinstall scriptlet (through /bin/sh):
    if [ ! -f /var/lib/autosshd/.ssh/id_dsa ]; then
        mkdir -p /var/lib/autosshd/.ssh
        /usr/bin/ssh-keygen -t dsa -b 1024 -C "AutoSSH daemon" -N "" -q -f /var/lib/autosshd/.ssh/id_dsa
        echo "StrictHostKeyChecking no" > /var/lib/autosshd/.ssh/config
        cp /var/lib/autosshd/.ssh/id_dsa.pub /var/lib/autosshd/.ssh/authorized_keys
    fi
    chown -R _autossh:_autossh /var/lib/autosshd/
    chown _autossh:_autossh /var/run/autossh.d/
    
    /usr/sbin/post_service autosshd
    preuninstall scriptlet (through /bin/sh):
    /usr/sbin/preun_service autosshd
    postuninstall scriptlet (through /bin/sh):
    /usr/sbin/userdel -r _autossh 2>/dev/null ||:
    /usr/sbin/groupdel -r _autossh 2>/dev/null ||:
    # 
    
  6. Хоть сам autossh может работать с современным ssh с -M 0, но autosshd устроен так, что он по номеру этого заданного порта выслеживает процесс autossh (и потом управляет им).