Язык Go реализует ssh-туннелирование

Go

как туннелировать

Туннелирование с помощью ssh — это то, чем я всегда хотел заниматься. Отправная точка: в компании некоторые машины часто недоступны, и к ним можно получить доступ только через машину разработки, предоставленную компанией, но мы можем получить доступ к машине разработки в интрасети.

Базовые знания

SSH — это сетевой протокол, используемый для зашифрованного входа между компьютерами.

  1. Удаленный хост получает запрос пользователя на вход в систему и отправляет пользователю свой собственный открытый ключ.
  2. Пользователь использует этот открытый ключ для шифрования пароля входа и отправки его обратно.
  3. Удаленный хост использует свой собственный закрытый ключ для расшифровки пароля для входа.Если пароль правильный, пользователю разрешается войти в систему.

Первый шаг, который уязвим для атаки в вышеописанном процессе, — как мы узнаем, что полученный публичный ключ является реальным хостом, что отражается в фактическом входе в систему, то есть он появится:

 $ ssh user@host

  The authenticity of host 'host (12.18.429.21)' can't be established.

  RSA key fingerprint is 98:2e:d7:e0:de:9f:ac:67:28:c2:42:2d:37:16:58:4d.

  Are you sure you want to continue connecting (yes/no)?

здесьRSA key fingerprintЭто подпись MD5 открытого ключа 128. Если да, она будет сохранена в $HOME/.ssh/known_hosts, указывая, что открытый ключ распознан.

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

Подводя итог, можно сказать, что существует два способа аутентификации ssh:

  1. имя пользователя + сертификат
  2. имя пользователя + пароль

Давайте посмотрим на соответствующий метод работы в go.

golang реализует ssh-клиент

go get -u golang.org/x/crypto/...

Во-первых, давайте поговорим о 2 методах аутентификации, отобразить пароль, пройтиssh.Passwordввести пароль

sshConfig := &ssh.ClientConfig{
	User: "your_user_name",
	Auth: []ssh.AuthMethod{
		ssh.Password("your_password")
	},
}

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

eval `ssh-agent` 启动agent代理
ssh-add /path/to/key/key_name 添加指定私钥
ssh-agent -k 关闭 agent
ssh-add -l 查看代理中私钥
ssh-add -L 查看代理中私钥对应的公钥
ssh-add -d /path/to/key/key_name 移除指定私钥
ssh-add -D 删除管理的所有私钥

читать из файла

func PublicKeyFile(file string) ssh.AuthMethod {
	buffer, err := ioutil.ReadFile(file)
	if err != nil {
		return nil
	}

	key, err := ssh.ParsePrivateKey(buffer)
	if err != nil {
		return nil
	}
	return ssh.PublicKeys(key)
}

чтение из ssh-агента

func SSHAgent() ssh.AuthMethod {
	if sshAgent, err := net.Dial("unix", os.Getenv("SSH_AUTH_SOCK")); err == nil {
		return ssh.PublicKeysCallback(agent.NewClient(sshAgent).Signers)
	}
	return nil
}

созданный клиентом

Когда у нас есть метод аутентификации, нужно сгенерировать ssh-client

sshClient, err := ssh.Dial("tcp", "host:port", sshConfig)
if err != nil {
	return nil, fmt.Errorf("Failed to dial: %s", err)
}

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

modes := ssh.TerminalModes{
	ssh.ECHO:          0,     // disable echoing
	ssh.TTY_OP_ISPEED: 14400, // input speed = 14.4kbaud
	ssh.TTY_OP_OSPEED: 14400, // output speed = 14.4kbaud
}

if err := session.RequestPty("xterm", 80, 40, modes); err != nil {
	session.Close()
	return nil, fmt.Errorf("request for pseudo terminal failed: %s", err)
}

Затем мы можем приступить к выполнению кода, см. полный кодssh_client

Ссылаться на

how-to-create-an-ssh-tunnel-in-go

Основные операции ssh в golang

Базовые знания