Question

I have a server running gitlab. All accesses to this server must go through apache https and clients must present a valid certificate signed by the CA which also issued the server certificate.

After a lot of research, I have been able to access the gitlab interface from the browser. But I'm not able to clone the repository. I seem to be able to present the right certificate at the apache level but then I get a "401 Unauthorized". I suppose the git authentification with the ssh public/private keys pair fails.

After several input of the certificate passphrase in the console or in the askpass GUI, I get the following output:

$ GIT_SSL_CERT=~/.ssh/cert.pem git clone https://host/gitlab/xxx/yyy.git
Cloning into 'yyy'...
* Couldn't find host host.domain in the .netrc file; using defaults
* About to connect() to host.domain port 443 (#0)
*   Trying 123.456.789.012...
* Connected to host.domain (123.456.789.012) port 443 (#0)
* Connected to host.domain (123.456.789.012) port 443 (#0)
Enter PEM pass phrase:
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL connection using DHE-RSA-AES256-GCM-SHA384
* Server certificate:
*        subject: C=FR; O=xyz; OU=Technique; CN=host.domain
*        start date: 2014-03-11 12:53:46 GMT
*        expire date: 2019-03-11 12:53:46 GMT
*        issuer: C=FR; O=XYZ; OU=0002 775685019; OU=AC; CN=XYZ 
*        SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> GET /gitlab/xxx/yyy.git/info/refs?service=git-upload-pack HTTP/1.1
User-Agent: git/1.8.1.5
Host: host.domain
Accept: */*
Accept-Encoding: gzip
Pragma: no-cache

* The requested URL returned error: 401 Unauthorized
* Closing connection #0
Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.
Fontconfig warning: "/etc/fonts/conf.d/50-user.conf", line 9: reading configurations from ~/.fonts.conf is deprecated.
* Couldn't find host host.domain in the .netrc file; using defaults
* About to connect() to host.domain port 443 (#0)
*   Trying 123.456.789.012...
* Connected to host.domain (123.456.789.012) port 443 (#0)
* Connected to host.domain (123.456.789.012) port 443 (#0)
Enter PEM pass phrase:
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL re-using session ID
* SSL connection using DHE-RSA-AES256-GCM-SHA384
* Server certificate:
*        subject: C=FR; O=xyz; OU=Technique; CN=host.domain
*        start date: 2014-03-11 12:53:46 GMT
*        expire date: 2019-03-11 12:53:46 GMT
*        issuer: C=FR; O=XYZ; OU=0002 775685019; OU=AC; CN=XYZ 
*        SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
> GET /gitlab/xxx/yyy.git/info/refs?service=git-upload-pack HTTP/1.1
User-Agent: git/1.8.1.5
Host: host.domain
Accept: */*
Accept-Encoding: gzip
Pragma: no-cache

< HTTP/1.1 401 Unauthorized
< Date: Tue, 18 Mar 2014 10:38:35 GMT
< Status: 401 Unauthorized
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 0
< WWW-Authenticate: Basic realm=""
< Cache-Control: no-cache
< X-Request-Id: 74f54f7b-b9b3-41c2-a55f-8e4c0f90b1e6
< X-Runtime: 0.003925
< Connection: close
< 
* Closing connection #0
* Issue another request to this URL: 'https://host.domain/gitlab/xxx/yyy.git/info/refs?service=git-upload-pack'
* Couldn't find host host.domain in the .netrc file; using defaults
* About to connect() to host.domain port 443 (#0)
*   Trying 123.456.789.012...
* Connected to host.domain (123.456.789.012) port 443 (#0)
* Connected to host.domain (123.456.789.012) port 443 (#0)
Enter PEM pass phrase:
* successfully set certificate verify locations:
*   CAfile: /etc/pki/tls/certs/ca-bundle.crt
  CApath: none
* SSL re-using session ID
* SSL connection using DHE-RSA-AES256-GCM-SHA384
* Server certificate:
*        subject: C=FR; O=xyz; OU=Technique; CN=host.domain
*        start date: 2014-03-11 12:53:46 GMT
*        expire date: 2019-03-11 12:53:46 GMT
*        issuer: C=FR; O=XYZ; OU=0002 775685019; OU=AC; CN=XYZ 
*        SSL certificate verify result: self signed certificate in certificate chain (19), continuing anyway.
* Server auth using Basic with user 'PASSWORDINCLEAR'
> GET /gitlab/xxx/yyy.git/info/refs?service=git-upload-pack HTTP/1.1
Authorization: Basic xxxxx
User-Agent: git/1.8.1.5
Host: host.domain
Accept: */*
Accept-Encoding: gzip
Pragma: no-cache

< HTTP/1.1 401 Unauthorized
< Date: Tue, 18 Mar 2014 10:38:44 GMT
< Status: 401 Unauthorized
< Content-Type: text/plain; charset=UTF-8
< Content-Length: 0
* Authentication problem. Ignoring this.
< WWW-Authenticate: Basic realm=""
< Cache-Control: no-cache
< X-Request-Id: 9fc67b79-180d-4b8a-8c42-95fd472a31a7
< X-Runtime: 0.005070
< Connection: close
* The requested URL returned error: 401
* Closing connection #0
fatal: Authentication failed

The apache ssl.conf file is:

# SSLRequireString is an environment variable defined like that: "%{SSL_CLIENT_S_DN_CN} =~ m/XXX/"

<VirtualHost _default_:443>
  SSLProxyEngine on

  ProxyPreserveHost On
  ProxyRequests Off
  ProxyPass /gitlab/ http://127.0.0.1:8080/
  ProxyPassReverse /gitlab/ http://127.0.0.1:8080/
  ProxyPass         /assets/ http://127.0.0.1:8080/gitlab/assets/
  ProxyPassReverse  /assets/ http://127.0.0.1:8080/gitlab/assets/

  ProxyPass /redmine/ http://127.0.0.1:80/redmine/
  ProxyPassReverse /redmine/ http://127.0.0.1:80/redmine/

  ProxyPass /buildbot/ http://127.0.0.1:8010/
  ProxyPassReverse /buildbot/ http://127.0.0.1:8010/

  ProxyPass /unit-tests/ http://127.0.0.1/unit-tests/
  ProxyPassReverse /unit-tests/ http://127.0.0.1/unit-tests/ 



  <Location /redmine/>
    ProxyPassReverse http://127.0.0.1:80/redmine/
    Order deny,allow
    Allow from all
    SSLRequire (    ${SSLRequireString} )
  </Location>

  <Location /gitlab/>
    ProxyPassReverse http://127.0.0.1:8080/
    Order deny,allow
    Allow from all
    SSLRequire (    ${SSLRequireString} )
  </Location>

  <Location /assets/>
    ProxyPassReverse http://127.0.0.1:8080/gitlab/assets/
    Order deny,allow
    Allow from all
    SSLRequire (    ${SSLRequireString} )
  </Location>

  <Location /buildbot/>
    ProxyPassReverse http://127.0.0.1:8010/
    Order deny,allow
    Allow from all
    SSLRequire (    ${SSLRequireString} )
  </Location>

  <Location /unit-tests/>
    ProxyPassReverse http://127.0.0.1/unit-tests/
    Order deny,allow
    Allow from all
    SSLRequire (    ${SSLRequireString} )
  </Location>

  RewriteEngine on
  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  RewriteRule .*gitlab.* http://127.0.0.1:8080%{REQUEST_URI} [P,QSA]
#  RewriteRule .*redmine.* http://127.0.0.1:80%{REQUEST_URI} [P,QSA]
  RequestHeader set X_FORWARDED_PROTO 'https'

ServerName host.domain:443

SSLEngine on
SSLProtocol all -SSLv2
SSLCipherSuite ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW
SSLCertificateFile /etc/pki/tls/certs/server.pem
SSLCertificateKeyFile /etc/pki/tls/private/server.key
#SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt
SSLCACertificateFile /etc/pki/tls/certs/server-bundle.pem
SSLVerifyClient require
SSLVerifyDepth  10
<Location />
SSLRequire (    ${SSLRequireString} )
</Location>

The ~/.ssh/config is:

Host * Compression yes ForwardX11 yes Ciphers arcfour,blowfish-cbc

Host host.domain
        Hostname host.domain
        User git
        IdentityFile ~/.ssh/id_rsa4

There is several steps where something can fail and right now, I'm stuck. I have no more idea to where to search for.

Update: Clone is susccessful by issuing

GIT_SSL_CERT=~/.ssh/cert.pem git clone https://host.domain/gitlab/xxx/xxx.git

Then entering the pem passphrase one time, entering the gitlab username and password in the two ssh-askpass dialogs that open and then entering the pem passphrase again three times.

During all this process, I get in the logs:

/var/log/httpd/ssl_access_log-20140318
ww.xx.yy.zz - - [24/Mar/2014:16:08:15 +0100] "GET /gitlab/xxx/yyy.git/info/refs?service=git-upload-pack HTTP/1.1" 401 -
ww.xx.yy.zz - - [24/Mar/2014:16:08:18 +0100] "GET /gitlab/xxx/yyy.git/info/refs?service=git-upload-pack HTTP/1.1" 200 282
ww.xx.yy.zz - - [24/Mar/2014:16:08:21 +0100] "POST /gitlab/xxx/yyy.git/git-upload-pack HTTP/1.1" 200 18482648

/home/git/gitlab/log/production.log
Started GET "/gitlab/xxx/yyy.git/info/refs?service=git-upload-pack" for 127.0.0.1 at 2014-03-24 16:07:59 +0100
Started GET "/gitlab/xxx/yyy.git/info/refs?service=git-upload-pack" for 127.0.0.1 at 2014-03-24 16:08:15 +0100
Started GET "/gitlab/xxx/yyy.git/info/refs?service=git-upload-pack" for 127.0.0.1 at 2014-03-24 16:08:18 +0100
Started POST "/gitlab/xxx/yyy.git/git-upload-pack" for 127.0.0.1 at 2014-03-24 16:08:21 +0100

So cloning somewhat works but it is not really convenient. Should I close this question and open a new one ?

P.S.: server and client are under GNU/Linux (respectively Scientific Linux 6.5 and Mageia 3). Gitlab versions are: GitLab 6.5.1, GitLab Shell 1.8.0, GitLab API v3, Ruby 1.9.3p194, Rails 4.0.2.

Was it helpful?

Solution 2

I finally made it work and wrote the following instructions for my colleagues:

You will be able to clone with the following configuration set beforehand:

# This is the certificate in PEM format to authenticate. 
git config --global http.sslCert <path to your X.509 (pem) certificate>
# This is the same certificate as above, this time to make git accept a self-signed certificate
git config --global http.sslCAInfo <path to your X.509 (pem) certificate>
# This allows to input the certificate password only once
git config --global http.sslCertPasswordProtected 1

You may also want to avoid setting global options like that as it will have unwanted side effects on other repositories. Then, you have to set the options locally by cloning through the command line with the following parameters:

git clone -c http.sslCAInfo=<path to your X.509 (pem) certificate> \
              -c http.sslCert=<path to your X.509 (pem) certificate> \
              -c http.sslCertPasswordProtected=1 \
     https://host.domain/path/to/repository.git

For issuing git commands, to avoid too much interactive inputs, include the gitlab username in the URL:

git clone 'https://user@host.domain/path/to/repository.git'

With this setting you should be asked two times for your "SSH passphrase": input you certificate password on the first time and your gitlab password on the second one.

OTHER TIPS

Did you try a local clone without going through apache, from the server using 127.0.0.1:8080...?

Also, check the logs to know if the 401 is coming from gitlab or apache.

Anyway, don't expect to use the ssh key if you are over HTTP so ssh config is irrelevant. It seems to be using login/password as expected as you can see on the line Server auth using Basic with user 'PASSWORDINCLEAR' but this should be the user there, not the password so you may have a problem there on your client configuration.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top