UMGUM.COM 

Slave + Cygwin + OpenSSH ( Подключение агентов исполнения "Jenkins Slaves" в операционных системах "MS Windows" в среде "Java 11+", через SSH-подключение. )

18 февраля 2021  (обновлено 28 марта 2021)

OS: "Linux Debian/Ubuntu", "MS Windows 7/8/10/2008/2012/2016/2019".
Apps: "Cygwin", "OpenSSH", "Cmd/PowerShell", "Java 11", "Jenkins".

Задача: подключение агентов исполнения "Jenkins Slaves" в операционных системах "MS Windows" в среде "Java 11+", через SSH-соединение.

Немного о том, отчего возникла надобность в написании этой инструкции. Ранее, когда "Jenkins" запускался в среде "Java 8", на операционных системах "Microsoft Windows" посредством технологии "WebStart (JNLP)" можно было быстро и непринуждённо запускать агенты исполнения "Jenkins Slaves" прямо из браузера, в пару щелчков мыши. Но из "Java 11" поддержка устаревшей "WebStart" была вырезана и теперь запуск агентов на windows-системах приходится осуществлять также, как и для linux-систем - через сеансы SSH-подключений. Это влечёт за собой необходимость устанавливать на windows-системах службы "OpenSSH", помимо "Java", в любом случае необходимой.

Последовательность дальнейших действий такова:

1. Установка "OpenSSH Server" и "Syslog-NG";
2. Настройка подсистемы журналирования "(cygwin) Syslog-NG";
3. Настройка сервера "(cygwin) OpenSSH Server";
4. Об интеграции и пользователях "(cygwin) OpenSSH Server";
5. Наладка аутентификации пользователей "(cygwin) OpenSSH Server" по ssh-ключу;
6. Установка среды исполнения "Java/OpenJDK" в ОС "MS Windows";
7. Подключение "Jenkins Slave" через "(cygwin) OpenSSH Server" на ОС "MS Windows";
8. Проверка работоспособности "Jenkins Slave" через простейшую задачу типа "Pipeline".


Установка "OpenSSH Server" и "Syslog-NG".

Начиная с "MS Windows 10 (Workstation)/2019 Server" в операционную систему как компонент был встроен "OpenSSH Server". С 2020-го года первые страницы вывода поисковых машин заняты рекомендациями использовать эту возможность для наладки SSH-подключений к windows-системам. Однако, производство ставит перед нами задачу сделать решение, работоспособное не только лишь в последних версиях операционной системы. Нам требуется, чтобы агента исполнения "Jenkins" можно было запустить как на "MS Win 2019", так и на всех предыдущих версиях этой операционной системы, где встроенного SSH-сервера нет.

Решение давно найдено - в рамках проекта "Cygwin" множество утилит и приложений, изначально написанных для posix-систем (это BSD, "Linux", etc.), собраны их исходных кодов с адаптацией до возможности исполнения в среде операционных систем "MS Windows" посредством трансляции posix-вызовов через библиотеку "cygwin1.dll". В проекте "Cygwin" поддерживается и отлично работают "OpenSSH Server", а также подсистема журналирования "Syslog-NG" (применение её необязательно, но удобно для локализации возможных проблем как при первичной наладке, так и эксплуатации).

Процедура установки приложений "Cygwin" проста и очевидна. С заглавной сайта проекта "https://cygwin.com", из раздела "Installing Cygwin" скачивается утилита "setup-x86_64.exe", посредством которой в дальнейшем осуществляется загрузка и развёртывание дистрибутивов, а также обновление уже установленных приложений. Настройка функциональности приложений как таковых при этом не производится.

Настройка подсистемы журналирования "(cygwin) Syslog-NG".

Надёжнее всего работать с компонентами "Cygwin" через имеющийся в его комплекте эмулятор терминала "mintty" - в нём уже преднастроена масса специфичных переменных окружения, помогающих обеспечить совместимость между posix-приложениями и несвойственной им среде исполнения. Обычно при инсталляции "Cygwin" ярлыки запуска "mintty" выводятся на рабочий стол и в стартовое меню.

Запускаем "mintty" в контексте пользователя, обладающего административными привилегиями (например, через пункт "Run as administrator" контекстного меню ярлыка или непосредственно "mintty"):

C:\Cygwin64\bin\mintty.exe

Запускаем конфигуратор "Syslog-NG":

$ syslog-ng-config

Creating default syslog-ng configuration files in /etc/syslog-ng
....
Do you want to install syslog-ng as service?
(Say "no" if it's already installed as service) (yes/no) yes

The service has been installed under LocalSystem account.
To start the service, call `net start syslog-ng' or `cygrunsrv -S syslog-ng'.
....

Результатом деятельности конфигуратора будет регистрация подсистемы журналирования в качестве автоматически запускаемого системного сервиса.

Мне не нравится предлагаемое разработчиками отображаемое название сервиса, и я меняю его:

C:\> sc config syslog-ng DisplayName= "Syslog-NG (Cygwin64)"

Запускаем сервис подсистемы журналирования (или он стартует сам при после несущей системы):

C:\> net start syslog-ng

The Syslog-NG (Cygwin64) service is starting.
The Syslog-NG (Cygwin64) service was started successfully.

По умолчанию "Syslog-NG" сваливает записи о всех событиях в один журнал "/var/log/messages". При желании можно отфильтровать события сервиса "sshd" с выводом их в отдельный журнал:

$ vi /etc/syslog-ng/syslog-ng.conf

....
# Location of the "OpenSSH Server" event log, filter and processing rule
destination d_sshd { file("/var/log/sshd.log"); };
filter f_sshd { program("sshd"); };
log { source(s_local); filter(f_sshd); destination(d_sshd); };
....

# Additional main filter with an exception for "OpenSSH Server"
filter f_local { not filter(f_sshd); };

# Modification of the main processing rule with the addition of a filter
log {
  ....
  filter(f_local);
....
};

Для принятия изменения в фильтрах потребуется перезапустить сервис журналирования:

C:\> net restart syslog-ng

Настройка сервера "(cygwin) OpenSSH Server".

Запускаем "mintty" в контексте пользователя, обладающего административными привилегиями (например, через пункт "Run as administrator" контекстного меню ярлыка или непосредственно "mintty"):

C:\Cygwin64\bin\mintty.exe

Запускаем конфигуратор "OpenSSH Server":

$ ssh-host-config

....
*** Info: Creating default /etc/ssh_config file
*** Info: Creating default /etc/sshd_config file
....
*** Query: Should StrictModes be used? (yes/no) yes
....
*** Query: Do you want to install sshd as a service? (yes/no) yes
....
*** Query: Enter the value of CYGWIN for the daemon: []
....
*** Info: The sshd service has been installed under the LocalSystem
*** Info: account (also known as SYSTEM). To start the service now, call
*** Info: `net start cygsshd' or `cygrunsrv -S cygsshd'.
....

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

Запускаем "cmd" в контексте пользователя, обладающего административными привилегиями (например, через пункт "Run as administrator" контекстного меню ярлыка или непосредственно "cmd"):

C:\> sc query state= all | find "sshd"
C:\> sc delete cygsshd

Как вариант, можно не удалять сервис, а поменять что-то - например отображаемое имя:

C:\> sc config cygsshd DisplayName= "OpenSSH Server (Cygwin64)"

Запускам сервис:

C:\> net start cygsshd

The OpenSSH Server (Cygwin64) service is starting.
The OpenSSH Server (Cygwin64) service was started successfully.

По умолчанию openssh-сервер пишет в журнал только события аутентификации (как успешные, так и нет), и этого вполне достаточно для начала работы. Если будет нужно увеличить детализацию, то в этом помогут опции "SysLogFacility" и "LogLevel" конфигурационного файла "/etc/sshd_config".

По умолчанию пользователям доступна как парольная, так и ключевая аутентификация, а также возможность подключения по протоколу SFTP. За это отвечают следующие опции конфигурационного файла "(cygwin) OpenSSH Server":

C\> notepad C:\Cygwin64\etc\sshd_config

....
PasswordAuthentication yes
....
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
....
Subsystem sftp /usr/sbin/sftp-server
....

Финальным этапом подготовки к работе "OpenSSH Server" в "MS Windows" посредством "Windows Firewall" разрешаем серверу принимать подключения на порту TCP:22.

Запускаем "cmd" в контексте пользователя, обладающего административными привилегиями (например, через пункт "Run as administrator" контекстного меню ярлыка или непосредственно "cmd"):

C:\> netsh advfirewall firewall add rule name= "OpenSSH Server (Cygwin64)" dir=in action=allow protocol=TCP localport=22

Проверка функциональности "(cygwin) OpenSSH Server".

Создаём пользователя для агента исполнения "Jenkins Slave", например с именем "jenkins-group0" и вводим его в группу "Administrators" для того, чтобы тот мог в дальнейшем инсталлировать и перезапускать сервисы.

Подключаемся к настроенному выше ssh-серверу, запущенному в операционной системе "MS-Windows":

$ ssh user@win-dev1.example.net

user@WIN-DEV1 ~
$

Запускаем в cygwin-ssh-сеансе командную оболочку "Windows PowerShell":

user@WIN-DEV1 ~
$ powershell

Windows PowerShell
....
PS C:\cygwin64\home\user>

При подключении из linux-систем к запущенному в "MS Windows" cygwin-openssh-серверу иногда могут наблюдаться проблемы передачи сигнальных символов, особо ярко выражающиеся в практической невозможности использования редактора "vi". Вероятная причина в несогласованности протоколов используемых псевдо-терминалов: например, на клиентской стороне это "xterm", а на стороне SSH-сервера это "mintty". Самое простое - явно указать в ssh-сеансе, какой эмулятор терминала следует использовать. Это можно сделать в уже открытом сеансе, командой "export TERM=mintty", или послав соответствующую переменную окружения при инициализации ssh-сеанса:

$ TERM=mintty ssh -o "SendEnv TERM" user@win-dev1.example.net

Об интеграции и пользователях "(cygwin) OpenSSH Server".

Большое количество популярных инструкций по настройке "OpenSSH Server", запускаемого в среде "Cygwin" в "MS Windows", говорят о том, что пользователей openssh-сервиса нужно явно регистрировать в среде "Cygwin" (как минимум внося их в конфигурационный файл "/etc/passwd").

На самом деле углубленное чтение документации в части описания методов сопоставления политик безопасности NT (MS Windows) и "Posix" (BSD, Linux) (https://cygwin.com/cygwin-ug-net/ntsec.html#ntsec-mapping) даёт понять, что современные реализации "Cygwin" уже давно (с 2015-го) избавляют нас от необходимости отдельно регистрировать уже имеющихся в несущей системе "MS Windows" пользователей:

....
Starting with Cygwin 1.7.34, Cygwin uses an automatic, internal translation from Windows SID to POSIX UID/GID.
....
If the first process in a Cygwin process tree determines that no /etc/passwd or /etc/group file is present, no other process in the entire process tree will try to read the files later on. This is done for self-preservation. It's rather bad if the uid or gid of a user changes during the lifetime of a process tree.
....

Внутри эмулятора терминала "mintty" (используемого также и в качестве оболочки для openssh-сеансов) хорошо перехватываются обращения к файловой структуре несущей windows-системы. Например, несмотря на то, что по умолчанию файловые posix-утилиты оперируют адресами вроде "/etc/...", префикс вроде "C:" будет прозрачно транслироваться в запрос к структуре "/cygdrive/c", которая отображает в себе иерархию файловой системы диска "C:".

Наладка аутентификации пользователей "(cygwin) OpenSSH Server" по ssh-ключу.

Прежде всего на стороне, откуда будут исходить ssh-подключения, например персональном компьютере пользователя или CI/CD-сервере, должна иметься пара ssh-ключей: "приватная (закрытая)" и "публичная (открытая)". Создаём ssh-ключи, при необходимости:

$ mkdir -p -m 700 /usr/local/etc/jenkins/.ssh/jenkins && cd /usr/local/etc/jenkins/.ssh/jenkins && ssh-keygen -q -t rsa -b 2048 -f ./id_rsa -P "" -C "User jenkins"

Через ssh-сеанс, который мы настроили и открыли ранее с парольной аутентификацией, настраиваем доступ посредством ключевой аутентификации:

$ ssh jenkins@win-dev1.example.net

На целевом windows-компьютере в "домашней" директории пользователя структуры "Cygwin", через ssh-сеанс или просто в псевдо-терминале "mintty", добавляем в специальном файле открытую часть ssh-ключа пользователя "jenkins":

jenkins@WIN-DEV1 ~
$ export TERM=mintty
$ mkdir.exe ~/.ssh
$ vi.exe ~/.ssh/authorized_keys

ssh-rsa AAA...l2w==

Закрываем доступ к ключевой информации от посторонних:

$ chmod.exe -R o-rwx ~/
$ chmod.exe -R go-rwx ~/.ssh

Теперь для подключения к ssh-серверу не потребуется вводить пароль, так как аутентификация будет производиться с более удобным и безопасным методом ssh-ключей:

$ ssh -i /usr/local/etc/jenkins/.ssh/jenkins/id_rsa jenkins@win-dev1.example.net

Установка среды исполнения "Java/OpenJDK".

Не уверен, что требование к совпадению версий среды исполнения для сервера "Jenkins" и его агентов "Slave" жёсткое, но в отсутствии других java-приложений проще и на стороне CI/CD-агентов установить ту же "Java 11".

Лично я загружаю дистрибутив "OpenJDK JRE 11 Windows 64-bit MSI", предназначенный для развёртывания в операционных системах "MS Windows", с сайта одного из разработчиков "Java" - "developers.redhat.com":

Также хорошим, и даже более простым, вариантом будет скачать немного другой вариант сборки от сообщества "AdoptOpenJDK".

Чтобы после установки "Java" и дополнения переменной "PATH" таковая обновилась в контексте cygwin-приложений последние следует перезапустить (как вариант можно в дополнение запускать службу "cygserver", которая будет следить за изменением системного окружения и обновлять среды исполнения cygwin-приложений):

C:\> net restart cygsshd

Проверяем, доступна ли свежеустановленная "Java" в эмуляторе терминала "mintty":

user@WIN-DEV1 ~
$ java -version

openjdk version "11.0.10" 2021-01-19 LTS
....

Подключение "Jenkins Slave" через "(cygwin) OpenSSH Server" на ОС "MS Windows".

Все предварительные работы в целевой windows-системе мы уже произвели, и остальное - в web-интерфейсе "Jenkins".

В "Jenkins v2" для хранения частных переменных окружения, паролей, ключей и сертификатов используется централизованная подсистема "Credentials Provider". Прежде всего добавляем подраздел для хранения "ключей", доступных только при явном указании на связь с указанным именем области:

Jenkins -> Credentials -> System -> Add domain:
  Domain Name: win-dev1.example.net

Добавляем ssh-ключи в область домена подключаемой "ноды" ("закрытый ключ" достаём из файла "./id_rsa", полученного в примере выше):

Jenkins -> Credentials -> System -> win-dev1.example.net -> Add Credentials:
  Kind: SSH Username with private key
  Scope: System (Jenkins and nodes only)
  Description: User jenkins for node win-dev1.example.net
  Username: jenkins
  Private Key:
    Enter directly:
      Key: -----BEGIN RSA PRIVATE KEY-----
           MIIEpQIBAAKCAQEA3nh9A9eCwl03...
           ....

Теперь настроим подключение "Jenkins Server" к "Jenkins Slave":

Jenkins -> Manage Jenkins -> Manage Nodes -> Permanent Agent:
  Node name: win-dev1.example.net
  Remote root directory: C:/Users/jenkins/.jenkins
  Labels: shell win-dev1 master
  Usage: Only build jobs with label expressions matching this node
  Launch method: Launch agent via SSH
    Host: win-dev1.example.net
    Credentials: jenkins (User for node win-dev1.example.net)
    Host Key Verification Strategy: Manuality trusted key Verification Strategy
  Availability: Keep this agent online
  Node Properties:
    Environment variables: on

В соответствии с выбранным методом дополнительной проверки подлинности соединения SSH-подключение к системе "Jenkins Slave" не состоится до тех пор, пока мы не подтвердим доверие к полученному от удалённого сетевого узла "fingerprint"-у:

Jenkins -> Manage Jenkins -> Manage Nodes -> win-dev1.example.net -> Trust SSH Host Key:
  Do you want to trust the SSH Host Key with fingerprint ... for future connections to this host? yes

По завершению настройки подключения к "Jenkins Slave" велим запустить агента, после чего "Jenkins Server" соединиться с целевой "нодой" (под управлением операционной системы "MS Windows") по SSH, загрузит туда посредством SFTP исполняемый файл агента "remoting.jar" и запустит его в режиме ожидания команд. Таких агентов в целевой системе может быть загружено неограниченно много, например в контексте отдельных пользователей, вроде "jenkins1", "jenkins2", "jenkinsX".

Проверка работоспособности "Jenkins Slave" через простейшую задачу типа "Pipeline".

Описываем "pipeline" (формат "Declarative", примеры "Pipeline), основная цель которого состоит в проверке необходимого минимума прав доступа и корректной работы в операционной системе с национальным набором символов (в нашем случае русского языка):

New Item (Job):
  Item name: project0_Hello
  Pipeline project:
    ....
    Pipeline:
      Definition: Pipeline script
      Script:
// Jenkins Declarative Pipeline
pipeline {
  agent none
  stages {
    stage('One') {
      agent {label "shell && win-dev1 && master"}
      steps {
        echo 'Hello & Привет!'
        sh 'printenv'
        sh 'set'
        sh "cmd /c echo hello & привет"
        bat encoding: 'UTF-8', script: """
          chcp 65001
          mkdir "${USERPROFILE}/test1Тест2"
          cd "${USERPROFILE}"
          dir
        """
        powershell encoding: 'UTF-8', script: '''
          Set-WinSystemLocale en-US
          New-Item -ItemType directory -Force -Path "${HOME}/test2Тест3"
          Get-ChildItem
          Set-Location -Path "${HOME}"
          Get-ChildItem
        '''
      }
    }
  }
}


Заметки и комментарии к публикации:


Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )