#git #ssh #ansible
Сценарий. Пользователь alice заходит на сервер msk-web-01 (centos7.2, selinux включен)
по своему ssh ключу и хочет в папке /www/mysite.ru/htdocs/ (владелец папки -- пользователь
apache) запустить команду git pull.
Для этого написан небольшой батник:
#!/bin/sh
#see http://ru.stackoverflow.com/questions/548545/ for details
sudo setfacl -m apache:x $(dirname "$SSH_AUTH_SOCK")
sudo setfacl -m apache:rwx "$SSH_AUTH_SOCK"
cd /www/mysite.ru/htdocs/
pwd
sudo su -s /bin/sh apache -c "/usr/bin/git pull"
....
И он работает... выдавая многочисленные предупреждения:
/www/site1.ru/htdocs
Could not create directory '/usr/share/httpd/.ssh'.
Failed to add the ECDSA host key for IP address '1.2.3.4' to the list of known hosts
(/usr/share/httpd/.ssh/known_ho).
Already up-to-date.
/www/site2.ru/htdocs
Could not create directory '/usr/share/httpd/.ssh'.
Failed to add the ECDSA host key for IP address '1.2.3.4' to the list of known hosts
(/usr/share/httpd/.ssh/known_ho).
Already up-to-date.
Задача -- избавиться от этих лишних записей, добившись чистого вывода при помощи
добавления записей в глобальный known_hosts.
Требуемый эффект можно получить если создать /usr/share/httpd/.ssh/known_hosts со
строкой CheckHostIP no:
/www/site1.ru/htdocs
Already up-to-date.
/www/site2.ru/htdocs
Already up-to-date.
/www/site3.ru/htdocs
Already up-to-date.
Разумеется, такой способ не рассматривается как решение задачи, так же как и другие
обходные пути типа "совсем отключить проверку" (скажем, раз или два)
PS Ключи сохранял одним из двух способов, первый:
ssh-keyscan -t rsa,dsa git.mycomany.ru >> /etc/ssh/ssh_known_hosts
второй:
ssh-keyscan git.mycomany.ru >> /etc/ssh/ssh_known_hosts
Разница не особо велика: в первом случае Failed to add the RSA host, во втором -
Failed to add the ECDSA host key.
И даже так с горя:
ssh-keyscan git.mycomany.ru,1.2.3.4 >> /etc/ssh/ssh_known_hosts
Ответы
Ответ 1
как выяснилось в комментариях, /usr/share/httpd — это домашний каталог пользователя
apache. именно этому пользователю и должен принадлежать каталог (и всё его содержимое)
/usr/share/httpd/.ssh:
$ sudo chown -R apache /usr/share/httpd/.ssh
также он должен быть доступен только самому пользователю:
$ sudo chmod -R go= /usr/share/httpd/.ssh
добавить публичные ключи (по умолчанию — типов rsa, ecdsa и ed25519 — см. $ man ssh-keyscan)
машины git.mycompany.ru в файл «известных хостов» пользователя apache (/usr/share/httpd/.ssh/known_hosts)
можно так:
$ ssh-keyscan git.mycompany.ru | sudo tee -a /usr/share/httpd/.ssh/known_hosts
если этот файл до этого не существовал, команды из первого пункта надо повторить
после этой операции.
вместо манипуляций с acl-ами (setfacl ...) лучше добавить строку
Defaults env_keep+=SSH_AUTH_SOCK
в /etc/sudoers (или даже ещё лучше — в файл с произвольным именем, не содержащем
точек и тильд в имени, в каталоге /etc/sudoers.d). подробнее см., например, здесь.
редактировать эти файлы лучше через «обёртку» visudo — см., например, здесь.
уточнение в связи с требованием не использовать каталог ~/.ssh пользователя apache.
чтобы не использовать ~/.ssh/config, но иметь возможность указать особую конфигурацию
для конкретного пользователя, можно воспользоваться директивой match user в /etc/ssh/ssh_config,
добавив в конец (это важно — см. $ man ssh_config на предмет опции match) этого файла
примерно следующее:
match user apache
# какие-либо персональные настройки для пользователя apache
чтобы процесс ssh не использовал ~/.ssh/knonw_hosts, можно (способом, описанным в
предыдущем пункте) переопределить для данного пользователя значение конфигурационной
переменной userknownhostsfile, указав в ней, например, файл /etc/ssh/ssh_known_hosts
(или любой другой доступный пользователю для чтения):
userknownhostsfile /etc/ssh/ssh_known_hosts
нужные ключи в этот файл, разумеется, уже должны быть добавлены заранее. например,
тем способом, что описан во втором пункте первой части ответа.
возможно, для пользователей по умолчанию включена необходимость хешировать записи
в known_hosts, тогда процесс ssh попытается перезаписать файл с ключами. чтобы он этого
не делал, укажите (хотя бы для этого пользователя) не хешировать записи, добавив (как
описано в первом пункте) строку:
hashknownhosts no
Ответ 2
В итоге, всё оказалось достаточно просто.
Сначала ещё раз о постановке задачи. Есть ряд доверенных серверов организации, между
которыми сотрудникам нужно перемещаться с сохранением авторизации (ForwardAgent), поэтому
нужно уметь заполнять файл /etc/ssh/ssh_known_hosts доверенными данными.
Во-первых, гит в своём общении с удалёнными репозиториями по протоколу ssh полагается
на системные утилиты, особых настроек ssh-подключения нет -- можно почитать про хаки
с созданием файла ssh и экспортированием переменной GIT_SSH. Поэтому изначально в вопросе
было больше про ssh, чем про конкретно git.
Во-вторых, когда я начал разбираться с ключами (rsa, dsa, esdca) и версиями протоколов
-- я решил не только абстрагироваться от гит, но и от ансибл - чтобы не влияло, на
всякий случай.
После тестов у меня получилось, что ключи были сгенерированы правильно, настройки
ssh (как дефолтные центоса, так и мои кастомные) тоже не влияют на работу.
Всё, что нужно -- это сдампить отпечатки и записать в общий known_hosts:
ssh-keyscan -t rsa,dsa git.mycomany.ru >> /etc/ssh/ssh_known_hosts
Включение хеширования не влияет на итог - тоже. А что влияет?
Как ни странно -- выяснилось, что влияет ansible. Если файла /etc/ssh/ssh_known_hosts
на диске нет -- он создаёт файл с правами rw-r--r-- но стоит лишь ещё раз запустить
повторно -- права чудесным образом становятся rw-------
Разумеется, что процессы, которые хотят прочитать хранилище и проверить, нет ли там
такого отпечатка обламываются и ничего не находят. Стоит лишь восстановить права на
файл -- и работа снова восстанавливается.
Пример заполнения ключей практически такой же, как и в документации:
- name: global pubkes for servers
known_hosts:
path='/etc/ssh/ssh_known_hosts'
name='{{ item }}'
key="{{ lookup('file', 'files/pubkeys/{{ item }}.pub') }}"
with_items:
- git.mycompany.ru
Я хотел было создать баг на гитхабе -- но перед заведением поискал, нет ли готового.
И нашёл, вот: https://github.com/ansible/ansible-modules-extras/issues/2513