基于golang+openssh 服务实现一个简单的git over ssh 服务

网友投稿 278 2022-11-02

基于golang+openssh 服务实现一个简单的git over ssh 服务

昨天看了开源的codefever 以及以前简单学习过gogs,刚才学习下git over ssh 的实现机制

基于openssh + golang (golang 部分参考了gogs 处理)实现了一个简单的git server (ssh 协议的)

原理说明

核心还是我们的openssh server 创建一个git 账户,此账户使用了authorized_keys的forcecommand 功能

forcecommand 中我们添加了git 的处理

forcecommand 代码

package main

import (

"fmt"

"log"

"os"

"os/exec"

"strings"

)

func init() {

file := "./" + "message" + ".txt"

logFile, err := os.OpenFile(file, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)

if err != nil {

panic(err)

}

log.SetOutput(logFile)

log.SetFlags(log.LstdFlags | log.Lshortfile | log.LUTC)

}

func parseSSHCmd(cmd string) (string, string) {

ss := strings.SplitN(cmd, " ", 2)

if len(ss) != 2 {

return "", ""

}

return ss[0], strings.Replace(ss[1], "'/", "'", 1)

}

func main() {

// forcecommand 会包含一个SSH_ORIGINAL_COMMAND 里边是git 的一些操作命令,包含了具体命令的处理

println(os.Getenv("SSH_ORIGINAL_COMMAND"))

sshCmd := os.Getenv("SSH_ORIGINAL_COMMAND")

verb, args := parseSSHCmd(sshCmd)

repoFullName := strings.ToLower(strings.Trim(args, "'"))

verbs := strings.Split(verb, " ")

var gitCmd *exec.Cmd

gitRepoPath := fmt.Sprintf("/opt/gitrepo/%s", repoFullName)

os.Setenv("MY_UID", "dalongrong")

if len(verb) == 2 {

println(verbs[0], verbs[1], gitRepoPath)

gitCmd = exec.Command(verbs[0], verbs[1], gitRepoPath)

} else {

println(verbs[0], gitRepoPath)

gitCmd = exec.Command(verb, gitRepoPath)

}

gitCmd.Stdin = os.Stdin

gitCmd.Stdout = os.Stdout

gitCmd.Stderr = os.Stderr

if err := gitCmd.Run(); err != nil {

log.Fatal("Internal error", "Failed to execute git command: %v", err)

}

return

}

docker 构建

FROM golang:1.17-alpine AS build-env

WORKDIR /go/src/app

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

ENV GO111MODULE=on

ENV GOPROXY=. .

RUN apk update && apk add git \

&& go build -o git-shell

FROM alpine:latest

WORKDIR /app

RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories

RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/*

COPY --from=build-env /go/src/app/git-shell /app/git-shell

authorized_keys 配置格式目前比较简单,没有进行复杂的校验处理command 部分使用了自己开发的git 处理

command="/opt/git-shell",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty

openssh 服务启动基于docker-compose 运行

version: '3'

services:

ssh:

image: dalongrong/openssh-server

build: ./

environment:

- PUID=1000

- PGID=1000

- TZ=Asia/Shanghai

- SUDO_ACCESS=true #optional

- PASSWORD_ACCESS=true #optional

- USER_PASSWORD=dalongdemo #optional

- USER_NAME=git #optional

volumes:

- ./config:/config

- ./gitrepo:/opt/gitrepo

ports:

- "2222:2222"

使用说明

创建bare git repo启动之后我们需要创建git repo 注意是bare 模式的进入openssh 容器

su git

cd /opt/gitrepo

git init --bare demoapp2.git

效果

添加ssh 认证客户config的.ssh 文件夹中的authorized_keys 格式如上clone 代码

git clone ssh://git@localhost:2222/demoapp2.git demoapp2

效果

push 代码

cd demoapp2

touch rong.txt

git add --all

git commit -m "add"

git push

效果

说明

如果有权限的问题就可能需要设置先权限了(openssh 容器内执行)

chmod 0755 /opt/gitrepo /config

chmod 700 /config/.ssh

以上是一个简单的学习,参考了gogs、gitlab 等开源项目,基于此可以对于git ssh server 就有了一个比较完整的了解

完整代码已经放github 了,大家可以参考,实际上目前一些开源的git 支持ssh 协议的基本都是这个套路,只是authorized_keys

的forcecommand 处理上大家好多是不一样的,而且新版本的gitlab 已经自己写了一个ssh server,同时推荐基于AuthorizedKeysCommand

更好的优化处ssh key 的处理了

参考资料

​​https://github.com/rongfengliang/write-one-git-ssh-server​​

​​https://github.com/gogs/gogs​​

​​https://github.com/PGYER/codefever​​

​​https://git-scm.com/docs/git-receive-pack​​

​​https://git-scm.com/docs/git-upload-pack​​

​​https://ssh.com/academy/ssh/authorized_keys/openssh​​

​​https://blog.scalesec.com/just-in-time-ssh-provisioning-7b20d9736a07​​

​​https://git-scm.com/book/zh/v2/Git-%E5%86%85%E9%83%A8%E5%8E%9F%E7%90%86-%E4%BC%A0%E8%BE%93%E5%8D%8F%E8%AE%AE​​

​​https://git-scm.com/docs/pack-protocol/2.2.3​​

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:基于golang cgi 实现一个简单的git http server
下一篇:无线网络接口卡收发器的设计与实现方案
相关文章

 发表评论

暂时没有评论,来抢沙发吧~