再谈初学者关心的ssh应用方方面面

http://blog.robertelder.org/what-is-ssh/

https://www.ssh.com/ssh/key/

什么是ssh?

ssh是一个在计算机之间实现安全通信的网络协议。通常人们在谈论使用ssh时,更多的是在说为了在另外一台计算机上执行一些命令而使用ssh client来连接到那台ssh服务器上。现代的计算机通常都既可以运行ssh client也可以跑ssh server.比如,执行以下命令:

ssh robert@192.168.0.123 "ls"

这条命令将试图使用'robert'这个username去远程登录192.168.0.123这个机器。一旦登录成功,它便试图去运行命令"ls",并且随后直接退出ssh session.为了这个过程能够工作,你可能需要键入远程机器的robert密码,或者使用其他的鉴权机制。

如果你在后面不加"ls"的命令,你将获得一个交互的session,你可以在远程机器上执行无限多的命令,直到你敲"exit"退出session.

在计算机之间拷贝文件

你可以通过‘scp’命令使用ssh协议在计算机之间拷贝文件:

scp /tmp/my_file robert@192.168.0.123:/mnt/my_file #  From your computer to 192.168.0.123
scp robert@192.168.0.123:/mnt/my_file /tmp/my_file #  From 192.168.0.123 to your computer

为其他服务提供隧道服务tunneling

这实际上是ssh真正强大的地方。你可以使用ssh经由ssh链接来为上层应用提供安全的数据传输隧道。比如,你可以在你自己家里搭建一个git repo作为远程备份用机。你可以使用下面的命令来clone repo:

git clone my-server:~/my_git_repo.git

最后,你甚至可以tunnel traffic on a port by port basis. 这允许你将远程服务当成本地服务一样来使用。比如,你可以允许将本地的一个web server或者database server用于接收来自任何地方的connections,只要使用一个有公网ip的proxy server即可。

为什么我们要用ssh?

在ssh之前,有一些更老也不安全的替代方案,比如telnent, ftp.这些老的协议之所以不安全,是因为login的信息明码传输,而ssh由于密码仅在安全通道建立后才会传输出去。ssh也支持公钥密码加密的方式,这比传统的基于password的认证更加安全。

ssh public and private keys

ssh可以以passowrd认证方式工作,但更加现代的方式是使用public key cryptography认证(鉴真)方式,而不是password方式。这对于初学者往往容易犯晕。实际上没有那么复杂,只要你多做几次,你就会觉得一切很自然。

大多数人已经习惯于传统密码认证方式:人们输入用户名和密码并且发往服务器鉴权。server然后检查password是否匹配以便决定是否允许你访问。而public key cryptography认证机制则有些不同,它需要人们创建一个'公钥私钥密码键值对public/private key pair':

1. 公钥,你可以分发给任何人

2.私钥,你应该对该文件保密,由创建该文件的人保管

这里不想对公钥加密机制做过多探讨(实际上需要非常多的数学知识),但是你需要了解以下概念和知识点:

1. 公钥和私钥之间有着非常复杂的关联关系;

2. 公钥用于加密消息,但却不能用公钥来解密消息;

3. 私钥可以解密由公钥加密的消息

ssh认证过程

具体流程为:

  • Negotiating the version of the protocol to use
  • Negotiating cryptographic algorithms and other options to use。
  • Negotiating a one-time session key for encrypting the rest of the session
  • Authenticating the server host using its host key
  • Authenticating the user using a password, public key authentication, or other means.

注意server向user proves its identity或者反过来user向server证明它的身份都是通过拥有对应的private key来实现的。比如user指定了-i xxxprivatekey启动ssh session,而server上authorized_keys文件中拥有user的public key,这两者能够对应起来的话,server就确信user是那个user。反之亦然.

多个key pair的管理

默认情况下sshkey_gen工具产生的私钥为id_rsa,对应公钥为id_rsa.pub,而你可能会有多个key pair的需求,比如一个用于github,一个用于bitbucket,一个用于你自己的server登录,这时就需要分别创建多个key pair,保持文件名对应即可,比如id_rsa_github/id_rsa_bitbucket及对应的_pub

非对称加密

在1976年以前,所有的加密都采用对称加密,既A使用某种加密规则对信息加密,B收到信息后逆向加密规则解密数据。这通信方式产生了一个难以解决的问题:A如何安全的把加密规则通知B?

在1976年有三位数学家提出了一个崭新的非对加密的概念(RSA):

