две команды с конвейерами, каждая из которых считывает пароль из stdin

Вопрос или проблема

Есть ли способ разумно сделать это:

scp user@host:/path/to/file /dev/tty | openssl [options] | less

без создания файла и без необходимости указывать пароль непосредственно в аргументах?

Проблема в том, что оба процесса запрашивают пароль, но порядок их запуска (и, следовательно, порядок, в котором они запрашивают пароль) неопределен.

Было бы нормально сначала завершить scp, а затем запустить openssl, но без временного файла.

Возможные решения на данный момент

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

Версия именованных каналов 1

mkfifo pipe && {
  scp user@host:/path/to/file pipe    # запрашивает пароль, затем ждет
                                      # завершения чтения из канала,
                                      # что произойдет только после того,
                                      # как был введен пароль для openssl
                                      # => нужно ^Z и ввести пароль
                                      #  => `pipe: Interrupted system call'

  openssl [options] -in pipe | less
}

Версия именованных каналов 2

mkfifo pipe && {
  scp user@host:/path/to/file pipe &  # запрашивает пароль (и работает, когда
                                      # введен пароль) несмотря на то, что
                                      # помещен в фоновый режим (что? как?
                                      # может кто-то объяснить?)

  openssl [options] -in pipe | less   # `bad password read'
}

Версия именованных каналов 3

mkfifo pipe && {
  scp user@host:/path/to/file pipe |  # сначала запрашивает пароль

  openssl [options] -in pipe | less   # запрашивает пароль после того, как
                                      # был введен пароль от scp
                                      # и все работает нормально
}

Поменять команды местами не помогает.

openssl [options] -in <(scp user@host:/path/to/file /dev/tty) | less не работает.

Может кто-то

  1. предложить другое решение,
  2. объяснить необычное поведение scp в примере 1 (`Interrupted system call’) (я предполагаю, что это либо ошибка, либо некое “защитное свойство”),

  3. объяснить, как работает ввод паролей, например, как задача, которая была запущена в фоновом режиме, может читать из stdin,

  4. (связано с 3.) объяснить, почему scp в примере 2 выводит запрос пароля, даже если stdout и stderr перенаправлены в /dev/null ?

scp user@host:/path/to/file /dev/tty пытается отправить содержимое удаленного файла в tty, а не в канал для openssl.

Насколько мне известно, ssh/scp не позволяют считывать пароли из stdin, вы можете использовать sshpass, если не можете воспользоваться более безопасными способами аутентификации. scp предназначен для копирования файлов, а не для вывода их содержимого. Вы можете использовать ssh cat вместо этого или даже сжимать данные на лету, чтобы сэкономить трафик.

И sshpass, и openssl поддерживают ввод паролей из переменных окружения.

SSHPASS=$password_for_ssh sshpass -e ssh host 'gzip -3 < /path/to/file' |
  gunzip |
  PASS=$password_for_openssl openssl -passin env:PASS ...

Ответ или решение

Для решения проблемы, связанной с использованием команд scp и openssl с запросом пароля из стандартного ввода, можно рассмотреть несколько подходов. Основная цель — обойти необходимость временных файлов и избежать прямого ввода паролей в командной строке.

Возможное решение

Одним из наиболее элегантных и безопасных способов является использование утилиты sshpass в сочетании с передачей данных через стандартный ввод. Вы можете передать пароли через переменные окружения, что значительно повышает безопасность по сравнению с их явным указанием в командной строке.

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

SSHPASS='ваш_пароль_для_ssh' sshpass -e ssh user@host 'gzip -c /path/to/file' | \
PASS='ваш_пароль_для_openssl' openssl enc -d -aes-256-cbc -pass env:PASS | less

Пояснение:

  1. Использование sshpass:

    • Утилита sshpass позволяет передавать пароль для аутентификации SSH, используя переменную окружения или файл. В данном примере используется переменная окружения (-e), содержащая пароль.
    • Команда ssh подключается к удаленному хосту и передает файл через gzip, который сжимает данные и отправляет их в стандартный вывод.
  2. openssl и передача пароля:

    • Утилита openssl позволяет передавать пароль для расшифровки через переменную окружения (-pass env:PASS).
    • В данном примере openssl ожидает входящие данные от gzip, которые затем передаются в less для построчного просмотра.

Объяснения поведения:

  1. Необычное поведение scp в первом варианте:

    • Команда scp ожидает завершения ввода, и Interrupted system call может возникать из-за того, что процесс был прерван (например, когда происходит попытка прерывания операции чтения из pipe). Это поведение может быть связано с особенностями синхронизации между процессами и механикой работы с stdin/stdout.
  2. Вход пароля из фонового процесса:

    • Процессы, запущенные в фоновом режиме, могут все еще взаимодействовать с stdin, если они не полностью отсоединены от терминала. Это может породить путаницу, но соль заключается в том, что scp продолжает ожидать ввода, даже если он запущен в фоне.
  3. Вывод scp, перенаправленный в /dev/null:

    • Программа scp выводит запрос пароля в стандартный вывод на tty.h, и, даже если stdout и stderr перенаправлены, её поведение остается прежним — запрос пароля осуществляется через терминал. Такой подход считается стандартным для программ, требующих интерактивного ввода.

Использование предложенной схемы с sshpass и openssl позволит без труда обойти проблему с вводом пароля и обеспечит надежный способ обработки данных из удаленного хоста без создания временных файлов.

Оцените материал
Добавить комментарий

Капча загружается...