之前两篇文章利用SSH代理访问内网资源和使用SSH代理在本地开发环境调试各种回调两篇文章,介绍了ssh的各种代理姿势,SSH的功能确实强悍。如果用过ssh代理功能,就有人要问了,我能否限制用户只允许使用代理功能,而不允许用户登录到我的系统中呢?
当然可以!否则又怎么会称为SSH(注:SSH是Secure Shell的缩写)呢?连权限都不能保障怎么敢叫Secure
呢?本篇文章就来详解下SSH的花式权限,来点不一样的干货。
NOTE: 本文提及的SSH
,主要指OpenSSH
的实现和功能,其他SSH
服务端和客户端可能实现不完全一致,比如putty
这个客户端使用的配置就和OpenSSH
不一样。其他SSH
服务端和客户端请务必参考官方文档。
SSH的功能概述
先谈谈SSH有哪些功能,才能谈到每个功能有哪些权限。SSH最常见的有三大功能:
- remote shell:可以说最初的功能了,用的最多最广的也是这个功能,也是绝大多数用户对ssh的初步印象
- proxy:这个功能相对来说可能运维接触的多,也用的多。我的前两篇文章重点介绍这个功能
- file transfer:
scp
/sftp
/rsync
等命令使用SSH协议实现文件远程传输,sshfs
通过SSH协议将远程目录挂载到本地,等等。
其次是SSH是一个典型的C/S应用,服务端运行sshd
守护进程,监听TCP/22
端口(默认情况下),客户端运行ssh
程序,远程连接sshd
应用,使用以上三种功能。
sshd
使用/etc/ssh/sshd_config
和~/.ssh/authorized_keys
(这个文件仅用于做密钥认证的配置,如果和sshd_config配置冲突则此文件配置生效。此配置文件可以实现细化到密钥的权限,gitlab使用此配置实现用户的ssh访问控制)配置文件做服务配置,ssh
客户端使用/etc/ssh/ssh_config
(全局配置)和~/.ssh/config
(个性配置)两个配置文件(windows 10的openssh使用%USERPROFILE%\.ssh\config
)。默认配置文件几乎不用动,ssh就帮我们做好了开箱即用的配置。本文不会讲解ssh每个配置项的含义,只会根据一些场景讲解对应的权限控制,所有场景都是以默认配置为基准,讲解一些常用的配置,一些不常用的配置项就不提及了。
下面我们将详解每个功能的权限
远程连接的权限限制
ssh user@ip
最基本的使用方式,直接远程连接到服务器的shell上,实现远程控制的需求。
不允许远程登录
只要用户满足以下条件之一,ssh便会拒绝登录:
- 用户无密码(由于默认开启了
PermitEmptyPasswords no
选项) - 用户无合法shell(注意如果不指定shell,则默认为
/bin/sh
) - 明确拒绝使用各种可登录的渠道(比如
PasswordAuthentication no
,PubkeyAuthentication no
等等) -
/etc/nologin
存在,则除root
外所有用户均拒绝登录,并打印/etc/nologin
文件内容作为提示信息
所以通常创建一个低权限账户,只负责运行本地服务的,使用的useradd命令大致如下:
useradd -r -M -s /bin/false user
新用户无密码,并且不是一个合法的shell,所以根本没法登录
/bin/false
,/sbin/nologin
等做shell的区别:/bin/false
只是返回1
退出码,什么都不输出,所以ssh登录的时候显示了一下motd
信息(如果有)就直接退出了。而/sbin/nologin
会输出一行This account is currently not available.
,然后再以1
退出码退出。所以用户如果登录除了会看到那些信息之外,还会看到/sbin/nologin
的提示信息。使用/etc/nologin
配置也有类似的效果。如果是其他压根不存在的文件做shell配置,那么就会反复提示登录失败。
如果连motd信息都不想让用户看到,可以直接创建一个~/.hushlogin
空文件即可。如果想通过修改配置文件,那么需要同时修改/etc/sshd_config
(PrintMotd no
)和/etc/pam.d/sshd
(去掉pam_motd.so
加载),比较麻烦。
不允许root登录
设置PermitRootLogin
选项即可。no
表示彻底拒绝root远程登录,想要切换成root就只能通过普通用户的su -
或sudo -i
切换root身份了。prohibit-password
和without-password
(Ubuntu 14.04以后默认)表示拒绝密码登录,表示只能通过密钥登录了。forced-commands-only
选项表示只允许密钥认证,但是必须给定command
,也就是非交互式执行ssh。
限定ip白名单登录
这个其实办法很多,比如在防火墙控制,在/etc/hosts.(deny|allow)
控制等,其实在/etc/sshd_config
也可以控制,方法就是使用Match address
,比如:
Match Address 127.0.0.*
PubkeyAuthentication yes
用sshd配置本身做ip白名单的比较少,但是Match
配置却是一个非常有用的配置项,它可以实现我们对用户或用户组区别对待,这个我们会在后面再细说。
代理的权限限制
有关代理的使用可以参考我之前写的利用SSH代理访问内网资源和使用SSH代理在本地开发环境调试各种回调两篇文章。
禁止端口转发
AllowTcpForwarding no
禁止X11转发
X11Forwarding no
x11转发功能实际应用会非常罕见,作用是将远程的图形数据在本地的X server上展示,以实现本地操作远程图形程序的功能。首先是Linux服务器大多运行在无图形环境下,本身就没有图形化程序跑在上面,再加上客户机可能多数是windows,又没有X环境,更加限制了这个功能的使用。还有就是x11 forwarding性能不是很好,实际使用会发现非常卡,不适合使用那种对响应速度要求比较灵敏的应用程序,比如浏览器,在x11 forwarding下运行动图会非常卡。最后就是需要跑图形化程序的服务器多数都安装有桌面环境,配置有vnc,因此就更没有人愿意使用这个功能了。
限制转发端口
如果不希望所有端口都能用于转发请求,可以配置PermitOpen
参数:
PermitOpen host:port
PermitOpen IPv4_addr:port
PermitOpen [IPv6_addr]:port
如果允许多个端口用于转发,那么必须一个个配置出来,any
(默认)表示所有端口都允许用于转发。
文件传输的权限限制
这个比较繁琐,因为目前常见的通过ssh传输文件的有三个命令scp
,rsync
,sftp
。它们的机制不一样,其中scp
和rsync
是通过远程非交互式执行命令实现的,而sftp
是通过openssh的sftp server实现的。
对于scp
和rsync
,只需要限制非交互式命令就可以了,比如
ForceCommand /bin/bash
或在~/.ssh/authorized_keys
对应的rsa public key 前面加上command="/bin/bash"
(参考gitlab的/var/opt/gitlab/.ssh/authorized_keys
),效果是等效的。这样就可以实现允许用户远程登录系统,但是scp
和rsync
命令失效,同时由于限定死了command参数,导致你的非交互式ssh命令也无法使用了,比如ssh user@ip ls /
这一类非交互式ssh不起作用了。
但是对于sftp
的限制则要容易的多,因为sftp
权限是单独分开的,不和ssh命令执行权限混在一起,并且sftp也和ftp一样,有自带的一些命令实现(比如ls, cd, get, put等等),如果设置
ForceCommand internal-sftp
或等效的~/.ssh/authorized_keys
配置,则表示只允许使用sftp,不允许shell登录。如果配置中去掉Subsystem sftp /usr/lib/openssh/sftp-server
这一行就可以关闭sftp服务
关于Match
经常时候我们需要混合以上各种权限使用。比如某些用户我们开放出来,但是限制它的功能,此时Match
配置就是我们的好朋友了。
限制某个用户只能使用TCP代理
Match User limited-user
AllowTcpForwarding yes # 这个是默认配置,如果没改过的话可以不加
X11Forwarding no # 禁止x11 forwarding
GatewayPorts yes # 允许ssh -R参数bind所有ip,否则只允许bind 127.0.0.1
AllowAgentForwarding no
PasswordAuthentication no # 不允许密码登录
PermitOpen localhost:62222 # 只允许打开localhost:62222做端口转发
ForceCommand echo 'This account can only be used for TCP proxy'
以上命令可以根据实际情况调节,比如将user的shell置为/sbin/nologin
,这样一来ForceCommand
其实可以去掉,如果用户登录shell就会提示This account is currently not available.
。
由于用户不能登录shell,不能使用密码认证,因此想要使用代理,必须使用类似于下面的命令:
ssh -R 62222:192.168.1.1:80 -i /path/to/id_rsa -N
使用-i
参数指定私钥文件用于公钥认证,使用-N
参数表示不执行远程命令,仅仅使用port forwarding。
NOTE:sshuttle
的原理是使用ssh command在远程执行python命令,转发请求,因此以上的配置由于不能执行command,所以sshuttle
就不能用了。
sftp only
Match Group sftp-only
ForceCommand internal-sftp
PasswordAuthentication yes
ChrootDirectory /var/sftp
PermitTunnel no
AllowAgentForwarding no
AllowTcpForwarding no
X11Forwarding no
这里我们Match了sftp-only
这个组,在这个组下面的用户都使用下面的配置。使用了ForceCommand,因此不能登录shell,使用了ChrootDirectory
限制了用户的根目录,关闭了各种转发功能。
root用户不允许外网访问,但是内网可以
PermitRootLogin no
Match Address 192.168.1.0/24
PermitRootLogin yes
通过Match
的组合,我们可以很方便的限制一些特定用户的权限,这样就实现了ssh用户的一些特殊化管理。
结语
这里只是按照一些可能遇到的场景讲解了下sshd_config
的配置,对于等效的~/.ssh/authorized_keys
配置同样适用。其实ssh还有很多强大的功能,但是用的可能比较少,这里就不详细讲解那些不太常见的参数了,有兴趣的读者可以自行查阅man手册获取更多资料:
-
sshd(8)) (关于
~/.ssh/authorized_keys
的帮助这里有详解) - sshd_config(5))
- ssh_config(5)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。