1.A生成一对两把密钥(公钥和私钥)。公钥是公开的,任何人都可以获得,私钥则是保密的。
2.B获取A生成的公钥,然后用它对信息加密。
3.A得到加密后的信息,用私钥解密。

虽然非对称加密很安全很强大,但是它也有缺点,相对于对称加密它计算量更大,计算时间更长。所以在大规模数据的安全通信场景中,普遍采用非对称加密技术来交换对称加密密钥,之后的通信都采用对称加密技术加密

https://www.jianshu.com/p/5e3f9dfd2cb4

ssh keys in server and client

https://www.ssh.com/ssh/public-key-authentication

如何创建公钥私钥对?

在linux中,你可以使用ssh-keygen命令来创建密钥对

ssh-keygen

运行这条命令后,你需要回答以下问题完成密钥对的创建:

1. 输入保存密钥的文件名(默认为/home/your_home/.ssh/id_rsa):

2. 输入passphrase(可以为空,主要用于二次安全认证):

3.输入相同的passphrase确认

上述命令执行后,将生成两个文件: id_rsa为私钥文件,id_rsa.pub为公钥文件.以下为公钥的例子:

ssh-rsa AAAAB3Nz4C1yc2EAAAADAQABAAABAQDG3eIHvpiK2At0G+e3Y0vgo0o3aZHM8rJLXMMsGxC5kCorySKb2qtvsSVVm+3KverdalhhuJdLHf1PmVfd+kGgglAYyos21eKevM6Syub4k1r6qvBe/jqwigI1kwr3cL6mU4ifIpUN1eddrcnRVo3F2zdtBXML5Ty+PZ4Hd2/nQKApzohIHDph9wxUMgRA+cevPQpYslyLsP1Bef5ZOlY7GrFwqxNJV5li0tMG5GI+kQ7lUuySkv5Wjqbu/NqHb1OmH++jWJdAZ8BtNUuKjlD9r7lfvzIInX4CNs7KYY/USfL5ZuL/yOIGjjIiY0UMZJkJebiT/CLN/pXkw8ZlDikz robert@ubuntu

该公钥对应的私钥id_rsa文件内容为:

-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAxt3iB76YitgLdBvnt2NL4KNKN2mRzPKyS1zDLBsQuZAqK8ki
m9qrb7ElVZvtyr3q3WpYYbiXSx39T5lX3fpBoIJQGMqLNtXinrzOksrm+JNa+qrw
Xv46sIoCNZMK93C+plOInyKVDdXnXa3J0VaNxds3bQVzC+U8vj2eB3dv50CgKc6I
SBw6YfcMVDIEQPnHrz0KWLJci7D9QXn+WTpWOxqxcKsTSVeZYtLTBuRiPpEO5VLs
kpL+Vo6m7vzKh29Tph/vo1iXQGfAbTVLio5Q/a+5X78yCJ1+AjbOymGP70ny+Wbi
/8jiCo4yImNFDGSZCXm4k/wizf6V5MPGZQ4pMwIDAQABAoIBAGavS3cUQ0/uHnvl
rNBUxWlI55mVOWPKLaYcT+sGTqyCdEQHp4cycjNKFS0PRsnZJt0NfHV5CyYOZi4j
z+sevaRJpWgnrZqy9kFg3ImPm5PfAqtMeLGUNFnT6TAgrRj3bnoTyAfjo3Nxb/Y/
NmaResMfXo88sRsDU0ooJuFUGsQdAUmYSDJ0wKkuCytW05hYx/sQS8fElhKg3c0f
CG/MQwBxOYWOelLBwE76D1RIWDAA9l4+Ol48lE+b5Ltv2dZFVKZht/oFNa/egvMw
YTikekakwfkg5MTaDyldD/idet2ZRoLllyObLsEH8c6y9oXVhkZsu6aQ02KEWx0W
iD0+IQECgYEA7RzbS3YbJ/Ds+zrf/Czy1j3B+h7x+w67kojpD2kxpS9BWB6957ST
ozCGx8ysdJ9kwtGTOe+MTykG0JHyQhV5qv2zIols/2EA2HIQFXUZDNqbfr9Hvekc
vRctd60H/jMAMR5DLHu0OorNoY0AA/HATAYQsovkDnlL8IRr3V17uAsCgYEA1rUf
pVFcjgoLPon+Zp3rV+9rwrMo8hOZ6EE+lX9uWBtPaKQNXiqkls+xIA8R8sNqdrB2
CkvyFpMz7HVV5rBsMhIqe8ti8Ot5Z2xp7cErxc7XpMuJBTTvmJX5Sti9R7I14CUf
4oFHeSdWJiOS55a85sPXZYHjHA1YuycUNWCcBHkCgYA6yBeZaosq6LBnS94xTxdY
g3DuR+PJoIphtm1Is8Rp9gAWD3D22y5qm2IecCAkvUsmfPwptbgr+7jDxhqvxVEn
UcOyAS2zVeH2xrg0CZaPODaqQlNPwlWsju1nqM69dvlKM/1lLrmsdbKqpSDm2WzZ
q/tBuCpuaBWqV7nB5CYCpwKBgHT2BAA1uzqxJAD0gT57ZnnntgdBO9vra5sG98XO
vliGwBJb0+BpUHHLQE0biIZ7h6KSbCsdxgogNFfqb1oU30vDc5suZ36gd+ksOORI
p8TA8d4W9lR8ysyPXlc0jJ/i59BryNvF2x6XnCl4lY1NIyh+pPbp88MTTjPdjPeq
4jLZAoGAVuHcLyNV0ZUxTmFZovXfxisc+zdJV3eSaVD7/c7v/sA35cQyojFZEi/l
JDJYIq5T4Mo5NnKb+mms3n34ehH50i8BTGeJfnlg63MIrd5fE7jZeFYX2cvx6jD5
mvPGakcGN6ftUaCbEfJfDjf85WjKwiVi52oY1wb/91OrIpoP3io=
-----END RSA PRIVATE KEY-----

