Python копирование файлов по ssh

Обновлено: 06.07.2024

Сегодня я хотел бы поведать вам о том, как можно работать с SSH в Python. SSH — Secure SHell — сетевой протокол, который позволяет производить удаленное управление операционной системой компьютера по зашифрованному соединению. При помощи SSH можно осуществлять передачу файлов. SSH применяется для соединения с удаленной операционной системой по SFTP.

В Python для работы с ssh используется модуль paramiko. Документацию по модулю вы можете почитать тут, ну а я покажу вам пару основных моментов, от которых вы оттолкнетесь и дальше уже будете применять то, что вам необходимо.

Paramiko присутствует в стандартных репозиториях Ubuntu и Debian, и установить его можно очень даже легко:

Теперь, когда модуль установлен, приступим к программированию)). Для работы с SSH в модуле предусмотрен класс — SSHClient. С него все и начинается:

Я создал объект ssh класса SSHClient, и теперь могу устанавливать соединение. Модуль позволяет авторизоваться как при помощи пары “имя пользователя - пароль”, так и при помощи ключа. Во втором случае, конечно же, нужно иметь “при себе” этот самый ключ.

Разумеется, на разных серверах SSH настроен по разному. Важно знать, что существует 3 варианта авторизации - по имени пользователя и паролю, ключом и гибридный. По умолчанию, скажем, на Debian-based дистрибутивах включен последний вариант. Осмелюсь предположить, что это наиболее популярный вариант настроек. Что он из себя представляет? Когда вы подключаетесь к серверу по SSH, он, перед запросом логина и пароля, предлагает вам принять ключ, чтобы, позже, вы, выгрузив в директорию с ключами на сервере свой ключ, могли авторизоваться именно по ключу. Что получает пользователь? Он получает удобный диалог, на утвердительный ответ которого SSH-клиент скопирует к себе ключики сервера сам. Что получает программист? Весьма неудобную ситуацию - дело в том, что по умолчанию SSHClient настроен так, чтобы не соединяться с сервером, если у клиента нет ключа. Даже если логин и пароль правильны. Это приводит к тому, что SSHClient сбрасывает соединение, и авторизоваться не получается. К счастью, на такие случаи в Paramiko предусмотрено удобное решение:

Ежели вам охота вернуть все обратно, можете просто не прописывать этот метод. Явно политика по умолчанию устанавливается так:

Объект создан и настроен, теперь можно и подключиться:

Необходимо указать свои сервер, имя пользователя и пароль. В качестве сервера можно указать IP-адрес или доменное имя, по которому резолвится ваш сервер.

После успешного соединения есть два варианта работы с сервером - продолжать работать по SSH и выполнять консольные команды сервера или переключиться в режим SFTP и использовать приемы SFTP для работы с файлами. Какой метод предпочтительнее - дело ваше. Посмотрим оба варианта.

Вариант номер один - SFTP. Для переключения в этот режим используем такую конструкцию:

И далее работа с сервером осуществляется по SFTP. В качестве примера приведу пару команд по навигации по директориям сервера и управлению файлами:

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

Во второй строке я осуществил переход в директорию /var/log . Таким образом можно перемещаться по директориям на сервере.

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

Для скачивания файла использется метод get() — строка четвертая. В качестве первого параметра задается имя локального файла (куда скачивать), в качестве второго — что скачивать наоборот. Можно указывать абсолютные пути.

Для выгрузки файла на сервер используется метод put() — параметры аналогично get() . Стоит отметить, что ни get() , ни put() не принимают в качестве входных параметров маски (например, *.php ).

Удалить файл можно при помощи метода unlink() . Параметр задается также, как и у get() и put() .

Для создания директории можно использовать метод mkdir() , а для удаления — rmdir() .

Вообще, если вы имели ранее дело с sftp/ftp, то, думаю, вы заметили похожесть в названиях методов и команд протоколов FTP/SFTP. Так что трудно не будет, а нюансы всегда можно найти в документации к paramiko.

Вариант номер два — работа с сервером по SSH. Работа с сервером не через SFTP, а через SSH отличается прежде всего тем, что можно выполнять консольные команды. Для выполнения команд по SSH служит метод exec_command() . Ниже пример (я продублировал соединение с сервером для наглядности):

