允许普通用户使用无法读取的私钥进行SSH


8

假设我有一台机器(这里称为客户机器),只允许一小部分人(称为支持人员)通过SSH(仅支持一个机器)一个帐户(支持访问帐户)进入。

支持人员只能使用密钥登录客户的计算机。此外,支持人员可以发展,因此不允许离开支持人员的任何人登录任何客户计算机。因此,禁止员工阅读用于登录客户机器的私钥。另外,禁止authorized_keys在客户计算机上修改文件。

为了实现该配置,我想到了使用支持人员登录(使用LDAP身份验证,但这是另一个问题)并且包含私钥的SSH代理的想法。

问题是:如何允许支持人员在无法读取SSH私钥的情况下使用它?

我相信我必须使一个守护程序在代理计算机上以root用户身份运行,该守护程序将接受用户的请求并为他们打开SSH会话,但是我不知道该怎么做。有任何想法吗?


编辑了问题,因为“客户端计算机”可能很难理解(并不意味着与服务器相反)。
Raspbeguy

这是非常大胆的,而且大多数看起来都是多余的。令人分心。您是否认为将来可以使用更少的粗体?谢谢。
DW

我假设authorized_keys限制仅涉及动态更改(例如,当新的支持成员加入/离开时),因为您需要在客户计算机中进行初始配置。
安赫尔

Answers:


6

我建议几个选择。

  1. 保护ssh密钥,并要求在sudo支持团队方面使用。您可以使用包装器透明地执行此操作。打电话给包装器说,/usr/local/bin/ssh-support并使其包含如下内容(未经测试):

    #!/bin/bash
    export PATH=/usr/local/bin:/usr/bin:/bin
    export IFS=$' \t\n'
    export SUSER=ssupport
    
    # Restart if not running under sudo
    test "X$1" != 'X-S' && exec sudo -u "$SUSER" /usr/local/bin/ssh-support -S "$@"
    shift
    export SHOME="$(getent passwd "$SUSER" | cut -d: -f6)"
    
    # Extract single argument as hostname LABEL and validate that we have
    # an RSA private key for it. The target username, real hostname, port,
    # etc. can be defined in ~/.ssh/config for the user $SUSER (ssupport)
    label="$1"
    idfile="$SUSER/.ssh/id_rsa_for_$label"
    cgfile="$SUSER/.ssh/config"
    
    ok=true
    [[ "$label" =~ '/' ]] && { echo "Invalid label: $label" >&2; ok=; }
    [[ ! -s "$idfile" ]] && { echo "Missing identity file: $idfile" >&2; ok=; }
    [[ ! -s "$cgfile" ]] && { echo "Missing configuration file: $cgfile" >&2; ok=; }
    
    if test -n "$ok"
    then
        logger -t ssh-support "$SUDO_USER requested ssh to $label"
        exec ssh -i "$idfile" -F "$cgfile" "$label"
    fi
    exit 1
    

    这将需要在sudoers文件中输入一个条目,以允许support组中的用户使用该工具。此命令允许他们以用户身份运行该ssh-support工具ssupport-必须创建该用户。它授予任何root特权。

    %support ALL = (ssupport) /usr/local/bin/ssh-support

    如果您对支持用户不需要提供自己的密码来运行该工具(如sudo脚本本身内的调用所要求的)感到满意,则可以修改sudoers定义,因此:

    %support ALL = (ssupport) NOPASSWD: /usr/local/bin/ssh-support

    假设您PATH包含/usr/local/bin/,则可以通过调用它ssh-support clientname。同时假设你已经创建的ssupport用户作为/home/ssupport您将创建/home/ssupport/.ssh/id_rsa_clientname/home/ssupport/.ssh/id_rsa_clientname.pub作为证书对,并在主机条目/home/ssupport/.ssh/configclientname所定义的用户,主机,端口等为目标机器。您可能会明确禁用X11转发,端口转发等。和往常一样,该/home/ssupport/.ssh目录需要使用权限保护0700

  2. 为每个支持人员提供他们自己的本地用户帐户,并让每个人使用自己的专用ssh密钥来访问客户端的服务器。当某人离开支持小组时,您将从客户的服务器中删除其ssh密钥。这意味着您不再需要担心阻止您的员工知道私密ssh密钥。