一旦你创建好了这两个文件,你就可以通过将公钥文件分发到server上这种方式来允许你登录到远程server上去.私钥文件永远只在你的客户端机器上,每一次你需要远程登录到保存了对应公钥的远程机器时,你都需要使用它。

如果你正在手工设置你所管理的两台机器,以便他们之间可以ssh,你需要做的是将你的public公钥存入你希望实现远程登录的remote远程机器中的'~/.ssh/authorized_keys'文件中.这个文件中可以包含多个pub keys以便运行多人通过ssh来登录该remote machine.

在Github上使用SSH

一个非常常见的SSH用例场景为:授权允许访问Github repo.本质原理上讲,在github上使用和其他任何场景下使用ssh并没有什么不同.你可以使用上面讲的方法来创建一个密钥对.这里是github关于创建密钥对的详细说明。需要说明的是github网站说明中也提到了将密钥通过ssh-agent这个小工具添加给你的authentication agent。通常情况下使用ssh-agent并不是必须的,但它确实是当你试图创建一个实际的remote connection时指定使用哪一个key的几种方法之一。

一旦你完成了密钥对创建,你可以接着浏览github网页:将你的key添加到特定的repo和帐号下  你只需将你的public key内容复制黏贴到github网站上就好了,这样任何能够证明它拥有该public key对应的私钥的人都是可信的,因此私钥保持私密非常重要。同时通过下面的ssh -i xxxxprivatekey来指定使用哪个私钥文件.在你创建好密钥对并且将公钥添加到你的github帐号上去之后,你就可以以下面的方式来登录到github上

ssh -i <path to your private key file> git@github.com : #注意,如果使用的是你的默认private key,比如id_rsa则无需使用-i来特别指定
ssh -i ~/.ssh/id_rsa git@github.com

 如果前面你的设置正确,那么将会有以下打印:

PTY allocation request failed on channel 0
Hi <Your Repo Name>! You've successfully authenticated, but GitHub does not provide shell access.
Connection to github.com closed.

上面的消息本身并不是错误消息,它告诉你你已经通过ssh pub key的方式正确认证了,但是github服务器本身并不提供ssh的shell access,它只允许你通过git client和github服务器进行通信.反过来,

如果你看到

Permission denied (publickey).

则表示你的配置还不正确.需要检查你的私钥目录是否正确,并检查确认你是否正确上传了公钥.并且确认你使用了'git'这个username,否则默认情况下username会使用你本机的当前用户.

为了clone或者push到你的repo中,你需要使用各种git commands,你需要理解的是所有这些git commands的运行都是在底层建立好的ssh tunnel隧道中传递信息的.

通过ssh来连接AWS EC2 instance

启动aws ec2时,当你被要求创建和下载一个key pair时你就获得了允许你访问那个ec2 instance的私钥. amazon会有一份public key的拷贝.你一旦使用那个key pair来launch一个新的ec2实例时,这个ec2实例就将在该机器实例的~/ssh/authorized_keys文件中添加public key.这也是为什么你不用手工将public key手工添加到~/.ssh/authorized_keys文件中去的原因。感兴趣的话可以点击 这里 了解

