Назад | Перейти на главную страницу

HTTP-авторизация Nginx только для git push

Я размещаю частный сервер git с помощью Nginx. Я бы хотел, чтобы кто-нибудь клонировал в мои репозитории (без авторизации), но требую авторизации, если они попытаются подтолкнуть коммит.

Моя конфигурация Nginx выглядит следующим образом:

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;

  }

Насколько я понимаю, git push запрос отправляет git-receive-pack на мой сервер. Моим простым решением было записать этот суффикс с помощью $1 и используйте оператор if, но я быстро обнаружил, что это неправильное использование ifs (Ифисевиль).

Есть ли более подходящее решение для того, что я пытаюсь достичь?

git может отправлять разные запросы при нажатии (например, /path/to/repo.git/path/in/repo/refs?service=git-upload-pack или подобное), и вы пытались использовать равное сравнение.

Попробуйте что-нибудь подобное:

  # 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 ...
    }
    ...
  }

Но также в качестве рабочего сценария вы можете использовать что-то вроде этого:

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

или просто другой URL (и местоположение) для push, которые перезаписывают его после авторизации. Тогда ты можешь настроить удаленный с другим push-url (содержащим имя пользователя или другое местоположение):

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

Кстати, директива «if» не является более злой, чем расположение некоторого регулярного выражения верхнего уровня (особенно если она применяется только в определенном месте и не беспокоит напрямую в разделе http / server).
Но вы действительно можете сделать все это и без «если» (как в примере ниже с именованным расположением), но отладить некоторые проблемы не так просто (если вы не знакомы с nginx):

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 ...
  }
}