• 再谈初学者关心的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
    ...
  • 相关阅读:
    JAVA获取昨天、今天、明天等日期
    IDEA设置调用方法时提示方法上的注释
    Hibernate使用distinct返回不重复的数据,使用group by 进行分组
    SpringBoot 自定义注解
    tailwindcss 使用总结
    nodejs nvm 包管理
    macos NPM 全局安装解决方案
    git 遇到修改github密码导致本地push失败解决方案
    Jupyter 快捷方式设置
    Vue indent eslint缩进webstorm冲突解决
  • 原文地址:https://www.cnblogs.com/kidsitcn/p/11013383.html
Copyright © 2020-2023  润新知