Далее я говорю о клиенте OpenSSH, установленном по умолчанию на debian.
Я хотел бы иметь несколько (под) доменов, указывающих на мой сервер (а) (то есть несколько на сервер), то есть database.example.com, webserver.example.com и т. д. Я хочу этого, потому что у меня несколько серверов, и иногда я не знаю наизусть, какая служба на каком сервере работает. Я хочу управлять этим с помощью DNS, имея субдомен для каждой службы, а затем я могу использовать этот субдомен для SSH на правильном сервере, не запоминая, на каком сервере работает служба.
Проблема: кажется, что отпечаток пальца включить доменное имя. Итак, если database.example.com и webserver.example.com указывают на один и тот же IP-адрес, и я использовал database.example.com и проверил отпечаток пальца (поэтому он добавлен в known_hosts), тогда мне нужно снова выполнить проверку, если я подключусь к SSH сервер через webserver.example.com позже.
Я не понимаю, почему здесь используется домен, а не IP-адрес, на который разрешается домен. Есть ли способ использовать IP вместо домена в отпечатке пальца? (может быть, какой-то вариант конфигурации).
И если это так, может ли это вызвать проблемы с безопасностью?
И почему это вообще реализовано таким образом? Кроме того, насколько я понимаю, отпечаток получен из открытого ключа сервера, для которого только сервер имеет соответствующий закрытый ключ. Так зачем вообще нужно включать что-то вроде домена или IP? Разве это не мешает мне случайно подключиться к одному из моих других серверов, которые я сохранил в known_hosts?
Добавление ключей для каждого субдомена, который я использую для подключения к серверу на known_hosts, - мой наименее предпочтительный вариант, так как это намного больше работы и предлагает игнорировать проверку ключа, так как каждый привык к тому факту, что несколько раз спрашивает, верен ли ключ для одного и того же сервера.
Я думаю этот пост имеет отношение, но он просто говорит, что он обработан таким образом, а не почему и есть ли способ изменить это поведение.
Заранее спасибо
Изменить:
Я также нашел этот пост , в котором теперь предлагается отключить StrictHostKeyChecking
, но, насколько я понимаю, это позволяет добавлять все отпечатки пальцев по ssh, что, насколько я понимаю, является проблемой с точки зрения безопасности. Я хочу, чтобы, даже если я использую домен для подключения к серверу, IP-адрес использовался для проверки отпечатков пальцев (ssh все равно разрешает IP, что вы можете увидеть при использовании флага -vvv
)
~ / .ssh / known_hosts
. Вы можете сделать это:
database.example.com,webserver.example.com,database,webserver,10.1.2.3 ssh-rsa …
Вы можете добавить альтернативные имена и IP-адреса для хоста в эту запятую -delimited формат.
Здесь используются настоящие имена хостов, а не псевдонимы Host
, которые вы можете создать в файле ~ / .ssh / config
.
known_hosts
Я создал крошечный скрипт под названием ssh-hosthashes , который может находить повторяющиеся записи в файле known_hosts
. Используйте его и вышеупомянутые знания, чтобы свернуть их.
Вот его результат для ключа Github (который, как вы могли заметить, я немного свернул, но недостаточно). Коллизии перечислены по номеру строки:
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAq2A7hRGmdnm9tUDbO9IDSwBK6TbQa+PXYPCPy6rbTrTt
...JEAvGq3lGHSZXy28G3skua2SmVi/w4yCE6gbODqnTWlg7+wC604ydGXA8VJiS5ap43JXiUFFAaQ==
72: github.com,gist.github.com,192.30.252.128,192.30.252.129,192.30.252.130,192.30.252.131,192.30.252.140,192.30.252.141,192.30.252.142,192.30.252.143
93: 192.30.253.113
95: 192.30.253.118
96: 192.30.253.119
97: 192.30.253.112
109: 192.30.255.113
110: 192.30.255.112
155: 140.82.113.3
158: 140.82.114.4
161: 140.82.113.4
Еще одна вещь, которую я часто делаю, - это проверяю, что я не сохранил отпечаток пальца для localhost. Таким образом, я могу подключиться по ssh к серверу с хоста, на котором сохранен и доверять отпечаток пальца, запустить ssh localhost
с этого сервера и сопоставить этот отпечаток с отпечатком, предложенным клиентом, у которого он не сохранен. уже. Однако следите за различными типами ключей (или форматами отпечатков пальцев). (Это полезно только потому, что дайджест, предоставленный клиентом ssh
, отличается от формата, хранящегося в файлах known_hosts
.)
Чтение ответа @AdamKatz заставило меня захотеть отсортировать мой файл known_hosts, поэтому я написал скрипт, который делает это, найдите его ниже (я тщательно написал его, но я только минимальное тестирование, так что используйте на свой страх и риск).
Что касается первоначального вопроса, я бы рекомендовал использовать запись конфигурации HostKeyAlias в .ssh/config, как объяснено в этом ответе ServerFault: «SSH в ящик с часто меняющимся IP».
# (python3)
# `organize_known_hosts.py`
# For all known hosts, sort them by algo+hashed value, grouping the known IPs and domain names into one comma-separted list
# Usage:
# Generated the sorted file:
# cat ~/.ssh/known_hosts | python organize_known_hosts.py > /tmp/known_hosts
# Print it for visual check
# cat /tmp/known_hosts
# mv /tmp/known_hosts ~/.ssh/
import sys
from collections import namedtuple
class Entry(namedtuple("Entry", ["domainString", "algorithm", "hash"])):
def __str__(self):
return f"{self.domainString} {self.algorithm} {self.hash}"
def rightHandSide(self):
"""algorithm+hash"""
return f"{self.algorithm}.{self.hash}"
entryMap = {}
for lineNumber, line in enumerate(sys.stdin, start=1):
content = line.strip().split()
if len(content) == 0:
continue # empty line -> skip
elif line[0].startswith("#") or len(content) != 3:
if not line[0].startswith("#"):
sys.stderr.write(f"could not parse a line; line moved to top|{lineNumber}: '{line}'\n")
sys.stdout.write(line)
continue # comment or erroneous line -> skip
entry = Entry(*content)
entryMap.setdefault(entry.rightHandSide(), []).append(entry)
compactEntryList = []
for k, entryList in sorted(entryMap.items()):
domainList = []
ipList = []
for entry in entryList:
for domainOrIp in entry.domainString.split(","):
if 'a' <= domainOrIp[0].lower() <= 'z':
domainList.append(domainOrIp)
else:
ipList.append(domainOrIp)
domainString = ",".join(sorted(domainList) + sorted(ipList))
compactEntryList.append(Entry(domainString, *k.split(".")))
sys.stdout.write("\n".join(map(str, compactEntryList)))