two-factor 认证的问题

研究了下 google 出的 google-authenticator,准备用在 ssh 的登陆上,安装配置确实很简单,参照这个文档一步步往下就可以。
很不幸的是,如果要在 ssh 的登陆过程中使用,就没那么理想了。
目前我们所有的服务器都是通过公私钥验证,理论上说,只要私钥不被窃取,是不可能登陆到我们服务器的。但是试用了 two-factor 之后,则必须要开启密码验证的方式,然后再输入那个随机生成的一串字符。根据这两个(1, 2)文档所示,目前没有好的方式可以让公钥认证跟密码登陆共存,这也就意味着,我们是不可能同时使用 two-factor 结合公私钥来登陆服务器的。除非不使用标准的 openssh。
这样看来,two-factor 并不是一个很好的选择。看到有不少公司把它拿来做跳板机,有钱的当然直接买 RSA 了,这或许是一个比较好的选择,不过这样意味着需要一些集中的用户管理方案。
很早之前,我无意发现有同事把自己电脑的整个 ~ 给同步到 github.com 上去了,这个目录里面包含要进入我们的内网环境的 VPN 证书文件,登陆服务器的私钥文件。不幸的是,这个项目还有不少的 fork,虽然事后做了大量的工作,不过现在看来,是不是上个 two-factor 能够最大程度的减小这类悲剧发生之后的影响。

scp 出现 stalled 的分析

在使用 scp 进行一些大文件传输时,会出现 stalled 的情况,不外乎下面两个原因。

scp 对带宽的使用是贪婪的,因此有多少的带宽他就会使用多少(实际情况很复杂,并不全是贪婪的情况,也不是有多少用多少),但是如果一旦由于网络设备或者防火墙造成了一些延时,就会导致此次传输出现 TCP stalled。对此,可以通过限速解决,以 200Kbit/s 的速度进行传输:
$ scp -l 200 file dst:

另外还有个次要原因,可能是由于 Linux 下的 SACK 的造成。一般开启限速功能应该就能解决绝大多数的情况了。SACK 是什么请看这里
要使用 TCP option 中的 SACK,需要两端都支持。

根据这篇文章的描述,在局域网或者低延迟的网络中,就完全没有必要开启 SACK options 了,另外在很小的带宽下,比如 1Mbps 的情况下,同样没有必要开启这个选项。该选项可以在 "high bandwidth, lossy (or high delay)" 的情况下开启。因此出现 stalled 的情况一般都是在客户从公网连接某台服务器,带宽一般都是比较小的,瓶颈带宽在客户端这边,而不大可能是两台同一链路(连在同一台交换机)的服务器之间的数据传输。因此关闭 SACK 会比较有利传输:
# echo 0 > /proc/sys/net/ipv4/tcp_sack

ref:
http://daybydaylinux.blogspot.jp/2011/02/scp-stalled-during-big-files-transfer.html

limits 不生效

正常情况下,改完 limits.conf 后,重新登录就会生效,但是一台机器(CentOS 6.2, 2.6.32-279.el6.x86_64)很奇怪,注销再次登录并不会生效。
messages 文件出现类似的错误:
Sep  1 12:08:35 jaseywang sshd[16119]: fatal: setresuid 500: Resource temporarily unavailable
Sep  1 12:08:41 jaseywang sshd[16120]: Accepted publickey for jaseywang from 111.111.111.111 port 53803 ssh2
Sep  1 12:08:41 jaseywang sshd[16122]: fatal: setresuid 500: Resource temporarily unavailable
Sep  1 12:08:46 jaseywang sshd[16123]: Accepted publickey for jaseywang from 111.111.111.111 port 53804 ssh2
Sep  1 12:08:46 jaseywang sshd[16125]: fatal: setresuid 500: Resource temporarily unavailable
Sep  1 12:08:52 jaseywang sshd[16126]: error: RSA_public_decrypt failed: error:0407006A:lib(4):func(112):reason(106)
Sep  1 12:08:52 jaseywang sshd[16126]: error: hash mismatch
Sep  1 12:08:52 jaseywang sshd[16126]: error: hash mismatch
Sep  1 12:31:06 jaseywang sshd[18049]: Accepted publickey for jaseywang from 111.241.250.121 port 20918 ssh2

后来通过重启 sshd,再次登录才会生效,可能跟 sshd 有关,不过按我的理解, sshd_config 文件并没有改变,重启实际上是没改变什么的,奇怪。

ssh:write failed

登录某台机器,出现如下错误:
$ ssh user@ip -vvv

Write failed: Broken pipe

g 了一番,大多都是啥修改 ServerAliveInterval 以及 ClientAliveInterval 这两个值,分别在客户端以及服务端设置,不过修改了下并没有效果。
查看 message 文件:
2692 Aug 28 20:59:38 jaseywang sshd[512]: Accepted publickey for ad from 1.1.1.1 port 54873 ssh2
2693 Aug 28 20:59:38 jaseywang sshd[514]: fatal: setresuid 500: Resource temporarily unavailable
2694 Aug 28 20:59:44 jaseywang sshd[515]: Accepted publickey for ad from 1.1.1.1 port 54885 ssh2
2695 Aug 28 20:59:44 jaseywang sshd[517]: fatal: setresuid 500: Resource temporarily unavailable
2696 Aug 28 20:59:49 jaseywang sshd[519]: Accepted publickey for ad from 1.1.1.1 port 54886 ssh2
2697 Aug 28 20:59:49 jaseywang sshd[538]: fatal: setresuid 500: Resource temporarily unavailable
2698 Aug 28 20:59:55 jaseywang sshd[539]: Accepted publickey for ad from 1.1.1.1 port 54887 ssh2
2699 Aug 28 20:59:55 jaseywang sshd[541]: fatal: setresuid 500: Resource temporarily unavailable
2700 Aug 28 21:00:00 jaseywang sshd[543]: Accepted publickey for ad from 1.1.1.1 port 54889 ssh2
2701 Aug 28 21:00:00 jaseywang sshd[545]: fatal: setresuid 500: Resource temporarily unavailable
2702 Aug 28 21:00:06 jaseywang sshd[640]: Accepted publickey for ad from 1.1.1.1 port 54890 ssh2
2703 Aug 28 21:00:06 jaseywang sshd[651]: fatal: setresuid 500: Resource temporarily unavailable
2704 Aug 28 21:00:11 jaseywang sshd[930]: Accepted publickey for ad from 1.1.1.1 port 54892 ssh2
2705 Aug 28 21:00:11 jaseywang sshd[932]: fatal: setresuid 500: Resource temporarily unavailable
2706 Aug 28 21:00:17 jaseywang sshd[935]: Accepted publickey for ad from 1.1.1.1 port 54898 ssh2
2707 Aug 28 21:00:17 jaseywang sshd[937]: fatal: setresuid 500: Resource temporarily unavailable

资源耗尽了,修改 limits.conf 文件,重启服务,done。

SSH 的一些细节

一般的 HTTPS 认证如下:
1.浏览器连接 HTTPS 默认的 443 端口
2.服务器提供起 public key,(X509 证书)
3.浏览器 check 该证书颁发自一个受信任的 CA
4.浏览器 check 服务器证书上的 CN(X509 Common Name)跟你浏览的域名相匹配

上面这个步骤跟 ssh 的连接过程很类似,除了一点:ssh 没有 CA 的概念。下面描述一下 ssh 连接过程:
1.用户发起连接的请求
2.服务器收到请求,将自己的公钥发给用户
3.用户使用该公钥加密密码,发送给服务器
4.服务器私钥解密,验证密码正确性

但是使用上面密码的验证方式有一个缺点,如果在客户跟服务器通信的过程中被一个中间人截获(Man-in-middle),也就是说中间人截获了客户的登录请求,假冒服务器,将中间人的公钥发给了客户端。上面说了,ssh 是没有 CA 概念的,因此用户无法辨认此公钥的真伪,如果被中间人截获,那么用户跟真正服务器之间就没有信息可言了。
Continue reading

ssh 使用不同的私钥登录

在 .ssh 下生成了两套密钥:
# ssh-keygen -f ~/.ssh/id_rsa.work -C "work key"
# ssh-keygen -f ~/.ssh/id_rsa.home -C "home key"

如何使用不同的私钥登录不同的机器?在 ssh_config 或者 ~/.ssh/config 里面定义:
Host work
    hostname YOUR_IP
    User jaseywang
    port YOUR_SSH_PORT
    IdentityFile ~/.ssh/id_rsa.work
 
Host home
    hostname YOUR_IP
    User jaseywang
    port YOUR_SSH_PORT
    IdentityFile ~/.ssh/id_rsa.home

如果将 IdentityFile 定义在 Host 外面则对全局生效, Host 内如果再定义该指定,覆盖全局的。