如何在登录后将SSH用户限制为一组预定义的命令?

时间:2008-12-31 09:41:00

标签: linux shell ssh

这是一个安全的想法。我们的员工可以访问Linux服务器上的一些命令,但不是全部。他们应该例如有可能访问日志文件(less logfile)或启动不同的命令(shutdown.sh / run.sh)。

背景资料:

所有员工使用相同的用户名访问服务器:我们的产品以“正常”用户权限运行,不需要“安装”。只需在用户目录中解压缩并运行即可。我们管理了几个“安装”应用程序的服务器。在每台计算机上都有一个用户johndoe。我们的员工有时需要在命令行上访问应用程序以访问和检查日志文件或手动重启应用程序。只有部分人才能拥有完整的命令行访问权限。

我们在服务器上使用ppk身份验证。

如果employee1只能访问日志文件而employee2也可以执行X等,那就太棒了......

解决方案: 作为解决方案,我将使用接受答案中所述的command选项。我将创建自己的小shell脚本,这是唯一可以为某些员工执行的文件。该脚本将提供几个可以执行的命令,但没有其他命令。我将使用authorized_keyshere所述的以下参数:

command="/bin/myscript.sh",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
ssh-dss AAAAB3....o9M9qz4xqGCqGXoJw= user@host

这对我们来说足够安全。谢谢,社区!

10 个答案:

答案 0 :(得分:62)

您还可以将密钥限制为允许的命令(在authorized_keys文件中)。

即。用户不会通过ssh登录然后拥有一组受限制的命令,而只允许通过ssh执行这些命令(例如“ssh somehost bin / showlogfile”)

答案 1 :(得分:29)

ssh遵循rsh传统,使用密码文件中的用户shell程序来执行命令。

这意味着我们可以在不涉及ssh配置的情况下解决此问题。

如果您不希望用户能够访问shell,那么只需用脚本替换该用户的shell即可。如果你查看/etc/passwd,你会看到有一个字段为每个用户分配一个shell命令解释器。该脚本用作交互式登录ssh user@host以及命令ssh user@host command arg ...的shell。

这是一个例子。我创建了一个用户foo,其shell是一个脚本。该脚本打印消息my arguments are:,后跟其参数(每个在单独的行和尖括号中)并终止。在登录的情况下,没有参数。以下是发生的事情:

webserver:~# ssh foo@localhost
foo@localhost's password:
Linux webserver [ snip ]
[ snip ]
my arguments are:
Connection to localhost closed.

如果用户尝试运行命令,它看起来像这样:

webserver:~# ssh foo@localhost cat /etc/passwd
foo@localhost's password:
my arguments are:
<-c>
<cat /etc/passwd>

我们的“shell”接收-c样式调用,整个命令作为一个参数,就像/bin/sh接收它一样。

正如您所看到的,我们现在可以做的是进一步开发脚本,以便在使用-c参数调用它时识别它,然后解析字符串(例如通过模式匹配) 。允许的那些字符串可以通过递归调用/bin/bash -c <string>传递给真实的shell。拒绝案例可以打印错误消息并终止(包括缺少-c的情况)。

你必须小心如何写这个。我建议只写正面匹配,只允许非常具体的事情,并禁止其他一切。

注意:如果您是root,您仍然可以通过覆盖su命令中的shell来登录此帐户,例如su -s /bin/bash foo。 (替换shell的选择。)非root无法做到这一点。

以下是一个示例脚本:限制用户仅使用ssh git访问/git下的存储库。

#!/bin/sh