第二个选项无效。正如我所说的,客户端服务器上只有一个支持帐户,您不能将公共密钥添加到ssh配置中,这就是规则。实际上,您不能在客户端计算机上修改有关ssh配置的任何内容。
Raspbeguy

4
顺便说一句,这个答案是(ab)使用sudo的典型示例。我写了一篇有关该主题的文章(dmitry.khlebnikov.net/2015/07/…),似乎有一种尝试使用sudo解决任何问题的趋势。但是,这只会削弱系统的安全性,而不能提高安全性。
星系

1
@Raspbeguy当然不会。该sudoers行限制了对单个命令的访问权限
roaima

1
您将未经检查的选项传递给以 root身份运行的“ $ @”到ssh!我可以想到其他方法来破坏系统文件(用于-E添加),转发特权端口(-L,-R,-D)或仅获取root(-o PermitLocalCommand=yes -o 'LocalCommand=/bin/bash'。来自星系的有关滥用sudo的评论是当场正确的
nkms 2015年

1
@roaima:所以,无论如何,您的sudo到根的想法是有问题的,但是它们是与银河系博客所讨论的问题不同的问题。他在谈论ssh root@somewhere按键,ssh user@somewhere然后是sudo。这实际上是一个很好的观点。但是,适用于这种情况的唯一方法ssh keyowner@localhost ssh_to_client client.example.org 是的替代方法 sudo -u keyowner ssh_to_client client.example.org。与sudo相似,SSH可以限制允许用户运行的命令。我们正在谈论非root用户的无密码sudo,而不是Galaxy的用例。
彼得·科德斯

11

您真正想做的是使用SSH CA和每个支持人员使用的签名密钥(它们应该有自己的ssh密钥,例如通行证),并配置客户端的服务器以TrustedUserCAKeys /etc/ssh/users_ca.pub在/ etc / ssh / sshd_config中使用。这样,服务器将接受由CA密钥签名的任何密钥(您可以访问),并且您甚至可以不动用authorized_keys即可撤销不再受支持的人员的密钥。

快速搜索“ ssh ca”指向此教程:https : //www.digitalocean.com/community/tutorials/how-to-create-an-ssh-ca-to-validate-hosts-and-clients-with -ubuntu(向下滚动至“如何配置用户密钥”)-尽管本教程提到了Ubuntu,它与发行版无关,但是您需要支持SSH CA的OpenSSH的全新版本

关于该主题的另一个不错的博客条目是https://ef.gy/hardening-ssh(向下滚动到“ SSH证书”)。

请特别注意,您可以在有限的时间内对密钥进行签名,因此密钥将自动失效!


如果客户的机器可以访问互联网(以更新签名的有效性),那将是一个好主意,但并非总是如此。我们通过客户提供的VPN连接到这些计算机。
Raspbeguy

好吧,这很接近,而且不会与离开公司的人泄露钥匙。我为您提供了该机制,您可以实现该机制的自动化,例如,可以有一个值班人员在人们离开公司时为您的HR提供支持,并且可以定义有关如何撤消钥匙的程序。
星系

1
此外,您可以注册一个有限的时间内键(支持人之一) -例如,你可以登录它只是8小时(其移),8小时后就会到期,服务器不会让他们进来。
星系

3
关于您的LDAP部分-我目前在一家管理数百个实例的公司中工作,并且我们正在研究一种开源解决方案,以集成SAML 2.0和SSHCA。这个想法是,一个人使用SSO进行身份验证,如果获得授权,他们将在规定的时间段内(例如5分钟)对他们的密钥进行签名。所有这些对于用户来说都是相当透明的,并且是使用〜/ .ssh / config的ProxyCommand实现的。
星系

2

对于通过sudo或setuid-executable(针对某个特殊用途的非root帐户)调用的ssh的包装脚本,有几个不同的答案。正如nkms所说,将所有args传递给ssh可使用户使用我们要保护的ssh密钥执行任意操作。有些人提出的另一种极端情况是仅允许主机名。

OP说管理员需要能够上传内容。

您可能有两个不同的fixed-args-ssh包装器。一个用于登录shell,另一个用于scp。除了主机名(和要上传的文件名)外,没有用户提供的args。

或者是一个包装器脚本,该包装器脚本使用getopt自身来解析非常有限的选项,并将其插入到大多数固定的ssh命令中。忽略(或错误)无法识别的选项将是解决之道。

不要尝试过滤掉“危险的” ssh选项,只需编写一个包装程序就可以完成两件事:交互式登录或上载文件(本地和远程文件名)。我想您仍然需要在那里进行消毒。

实际上,这仍然容易出错。您必须找到一种方法来阻止用户将持有ssh键的文件作为本地文件提供。因此,您仍在尝试考虑需要禁止的所有内容,而不是从不允许任何内容开始。这将是确保文件名不包含任何@或的开始:


包装器的想法确实是解决方案,但这意味着需要填补安全漏洞。
Raspbeguy 2015年

我惊讶于人们在不需要它的情况下如何重新发明轮子。SSH CA功能是完全出于诸如原始问题之类的原因和情况而引入OpenSSH的。我的解决方案没有使用任何包装程序,并且完全能够满足要求,但是由于某种原因,@ Raspbeguy决定采用DIY方式,但对安全性有疑问。:)
星系