Данный метод примечателен тем, что при выполнении команды необходимо обрабатывать три возвращаемых канала — это содержимое стандартного ввода, стандартного вывода и стандартного вывода ошибок. Например, результат выполнения вышеописанной команды, если он будет успешен, будет содержаться в stdout. Ко всем трём возвращаемым каналам можно обратиться как к файлу и, например, считать оттуда всё, что необходимо. Для получения результата выполнения всё той же команды выше (результатом будет содержимое файла), я могу просто считать его построчно из stdout:

Таким образом я получил кортеж строк системного лога удаленного сервера.

Усложним немного. Допустим, мне понадобилось перезагрузить сервер. Команда перезагрузки доступна только для root ( /sbin/reboot ). Для выполнения команд, доступных только root, от обычного пользователя, можно воспользоваться утилитой sudo . Я исхожу из того, что на сервере установлена и настроена sudo , и моя учетная запись может выполнять эту утилиту (является т.н. sudoer’ом):

  1. выполняю команду “sudo reboot”
  2. в результате выполнения мне нужно ввести пароль пользователя (настройки по умолчанию для sudo — пароль вашего пользователя). Для этого я пишу в stdin, как в обычный файл, свой пароль вместе с переносом строки, и отправляю содержимое stdin серверу.

Результатом выполнения будет перезагрузка сервера :). Так что для большей наглядности можете повыполнять другие команды через sudo :).

Это основные моменты работы с ssh в Python, для более подробной информации вы всегда можете обратиться к документации, ссылку на которую я дал в начале статьи. Удачи! ;)

У меня на локальном компьютере есть текстовый файл, который генерируется ежедневным скриптом Python, запускаемым в cron.

Я хотел бы добавить немного кода для безопасной отправки этого файла на мой сервер через SSH.

Если вы хотите простой подход, это должно работать.

Сначала вы захотите ".close ()" файл, чтобы вы знали, что он записан на диск из Python.

Вам нужно сгенерировать (на исходном компьютере) и установить (на конечном компьютере) ключ ssh заранее, чтобы scp автоматически проходил аутентификацию с вашим открытым ключом ssh (другими словами, чтобы ваш скрипт не запрашивал пароль) ,

Чтобы сделать это в Python (то есть не оборачивая scp через subprocess.Popen или аналогичный) с библиотекой Paramiko , вы должны сделать что-то вроде этого:

(Возможно, вы захотите иметь дело с неизвестными хостами, ошибками, созданием любых необходимых каталогов и т.д.).

Возможно, вы бы использовали модуль подпроцесса . Что-то вроде этого:

Убедитесь, что вы установили правильные учетные данные, чтобы вы могли выполнить автоматическая scp без пароля между компьютерами . Существует вопрос stackoverflow для этого уже .

Есть несколько разных способов решения проблемы:

  1. Обтекание программ командной строки
  2. использовать библиотеку Python, которая предоставляет возможности SSH (например, - Paramiko или Twisted Conch )

У каждого подхода есть свои причуды. Вам нужно будет настроить ключи SSH для включения входа без пароля, если вы переносите системные команды, такие как «ssh», «scp» или «rsync». Вы можете встроить пароль в сценарий, используя Paramiko или какую-либо другую библиотеку, но вы можете столкнуться с недостатком документации, особенно если вы не знакомы с основами SSH-соединения (например, обмен ключами, агенты и т.д.). Вероятно, само собой разумеется, что ключи SSH почти всегда лучше, чем пароли для такого рода вещей.

ПРИМЕЧАНИЕ: rsync трудно победить, если вы планируете передавать файлы через SSH, особенно если альтернативой является старый scp.

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

У меня есть текстовый файл на моем локальном компьютере, который генерируется ежедневным скриптом Python, запущенным в cron.

Я хотел бы добавить немного кода, чтобы этот файл был безопасно отправлен на мой сервер через SSH.

Если вы хотите простой подход, это должно работать.

вы хотите ".close () " сначала файл, чтобы вы знали, что он сброшен на диск С Python.

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

сделать это в Python (т. е. не обертывать scp через подпроцесс.Popen или аналогичный) с Парамико библиотека, вы бы сделали что-то вроде этого:

