SSH — принудительное выполнение команды при входе в систему даже без оболочки

Я создаю пользователя с ограниченным доступом без оболочки только для переадресации портов, и мне нужно выполнить скрипт при входе в систему через открытый ключ, даже если пользователь подключен через ssh -N user@host, который не запрашивает у SSH-сервера оболочку.

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

Я пытался безрезультатно:

  • Установка команды в /etc/ssh/sshrc.
  • Использование command="COMMAND" в .ssh/authorized_keys (человек авторизован_keys)
  • Настройка скрипта с командой в качестве оболочки пользователя. (chsh -s /sbin/myscript.sh USERNAME)
  • Соответствующий пользователь в /etc/ssh/sshd_config вроде: Match User MYUSERNAME ForceCommand "/sbin/myscript.sh"

Все работает, когда пользователь запрашивает оболочку, но если войти только для переадресации портов и без оболочки (ssh -N), это не работает.


person Iacchus    schedule 14.11.2015    source источник
comment
ForceCommand работает без pty, если только он не запрошен. Исправьте свой скрипт, чтобы он не требовал pty.   -  person Todd A. Jacobs    schedule 15.11.2015


Ответы (4)


Параметр ForceCommand выполняется без PTY, если только клиент не запрашивает его. . В результате у вас фактически нет оболочки для выполнения сценариев так, как вы могли бы ожидать. Кроме того, на справочной странице OpenSSH SSHD_CONFIG(5) четко сказано:

Команда вызывается с помощью оболочки входа пользователя с параметром -c.

Это означает, что если вы отключили оболочку входа пользователя или установили для нее что-то вроде /bin/false, то ForceCommand не сможет работать. При условии, что:

  1. у пользователя определена разумная оболочка,
  2. что ваш целевой скрипт является исполняемым, и
  3. что ваш сценарий имеет соответствующую строку shebang

то следующее должно работать в вашем глобальном файле sshd_config после правильного изменения с правильным именем пользователя и полным путем к вашему пользовательскому скрипту:

Match User foo
    ForceCommand /path/to/script.sh
person Todd A. Jacobs    schedule 14.11.2015
comment
Это работает, только если я не использую флаг ssh -N для подключения. Но в любом случае вы заставили меня понять, что невозможно добиться этого, используя только sshd ... скрипт должен предупреждать о соединениях, аутентифицированных с помощью pubkey, поэтому пользователь, подключающийся, не должен иметь возможность пропустить его, используя «ssh -N». - person Iacchus; 15.11.2015

Я автор ОП; Я пришел к выводу, что то, что мне нужно достичь, невозможно использовать SSH только до даты (OpenSSH_6.9p1 Ubuntu-2, OpenSSL 1.0.2d 9 Jul 2015), но я нашел отличное программное обеспечение, которое использует зашифрованную SPA-аутентификацию для открытия порта SSH и его новую версию (на дату этого post, это главная ветка GitHub) имеет функцию всегда выполнять команду, которую пользователь успешно авторизует.

FWKNOP — авторизация одного зашифрованного пакета

FWKNOP устанавливает правила iptables, которые разрешают доступ к указанным портам для одного зашифрованного пакета, который отправляется через UDP. Затем после авторизации разрешает доступ авторизованному пользователю на заданное время, например 30 секунд, закрывая после этого порт, оставляя соединение открытым.

1. Чтобы установить на Ubuntu Linux:

Текущая версия (2.6.0-2.1build1) в репозиториях Ubuntu на сегодняшний день по-прежнему не позволяет выполнять команды при успешном SPA; (вместо этого используйте версию 2.6.8 с GitHub)

На клиентской машине:

sudo apt-get install fwknop-client

На стороне сервера:

sudo apt-get install fwknop-server

Вот руководство по настройке клиентского и серверного компьютеров https://help.ubuntu.com/community/SinglePacketAuthorization

Затем, после настройки, на стороне сервера:

  1. Изменить /etc/default/fwknop-server
  2. Измените строку START_DAEMON="no" на START_DAEMON="yes"
  3. Затем запустите:

    sudo service fwknop-server stop

    sudo service fwknop-server start

2. Предупреждение администратора об успешном SPA (электронная почта, скрипт pushover и т. д.)

Итак, как указано выше, текущая версия, присутствующая в репозиториях Ubuntu (2.6.0-2.1build1), не может выполнить команду при успешном SPA. Если вам нужна эта функция начиная с OP, но она будет выпущена в версии fwknop (2.6.8), как это указано здесь:

https://github.com/mrash/fwknop/issues/172

Поэтому, если вам нужно использовать его прямо сейчас, вы можете собрать его из мастера ветки github, у которого есть опция CMD_CYCLE_OPEN.

3. Дополнительные ресурсы на fwknop

https://help.ubuntu.com/community/SinglePacketAuthorization

https://github.com/mrash/fwknop/ (проект на GitHub)

http://www.cipherdyne.org/fwknop/ (сайт проекта)

https://www.digitalocean.com/community/tutorials/how-to-use-fwknop-to-enable-single-packet-authentication-on-ubuntu-12-04 (руководство по сообществу DO)