@galaxy:是的,您的SSH CA解决方案肯定是最好的解决方案,除非您有绝对的要求,不能一次性更改远程系统以配置其sshd以使用它。听起来很完美,而且很容易正确。
彼得·科德斯

@galaxy:您的解决方案确实很优雅,但不适用于我前面所说的情况。我非常喜欢这个主意,我曾与老板谈过,但这仍然是不可能的。无需生气。
Raspbeguy 2015年

1
@Raspbeguy,我没有难过,我只是不明白为什么您的公司为什么要牺牲自己的安全性,并在有适当方法的情况下使用“导带”实现某些功能。您的评论是,这将是一个很好的解决方案,但您不希望无法自动执行撤销-我也为您提供了解决方案(仅通过签署班次的密钥)。无论如何,您选择了答案,让我们继续:)
星系

1

如果设置SSH代理服务器,则可以安排职员用户的shell(在中/etc/passwd)未设置为bash之类的shell,而是设置为不允许shell访问的简单脚本。相反,它将要求输入目标主机名(read target),然后输入exec ssh "support@$target"

请注意,使用这样的代理可能会使使用工具(例如,scp向客户计算机传输文件或从客户计算机传输文件)变得困难。这可能是一个问题或优势!


包装脚本的想法类似于@roaima的想法。您可以使用ssh对其进行访问,但sudo也可以使用。他的答案是建议使用本地root用户,但非root用户也可以使用。请参阅我对他的回答的评论以进行讨论。(我的ssh keyowner@localhost想法与您的想法相同。)
Peter Cordes

@Peter-非常正确:root 绝对是错误的用户!
Toby Speight

支持人员必须上传内容,因此此解决方案可能不起作用。
Raspbeguy

@Raspbeguy:发布了解决此问题的答案。与roaima的非root用户sudo设置结合使用。
彼得·科德斯

0

您的支持人员始终仅通过该代理计算机进行连接,并且仅通过该代理计算机进行连接,因此客户端可以使用HostbasedAuthentication简单地对代理计算机进行身份验证

假设代理服务器是supporters.pc您提供的支持customer.pc

customer.pc将有Hostbase验证是/etc/ssh/ssd_configsupporters.pc中列出/etc/ssh/shosts.equiv,并在其公共密钥/etc/ssh/ssh_known_hosts

