96

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

背景资料:

所有员工使用相同的用户名访问服务器:我们的产品以“普通”用户权限运行,无需“安装”。只需在您的用户目录中解压缩并运行它。我们管理“安装”我们的应用程序的几台服务器。在每台机器上都有一个用户johndoe。我们的员工有时需要通过命令行访问应用程序以访问和检查日志文件或手动重新启动应用程序。只有某些人拥有完整的命令行访问权限。

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

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

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

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

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

4

9 回答 9

72

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

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

于 2008-12-31T10:06:00.747 回答
34

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

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

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

这是一个例子。我创建了一个用户foo,其外壳是一个脚本。该脚本打印消息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参数调用它时识别大小写,然后解析字符串(例如通过模式匹配)。那些允许的字符串可以通过递归调用传递给真实的shell /bin/bash -c <string>。拒绝案例可以打印错误消息并终止(包括-c丢失时的案例)。

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

注意:如果您是,您仍然可以通过在命令root中覆盖 shell 来登录此帐户,如下所示。(选择的替代外壳。)非根不能这样做。susu -s /bin/bash foo

这是一个示例脚本:将用户限制为仅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].

于 2012-10-20T23:57:56.360 回答
15

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

我发现这个线程非常具有说明性,如果有点过时的话。

于 2008-12-31T10:02:13.437 回答
6

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

Bash 中的示例

使用您喜欢的编辑器创建文件/root/rbash.sh(可以是任何名称或路径,但应该是chown root:rootand chmod 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文件,并将该用户的当前登录 shell 替换/bin/bash/root/rbash.sh.

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

您可以使用以下方法对其进行测试:su -s /root/rbash.sh.

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

根据您给予用户的自由度,没有比这更安全的了。我发现通常我只需要创建一个只能访问几个相关命令的用户,在这种情况下,这确实是更好的解决方案。但是,您是否希望给予更多自由,监狱和权限可能更合适。错误很容易犯,只有在为时已晚时才注意到。

于 2017-05-04T22:31:17.023 回答
4

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

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

由于您的大多数用户通过 sshd 访问您的终端,因此您可能还应该查看 sshd_conifg(SSH 守护程序配置文件)以通过 SSH 应用某些限制。不过要小心。正确理解您尝试实现的内容,因为不正确配置的后果可能相当可怕。

于 2008-12-31T21:57:24.880 回答
3

GNU Rush可能是完成此任务的最灵活和最安全的方式:

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

于 2019-10-03T07:18:22.557 回答
1

你可能想看看建立一个监狱

于 2008-12-31T21:02:50.373 回答
0

另一种看待这个问题的方法是使用 POSIX ACL,它需要你的文件系统支持,但是你可以在 linux 中对所有命令进行细粒度调整,就像你在 Windows 上拥有相同的控制一样(只是没有更好的 UI )。关联

要研究的另一件事是PolicyKit

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

于 2008-12-31T22:23:01.727 回答
0

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

如果您希望登录是交互式的,那么设置受限 shell 可能是正确的答案。但是,如果您想要允许一组实际的命令(仅此而已),并且可以通过 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 命令的防火墙或白名单控制。

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

于 2019-04-24T03:42:28.033 回答