[英]How to restrict git SSH access based on ssh key given
我有一个私人 git 服务器,一个用户git
和 ssh 密钥认证。 目前,我是唯一一个使用它的人,但我想添加更多人,我希望每个人都使用用户git
连接到服务器并执行git clone
, git push
等。如果所有存储库都是“公共”,那么我知道如何解决这个问题。 但是例如我想要一个私有存储库,我仍然会使用我的 SSH 密钥通过git clone git@server:repo
克隆它,但是我不希望其他用户能够使用他们的 SSH 密钥克隆它。
我检查了关于设置服务器的 git-scm 文档(这对公共存储库很有帮助)和这篇文章,但是这篇文章似乎只解决了私有存储库的问题。
TLDR:当你在 GitHub 上克隆一个存储库时,你说git clone git@github.com:user/repo
和你的 git 用户名和 ssh 密钥被发送过来。 现在,根据您是否拥有此存储库的权限,您可以克隆它,否则不能。 所以基本上,表面上每个人都在使用git
用户,但在幕后进行了一些授权。 例如,GitHub 是如何处理的?
要实现类似的功能,您可以依赖专用工具,例如gitolite 。
否则,您可以安装一个成熟的GitLab 服务器,该服务器还可以提供对存储库的细粒度访问控制,使用“Git URL”,例如git@your-gitlab-domain.com:user/repo.git
(顺便说一句,似乎 GitLab 以前依赖gitolite
, 版本 5.0.0 之前)
gitolite
似乎正是您正在寻找的基于 ssh 密钥管理对存储库/分支的访问。
但是如果你想从头开始构建这样的东西,你需要查看authorized_keys
文件中的选项,尤其是command
和environment
。 使用这些,您可以强制执行特定的命令/脚本或添加/覆盖环境变量,基于使用的 ssh 密钥。
例如,您可以编写一个脚本,将用户允许的存储库读取为其 arguments 并强制它为选定的 ssh 密钥运行:
# file ~/.ssh/authorized_keys
command="/home/git/bin/git-only-shell /home/git/repos/repo1" ssh-rsa AAAAB2...
command="/home/git/bin/git-only-shell /home/git/repos/repo1 /home/git/repos/repo2" ssh-rsa AAAAB3...
该脚本现在可以从$SSH_ORIGINAL_COMMAND
读取请求的 repo 并检查它是否包含在传递的列表中。 这个脚本git-only-shell
的完整但粗略的示例实现可能是这样的:
#!/bin/bash
# verify that $SSH_ORIGINAL_COMMAND starts with git-upload-pack, git-upload-archive or
# git-receive-pack, followed by a space
if ! [[ "$SSH_ORIGINAL_COMMAND" == git-upload-pack\ * || "$SSH_ORIGINAL_COMMAND" == git-upload-archive\ * || "$SSH_ORIGINAL_COMMAND" == git-receive-pack\ * ]]; then
echo "unsupported command" >&2
exit 1
fi
# remove first word (git command)
ARGUMENTS="${SSH_ORIGINAL_COMMAND#git-* }"
# use eval to un-quote repo path (it is passed in single-quotes)
REPO_PATH="$(eval "echo $ARGUMENTS")"
# allowed repos are passed as arguments to this script
ALLOWED_REPOS="$@"
# check if repo was whitelisted
IS_ALLOWED=false
for repo in $ALLOWED_REPOS; do
if [[ "$REPO_PATH" == "$repo" ]]; then
IS_ALLOWED=true
fi
done
if [[ $IS_ALLOWED == "false" ]]; then
echo "access to this repo not allowed" >&2
exit 1
fi
# execute the original command
eval "$SSH_ORIGINAL_COMMAND"
gitolite
之类的工具过于复杂且使用起来不愉快,或者无法提供所需的功能。 我最终得到了以下解决方案:
user
和repo
以及多对多表permissions
的 PostgreSQL 数据库。$SSH_ORIGINAL_COMMAND
中提取的请求存储库的读/写权限。.ssh/authorized_keys
中,每个密钥都有自己的command
,该命令调用 C 程序,用户名与该密钥关联,并且当该密钥用于git
操作时,从 SSH 命令中提取的存储库。 因此,当用户将 SSH 密钥添加到他的帐户时,会在.ssh/authorized_keys
中添加一行,例如
command="/home/git/check_perms username \"${SSH_ORIGINAL_COMMAND}\"" no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-rsa ...
然后每次使用此密钥执行 git 操作时,都会运行该command
,如果用户没有足够的权限,则终止 git 操作。
我通过使用git-shell和一点点 bash 解决了这个问题。一般的想法是检查密钥用户是否应该访问给定的存储库,如果是,则使用git-shell
运行他们的命令。
shell脚本如下;
#!/bin/bash
SSH_ORIGINAL_COMMAND=${SSH_ORIGINAL_COMMAND#git-}
a=( ${SSH_ORIGINAL_COMMAND//\'/} ) # strip single qoutes [^1]
cmd=${a[0]} # git * command
path=${a[-1]} # targeted path
unset a[0] a[-1]
# optional arguments
if (( ${#a[@]} )); then
args="#{a[*]} "
fi
# check if the target path is whitelisted
for a_path in $@; do
f_path="${a_path}${path#@(a_path/|../)}/" # f(ull)_path
if [ -d "$f_path" ]; then
/path/to/git-shell -c "git $cmd $args'$f_path'"
fi
done
然后我们修改 git 用户的.ssh/authorized_keys
;
command="/path/to/script /foo/ /bar/ /biz/" ssh-...
通过独家使用git-shell
可以防止任意命令执行,所以我们只需要担心访问未经授权的存储库——这有两种方式解决;
f_path
时删除../
的实例。例如;
- foo [Authorised]
|_ biz
- bar
|_ boo
====
- `git clone git@server.dom:foo/../bar/boo` fails
- `git clone git@server.dom:bar` fails
- `git clone git@server.dom:foo/biz` passes
[1]:这里形成a
的方式可能不适合 globing; 有关更多上下文,请参阅此 SO 答案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.