if [ $# -ne 2 ] || [ "$1" != "-c" ] ; then
  printf "interactive login not permitted\n"
  exit 1
fi

set -- $2

if [ $# != 2 ] ; then
  printf "wrong number of arguments\n"
  exit 1
fi

case "$1" in
  ( git-upload-pack | git-receive-pack )
    ;; # continue execution
  ( * )
    printf "command not allowed\n"
    exit 1
    ;;
esac

# Canonicalize the path name: we don't want escape out of
# git via ../ path components.

gitpath=$(readlink -f "$2")  # GNU Coreutils specific

case "$gitpath" in
  ( /git/* )
     ;; # continue execution
  ( * )
    printf "access denied outside of /git\n"
    exit 1
    ;;
esac

if ! [ -e "$gitpath" ] ; then
   printf "that git repo doesn't exist\n"
   exit 1
fi

"$1" "$gitpath"

当然,我们相信这些Git程序git-upload-packgit-receive-pack没有漏洞或逃生舱口,可以让用户访问系统。

这是这种限制方案所固有的。用户通过身份验证以执行某个安全域中的代码,我们正在限制将该域限制为子域。例如,如果您允许用户在特定文件上运行vim命令进行编辑,则用户可以获得一个:!sh[Enter]的shell。

答案 2 :(得分:14)

您要找的是Restricted Shell。 Bash提供了这样一种模式,用户只能执行其主目录中存在的命令(并且它们不能移动到其他目录),这对您来说可能已经足够了。

我发现this thread非常具有说明性,如果有点过时了。

答案 3 :(得分:4)

你应该获得`rssh',受限制的shell

您可以按照上面提到的限制指南,它们都是不言自明的,并且易于遵循。理解术语`chroot jail',以及如何有效地实现sshd / terminal配置等等。

当您的大多数用户通过sshd访问您的终端时,您还应该查看SSH守护程序配置文件sshd_conifg,以通过SSH应用某些限制。但是要小心。正确理解您尝试实施的内容,因为错误配置的后果可能相当严重。

答案 4 :(得分:3)

为什么不编写自己的登录shell?使用Bash非常简单,但你可以使用任何语言。

Bash中的示例

使用您喜欢的编辑器创建文件/root/rbash.sh(可以是任何名称或路径,但应为chown root:rootchmod 700):

#!/bin/bash

commands=("man" "pwd" "ls" "whoami")
timestamp(){ date +'%Y-%m-%s %H:%M:%S'; }
log(){ echo -e "$(timestamp)\t$1\t$(whoami)\t$2" > /var/log/rbash.log; }
trycmd()
{
    # Provide an option to exit the shell
    if [[ "$ln" == "exit" ]] || [[ "$ln" == "q" ]]
    then
        exit

    # You can do exact string matching for some alias:
    elif [[ "$ln" == "help" ]]
    then
        echo "Type exit or q to quit."
        echo "Commands you can use:"
        echo "  help"
        echo "  echo"
        echo "${commands[@]}" | tr ' ' '\n' | awk '{print "  " $0}'

    # You can use custom regular expression matching:
    elif [[ "$ln" =~ ^echo\ .*$ ]]
    then
        ln="${ln:5}"
        echo "$ln" # Beware, these double quotes are important to prevent malicious injection

        # For example, optionally you can log this command
        log COMMAND "echo $ln"

    # Or you could even check an array of commands:
    else
        ok=false
        for cmd in "${commands[@]}"
        do
            if [[ "$cmd" == "$ln" ]]
            then
                ok=true
            fi
        done
        if $ok
        then
            $ln
        else
            log DENIED "$cmd"
        fi
    fi
}

# Optionally show a friendly welcome-message with instructions since it is a custom shell
echo "$(timestamp) Welcome, $(whoami). Type 'help' for information."

# Optionally log the login
log LOGIN "$@"

# Optionally log the logout
trap "trap=\"\";log LOGOUT;exit" EXIT

# Optionally check for '-c custom_command' arguments passed directly to shell
# Then you can also use ssh user@host custom_command, which will execute /root/rbash.sh
if [[ "$1" == "-c" ]]
then
    shift
    trycmd "$@"
else
    while echo -n "> " && read ln
    do
        trycmd "$ln"
    done
fi

您所要做的就是将此可执行文件设置为您的登录shell。例如,修改您的/etc/passwd文件,并将该用户/bin/bash的当前登录shell替换为/root/rbash.sh

这只是一个简单的例子,但您可以根据需要将其设置为高级,这个想法就在那里。小心不要通过更改自己和唯一用户的登录shell来锁定自己。并且总是测试奇怪的符号和命令,看看它是否真的安全。

您可以使用以下代码进行测试:su -s /root/rbash.sh

小心,确保匹配整个命令,并注意通配符!最好排除Bash符号,例如;&&&||$和反引号,以确定。

根据您为用户提供的自由,它不会比这更安全。我发现通常我只需要让一个只能访问少量相关命令的用户,在这种情况下,这确实是更好的解决方案。 但是,您是否希望提供更多自由,监狱和权限可能更合适。错误很容易发生,只有在已经太晚的时候才会被发现。

答案 5 :(得分:1)

您可能需要查看设置jail

答案 6 :(得分:1)

GNU Rush可能是完成此操作的最灵活,最安全的方法:

  

GNU Rush是受限制的用户外壳程序,设计用于提供对其资源(例如svn或git存储库,scp等)的远程访问受限的站点。使用复杂的配置文件,GNU Rush使您可以完全控制用户执行的命令行以及对系统资源的使用,例如虚拟内存,CPU时间等。

答案 7 :(得分:0)

另一种看待这种情况的方法是使用POSIX ACL,它需要您的文件系统支持,但是您可以像在Windows上使用相同的控件一样对Linux中的所有命令进行细粒度调整(只是没有更好的UI)。 link

另一件需要关注的事情是PolicyKit

你必须做一些谷歌搜索才能让一切正常,因为这绝对不是Linux的强项。

答案 8 :(得分:0)

[披露:我写了下面描述的sshdo]

如果您希望登录名是交互式的,那么设置受限制的外壳可能是正确的答案。但是,如果有一组实际要允许的命令(别无其他),并且可以通过ssh单独执行这些命令(例如ssh user @ host cmd arg blah blah),则可以使用通用的白名单控件ssh可能就是您所需要的。当命令在客户端以某种方式编写脚本并且不需要用户实际键入ssh命令时,此功能很有用。

有一个名为sshdo的程序可以执行此操作。它控制可以通过传入的ssh连接执行哪些命令。可以从以下位置下载:

http://raf.org/sshdo/(在此处阅读手册页) https://github.com/raforg/sshdo/

它具有训练模式以允许尝试所有命令,并且提供一个--learn选项以生成永久允许学习的命令所需的配置。然后可以关闭训练模式,并且将不执行任何其他命令。

它还具有--unlearn选项,以停止允许不再使用的命令,以便在需求随时间变化时保持严格的最小特权。

它允许什么非常挑剔。不允许带有任何参数的命令。仅允许使用完整的Shell命令。

但是它确实支持简单的模式来表示类似的命令,这些命令仅在命令行上出现的数字(例如序列号或日期/时间戳)上有所不同。

这就像ssh命令的防火墙或白名单控件。

它支持允许不同用户使用的不同命令。

答案 9 :(得分:-2)