person Iacchus    schedule 04.12.2015

Если вам нужно только запустить скрипт, вы можете положиться на pam_exec.

По сути, вы ссылаетесь на скрипт, который вам нужно запустить в конфигурации /etc/pam.d/sshd:

session optional pam_exec.so seteuid /path/to/script.sh

После некоторого тестирования вы можете изменить optional на required.

Пожалуйста, обратитесь к этому ответу "bash - Как настроить оповещение по электронной почте при успешном входе в систему ssh? - Спросите Ubuntu" для аналогичный запрос.

Действительно, в сценарии доступно только ограниченное подмножество переменных среды:

LANGUAGE=en_US.UTF-8
PAM_USER=bitnami
PAM_RHOST=192.168.1.17
PAM_TYPE=open_session
PAM_SERVICE=sshd
PAM_TTY=ssh
LANG=en_US.UTF-8
LC_ALL=en_US.UTF-8
PWD=/

Если вы хотите получить информацию о пользователе от authorized_keys, этот скрипт может быть полезен:

#!/bin/bash
# Get user from authorized_keys
# pam_exec_login.sh
# * [ssh - What is the SHA256 that comes on the sshd entry in auth.log? - Server Fault](https://serverfault.com/questions/888281/what-is-the-sha256-that-comes-on-the-sshd-entry-in-auth-log)
# * [bash - How to get all fingerprints for .ssh/authorized_keys(2) file - Server Fault](https://serverfault.com/questions/413231/how-to-get-all-fingerprints-for-ssh-authorized-keys2-file)

# Setup log
b=$(basename $0| cut -d. -f1)
log="/tmp/${b}.log"

function timeStamp () {
  echo "$(date '+%b %d %H:%M:%S') ${HOSTNAME} $b[$$]:"
}

# Check if opening a remote session with sshd
if [ "${PAM_TYPE}" != "open_session" ] || [ $PAM_SERVICE != "sshd" ] || [ $PAM_RHOST == "::1" ]; then
  exit $PAM_SUCCESS
fi

# Get info from auth.log
authLogLine=$(journalctl -u ssh.service |tail -100 |grep "sshd\[${PPID}\]" |grep "${PAM_RHOST}")
echo ${authLogLine} >> ${log}

PAM_USER_PORT=$(echo ${authLogLine}| sed -r 's/.*port (.*) ssh2.*/\1/')
PAM_USER_SHA256=$(echo ${authLogLine}| sed -r 's/.*SHA256:(.*)/\1/')

# Get details from .ssh/authorized_keys
authFile="/home/${PAM_USER}/.ssh/authorized_keys"
PAM_USER_authorized_keys=""

while read l; do
  if [[ -n "$l" && "${l###}" = "$l" ]]; then
    authFileSHA256=$(ssh-keygen -l -f <(echo "$l"))
    if [[ "${authFileSHA256}" == *"${PAM_USER_SHA256}"* ]]; then
      PAM_USER_authorized_keys=$(echo ${authFileSHA256}| cut -d" " -f3)
      break
    fi
  fi
done < ${authFile}

if [[ -n ${PAM_USER_authorized_keys} ]]
then
  echo "$(timeStamp) Local user: ${PAM_USER}, authorized_keys user: ${PAM_USER_authorized_keys}" >> ${log}
else
  echo "$(timeStamp) WARNING: no matching user in authorized_keys" >> ${log}
fi
person emaV    schedule 07.04.2020

Я автор ОП. Кроме того, вы можете реализовать простой logwatcher, как показано ниже, написанный на python3, который продолжает читать файл и выполняет команду, когда строка содержит шаблон.

logwatcher.python3

#!/usr/bin/env python3

# follow.py
#
# Follow a file like tail -f.

import sys
import os
import time

def follow(thefile):
    thefile.seek(0,2)
    while True:
        line = thefile.readline()
        if not line:
            time.sleep(0.5)
            continue
        yield line

if __name__ == '__main__':
    logfilename = sys.argv[1]
    pattern_string = sys.argv[2]
    command_to_execute = sys.argv[3]

    print("Log filename is: {}".format(logfilename))

    logfile = open(logfilename, "r")
    loglines = follow(logfile)

    for line in loglines:
        if pattern_string in line:
            os.system(command_to_execute)

Применение

  1. Сделайте приведенный выше скрипт исполняемым:

chmod +x logwatcher.python3

  1. Добавьте cronjob для его запуска после перезагрузки

crontab -e

Затем напишите туда эту строку и сохраните ее после этого:

@reboot /home/YOURUSERNAME/logwatcher.python3 "/var/log/auth.log" "session opened for user" "/sbin/myscript.sh"

Первый аргумент этого скрипта — это файл журнала для просмотра, а второй аргумент — это строка, которую нужно искать в нем. Третий аргумент — это сценарий, который выполняется при обнаружении строки в файле.

Лучше всего использовать что-то более надежное для запуска/перезапуска скрипта в случае его сбоя.

person Iacchus    schedule 07.01.2017
comment
следует использовать pattern_string там, где используется startup_string? Не могу отредактировать себя - person jdog; 27.03.2017