ssh config file

当你使用ssh时有一种可以大大提高你使用ssh效率的方法,这就是config文件.通过这种机制,config可以记住你的所有连接的参数,存储在~/.ssh/config文件中.如果你还没有的话,建议你创建开始使用.用它的好处是,你不用敲下面的长命令,你只用敲对应的短命令:

ssh robert@192.168.0.123 -p 1800 -i ~/.ssh/my_private_key
ssh robert-server

只要你的~/.ssh/config文件中包含以下信息就可以了:

Host robert-server
    HostName 192.168.0.123
    Port 1800
    User robert
    IdentityFile ~/.ssh/my_private_key

有了这样的config后还有个好处是,其他使用ssh的地方依然有效,比如git clone或者scp:

git clone robert-server:/mnt/my_repo.git
scp /tmp/my_file robert-server:/tmp/new_file

关于ssh config文件还有一点需要说明: 有些isp会关闭idle的连接,这意味着如果你打开了一个ssh connection,但是不做任何事情,你的isp将会将这条ssh connection timeout掉,你的终端将不再可用.

你可以通过在ssh config文件中每一个host connection参数区域添加 ServerAliveInterval参数:

ServerAliveInterval 60

通过ssh做远程管理

如前面所说,你可以使用ssh来远程登录,只要远程服务器运行着ssh server软件组,并且在远程服务器上已经正确配置了为incoming user的认证的方式

通常当你远程登录到remote server上,如果你执行一个长期运行的任务并且关闭terminal,有的ssh连接就将被关闭,这样你远程执行的命令也将在terminal关闭时被killed掉.这往往并不是你所想要的,你可能希望的是远程登录一下,执行对应命令关闭本地机器,并希望远程的命令能够一直运行.为解决这个terminal关闭后remotely执行的命令进程被killed的问题,可以有以下方案:

while true; do sleep 1; done   #  This will cause the terminal to hang until the command is killed by the user
while true; do sleep 1; done &  #  This will run forever in the background

另外一个办法是使用一个terminal multiplexer , 这是一个能够增加更多功能到你的terminal session的软件.比较出名的有GUN Screen, tmux 

无论你用哪一个multiplexer,都会提供允许你创建新的terminal session的命令.如果在新的session中执行了相关命令,该命令可以以background方式运行.下一次你登录到server上时,你可以再次运行multiplexer程序并且连接到前面使用过的terminal sessions.

使用ssh执行端口转发

使用SSH你可以做的真正很cool的事情是捕获你本地port的信息并且经由已经搭建起来的ssh隧道转发出去,并在tunnel的另一端forward给其他的应用.比如:

ssh -L 4005:127.0.0.1:80 robert-server

当上述命令执行时,将会创建一个在~/.ssh/config文件中定义的参数创建一条正常的ssh链接到'robert-server'远程服务器上去.而且任何本来将在本地机器的4005端口上接收到的traffic将被截流(traffic that would otherwise be receieved on the local port 4005)送进该tunnel(will instead be sent into the tunnel), 然后在另外一端将被forwarded到IP 127.0.0.1主机的80端口.如果‘robert-server'是一个web-server,那么在执行了上述命令的本地主机上浏览127.0.0.1则显示的是web-server上的page内容,这一切就像是该web-server运行在本地上一样. 这就是类似nginx的web proxy的基本原理!

你也可以对database server做相同的事情,该database可能放置在防火墙的背后因此外部无法访问,而通过这种方式,你的机器(放在互联网上的本地主机)在执行类似上述命令后就能够代理外部对数据库的访问,但同时却不允许外部的直接访问请求!

通常会碰到的共性问题

在下面的几个section,我们将来看看ssh相关的几个常见问题

SSH: Connect to Host: Connection Refused

如果你要ssh到的host本身并没有运行ssh server软件则会导致该错误.当然也有可能你指定了错误的端口号,ssh通常在port 22上.

Permission Denied(publickey)

如果你正在使用public key认证方式去登录ssh server而被服务器器拒绝的话就会有这个错误信息.通常情况下原因是你没有指定正确的private key导致的.

The authenticity of host 'hostname' can't be established

这个信息往往在你首次连接到一个ssh server时出现,因为每次你试图连接到server时,你的local client将会到本地保存的ssh信息文件(通常是在~/.ssh/known_hosts文件中)去找一点信息,该known_hosts文件会记住你信任的机器的id(identity of machines that you trust). 通常你只要敲'yes'就好了,当然如果你是个安全洁癖者,你可以打电话给那台你将登录的system administrator索取那台机器的RSA key fingerprint.然后你可以手工地将该RSA key fingerprint加到~/.ssh/know_hosts中,你就不会再见到这个warning了.

WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED

有时候,你可能看到类似下面的消息:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA:AA.
Please contact your system administrator.
Add correct host key in /home/robert/.ssh/known_hosts to get rid of this message.
Offending RSA key in /home/robert/.ssh/known_hosts:1
RSA host key for 192.168.0.1 has changed and you have requested strict checking.
Host key verification failed.

这条消息是说你试图连接的ssh server的identity发生了改变。这有可能说明:如果别人试图创建一个他们自己的ssh server并且欺骗你(很有可能通过建立他们自己的DNS server)登录到他们的ssh server上去而不是你真正希望登录的那台机器.

当然,以下几个场景也会出现这种消息: 如果你在使用AWS,EC2,如果你通过使用一个elastic IP去连接的话,ssh将会保存那个server的RSA key fingerprint并且将此fingerprint绑定到那个静态IP地址.随后,如果你又启动了一个不同的server而又绑定了那个静态IP,你将得到该错误,因为在你本地机器的~/.ssh/known_hosts文件中该IP对应着老EC2机器的RSA fingerprint key

122.32.210.134 ssh-rsa AAAAB3zew1yc2DAQABAAABAQDHOWdwLpkos2CLli6DFvQ36yQE6Pe/PtFp3XwyirfZCIoGWnedaWI8zkJWVCs0wgOB9/urFepTDfV2wN49KGy1sl2/CCDEH2K/zeoEAZlTcBrhU17bwg1yMHCyJ7IM+zdLzItDEKYjg1dXQQlwt7GP4W7HqffelQQoVxOMoZ5N50MzD+nvV4y8iq0KwDQNy62iU4hui9ajCSVUDLu/06ucd5IojSI9keRIYAXvQf52TJ5EbvoRhjuWNEG8IhnPP6rzPS11Ocmwg/xxxxxOKL28AeDBAh6B6MEBDtlyp5Yfu9cwZJ9CFtU/x5fHFPtAyyyyyhAfwN1 

如果你确认这不是什么问题,你访问的机器就是你要访问的机器,则可以通过以下命令来清除对应的警告信息:

ssh-keygen -R <Whatever the IP address in the message was>

什么是known_hosts中的RSA Key fingerprint(指纹),怎么创建,有啥用?

https://superuser.com/questions/421997/what-is-a-ssh-key-fingerprint-and-how-is-it-generated

fingerprint基于主机的public key,通常就保存在~/.ssh/id_rsa.pub,通常是用做简单地identification/verification of the host your are connecting to.你要连的是你想连的.

如果fingerprint变化了,那么意味着你正在连接的那台机器已经变更了他们的public key。这有可能并不是什么大的问题,但是至少说明和上一次连接相比,现在你连接的domain/ip本身最终连接到了不同的机器上(这种情况可能会在load balancer的场景上经常发生),当然也有可能你正在被man-in-the-middle攻击,这种攻击有可能骗你把你的ssh登录请求引导到他们自己的ssh server上去,从而偷了你的username/password.

ssh-keygen -E md5 -lf ~/.ssh/id_dsa.pub
2048 MD5:4d:5b:97:19:8c:fe:06:f0:29:e7:f5:96:77:cb:3c:71 (DSA)
ssh-keygen -lf ~/.ssh/id_dsa.pub 
1024 SHA256:19n6fkdz0qqmowiBy6XEaA87EuG/jgWUr44ZSBhJl6Y (DSA)

WARNING: UNPROTECTED PRIVATE KEY FILE!

如果你的private key文件放开的权限太多,你将会看到这条消息

调试SSH的connections

 如果你试图连接的ssh无法工作,那么有一些调试方法:

ssh -vvv <...arguments...>
debug1: Reading configuration data /home/robert/.ssh/config
debug1: /home/robert/.ssh/config line 12: Applying options for hostname
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: /etc/ssh/ssh_config line 13: Applying options for host
debug2: resolving "hostname.com" port 123
debug2: ssh_connect_direct: needpriv 0
debug1: Connecting to hostname.com [192.168.0.1] port 123.
debug1: Connection established.
...
debug1: kex: client->server cipher: chacha20-poly1305@openssh.com MAC: <implicit> compression: none
debug3: send packet: type 30
...
原文地址:https://www.cnblogs.com/kidsitcn/p/11013383.html