(вы, вероятно, захотите иметь дело с неизвестными хостами, ошибками, созданием любых необходимых каталогов и т. д.).

вы, вероятно, использовать модуль подпроцесс. Что-то вроде этого:--7-->

здесь destination вероятно, имеет вид user@remotehost:remotepath . Благодаря @Charles Duffy за указание на слабость в моем исходном ответе, который использовал один строковый аргумент для указания операции scp shell=True - это не будет обрабатывать пробелы в путях.

убедитесь, что вы настроили правильные учетные данные, чтобы вы могли выполнить без присмотра, беспарольный УПП между машинами. Есть stackoverflow вопрос для этого уже.

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

  1. обернуть программы командной строки
  2. используйте библиотеку Python, которая предоставляет возможности SSH (например -Парамико или Витой Рог)

каждый подход имеет свои тонкости. Вам нужно будет настроить SSH-ключи для включения входа без пароля, если вы переносите системные команды, такие как" ssh"," scp "или" rsync."Вы можете встроить пароль в скрипт с помощью Paramiko или какая - то другая библиотека, но вы можете найти отсутствие документации расстраивает, особенно если вы не знакомы с основами SSH-соединения (например, обмен ключами, агенты и т.д.). Это, вероятно, само собой разумеется, что SSH-ключи, почти всегда лучше, чем пароли для такого рода вещи.

Примечание: его трудно победить rsync, если вы планируете передавать файлы через SSH, особенно если альтернативой является простой старый scp.

Я использовал Paramiko с глазом в сторону замена системных вызовов, но обнаружил, что меня тянет обратно к обернутым командам из-за их простоты использования и непосредственного знакомства. Ты можешь быть другим. Некоторое время назад я осмотрел Конча, но мне это не понравилось.

Если вы выбираете путь системного вызова, Python предлагает множество опций, таких как os.система или команды / модули подпроцесса. Я бы пошел с модулем подпроцесса, если бы использовал версию 2.4+.

достигла той же проблемы, но вместо "взлома" или эмуляции командной строки:

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

Сам OpenSSH - это набор инструментов, основанный на протоколе ssh2. Он содержит инструменты для удалённого безопасного входа (ssh), безопасной передачи файлов (scp и sftp) и инструмент управления ключами.

На большинстве ОС клиентские инструменты (ssh, scp, sftp) уже доступны для пользователя. Кроме того, пользователи могут легко установить и сконфигурировать серверные утилиты на той машине, к которой они хотят получить удалённый доступ.

Многие люди ежедневно пользуются OpenSSH и многие тратят уйму времени на попытки написать скрипты для автоматизации его использования. Большая часть этих скриптов оборачивает команды командной строки напрямую (ssh, scp и т.д.). Они используют инструменты типа Pexpect для получения паролей и пытаются работать напрямую с выводом исполняемых файлов.

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

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

Я познакомился с Paramiko некоторое время назад. Он использует PyCrypto для предоставления Python'у интерфейса к протоколу ssh2. Этот модуль предоставляет всё, что Вы только можете желать, включая аутентификацию на основе ssh ключей, доступ к ssh-шелу и sftp.

После моего знакомства с Paramiko мой подход к использованию ssh изменился. Вместо изнурительных экспериметов работы с командной строкой, я получаю программный доступ к протоколу и ко всем его инструментам. При чём всё это в Python-стиле.

О Paramiko

Paramiko - это "чистый" модуль Python, который может быть легко установлен, как и любой другой модуль. Однако, PyCrypto написан большей частью на С, так что Вам может потребоваться компилятор, чтобы установить его на свою платформу.

Сам Paramiko имеет обширную документацию по API и активную рассылку. В качестве дополнительного бонуса, есть порт всего этого на Java (но давайте не будем об этом) если Вам понадобится сделать что-то на Java.

Paramiko так же предоставляет реализацию ssh и sftp для сервера. С полным набором функций. Я использую его в как в полноценных многопоточных приложениях, так и в ежедневных скриптах. Так же есть система установки и развёртывания под названием Fabric, тоже построенная на Paramiko, предоставляющая возможность развёртывания утилит через ssh.

Начнём

