Nginx HTTP-Autorisierung nur für Git Push

Nginx HTTP-Autorisierung nur für Git Push

Ich hoste einen privaten Git-Server mit Nginx. Ich möchte, dass jeder (ohne Autorisierung) in meine Repos klonen kann, aber eine Autorisierung erforderlich ist, wenn jemand versucht, ein Commit zu pushen.

Meine Nginx-Konfiguration ist wie folgt:

server {
  listen 443 ssl;
  server_name git.example.com;
  ssl_certificate /fullchain.pem;
  ssl_certificate_key /privkey.pem;

  location ~ ^.*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|recieve)-pack) {
    root /usr/share/nginx/git;

# --- incorrect solution ---

#    if ($1 = git-upload-pack) {
#        auth_basic "Restricted";
#        auth_basic_user_file /usr/share/nginx/htpasswd;
#    }
    client_max_body_size 0;
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend;
    fastcgi_param GIT_HTTP_EXPORT_ALL "";
    fastcgi_param GIT_PROJECT_ROOT $realpath_root;
    fastcgi_param REMOTE_USER $remote_user;
    fastcgi_param PATH_INFO $uri;
    fastcgi_param unix:/var/fcgiwrap.socket;

  }

Nach meinem Verständnis git pushsendet eine Anfrage ein git-receive-packan meinen Server. Meine einfache Lösung bestand darin, dieses Suffix mit abzufangen $1und eine if-Anweisung zu verwenden, aber ich stellte schnell fest, dass dies nicht die richtige Verwendung für ifs ist (Abonnieren).

Gibt es für mein Ziel eine passendere Lösung?

Antwort1

Git könnte beim Pushen unterschiedliche Anfragen senden (zB /path/to/repo.git/path/in/repo/refs?service=git-upload-packoder ähnlich), und Sie haben versucht, einen Gleichvergleich durchzuführen.

Versuchen Sie so etwas:

  # static repo files for faster cloning over https:
  location ~ \.git/objects/(?:[0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+\.(?:pack|idx))$ {
    root /home/git/repositories/;
  }                                                                                                                                               

  # requests that need to go to git-http-backend:
  location ~ \.git/(?:HEAD|info/refs|objects/info/|git-(?:upload|receive)-pack$) {
    root /home/git/repositories;
    # if upload:
    if ( $uri ~* "git-upload-pack$" ) {
       auth_basic ...
    }
    ...
  }

Als Arbeitsszenario können Sie aber auch so etwas verwenden:

    # authorize if user name is specified:
    if ( $remote_user != "" ) {
       auth_basic ...
    }

oder einfach eine andere URL (und einen anderen Ort) für Push, die es nach der Autorisierung neu schreiben. Dann können SieRemote konfigurierenmit anderer Push-URL (die einen Benutzernamen oder einen anderen Ort enthält):

# with user:
git remote set-url --push origin https://[email protected]/repo/...
# with "rw" location (to force authorization):
git remote set-url --push origin https://git.domail.tld/rw/repo/...

Übrigens ist die Direktive „if“ nicht schlimmer als eine Regex-Position auf oberster Ebene (insbesondere, wenn sie nur an einer bestimmten Position angewendet wird und sich nicht direkt um den http/server-Abschnitt kümmert).
Sie können das alles tatsächlich auch ohne „if“ tun (wie im Beispiel unten mit benannter Position), aber bei einigen Problemen ist das Debuggen nicht so einfach (wenn Sie mit nginx nicht vertraut sind):

location ...condGit... {
  root ...;

  location ...condA... {
    ## authorize and supply request to @gitweb:
    auth_basic ...
    try_files "" @gitweb;
  }

  location ...condB... {
    ## authorize and supply request to @gitweb:
    auth_basic ...
    try_files "" @gitweb;
  }

  # send anything else to gitweb if it's not a real file (inside root of gitweb):
  try_files $uri @gitweb;

  location @gitweb {
    # ... single location of fcgi wrapper of git http backend ...
  }
}

verwandte Informationen