当您的支持人员登录到support@supporters.pc并执行时ssh customer.pc,它将生成ssh-keysign(8)(需要设置为setuid),该文件将使用您无法读取的文件和向supporters.pc提供证明连接确实来自supporters.pc。由于customer.pc信任supporters.pc,因此您的工作人员将作为支持登录。


从安全的角度来看,这是一个糟糕的解决方案,因为如果您授予对整个计算机的访问权限,并且您对谁做的事情失去了责任。在现代世界中,IT安全开始成为一个非常热门的话题,因此应该禁止机器对机器的信任。
星系

@galaxy,从OP中我的理解是,他们已经基本上在这样做了。该机器的信任在于规格。请特别注意,他们“仅使用一个机器帐户(支持访问帐户)”,有可能他们使用了customer.pc中的共享帐户,但以其自己的用户身份连接到服务器。更改ssh和ssh-keygen的权限以强制sudo -u支持ssh…可以解决该问题,并添加一个日志条目。
安赫尔

0

使用包装器二进制文件

对于此特定用例(请参阅下面的重要说明),一种可能性是创建一个support-ssh专门用于这些传出SSH连接的用户(例如),然后安装一个小型包装器execs /usr/bin/ssh

  • 不要复制+ chmod ssh二进制文件本身,因为您将不记得每次应用安全更新时都要重新复制它。
  • 并且不要使用root特权更高的用户,因为我相信显而易见的原因。

这是功能上等效的替代方法,用于通过以下折衷sudo来将特权提升到support-ssh帐户的特权:

  • sudo,它更小,更精简,因此出现配置错误的风险比您预期的要小。
  • 正确编码是您的责任-仅当您非常小心并且(理想情况下)具有安全性至关重要的编码经验时,才可以这样做。
  • 可以对其进行定制,使其比sudo(例如,但编写的代码越多,就需要对安全性进行审核的代码越多)就越具体。

包装程序二进制文件应设置HOMEsupport-ssh用户的主目录,以便ssh可以选择适当的ssh_config私钥。但是,不应允许调用用户阅读~support-ssh/.ssh/其内容。

包装程序可以很简单:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    setenv("HOME", "/home/support-ssh", 1);
    /* allow only a single, non-option argument */
    if (argc!=2 || *argv[1]=='-') {
        fprintf(stderr, "Usage: %s <hostname>", argv[0]);
        exit(EXIT_FAILURE);
    }
    execv("/usr/bin/ssh", argv);
    return EXIT_FAILURE;
}

您可能希望限制更多,并检查参数argv[1]是否在一组允许的主机名中。或更严格的限制,并允许(一部分)选项参数。你可能想完全取代环境变量(但保留重要的,如TERMLC_*等); 请注意,LD_LIBRARY_PATH并且LD_PRELOAD特别危险。

scp如果需要,可以提供类似的包装程序。

适用说明

该答案解决了该问题的具体情况,即合同规定用户必须遵守程序,并且有违反该程序的制裁措施(例如解雇)。它假定您要防止员工随便复制私钥,而不是阻止坚定的攻击者获得未经授权的访问。

我认为,安全既可以通过技术防御也可以通过非技术防御来实现,并且这里或通过使用这种方法实现的平衡sudo适合当前的情况。


您将未经检查的参数传递给以其他用户身份运行的ssh,请参见我对以上答案的评论。我仍然可以阅读密钥...而且我也不会指望严格的参数检查,ssh并不意味着要以这种方式运行。
nkms

@nkms-我使包装器更具限制性。如果需要,可以使它更加开放,但是除非有其他要求,否则您应该锁定事物,而不是相反。
Toby Speight 2015年

@TobySpeight:是的,看起来不错。无论如何,我都会将自己在评论中所说的大部分内容放入自己的答案中。
彼得·科德斯

1
最好使用sudo而不是二进制包装器。与您声称的相反,使用sudo的风险要比滚动自己的风险小得多。Sudo具有安全默认值。您如何确定没有忘记删除会影响ssh的环境变量?
吉尔斯(Gillles)“所以-别再邪恶了”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.