Главный класс API Paramiko - это "paramiko.SSHClient". Он предоставляет базовый интерфейс, который Вам поднадобится для установки соединения и передачи файлов. Вот простой пример:

Этот код создаёт новый объект SSHClient и затем вызывает метод connect() для подключения к локальному ssh серверу. Проще и быть не может!

Host keys

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

Поведение по умолчанию SSHClient'а - отвергать соединение с узлом ("paramiko.RejectPolicy"), чей ключ не сохранён в вашем файле known_hosts. Это может быстро надоесть при работе в тестовом окружении, где машины то появляются, то уходят, и где Вам постоянно приходится переустанавливать системы.

Установка политики работы с ключами требует одного метода, который вызывается у объекта ssh клиента (set_missing_host_key_poliy()), который задаёт поведение, которое должны быть применено к несвязаным ключам. Если Вы, как и я, ленивы, то Вы будете использовать paramiko.AutoAddPolicy(), что приводит к автоматическому принятию неизвестных ключей.

Конечно, не используйте эту политику если Вы работаете с машинами, которые Вам не известны или которым Вы не доверяете. Инструменты, построенные на Paramiko должны использовать эту чрезмерно либеральную политику лишь как опцию настройки .

Запускаем простые команды

После того, как мы подключились, мы можем запускать команды и получать их результат.

ssh использует тот же тип ввода / вывода / обработки ошибок, с которым Вы должны быть знакомы по другим UNIX-подобным приложениям. Ошибки посылаются на стандартный вывод ошибок, вывод - на стандартный вывод, а ввод берётся со стандартного ввода.

Итак, ответ от клиента возвращается в виде кортежа - (stdin, stdout, stderr) - где все три элемента - файлоподобные объекты, из которых Вы можете читать (или писать - в stdin). Например:

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

Упс. Я только что запустил команду sudo. А ведь ей нужен пароль для удалённого хоста. Без проблем:

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

Используя Paramiko сделать это становится просто. В листинге 1.1 показан простой способ достичь этого - мы оборачиваем манипуляции paramiko в методы RunCommand, позволяя пользователю добавлять столько хостов, сколько он захочет, соединяясь с ними и выполняя на них команды.

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

Как и когда дело касается шелла границей тут будет только ваша фантазия. Такие инструменты, как pssh, osh, Fabric и т.д. все отображают данные по разному и каждый из них по своему группирует вывод от разных хостов.

Отправка и получение файлов

Работа с файлами в Paramiko управляется реализацией sftp, и, как и работа с клиентом ssh, она проста как два пальца.

Мы начинаем с создания нового paramiko.SSHClient, как и раньше:

ftp = ssh.open_sftp()
ftp.get('remotefile.py', 'localfile.py')
ftp.close()

То, что мне нравится в sftp клиенте, реализованном в Paramiko, так это то, что он поддерживает такие операции как stat, chmod, chown и т.д. Очевидно, что они могут работать по разному на разных удалённых машинах, так как не все сервера реализуют протокол целиком, но всё равно их наличие - большой плюс.

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

Однако, стоит заметить (и я часто с этим сталкивался): sftp, как протокол, гораздо более ограничен, чем scp. scp позволяет использовать шаблоны UNIX в имени файла при получении его с удалённой машины. А вот sftp ожидает от Вас полного пути к файлу, который Вы хотите скачать. Вот пример:

В большинстве случаев это значит "скачать все файлы с расширением .py в локальную директорию на моей машине". Но, к сожалению, sftp Вас не поймёт (см листинг 2). Мне это знание досталось тяжёлым путём, после того, как я потратил несколько часов на разбор реализации клиента sftp.

В заключение

Я надеюсь, что Вы увидели достаточно, чтобы оценить Paramiko. Это одна из тех жемчужин в сообществе Python, которая помогает мне в ежедневной работе. Я могу программировать удалённое администрирование, писать тестовые плагины, которые легко исполняют удалённые операции, и всё это без необходимости устанавливать дополнительных демонов на удалённой машине.

SSH везде, и раньше или позже Вы тоже столкнётесь необходимостью писать под него программы. Так почему бы сразу не сэкономить себе время и не воспользоваться Paramiko?

Читайте также: