Могу ли я автоматически добавить новый хост в known_hosts?
Вот моя ситуация: я устанавливаю тестовую систему, которая с центрального клиента запускает несколько экземпляров виртуальной машины, а затем выполняет команды на них с помощью ssh
, Виртуальные машины будут иметь ранее неиспользуемые имена хостов и IP-адреса, поэтому они не будут в ~/.ssh/known_hosts
файл на центральном клиенте.
У меня проблема в том, что первый ssh
Команда запуска нового виртуального экземпляра всегда выдает интерактивную подсказку:
The authenticity of host '[hostname] ([IP address])' can't be established.
RSA key fingerprint is [key fingerprint].
Are you sure you want to continue connecting (yes/no)?
Есть ли способ, которым я могу обойти это и сделать так, чтобы новый хост уже был известен клиентской машине, возможно, с помощью открытого ключа, уже встроенного в образ виртуальной машины? Я действительно хотел бы избежать использования Expect или чего-либо еще, чтобы ответить на интерактивное приглашение, если смогу.
27 ответов
Установить StrictHostKeyChecking
возможность no
либо в конфигурационном файле, либо через -o
:
ssh -o StrictHostKeyChecking=no username@hostname.com
ИМО, лучший способ сделать это заключается в следующем:
ssh-keygen -R [hostname]
ssh-keygen -R [ip_address]
ssh-keygen -R [hostname],[ip_address]
ssh-keyscan -H [hostname],[ip_address] >> ~/.ssh/known_hosts
ssh-keyscan -H [ip_address] >> ~/.ssh/known_hosts
ssh-keyscan -H [hostname] >> ~/.ssh/known_hosts
Это позволит убедиться, что нет повторяющихся записей, что вы застрахованы как для имени хоста, так и для IP-адреса, а также будет хэшировать вывод, что является дополнительной мерой безопасности.
Для ленивых:
ssh-keyscan -H <host> >> ~/.ssh/known_hosts
-H хеширует имя хоста / IP-адрес
Как уже упоминалось, использование сканирования клавиш было бы правильным и ненавязчивым способом сделать это.
ssh-keyscan -t rsa,dsa HOST 2>&1 | sort -u - ~/.ssh/known_hosts > ~/.ssh/tmp_hosts
mv ~/.ssh/tmp_hosts ~/.ssh/known_hosts
Вышеприведенный способ поможет добавить хост, ТОЛЬКО если он еще не добавлен. Это также не безопасно для параллелизма; Вы не должны выполнять сниппет на одном и том же компьютере-источнике более одного раза в одно и то же время, поскольку файл tmp_hosts может быть засорен, что в конечном итоге приведет к раздутию файла known_hosts...
Вы могли бы использовать ssh-keyscan
команда, чтобы захватить открытый ключ и добавить его к вашему known_hosts
файл.
Лучше всего, вы проверите отпечаток каждого нового сервера / хоста. Это единственный способ аутентификации сервера. Без этого ваше SSH-соединение может подвергнуться атаке "человек посередине".
Если вы действительно уверены, что хотите игнорировать проверку отпечатка пальца, тогда второй лучший, менее безопасный вариант - использовать StrictHostKeyChecking=accept-new
, который был представлен в OpenSSH версии 7.6 (2017-10-03):
Первый "accept-new" автоматически примет ранее невидимые ключи, но откажет в соединениях для измененных или недействительных ключей хоста.
Не используйте старое значение StrictHostKeyChecking=no
который никогда не проверяет подлинность сервера вообще. (Хотя смысл этого =no
настройка будет перевернута позже.)
Вот как вы можете включить ssh-keyscan в свою игру:
---
# ansible playbook that adds ssh fingerprints to known_hosts
- hosts: all
connection: local
gather_facts: no
tasks:
- command: /usr/bin/ssh-keyscan -T 10 {{ ansible_host }}
register: keyscan
- lineinfile: name=~/.ssh/known_hosts create=yes line={{ item }}
with_items: '{{ keyscan.stdout_lines }}'
Чтобы сделать это правильно, вы действительно хотите собрать открытые ключи хоста виртуальных машин по мере их создания и поместить их в файл в known_hosts
формат. Затем вы можете использовать -o GlobalKnownHostsFile=...
, указывая на этот файл, чтобы убедиться, что вы подключаетесь к хосту, к которому, по вашему мнению, вы должны подключаться. Однако то, как вы это сделаете, зависит от того, как вы настраиваете виртуальные машины, но, если возможно, считываете это из виртуальной файловой системы или даже заставляете хост печатать содержимое /etc/ssh/ssh_host_rsa_key.pub
во время настройки может сделать свое дело.
Тем не менее, это может не стоить того, в зависимости от того, в какой среде вы работаете и кто ваши предполагаемые противники. Выполнение простого "сохранения при первом подключении" (посредством сканирования или просто во время первого "реального" подключения), как описано в нескольких других ответах выше, может быть значительно проще и все же обеспечивает некоторую степень безопасности. Однако, если вы сделаете это, я настоятельно рекомендую вам изменить файл известных хостов (-o UserKnownHostsFile=...
) в файл, специфичный для данной конкретной тестовой установки; это позволит избежать загрязнения вашего личного известного хост-файла тестовой информацией и упростит очистку теперь бесполезных открытых ключей при удалении ваших виртуальных машин.
Я делаю однострочный скрипт, немного длинный, но полезный, чтобы выполнить эту задачу для хостов с несколькими IP-адресами, используя dig
а также bash
(host=github.com; ssh-keyscan -H $host; for ip in $(dig @8.8.8.8 github.com +short); do ssh-keyscan -H $host,$ip; ssh-keyscan -H $ip; done) 2> /dev/null >> .ssh/known_hosts
Это было бы полным решением, принимая ключ хоста только в первый раз
#!/usr/bin/env ansible-playbook
---
- name: accept ssh fingerprint automatically for the first time
hosts: all
connection: local
gather_facts: False
tasks:
- name: "check if known_hosts contains server's fingerprint"
command: ssh-keygen -F {{ inventory_hostname }}
register: keygen
failed_when: keygen.stderr != ''
changed_when: False
- name: fetch remote ssh key
command: ssh-keyscan -T5 {{ inventory_hostname }}
register: keyscan
failed_when: keyscan.rc != 0 or keyscan.stdout == ''
changed_when: False
when: keygen.rc == 1
- name: add ssh-key to local known_hosts
lineinfile:
name: ~/.ssh/known_hosts
create: yes
line: "{{ item }}"
when: keygen.rc == 1
with_items: '{{ keyscan.stdout_lines|default([]) }}'
Как вы строите эти машины? Вы можете запустить скрипт обновления DNS? Вы можете присоединиться к домену IPA?
FreeIPA делает это автоматически, но по сути все, что вам нужно - это записи SSHFP dns и DNSSEC в вашей зоне (freeipa предоставляет в качестве настраиваемых параметров (dnssec отключен по умолчанию)).
Вы можете получить существующие записи SSHFP с вашего хоста, запустив.
ssh-keygen -r jersey.jacobdevans.com
jersey.jacobdevans.com В SSHFP-1 4d8589de6b1a48e148d8fc9fbb967f1b29f53ebc jersey.jacobdevans.com В SSHFP-2 6503272a11ba6d7fec2518c02dfed88f3d455ac7786ee5dbd72df63307209d55 jersey.jacobdevans.com В SSHFP-1 5a7a1e8ab8f25b86b63c377b303659289b895736 > jersey.jacobdevans.com В SSHFP-2 1f50f790117dfedd329dbcf622a7d47551e12ff5913902c66a7da28e47de4f4b
затем, после публикации, вы добавите VerifyHostKeyDNS yes
в ваш ssh_config или ~/.ssh/config
Если / когда Google решит включить DNSSEC, вы можете войти в ssh без запроса hostkey.
ssh jersey.jacobdevans.com
НО мой домен еще не подписан, так что пока вы увидите....
debug1: ключ хоста сервера: ecdsa-sha2-nistp256 SHA256: H1D3kBF9 / t0ynbz2IqfUdVHhL / WROQLGan2ijkfeT0s
debug1: найдено 4 небезопасных отпечатка в DNS
debug1: соответствующий отпечаток ключа хоста
найдено в DNS. Невозможно установить подлинность хоста "jersey.jacobdevans.com (2605:6400:10:434::10)". Отпечаток ключа ECDSA - SHA256:H1D3kBF9/t0ynbz2IqfUdVHhL/WROQLGan2ijkfeT0s. Соответствующий отпечаток ключа хоста найден в DNS. Вы уверены, что хотите продолжить подключение (да / нет)? нет
У меня была похожая проблема, и я обнаружил, что некоторые из предоставленных ответов лишь частично помогли мне найти автоматизированное решение. Вот то, что я в конечном итоге использовал, надеюсь, это поможет:
ssh -o "StrictHostKeyChecking no" -o PasswordAuthentication=no 10.x.x.x
Это добавляет ключ к known_hosts
и не запрашивает пароль.
Следующее избегает повторяющихся записей в ~/.ssh/known_hosts:
if ! grep "$(ssh-keyscan github.com 2>/dev/null)" ~/.ssh/known_hosts > /dev/null; then
ssh-keyscan github.com >> ~/.ssh/known_hosts
fi
Итак, я искал простой способ обойти неизвестное взаимодействие с хостом при клонировании git-репо, как показано ниже:
brad@computer:~$ git clone git@bitbucket.org:viperks/viperks-api.git
Cloning into 'viperks-api'...
The authenticity of host 'bitbucket.org (104.192.143.3)' can't be established.
RSA key fingerprint is 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40.
Are you sure you want to continue connecting (yes/no)?
Обратите внимание на отпечаток ключа RSA...
Итак, это SSH, это будет работать для git over SSH и просто для SSH в целом...
brad@computer:~$ nmap bitbucket.org --script ssh-hostkey
Starting Nmap 7.01 ( https://nmap.org ) at 2016-10-05 10:21 EDT
Nmap scan report for bitbucket.org (104.192.143.3)
Host is up (0.032s latency).
Other addresses for bitbucket.org (not scanned): 104.192.143.2 104.192.143.1 2401:1d80:1010::150
Not shown: 997 filtered ports
PORT STATE SERVICE
22/tcp open ssh
| ssh-hostkey:
| 1024 35:ee:d7:b8:ef:d7:79:e2:c6:43:9e:ab:40:6f:50:74 (DSA)
|_ 2048 97:8c:1b:f2:6f:14:6b:5c:3b:ec:aa:46:46:74:7c:40 (RSA)
80/tcp open http
443/tcp open https
Nmap done: 1 IP address (1 host up) scanned in 42.42 seconds
Сначала установите nmap на свой ежедневный драйвер. Nmap очень полезен для определенных вещей, таких как обнаружение открытых портов и это - ручная проверка отпечатков SSH. Но вернемся к тому, что мы делаем.
Хорошо. Я либо скомпрометирован в нескольких местах и машинах, которые я проверил, либо более правдоподобным объяснением того, что все происходит так, как надо, является то, что происходит.
Этот "отпечаток пальца" - это просто строка, сокращенная с помощью одностороннего алгоритма для удобства человека, и существует риск того, что более одной строки будут преобразованы в один и тот же отпечаток пальца. Бывает, они называются столкновениями.
Независимо от этого, вернемся к исходной строке, которую мы можем увидеть в контексте ниже.
brad@computer:~$ ssh-keyscan bitbucket.org
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-128
no hostkey alg
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-129
bitbucket.org ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-123
no hostkey alg
Итак, заблаговременно, у нас есть способ запросить форму идентификации у оригинального хоста.
На данный момент мы вручную так же уязвимы, как и автоматически: строки совпадают, у нас есть базовые данные, которые создают отпечаток, и мы можем запросить эти базовые данные (предотвращая столкновения) в будущем.
Теперь, чтобы использовать эту строку таким образом, чтобы не спрашивать о подлинности хостов...
Файл known_hosts в этом случае не использует незашифрованные записи. Вы увидите хэшированные записи, когда увидите их, они выглядят как хэши со случайными символами вместо xyz.com или 123.45.67.89.
brad@computer:~$ ssh-keyscan -t rsa -H bitbucket.org
# bitbucket.org SSH-2.0-conker_1.0.257-ce87fba app-128
|1|yr6p7i8doyLhDtrrnWDk7m9QVXk=|LuKNg9gypeDhfRo/AvLTAlxnyQw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==
Первая строка комментария выводит из себя, но вы можете избавиться от нее простым перенаправлением через соглашение ">" или ">>".
Поскольку я сделал все возможное, чтобы получить незапятнанные данные, которые будут использоваться для идентификации "хоста" и доверия, я добавлю эту идентификацию в мой файл known_hosts в моем каталоге ~/.ssh. Поскольку теперь он будет определен как известный хост, я не получу подсказку, упомянутую выше, когда вы были ребенком.
Спасибо, что остались со мной, вот и все. Я добавляю ключ bitbucket RSA, чтобы я мог взаимодействовать со своими репозиториями git неинтерактивным способом как часть рабочего процесса CI, но независимо от того, что вы делаете, что хотите.
#!/bin/bash
cp ~/.ssh/known_hosts ~/.ssh/known_hosts.old && echo "|1|yr6p7i8doyLhDtrrnWDk7m9QVXk=|LuKNg9gypeDhfRo/AvLTAlxnyQw= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAubiN81eDcafrgMeLzaFPsw2kNvEcqTKl/VqLat/MaB33pZy0y3rJZtnqwR2qOOvbwKZYKiEO1O6VqNEBxKvJJelCq0dTXWT5pbO2gDXC6h6QDXCaHo6pOHGPUy+YBaGQRGuSusMEASYiWunYN0vCAI8QaXnWMXNMdFP3jHAJH0eDsoiGnLPBlBp4TNm6rYI74nMzgz3B9IikW4WVK+dc8KZJZWYjAuORU3jc1c/NPskD2ASinf8v3xnfXeukU0sJ5N6m5E8VLjObPEO+mN2t/FZTMZLiFqPWc/ALSqnMnnhwrNi2rbfg/rd/IpL8Le3pSBne8+seeFVBoGqzHM9yXw==" >> ~/.ssh/known_hosts
Итак, вот как ты остаешься девственницей на сегодня. Вы можете сделать то же самое с GitHub, следуя аналогичным инструкциям в свое время.
Я видел так много сообщений о переполнении стека, в которых говорилось, что вы должны программно добавлять ключ вслепую без какой-либо проверки. Чем больше вы проверяете ключ на разных машинах в разных сетях, тем больше вы можете быть уверены, что хост - это тот, о котором он говорит, - и это лучшее, на что вы можете надеяться на этом уровне безопасности.
НЕПРАВИЛЬНОssh -oStrictHostKeyChecking= нет имени хоста [команда]
НЕПРАВИЛЬНОssh-keyscan -t rsa -H имя хоста >> ~/.ssh/known_hosts
Не делайте ничего из вышеперечисленного, пожалуйста. Вам предоставляется возможность повысить ваши шансы избежать того, чтобы кто-то подслушивал ваши передачи данных через человека, находящегося в середине атаки - воспользуйтесь этой возможностью. Разница заключается в том, что вы в буквальном смысле проверяете, что у вас есть ключ RSA, принадлежащий добросовестному серверу, и теперь вы знаете, как получить эту информацию для сравнения, чтобы вы могли доверять соединению. Просто помните, что больше сравнений с разных компьютеров и сетей, как правило, увеличит вашу способность доверять соединению.
Если вы хотите проверить ключ перед тем, как добавить его вслепую, вы можете использовать этот код:
# verify github and gitlab key
# GitHub
github=SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8
ssh-keyscan github.com >> githubKey
read bit githubkey host <<< $(ssh-keygen -lf githubKey)
if [ "$githubkey" != "$github" ]
then
echo "The GitHub fingerprint is incorrect"
exit 1
fi
echo "github.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTtw7PHkccKrpp0yVhp5HdEIcKr6pLlVDBfOLX9QUsyCOV0wzfjIJNlGEYsdlLJizHhbn2mUjvSAHQqZETYP81eFzLQNnPHt4EVVUh7VfDESU84KezmD5QlWpXLmvU31/yMf+Se8xhHTvKSCZIFImWwoG6mbUoWf9nzpIoaSjB+weqqUUmpaaasXVal72J+UX2B+2RPW3RcT0eOzQgqlJL3RKrTJvdsjE3JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==" | sudo tee -a /etc/ssh/ssh_known_hosts
# GitLab
gitlab=SHA256:ROQFvPThGrW4RuWLoL9tq9I9zJ42fK4XywyRtbOz/EQ
ssh-keyscan gitlab.com >> gitlabKey
read bit gitlabkey host <<< $(ssh-keygen -lf gitlabKey)
if [ "$githubkey" != "$github" ]
then
echo "The GitLab fingerprint is incorrect"
exit 1
fi
echo "gitlab.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCsj2bNKTBSpIYDEGk9KxsGh3mySTRgMtXL583qmBpzeQ+jqCMRgBqB98u3z++J1sKlXHWfM9dyhSevkMwSbhoR8XIq/U0tCNyokEi/ueaBMCvbcTHhO7FcwzY92WK4Yt0aGROY5qX2UKSeOvuP4D6TPqKF1onrSzH9bx9XUf2lEdWT/ia1NEKjunUqu1xOB/StKDHMoX4/OKyIzuS0q/T1zOATthvasJFoPrAjkohTyaDUz2LN5JoH839hViyEG82yB+MjcFV5MU3N1l1QL3cVUCh93xSaua1N85qivl+siMkPGbO5xR/En4iEY6K2XPASUEMaieWVNTRCtJ4S8H+9" | sudo tee -a /etc/ssh/ssh_known_hosts
Ключи GitHub и GitLab могут измениться в случае их взлома. В этом случае проверьте самые свежие здесь и там
Примечание. Возможно, вам потребуется убедиться, что ключ не добавляется дважды. Для этого обратитесь к другим ответам.
Весь этот
- SSH-ключ-сканирования
- SSH-копия-идентификатор
- Предупреждение ключа ECSDA
бизнес продолжал раздражать меня, поэтому я выбрал
Один сценарий, чтобы управлять ими всеми
Это вариант сценария на https://askubuntu.com/a/949731/129227 с ответом Амаду Баха /questions/452911/mogu-li-ya-avtomaticheski-dobavit-novyij-host-v-knownhosts/452935#452935 в цикле.
пример вызова
./sshcheck somedomain site1 site2 site3
Сценарий зацикливает имена сайтов, изменяет файлы.ssh/config и.ssh/known_hosts и выполняет ssh-copy-id по запросу - для последней функции только вызовы теста let ssh завершатся неудачно, например, нажав 3 раза на enter запрос пароля.
скрипт sshcheck
#!/bin/bash
# WF 2017-08-25
# check ssh access to bitplan servers
#ansi colors
#http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.html
blue='\033[0;34m'
red='\033[0;31m'
green='\033[0;32m' # '\e[1;32m' is too bright for white bg.
endColor='\033[0m'
#
# a colored message
# params:
# 1: l_color - the color of the message
# 2: l_msg - the message to display
#
color_msg() {
local l_color="$1"
local l_msg="$2"
echo -e "${l_color}$l_msg${endColor}"
}
#
# error
#
# show an error message and exit
#
# params:
# 1: l_msg - the message to display
error() {
local l_msg="$1"
# use ansi red for error
color_msg $red "Error: $l_msg" 1>&2
exit 1
}
#
# show the usage
#
usage() {
echo "usage: $0 domain sites"
exit 1
}
#
# check known_hosts entry for server
#
checkknown() {
local l_server="$1"
#echo $l_server
local l_sid="$(ssh-keyscan $l_server 2>/dev/null)"
#echo $l_sid
if (! grep "$l_sid" $sknown) > /dev/null
then
color_msg $blue "adding $l_server to $sknown"
ssh-keyscan $l_server >> $sknown 2>&1
fi
}
#
# check the given server
#
checkserver() {
local l_server="$1"
grep $l_server $sconfig > /dev/null
if [ $? -eq 1 ]
then
color_msg $blue "adding $l_server to $sconfig"
today=$(date "+%Y-%m-%d")
echo "# added $today by $0" >> $sconfig
echo "Host $l_server" >> $sconfig
echo " StrictHostKeyChecking no" >> $sconfig
echo " userKnownHostsFile=/dev/null" >> $sconfig
echo "" >> $sconfig
checkknown $l_server
else
color_msg $green "$l_server found in $sconfig"
fi
ssh -q $l_server id > /dev/null
if [ $? -eq 0 ]
then
color_msg $green "$l_server accessible via ssh"
else
color_msg $red "ssh to $l_server failed"
color_msg $blue "shall I ssh-copy-id credentials to $l_server?"
read answer
case $answer in
y|yes) ssh-copy-id $l_server
esac
fi
}
#
# check all servers
#
checkservers() {
me=$(hostname -f)
for server in $(echo $* | sort)
do
os=`uname`
case $os in
# Mac OS X
Darwin*)
pingoption=" -t1";;
*) ;;
esac
pingresult=$(ping $pingoption -i0.2 -c1 $server)
echo $pingresult | grep 100 > /dev/null
if [ $? -eq 1 ]
then
checkserver $server
checkserver $server.$domain
else
color_msg $red "ping to $server failed"
fi
done
}
#
# check configuration
#
checkconfig() {
#https://askubuntu.com/questions/87449/how-to-disable-strict-host-key-checking-in-ssh
if [ -f $sconfig ]
then
color_msg $green "$sconfig exists"
ls -l $sconfig
fi
}
sconfig=~/.ssh/config
sknown=~/.ssh/known_hosts
case $# in
0) usage ;;
1) usage ;;
*)
domain=$1
shift
color_msg $blue "checking ssh configuration for domain $domain sites $*"
checkconfig
checkservers $*
#for server in $(echo $* | sort)
##do
# checkknown $server
#done
;;
esac
Современные версии SSH поддерживают центры сертификации, во многом аналогичные тем, которые используются для SSL/TLS, которые обеспечивают безопасность вашего повседневного просмотра веб-страниц. Это позволяет обойти механизм доверия при первом использовании, поскольку доверие уже установлено центром сертификации. Это работает как для пользователей (авторизованные ключи), так и для хостов (известных хостов).
Обратите внимание, что это усложнит процесс запуска виртуальных машин, поскольку вам потребуются все системы, настроенные на доверие к ЦС, и вам нужно будет, чтобы ваш ЦС подписал ключи хоста для виртуальных машин, прежде чем вы сможете использовать его для пропуска TOFU.
Вот несколько ссылок на документацию по этому поводу:
https://www.lorier.net/docs/ssh-ca.html
https://jameshfisher.com/2018/03/16/how-to-create-an-ssh-certificate-authority/
Вот как сделать коллекцию хостов
определить коллекцию хостов
ssh_hosts:
- server1.domain.com
- server2.domain.com
- server3.domain.com
- server4.domain.com
- server5.domain.com
- server6.domain.com
- server7.domain.com
- server8.domain.com
- server9.domain.com
Затем определите две задачи для добавления ключей к известным хостам:
- command: "ssh-keyscan {{item}}"
register: known_host_keys
with_items: "{{ssh_hosts}}"
tags:
- "ssh"
- name: Add ssh keys to know hosts
known_hosts:
name: "{{item.item}}"
key: "{{item.stdout}}"
path: ~/.ssh/known_hosts
with_items: "{{known_host_keys.results}}"
Чтобы автоматически принимать и запоминать отпечаток пальца на невидимом удаленном сервере git, например, при выполненииgit clone git@example.com
, вы можете использовать gitGIT_SSH_COMMAND
вместе с ssh-o StrictHostKeyChecking=accept-new
:
GIT_SSH_COMMAND="ssh -o StrictHostKeyChecking=accept-new" git clone git@example.com
Если у вас уже есть
.pub
тогда кто-нибудь говорит вам о
ssh-keyscan
просит вас рискнуть атаковать MitM.
Я настраиваю тестовую систему, которая из центрального клиента запускает несколько экземпляров виртуальных машин, а затем выполняет на них команды через ssh.
У этого ответа от StackOverflow есть лучший и более правильный ответ. Вы должны получить
.pub
файл из надежного источника - ваш системный загрузчик должен позвонить домой и предоставить файл системе управления.
#!/usr/bin/env bash
: "${pubkey=-"$2"}"
: "${host=-"$1"}"
TMP_KNOWN_HOSTS=$(mktemp)
echo "${host}" "$(cat "${pubkey}")" > "${TMP_KNOWN_HOSTS}"
ssh-keygen -H -f "${TMP_KNOWN_HOSTS}"
ssh-keygen -F "${host}" -f "${TMP_KNOWN_HOSTS}" | tee ~/.ssh/known_hosts
shred "${TMP_KNOWN_HOSTS}.old"
rm -f "${TMP_KNOWN_HOSTS}" "${TMP_KNOWN_HOSTS}.old"
Вы можете попробовать это с ключами локального хоста:
$ for pubkey in /etc/ssh/ssh_host_*.pub; do ./add_pubkey localhost "${pubkey}"; done
Поскольку это «виртуальные машины», вы сможете войти в них другими способами (например, смонтировать файловую систему) и получить ключи.
Как только вы получите открытый ключ, вы сможете создать свои «известные_хосты» (объединить открытые ключи).
Или наоборот: нажмите известный закрытый ключ на каждом подчиненном устройстве, получив доступ к файловой системе виртуальной машины.
Это решение является излишним для простых случаев, когда вы владеете своей средой, но оно нецелесообразно для атаки «человек посередине»...
Для всех, кто жалуется на проблемы MITM:
Во-первых, если вы боитесь атак MITM, переосмыслите развертывание инфраструктуры и проектирование сети.
Но если у вас нет выбора. Это может быть жизнеспособным решением:
На хосте с SSHD выполните:
ssh-keygen -l -v -E sha256 -f /etc/ssh/ssh_host_ecdsa_key.pub
На вашем клиентском хосте SSH выполните:
ssh -o Visualhostkey=yes -o FingerprintHash=sha256 [электронная почта защищена]
А теперь сравните картинки, похожи ли они? Поздравляем, введите «да» на своем клиентском хосте, чтобы автоматически добавить его в списокknown_hosts. Они разные? Возможно, это MITM-атака, а возможно, вы просто ведете себя небрежно. Это нормальное решение, если у вас есть доступ только по паролю. Будем надеяться, что ни у кого нет вашего пароля.
Но давайте копнем глубже и проанализируем реальную проблему:
Проблема на самом деле скорее физическая, чем техническая. Спросите себя, что такое первый сетевой уровень? Думаю об этом.
Некоторые жизнеспособные решения этой проблемы:
Если вы находитесь в том же физическом месте. Возьмите новый маршрутизатор, коммутатор и создайте локальную сеть, не подключенную к Интернету или какой-либо другой неизвестной сети. Здесь вы можете использовать StrictHostKeyChecking=no сколько угодно, не беспокоясь о MITM. То же самое касается виртуальных машин, которые вы запускаете непосредственно на своей рабочей станции в изолированной сети. Не нужно беспокоиться об атаках MITM, если вы контролируете физический сетевой уровень.
Подумайте о покупке KVM-переключателя, используйте HPE iLO, IPMI или даже Pi-KVM, если ваш сервер его поддерживает. Но даже в этом случае эти службы также должны находиться в изолированной сети. Вы также можете использовать Intel-ME на ноутбуках или рабочих станциях, но это уже совсем другая проблема.
Скопируйте отпечаток ключа вашего сервера на USB-накопитель, вернитесь к своему клиенту и вручную добавьте отпечаток пальца в известные_хосты с USB-накопителя. Это сложно, но вы сможете спать по ночам. Вы даже можете несколько автоматизировать это с помощью скрипта. Если вы хотите проявить сверхумность и произвести впечатление на высокомерного миньона над вами, автоматизируйте это с помощью «Rubber Ducky» или чего-то подобного. Но не умничай. Чья-то «умность» вообще привела нас сюда.
Рассмотрите возможность добавления ключей во время установки клиентов. Например, в Debian вы можете использовать Preseed и собственный ISO. Здесь есть много-много решений.
Если у вас нет доступа к расположению серверов. Позвоните другу, которому вы доверяете, и попросите его проверить отпечаток пальца, прежде чем добавлять его в списокknown_hosts. Но часто, если у вас нет физического доступа, вы, вероятно, работаете в компании, у которой уже есть безопасные решения для подобных ситуаций. Если нет, подумайте о смене работы или проявите смекалку и предложите своему начальнику лучшее решение в обмен на повышение. (не забудьте упомянуть слово «программа-вымогатель» не менее 5 раз во время разговора).
Если все вышеперечисленное не для вас. И вы отчаянно хотите подключиться к неизвестному компьютеру где-нибудь в Интернете, используя незашифрованную цепочку прокси. Вам следует пересмотреть свой жизненный выбор. Или вы можете быть просто человеком посередине.
if ! ssh-keygen -F HOST; then
ssh-keyscan HOST >> ~/.ssh/known_hosts
fi
или в случае пользовательского порта:
if ! ssh-keygen -F [HOST]:PORT; then
ssh-keyscan -p PORT HOST >> ~/.ssh/known_hosts
fi
Но это уязвимо для MITM.
Должно быть, это редкий случай, но мне нужно было подключить 2docker
контейнеры, использующие SSH в последнее время. Сначала я заставил его работать , используя :
/usr/sbin/sshd
wait4ports tcp://"$1":22
if ! ssh-keygen -F "$1"; then
ssh-keyscan "$1" > ~/.ssh/known_hosts
fi
Тогда без
ssh-keyscan
(путем предварительного создания ключей и внедрения их с хоста):
awk -v "host=$1" '{print host, $1, $2}' \
/etc/ssh/ssh_host_ecdsa_key.pub \
/etc/ssh/ssh_host_ed25519_key.pub \
/etc/ssh/ssh_host_rsa_key.pub \
> ~/.ssh/known_hosts
/usr/sbin/sshd
Ключи хоста можно сгенерировать следующим образом (ну, может быть, есть более простой способ):
docker run --rm alpine:3.15 sh -euc '
(apk add openssh
ssh-keygen -A
cd /etc/ssh
tar czf keys.tar.gz ssh_host*) >/dev/null
cat ~/.ssh/keys.tar.gz
' > keys.tar.gz
tar xf keys.tar.gz
rm keys.tar.gz
Я столкнулся с аналогичной проблемой, когда, несмотря на использование вышеупомянутого проверенного решения, мой ssh не работал, потому что файл known_hosts отсутствовал в каталоге ~/.ssh/, а файловая система была доступна только для чтения. ТАК, во время выполнения мне также не удалось создать файл ~/.ssh/known_hosts.
Если вы столкнулись с подобной проблемой, посмотрите, можете ли вы записать файл known_hosts в папку /tmp. В большинстве случаев запись разрешена даже в файловой системе, доступной только для чтения.
Позже в команде ssh вы можете указать ssh для чтения файла known_hosts из местоположения /tmp.
ssh -o UserKnownHostsFile = /tmp / known_hosts -o StrictHostKeyChecking=no user_name@destination_server_ip
Вот мой крайний случай:
Я создаю сценарий Fabric 2.5 для развертывания веб-сайта на новом сайте. В какой-то момент он создаст ключ ssh и добавит открытый ключ в gitlab, используя его api. Затем он клонирует репо (содержащий исходный код веб-сайта). Команда clone не удалась в сценарии, и когда я пошел на сервер и вручную запустил команду, у меня был
The authenticity of host 'host.com ()' can't be established. Are you sure you want to continue connecting (yes/no)?
незамедлительный.
Сначала моим решением было поискать, как его автоматически принять, но из соображений безопасности я добавил
pty=True
arg в
c.run("command")
функция, и мне был предоставлен доступ к ошибке во время выполнения моего скрипта.
Используйте эту команду, чтобы добавить хост в ~/.ssh/known-hosts (и не добавляйте дубликаты), как указано здесь .
например добавлениеgitlab.com
ssh-keygen -F gitlab.com || ssh-keyscan gitlab.com >> ~/.ssh/known_hosts