Difference between revisions of "Git, Apache and HTTPS with a free certificate"

From Wiki de Caballero
Jump to navigation Jump to search
 
(17 intermediate revisions by the same user not shown)
Line 9: Line 9:
This is a basic setup to allow Git on a server to be accessible via HTTP (no HTTPS yet, read further).
This is a basic setup to allow Git on a server to be accessible via HTTP (no HTTPS yet, read further).


===Configuration===
# Install Apache <source lang="bash">
# Install Apache <source lang="bash">
sudo apt-get install apache2 apache2-utils
sudo apt-get install apache2 apache2-utils
Line 55: Line 56:
* [https://git-scm.com/docs/git-http-backend Git - git-http-backend Documentation]
* [https://git-scm.com/docs/git-http-backend Git - git-http-backend Documentation]
* For more info on htpasswd, read the docs.
* For more info on htpasswd, read the docs.
===File permissions===
For Git push to work Apache must be able to write in the git repositories. There are several ways to do this but I can think of two easy ones:
* Change the Git repositories group to www-data and allow group to write.
* Change the Git repositories to a group created by you and add the user www-data to this group.
I prefer the second way because it allows more users to be part of a group and it feels more controllable and ordered.


==Self signed Certificate==
==Self signed Certificate==
Line 126: Line 134:
openssl x509 -text -noout -in selfsigned.crt
openssl x509 -text -noout -in selfsigned.crt
</source>
</source>
<hr><hr><hr>


Sources:
Sources:
Line 152: Line 159:
Notes:
Notes:
* default-ssl.conf configures a site using the certificate but you must be careful to show only what you want to show, for instance copy some of the configuration from the 000-default.conf like DocumentRoot and additional custom information.
* default-ssl.conf configures a site using the certificate but you must be careful to show only what you want to show, for instance copy some of the configuration from the 000-default.conf like DocumentRoot and additional custom information.
* This is the default default-ssl.conf file with the the changes made in the previous instructions:<div class="toccolours mw-collapsible mw-collapsed"><source lang="apache">

* This is the default default-ssl.conf file with the changes made in the previous instructions:
<div class="toccolours mw-collapsible mw-collapsed">
/etc/apache2/sites-available/default-ssl.conf
<div class="mw-collapsible-content"><source lang="apache">

<IfModule mod_ssl.c>
<IfModule mod_ssl.c>
<VirtualHost _default_:443>
<VirtualHost _default_:443>
Line 288: Line 298:
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet


</source>
</div>
</source>

</div>
</div>


Sources:
Sources:
* https://www.maketecheasier.com/apache-server-ssl-support/
* [https://www.maketecheasier.com/apache-server-ssl-support/ Setting up Apache Server with SSL Support on Ubuntu]
https://www.digicert.com/ssl-certificate-installation-apache.htm
* [https://www.digicert.com/ssl-certificate-installation-apache.htm SSL Certificate Installation - Apache Server | DigiCert.com]
* https://www.youtube.com/watch?v=YR6-6XUC3sY
* [https://www.youtube.com/watch?v=YR6-6XUC3sY Configuring HTTPS or SSL on apache web server - YouTube]
* https://www.youtube.com/watch?v=m06TttS2ZAM
* [https://www.youtube.com/watch?v=m06TttS2ZAM How to Install SSL Certificate on Linux Apache Web Server - YouTube]


Forcing the right protocol:
Forcing the right protocol:
Line 301: Line 313:
* https://serverfault.com/questions/314858/how-to-enable-tls-1-1-and-1-2-with-openssl-and-apache
* https://serverfault.com/questions/314858/how-to-enable-tls-1-1-and-1-2-with-openssl-and-apache


Other links:
==Git using the Self-Signed Certificate==
* https://httpd.apache.org/docs/2.4/ssl/ssl_howto.html#ocspstapling
 
If you use a valid Certificate, that is checkable by a Root authority, you probably don’t need to follow these steps. However, if you use a self-signed certificate Git won’t pull or push since it won’t trust the certificate given by the server.
 
'''Server''' is where Apache is running with Git. '''Client''' is the computer where we want to use Git connected via https to the server.
 
To avoid the above problem we will transfer manually the certificate to the computer where we want to connect using Git. Then we will configure Git to use the certificate. The usual flow to obtain a Git repository is to use clone, we will not use this flow as Git won't clone.
 
<h3 style="font-weight: bold; color: salmon;">Important</h3>
* When generating the certificate in the previous steps for '''Common Name (e.g. server FQDN or YOUR name)''' use the server's IP or domain. If you're using a dynamic IP you should probably use some kind of dynamic DNS to assign a domain to your server so your certificate will always match the same domain.
* The per server syntax (<code>git config http."https://servername/".sslCAInfo [directory where crt is located]/selfsigned.crt</code>) is not supported by all Git versions. If your version doesn't support it you can go in one of tow ways:<source lang="bash">
# Way 1
# Add a configuration parameter to the git command every time communication with the server is needed: -c http.sslcainfo="[location of certificate]/selfsigned.crt"
# For instance
git -c http.sslcainfo="[location of certificate]/selfsigned.crt" pull
 
 
# Way 2
# Use your certificate for all verifications
# Inside the git repository do
git config http.sslCAInfo [directory where crt is located]/selfsigned.crt
 
# I haven't tried but...
# You might also want to check the configuration variable http.sslCAPath, it might have a directory for multiple certificates.
</source>
 
===Way 1===
# Transfer the certificate from the server to the client. The file ending with crt. '''Do not transfer the Private Key''', this key is meant for the server only. Try using a secure connection to transfer it, for instance use ssh. You can place the certificate wherever you want, to avoid headaches place it outside the git project you will next create, it can be done but it's a pain.
# Create an empty repository on the client.<source lang="bash">
git init [name]
# name is the name of the repository, the same name that would be used with git clone
# You could use whatever but perhaps it's a good idea to use the same name
</source>
# Add the remote <source lang="bash">
git remote add origin https://servername/git/givenRepository
# serverName could also be an IP
</source>
# Configure Git to use this certificate to communicate with the server. You can do this two different ways:<source lang="bash">
# Way 1
# This configures the CA for every remote
git config http.sslCAInfo [directory where crt is located]/selfsigned.crt
 
# Way 2
# This configures the CA only to be used with https://servername/
git config http."https://servername/".sslCAInfo [directory where crt is located]/selfsigned.crt
</source>
# Prepare your client's Git repository:<source lang="bash">
git pull origin master
# Enter user/pass if needed
 
git push --set-upstream origin master
# Enter user/pass if needed
</source>
# Use the client's repository as you would normally do
 
===Way 2===
# Transfer the certificate from the server to the client. The file ending with crt. '''Do not transfer the Private Key''', this key is meant for the server only. Try using a secure connection to transfer it, for instance use ssh. You can place the certificate wherever you want, to avoid headaches place it outside the git project you will next create, it can be done but it's a pain.
# Clone but pass a configuration option in the cloning process:<source lang="bash">
git -c http.sslcainfo="[location of certificate]/selfsigned.crt" clone https://servername/git/givenRepository
</source>
# Configure Git to use this certificate to communicate with the server. You can do this two different ways:<source lang="bash">
# Way 1
# This configures the CA for every remote
git config http.sslCAInfo [directory where crt is located]/selfsigned.crt
 
# Way 2
# This configures the CA only to be used with https://servername/
git config http."https://servername/".sslCAInfo [directory where crt is located]/selfsigned.crt
</source>


==Configuring Git to use the self signed certificate==
Sources:
* https://stackoverflow.com/questions/11621768/how-can-i-make-git-accept-a-self-signed-certificate
* https://stackoverflow.com/questions/11621768/how-can-i-make-git-accept-a-self-signed-certificate
* https://stackoverflow.com/questions/23807313/adding-self-signed-ssl-certificate-without-disabling-authority-signed-ones
* https://stackoverflow.com/questions/23807313/adding-self-signed-ssl-certificate-without-disabling-authority-signed-ones
* https://stackoverflow.com/questions/9072376/configure-git-to-accept-a-particular-self-signed-server-certificate-for-a-partic
==Git using only https (and not http)==
To only allow access Git in a secure way (encrypted using https) remove all git directives from the file <code>/etc/apache2/apache2.conf</code> and add them to the file <code>/etc/apache2/sites-available/default-ssl.conf</code>. The file should look something like this:
<div class="toccolours mw-collapsible mw-collapsed">
/etc/apache2/sites-available/default-ssl.conf
<div class="mw-collapsible-content"><source lang="apache">

<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/html
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf
#  SSL Engine Switch:
#  Enable/Disable SSL for this virtual host.
SSLEngine on
#  A self-signed (snakeoil) certificate can be created by installing
#  the ssl-cert package. See
#  /usr/share/doc/apache2/README.Debian.gz for more info.
#  If both key and certificate are stored in the same file, only the
#  SSLCertificateFile directive is needed.
SSLCertificateFile /etc/apache2/ssl/selfsigned.crt
SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key
#  Server Certificate Chain:
#  Point SSLCertificateChainFile at a file containing the
#  concatenation of PEM encoded CA certificates which form the
#  certificate chain for the server certificate. Alternatively
#  the referenced file can be the same as SSLCertificateFile
#  when the CA certificates are directly appended to the server
#  certificate for convinience.
#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt
#  Certificate Authority (CA):
#  Set the CA certificate verification path where to find CA
#  certificates for client authentication or alternatively one
#  huge file containing all of them (file must be PEM encoded)
#  Note: Inside SSLCACertificatePath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCACertificatePath /etc/ssl/certs/
#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
#  Certificate Revocation Lists (CRL):
#  Set the CA revocation path where to find CA CRLs for client
#  authentication or alternatively one huge file containing all
#  of them (file must be PEM encoded)
#  Note: Inside SSLCARevocationPath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCARevocationPath /etc/apache2/ssl.crl/
#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
#  Client Authentication (Type):
#  Client certificate verification type and depth.  Types are
#  none, optional, require and optional_no_ca.  Depth is a
#  number which specifies how deeply to verify the certificate
#  issuer chain before deciding the certificate is not valid.
#SSLVerifyClient require
#SSLVerifyDepth  10


More sites:
#  SSL Engine Options:
* https://stackoverflow.com/questions/9072376/configure-git-to-accept-a-particular-self-signed-server-certificate-for-a-partic
#  Set various options for the SSL engine.
#  o FakeBasicAuth:
# Translate the client X.509 into a Basic Authorisation.  This means that
# the standard Auth/DBMAuth methods can be used for access control.  The
# user name is the `one line' version of the client's X.509 certificate.
# Note that no password is obtained from the user. Every entry in the user
# file needs this password: `xxj31ZMTZzkVA'.
#  o ExportCertData:
# This exports two additional environment variables: SSL_CLIENT_CERT and
# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
# server (always existing) and the client (only existing when client
# authentication is used). This can be used to import the certificates
# into CGI scripts.
#  o StdEnvVars:
# This exports the standard SSL/TLS related `SSL_*' environment variables.
# Per default this exportation is switched off for performance reasons,
# because the extraction step is an expensive operation and is usually
# useless for serving static content. So one usually enables the
# exportation for CGI and SSI requests only.
#  o OptRenegotiate:
# This enables optimized SSL connection renegotiation handling when SSL
# directives are used in per-directory context.
#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
 
#  SSL Protocol Adjustments:
#  The safe and default but still SSL/TLS standard compliant shutdown
#  approach is that mod_ssl sends the close notify alert but doesn't wait for
#  the close notify alert from client. When you need a different shutdown
#  approach you can use one of the following variables:
#  o ssl-unclean-shutdown:
# This forces an unclean shutdown when the connection is closed, i.e. no
# SSL close notify alert is send or allowed to received. This violates
# the SSL/TLS standard but is needed for some brain-dead browsers. Use
# this when you receive I/O errors because of the standard approach where
# mod_ssl sends the close notify alert.
#  o ssl-accurate-shutdown:
# This forces an accurate shutdown when the connection is closed, i.e. a
# SSL close notify alert is send and mod_ssl waits for the close notify
# alert of the client. This is 100% SSL/TLS standard compliant, but in
# practice often causes hanging connections with brain-dead browsers. Use
# this only for browsers where you know that their SSL implementation
# works correctly.
#  Notice: Most problems of broken clients are also related to the HTTP
#  keep-alive facility, so you usually additionally want to disable
#  keep-alive for those clients, too. Use variable "nokeepalive" for this.
#  Similarly, one has to force some clients to use HTTP/1.0 to workaround
#  their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
#  "force-response-1.0" for this.
# BrowserMatch "MSIE [2-6]" \
# nokeepalive ssl-unclean-shutdown \
# downgrade-1.0 force-response-1.0
 
 
# ******************************************
# ******************************************
# Added part
# Git
 
# Path to the Git directory (inside the OS)
SetEnv GIT_PROJECT_ROOT /git
 
# Allows all projects to be served
# If commented a file must exist in each available repository via Apache, file name: git-daemon-export-ok
SetEnv GIT_HTTP_EXPORT_ALL
 
# Defines the URL path where git is located, as seen via http
# First param is path, second is os path to git-http-backend, don't forget the last slash
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
 
# Access configuration
<Files "git-http-backend">
# Enable Basic HTTP Authentication
AuthType Basic
AuthName "Git Access"
AuthUserFile /git/.htpasswd
# The following line allows to obtain a repository (pull/fetch) without having a user/pass combo
# Comment it if user/pass are needed to obtain info as well
# Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
Require valid-user
# END Enable Basic HTTP Authentication
</Files>
# END Git
 
</VirtualHost>
</IfModule>
 
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
 
</source>

</div>
</div>


==Client based authentication using certificates in Apache==
==Client based authentication using certificates in Apache==
Used links:
===Apache configuration===
* http://wiki.cacert.org/ApacheServerClientCertificateAuthentication
To force Apache to serve only to clients that have a valid certificate add the following lines to <code>/etc/apache2/sites-available/default-ssl.conf</code>:
* https://stackoverflow.com/a/24543642/1071459
<source lang="apache">

* http://stuff-things.net/2015/09/28/configuring-apache-for-ssl-client-certificate-authentication/
# To allow certificate based authentication for clients
# Clients must have a certificate to login
SSLCACertificateFile /etc/apache2/ssl/selfsigned.crt
SSLVerifyClient require
</source>
 
The file should look like this:
<div class="toccolours mw-collapsible mw-collapsed">
/etc/apache2/sites-available/default-ssl.conf
<div class="mw-collapsible-content"><source lang="apache">

<IfModule mod_ssl.c>
<VirtualHost _default_:443>
ServerAdmin webmaster@localhost
 
DocumentRoot /var/www/html
 
# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
# error, crit, alert, emerg.
# It is also possible to configure the loglevel for particular
# modules, e.g.
#LogLevel info ssl:warn


Other links:
ErrorLog ${APACHE_LOG_DIR}/error.log
* http://pages.cs.wisc.edu/~zmiller/ca-howto/
CustomLog ${APACHE_LOG_DIR}/access.log combined
* https://httpd.apache.org/docs/current/mod/mod_ssl.html#sslcacertificatefile
 
# For most configuration files from conf-available/, which are
# enabled or disabled at a global level, it is possible to
# include a line for only one particular virtual host. For example the
# following line enables the CGI configuration for this host only
# after it has been globally disabled with "a2disconf".
#Include conf-available/serve-cgi-bin.conf


==(Possibly) Giving Git a Client Certificate==
#  SSL Engine Switch:
#  Enable/Disable SSL for this virtual host.
SSLEngine on


==More (possibly useful) info==
#  A self-signed (snakeoil) certificate can be created by installing
* https://www.creang.com/howtoforge/howto_set_up_git_over_https_with_apache_on_ubuntu/
#  the ssl-cert package. See
* http://ubuntuwiki.net/index.php/Apache,_Digest_authentication
#  /usr/share/doc/apache2/README.Debian.gz for more info.
#  If both key and certificate are stored in the same file, only the
#  SSLCertificateFile directive is needed.
SSLCertificateFile /etc/apache2/ssl/selfsigned.crt
SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key
 
#  Server Certificate Chain:
#  Point SSLCertificateChainFile at a file containing the
#  concatenation of PEM encoded CA certificates which form the
#  certificate chain for the server certificate. Alternatively
#  the referenced file can be the same as SSLCertificateFile
#  when the CA certificates are directly appended to the server
#  certificate for convinience.
#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt
 
#  Certificate Authority (CA):
#  Set the CA certificate verification path where to find CA
#  certificates for client authentication or alternatively one
#  huge file containing all of them (file must be PEM encoded)
#  Note: Inside SSLCACertificatePath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCACertificatePath /etc/ssl/certs/
#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
 
#  Certificate Revocation Lists (CRL):
#  Set the CA revocation path where to find CA CRLs for client
#  authentication or alternatively one huge file containing all
#  of them (file must be PEM encoded)
#  Note: Inside SSLCARevocationPath you need hash symlinks
# to point to the certificate files. Use the provided
# Makefile to update the hash symlinks after changes.
#SSLCARevocationPath /etc/apache2/ssl.crl/
#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
 
#  Client Authentication (Type):
#  Client certificate verification type and depth.  Types are
#  none, optional, require and optional_no_ca.  Depth is a
#  number which specifies how deeply to verify the certificate
#  issuer chain before deciding the certificate is not valid.
#SSLVerifyClient require
#SSLVerifyDepth  10
 
#  SSL Engine Options:
#  Set various options for the SSL engine.
#  o FakeBasicAuth:
# Translate the client X.509 into a Basic Authorisation.  This means that
# the standard Auth/DBMAuth methods can be used for access control.  The
# user name is the `one line' version of the client's X.509 certificate.
# Note that no password is obtained from the user. Every entry in the user
# file needs this password: `xxj31ZMTZzkVA'.
#  o ExportCertData:
# This exports two additional environment variables: SSL_CLIENT_CERT and
# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
# server (always existing) and the client (only existing when client
# authentication is used). This can be used to import the certificates
# into CGI scripts.
#  o StdEnvVars:
# This exports the standard SSL/TLS related `SSL_*' environment variables.
# Per default this exportation is switched off for performance reasons,
# because the extraction step is an expensive operation and is usually
# useless for serving static content. So one usually enables the
# exportation for CGI and SSI requests only.
#  o OptRenegotiate:
# This enables optimized SSL connection renegotiation handling when SSL
# directives are used in per-directory context.
#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
<FilesMatch "\.(cgi|shtml|phtml|php)$">
SSLOptions +StdEnvVars
</FilesMatch>
<Directory /usr/lib/cgi-bin>
SSLOptions +StdEnvVars
</Directory>
 
#  SSL Protocol Adjustments:
#  The safe and default but still SSL/TLS standard compliant shutdown
#  approach is that mod_ssl sends the close notify alert but doesn't wait for
#  the close notify alert from client. When you need a different shutdown
#  approach you can use one of the following variables:
#  o ssl-unclean-shutdown:
# This forces an unclean shutdown when the connection is closed, i.e. no
# SSL close notify alert is send or allowed to received.  This violates
# the SSL/TLS standard but is needed for some brain-dead browsers. Use
# this when you receive I/O errors because of the standard approach where
# mod_ssl sends the close notify alert.
#  o ssl-accurate-shutdown:
# This forces an accurate shutdown when the connection is closed, i.e. a
# SSL close notify alert is send and mod_ssl waits for the close notify
# alert of the client. This is 100% SSL/TLS standard compliant, but in
# practice often causes hanging connections with brain-dead browsers. Use
# this only for browsers where you know that their SSL implementation
# works correctly.
#  Notice: Most problems of broken clients are also related to the HTTP
#  keep-alive facility, so you usually additionally want to disable
#  keep-alive for those clients, too. Use variable "nokeepalive" for this.
#  Similarly, one has to force some clients to use HTTP/1.0 to workaround
#  their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
#  "force-response-1.0" for this.
# BrowserMatch "MSIE [2-6]" \
# nokeepalive ssl-unclean-shutdown \
# downgrade-1.0 force-response-1.0
 
 
# ******************************************
# ******************************************
# Added part
# Git
 
# Path to the Git directory (inside the OS)
SetEnv GIT_PROJECT_ROOT /git
 
# Allows all projects to be served
# If commented a file must exist in each available repository via Apache, file name: git-daemon-export-ok
SetEnv GIT_HTTP_EXPORT_ALL
 
# Defines the URL path where git is located, as seen via http
# First param is path, second is os path to git-http-backend, don't forget the last slash
ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
 
# Access configuration
<Files "git-http-backend">
# Enable Basic HTTP Authentication
AuthType Basic
AuthName "Git Access"
AuthUserFile /git/.htpasswd
# The following line allows to obtain a repository (pull/fetch) without having a user/pass combo
# Comment it if user/pass are needed to obtain info as well
# Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
Require valid-user
# END Enable Basic HTTP Authentication
</Files>
# END Git
 
</VirtualHost>
</IfModule>
 
# vim: syntax=apache ts=4 sw=4 sts=4 sr noet
 
</source>

</div>
</div>
 
===Client certificate===
The client certificate generation works like this:
* Setup a root CA key and certificate, in our case the file selfsigned.crt acts as a root CA.
* The client generates his private key and certificate request, since we control both the server and the client this can be done in either machine.
* Generate the client certificate using the cliente certificate request, the root certificate and the root key.
 
Steps:
<source lang="bash">
# Generate the client key
openssl genrsa -out client.key 2048
# Generate the client csr (Certificate Signing Request)
openssl req -new -key client.key -out client.csr
# Generate the client certificate, change serial number for every new certificate
openssl x509 -req -in client.csr -CA selfsigned.crt -CAkey selfsigned.key -set_serial 01 -out client.crt
 
# Generate a p12 file, this can be used for a browser but will probably have to be installed in the OS or the Browser
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -chain -CAfile ../oneline/selfsigned.crt
</source>
 
Source:
* [http://stuff-things.net/2015/09/28/configuring-apache-for-ssl-client-certificate-authentication/ Configuring Apache for SSL Client Certificate Authentication - Stuff… And Things…]
* [https://stackoverflow.com/a/24543642/1071459 How to do client certificate authentication with Apache - Stack Overflow]
 
==Git using a Client Certificate==
If we configured Apache for client based authentication then Git needs a certificate to use to communicate with Apache.
 
Steps:
# Transfer the client key and certificate to the client. This means client.key and client.csr.
# Follow steps from the previos section: [[#Git using the Self-Signed Certificate|Git using the Self-Signed Certificate]].
# Configure Git to use the transferred files: <source lang="bash">
git config http.sslCert [client os location]/client.crt
git config http.sslKey [client os location]/client.key
</source>


==Further reading==
==Further reading==
* [https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-16-04 How To Create a Self-Signed SSL Certificate for Apache in Ubuntu 16.04 | DigitalOcean]
* [https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-apache-in-ubuntu-16-04 How To Create a Self-Signed SSL Certificate for Apache in Ubuntu 16.04 | DigitalOcean]
* [http://ubuntuwiki.net/index.php/Apache,_Digest_authentication Apache, Digest authentication - Ubuntuwiki.net]
[[Category:git]]
[[Category:http]]
[[Category:https]]
[[Category:apache]]
[[Category:web]]

Latest revision as of 21:31, 30 August 2019

Prerequisites

  • Ubuntu CLI understanding
  • Git knowledge
  • Ubuntu, this was tested using Ubuntu 16
  • Apache 2

Git using Apache

This is a basic setup to allow Git on a server to be accessible via HTTP (no HTTPS yet, read further).

Configuration

  1.  Install Apache
    sudo apt-get install apache2 apache2-utils
  2. Enable necessary modules
    a2enmod cgi alias env
  3. (Optional) Add user(s) to the htpasswd file. This step is optional if this setup is going to serve only anonymous repository (pull/fetch). However if you want to push or if you want to allow to only obtain a repository using user/pass combo this step is necessary (see next step).
    # Create file and add a user
    # -c = create file
    # The file is stored in /git/ the git repository for this specific setup
    htpasswd -c /git/.htpasswd [user name]
    # This will ask for a password
    
    # Add a user to the file
    htpasswd /git/.htpasswd [user name]
  4. To allow to obtain a git repository using http, add the following to the apache2.conf
    # Path to the Git directory (inside the OS)
    SetEnv GIT_PROJECT_ROOT /git
    
    # Allows all projects to be served
    # If commented a file must exist in each available repository via Apache, file name: git-daemon-export-ok
    SetEnv GIT_HTTP_EXPORT_ALL
    
    # Defines the URL path where git is located, as seen via http
    # First param is path, second is os path to git-http-backend, don't forget the last slash
    ScriptAlias /git/ /usr/lib/git-core/git-http-backend/
    
    # Access configuration
    <Files "git-http-backend">
    	# Enable Basic HTTP Authentication
    	AuthType Basic
    	AuthName "Git Access"
    	AuthUserFile /git/.htpasswd
    	# The following line allows to obtain a repository (pull/fetch) without having a user/pass combo
    	# Comment it if user/pass are needed to obtain info as well
    	Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
    	Require valid-user
    	# END Enable Basic HTTP Authentication
    </Files>

Additional info:

File permissions

For Git push to work Apache must be able to write in the git repositories. There are several ways to do this but I can think of two easy ones:

  • Change the Git repositories group to www-data and allow group to write.
  • Change the Git repositories to a group created by you and add the user www-data to this group.

I prefer the second way because it allows more users to be part of a group and it feels more controllable and ordered.

Self signed Certificate

How Certificates work

Here are some videos on how certificates and SSL (TLS) work:

Additional info:

Why certificates are needed

To allow git to be served using https the server must have a certificate. Now, this certificate can be signed by a root Certificate Authority (CA), an Intermediate Cerfificate Authority (validated by a root CA) or a self signed certificate. To get a root or intermediate CA Certificate you must contact a company to give you one and pay for it. You could also create your own root or intermediate CA but this outside the scope of this article.

How to create a Self-Signed Certificate

Disclaimer: I am not an expert in OpenSSL, these are my tests and I might have made wrong assumptions. Please read the OpenSSL docs.

This is done on an Ubuntu 16 but you could do this in another system, you do need OpenSSl. The process is actually very simple.

Here are three ways of creating a Self-Signed Certificate:

# Way 1 - One line
# ********************
# This command outputs two files, the private key and the certificate. The certificate will be valid for 1 year (use '-days [number]' to change this).
#
#
# -nodes = not encrypted, if you leave this out, Apache will ask for a password when using the private key
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout selfsigned.key -out selfsigned.crt


# Way 2 - Two steps
# ********************
# First the key is generated and second the certificate is generated using the generated key.
#
# Step 1: Generate the Private Key
# Step 1 - Option 1) -des3 encrypts the key, Apache will ask for a password when using the private key
openssl genrsa -des3 -out selfsigned.key 2048
# Step 1 - Option 2) No key encryption
openssl genrsa -out selfsigned.key 2048
#
# Step 2
# The certificate will be valid for 1 year (use '-days [number]' to change this).
openssl req -x509 -new -key selfsigned.key -out selfsigned.crt


# Way 3 - Three steps
# ********************
# First the key is generated, then a signing request is generated and finally the certificate is generated using the generated key and the signing request.
#
# Step 1: Generate the Private Key
# Step 1 - Option 1) -des3 encrypts the key, Apache will ask for a password when using the private key
openssl genrsa -des3 -out selfsigned.key 2048
# Step 1 - Option 2) No key encryption
openssl genrsa -out selfsigned.key 2048
#
# Step 2: Generate the Signing Request (.csr = Certificate Signing Request)
openssl req -new -key selfsigned.key -out selfsigned.csr
#
# Step 3: Generate the certificate using the Private Key and the Signing Request
# The certificate will be valid for 1 year (use '-days [number]' to change this).
openssl x509 -req -in selfsigned.csr -signkey selfsigned.key -out selfsigned.crt



# Check the certificate (a.k.a. see what's inside)
# ********************
openssl x509 -text -noout -in selfsigned.crt

Sources:

More info on how to create a root Certificate and how to create a Certificate Authority

Configuring Apache to use https

This are the steps to allow Apache to use https:

  1. Pick a location for the certificates and move them there (they could also be linked or copied), the location used in this example will be /etc/apache2/ssl.
  2. Enable SSL module for Apache:
    a2enmod ssl
  3. Edit /etc/apache2/sites-available/default-ssl.conf, change (or add) the following lines to point to the certificate and the private key:
    	# Certificate file
    	SSLCertificateFile	/etc/apache2/ssl/selfsigned.crt
    	# Private key
    	SSLCertificateKeyFile	/etc/apache2/ssl/selfsigned.key

  4. Enable the default ssl site:
    a2ensite default-ssl.conf
  5. Restart Apache:
    service apache2 restart

Notes:

  • default-ssl.conf configures a site using the certificate but you must be careful to show only what you want to show, for instance copy some of the configuration from the 000-default.conf like DocumentRoot and additional custom information.
  • This is the default default-ssl.conf file with the changes made in the previous instructions:

/etc/apache2/sites-available/default-ssl.conf



<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		ServerAdmin webmaster@localhost

		DocumentRoot /var/www/html

		# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
		# error, crit, alert, emerg.
		# It is also possible to configure the loglevel for particular
		# modules, e.g.
		#LogLevel info ssl:warn

		ErrorLog ${APACHE_LOG_DIR}/error.log
		CustomLog ${APACHE_LOG_DIR}/access.log combined

		# For most configuration files from conf-available/, which are
		# enabled or disabled at a global level, it is possible to
		# include a line for only one particular virtual host. For example the
		# following line enables the CGI configuration for this host only
		# after it has been globally disabled with "a2disconf".
		#Include conf-available/serve-cgi-bin.conf

		#   SSL Engine Switch:
		#   Enable/Disable SSL for this virtual host.
		SSLEngine on

		#   A self-signed (snakeoil) certificate can be created by installing
		#   the ssl-cert package. See
		#   /usr/share/doc/apache2/README.Debian.gz for more info.
		#   If both key and certificate are stored in the same file, only the
		#   SSLCertificateFile directive is needed.
		SSLCertificateFile	/etc/apache2/ssl/selfsigned.crt
		SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key

		#   Server Certificate Chain:
		#   Point SSLCertificateChainFile at a file containing the
		#   concatenation of PEM encoded CA certificates which form the
		#   certificate chain for the server certificate. Alternatively
		#   the referenced file can be the same as SSLCertificateFile
		#   when the CA certificates are directly appended to the server
		#   certificate for convinience.
		#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt

		#   Certificate Authority (CA):
		#   Set the CA certificate verification path where to find CA
		#   certificates for client authentication or alternatively one
		#   huge file containing all of them (file must be PEM encoded)
		#   Note: Inside SSLCACertificatePath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCACertificatePath /etc/ssl/certs/
		#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt

		#   Certificate Revocation Lists (CRL):
		#   Set the CA revocation path where to find CA CRLs for client
		#   authentication or alternatively one huge file containing all
		#   of them (file must be PEM encoded)
		#   Note: Inside SSLCARevocationPath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCARevocationPath /etc/apache2/ssl.crl/
		#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl

		#   Client Authentication (Type):
		#   Client certificate verification type and depth.  Types are
		#   none, optional, require and optional_no_ca.  Depth is a
		#   number which specifies how deeply to verify the certificate
		#   issuer chain before deciding the certificate is not valid.
		#SSLVerifyClient require
		#SSLVerifyDepth  10

		#   SSL Engine Options:
		#   Set various options for the SSL engine.
		#   o FakeBasicAuth:
		#	 Translate the client X.509 into a Basic Authorisation.  This means that
		#	 the standard Auth/DBMAuth methods can be used for access control.  The
		#	 user name is the `one line' version of the client's X.509 certificate.
		#	 Note that no password is obtained from the user. Every entry in the user
		#	 file needs this password: `xxj31ZMTZzkVA'.
		#   o ExportCertData:
		#	 This exports two additional environment variables: SSL_CLIENT_CERT and
		#	 SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
		#	 server (always existing) and the client (only existing when client
		#	 authentication is used). This can be used to import the certificates
		#	 into CGI scripts.
		#   o StdEnvVars:
		#	 This exports the standard SSL/TLS related `SSL_*' environment variables.
		#	 Per default this exportation is switched off for performance reasons,
		#	 because the extraction step is an expensive operation and is usually
		#	 useless for serving static content. So one usually enables the
		#	 exportation for CGI and SSI requests only.
		#   o OptRenegotiate:
		#	 This enables optimized SSL connection renegotiation handling when SSL
		#	 directives are used in per-directory context.
		#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
		<FilesMatch "\.(cgi|shtml|phtml|php)$">
				SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
				SSLOptions +StdEnvVars
		</Directory>

		#   SSL Protocol Adjustments:
		#   The safe and default but still SSL/TLS standard compliant shutdown
		#   approach is that mod_ssl sends the close notify alert but doesn't wait for
		#   the close notify alert from client. When you need a different shutdown
		#   approach you can use one of the following variables:
		#   o ssl-unclean-shutdown:
		#	 This forces an unclean shutdown when the connection is closed, i.e. no
		#	 SSL close notify alert is send or allowed to received.  This violates
		#	 the SSL/TLS standard but is needed for some brain-dead browsers. Use
		#	 this when you receive I/O errors because of the standard approach where
		#	 mod_ssl sends the close notify alert.
		#   o ssl-accurate-shutdown:
		#	 This forces an accurate shutdown when the connection is closed, i.e. a
		#	 SSL close notify alert is send and mod_ssl waits for the close notify
		#	 alert of the client. This is 100% SSL/TLS standard compliant, but in
		#	 practice often causes hanging connections with brain-dead browsers. Use
		#	 this only for browsers where you know that their SSL implementation
		#	 works correctly.
		#   Notice: Most problems of broken clients are also related to the HTTP
		#   keep-alive facility, so you usually additionally want to disable
		#   keep-alive for those clients, too. Use variable "nokeepalive" for this.
		#   Similarly, one has to force some clients to use HTTP/1.0 to workaround
		#   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
		#   "force-response-1.0" for this.
		# BrowserMatch "MSIE [2-6]" \
		#		nokeepalive ssl-unclean-shutdown \
		#		downgrade-1.0 force-response-1.0

	</VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Sources:

Forcing the right protocol:

Git using the Self-Signed Certificate

If you use a valid Certificate, that is checkable by a Root authority, you probably don’t need to follow these steps. However, if you use a self-signed certificate Git won’t pull or push since it won’t trust the certificate given by the server.

Server is where Apache is running with Git. Client is the computer where we want to use Git connected via https to the server.

To avoid the above problem we will transfer manually the certificate to the computer where we want to connect using Git. Then we will configure Git to use the certificate. The usual flow to obtain a Git repository is to use clone, we will not use this flow as Git won't clone.

Important

  • When generating the certificate in the previous steps for Common Name (e.g. server FQDN or YOUR name) use the server's IP or domain. If you're using a dynamic IP you should probably use some kind of dynamic DNS to assign a domain to your server so your certificate will always match the same domain.
  • The per server syntax (git config http."https://servername/".sslCAInfo [directory where crt is located]/selfsigned.crt) is not supported by all Git versions. If your version doesn't support it you can go in one of tow ways:
    # Way 1
    # Add a configuration parameter to the git command every time communication with the server is needed: -c http.sslcainfo="[location of certificate]/selfsigned.crt"
    # For instance
    git -c http.sslcainfo="[location of certificate]/selfsigned.crt" pull
    
    
    # Way 2
    # Use your certificate for all verifications
    # Inside the git repository do
    git config http.sslCAInfo [directory where crt is located]/selfsigned.crt
    
    # I haven't tried but...
    # You might also want to check the configuration variable http.sslCAPath, it might have a directory for multiple certificates.

Way 1

  1. Transfer the certificate from the server to the client. The file ending with crt. Do not transfer the Private Key, this key is meant for the server only. Try using a secure connection to transfer it, for instance use ssh. You can place the certificate wherever you want, to avoid headaches place it outside the git project you will next create, it can be done but it's a pain.
  2. Create an empty repository on the client.
    git init [name]
    # name is the name of the repository, the same name that would be used with git clone
    # You could use whatever but perhaps it's a good idea to use the same name
  3. Add the remote
    git remote add origin https://servername/git/givenRepository
    # serverName could also be an IP
  4. Configure Git to use this certificate to communicate with the server. You can do this two different ways:
    # Way 1
    # This configures the CA for every remote
    git config http.sslCAInfo [directory where crt is located]/selfsigned.crt
    
    # Way 2
    # This configures the CA only to be used with https://servername/
    git config http."https://servername/".sslCAInfo [directory where crt is located]/selfsigned.crt
  5. Prepare your client's Git repository:
    git pull origin master
    # Enter user/pass if needed
    
    git push --set-upstream origin master 
    # Enter user/pass if needed
  6. Use the client's repository as you would normally do

Way 2

  1. Transfer the certificate from the server to the client. The file ending with crt. Do not transfer the Private Key, this key is meant for the server only. Try using a secure connection to transfer it, for instance use ssh. You can place the certificate wherever you want, to avoid headaches place it outside the git project you will next create, it can be done but it's a pain.
  2. Clone but pass a configuration option in the cloning process:
    git -c http.sslcainfo="[location of certificate]/selfsigned.crt" clone https://servername/git/givenRepository
  3. Configure Git to use this certificate to communicate with the server. You can do this two different ways:
    # Way 1
    # This configures the CA for every remote
    git config http.sslCAInfo [directory where crt is located]/selfsigned.crt
    
    # Way 2
    # This configures the CA only to be used with https://servername/
    git config http."https://servername/".sslCAInfo [directory where crt is located]/selfsigned.crt

Sources:

Git using only https (and not http)

To only allow access Git in a secure way (encrypted using https) remove all git directives from the file /etc/apache2/apache2.conf and add them to the file /etc/apache2/sites-available/default-ssl.conf. The file should look something like this:

/etc/apache2/sites-available/default-ssl.conf



<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		ServerAdmin webmaster@localhost

		DocumentRoot /var/www/html

		# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
		# error, crit, alert, emerg.
		# It is also possible to configure the loglevel for particular
		# modules, e.g.
		#LogLevel info ssl:warn

		ErrorLog ${APACHE_LOG_DIR}/error.log
		CustomLog ${APACHE_LOG_DIR}/access.log combined

		# For most configuration files from conf-available/, which are
		# enabled or disabled at a global level, it is possible to
		# include a line for only one particular virtual host. For example the
		# following line enables the CGI configuration for this host only
		# after it has been globally disabled with "a2disconf".
		#Include conf-available/serve-cgi-bin.conf

		#   SSL Engine Switch:
		#   Enable/Disable SSL for this virtual host.
		SSLEngine on

		#   A self-signed (snakeoil) certificate can be created by installing
		#   the ssl-cert package. See
		#   /usr/share/doc/apache2/README.Debian.gz for more info.
		#   If both key and certificate are stored in the same file, only the
		#   SSLCertificateFile directive is needed.
		SSLCertificateFile	/etc/apache2/ssl/selfsigned.crt
		SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key

		#   Server Certificate Chain:
		#   Point SSLCertificateChainFile at a file containing the
		#   concatenation of PEM encoded CA certificates which form the
		#   certificate chain for the server certificate. Alternatively
		#   the referenced file can be the same as SSLCertificateFile
		#   when the CA certificates are directly appended to the server
		#   certificate for convinience.
		#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt

		#   Certificate Authority (CA):
		#   Set the CA certificate verification path where to find CA
		#   certificates for client authentication or alternatively one
		#   huge file containing all of them (file must be PEM encoded)
		#   Note: Inside SSLCACertificatePath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCACertificatePath /etc/ssl/certs/
		#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt

		#   Certificate Revocation Lists (CRL):
		#   Set the CA revocation path where to find CA CRLs for client
		#   authentication or alternatively one huge file containing all
		#   of them (file must be PEM encoded)
		#   Note: Inside SSLCARevocationPath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCARevocationPath /etc/apache2/ssl.crl/
		#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl

		#   Client Authentication (Type):
		#   Client certificate verification type and depth.  Types are
		#   none, optional, require and optional_no_ca.  Depth is a
		#   number which specifies how deeply to verify the certificate
		#   issuer chain before deciding the certificate is not valid.
		#SSLVerifyClient require
		#SSLVerifyDepth  10

		#   SSL Engine Options:
		#   Set various options for the SSL engine.
		#   o FakeBasicAuth:
		#	 Translate the client X.509 into a Basic Authorisation.  This means that
		#	 the standard Auth/DBMAuth methods can be used for access control.  The
		#	 user name is the `one line' version of the client's X.509 certificate.
		#	 Note that no password is obtained from the user. Every entry in the user
		#	 file needs this password: `xxj31ZMTZzkVA'.
		#   o ExportCertData:
		#	 This exports two additional environment variables: SSL_CLIENT_CERT and
		#	 SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
		#	 server (always existing) and the client (only existing when client
		#	 authentication is used). This can be used to import the certificates
		#	 into CGI scripts.
		#   o StdEnvVars:
		#	 This exports the standard SSL/TLS related `SSL_*' environment variables.
		#	 Per default this exportation is switched off for performance reasons,
		#	 because the extraction step is an expensive operation and is usually
		#	 useless for serving static content. So one usually enables the
		#	 exportation for CGI and SSI requests only.
		#   o OptRenegotiate:
		#	 This enables optimized SSL connection renegotiation handling when SSL
		#	 directives are used in per-directory context.
		#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
		<FilesMatch "\.(cgi|shtml|phtml|php)$">
				SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
				SSLOptions +StdEnvVars
		</Directory>

		#   SSL Protocol Adjustments:
		#   The safe and default but still SSL/TLS standard compliant shutdown
		#   approach is that mod_ssl sends the close notify alert but doesn't wait for
		#   the close notify alert from client. When you need a different shutdown
		#   approach you can use one of the following variables:
		#   o ssl-unclean-shutdown:
		#	 This forces an unclean shutdown when the connection is closed, i.e. no
		#	 SSL close notify alert is send or allowed to received.  This violates
		#	 the SSL/TLS standard but is needed for some brain-dead browsers. Use
		#	 this when you receive I/O errors because of the standard approach where
		#	 mod_ssl sends the close notify alert.
		#   o ssl-accurate-shutdown:
		#	 This forces an accurate shutdown when the connection is closed, i.e. a
		#	 SSL close notify alert is send and mod_ssl waits for the close notify
		#	 alert of the client. This is 100% SSL/TLS standard compliant, but in
		#	 practice often causes hanging connections with brain-dead browsers. Use
		#	 this only for browsers where you know that their SSL implementation
		#	 works correctly.
		#   Notice: Most problems of broken clients are also related to the HTTP
		#   keep-alive facility, so you usually additionally want to disable
		#   keep-alive for those clients, too. Use variable "nokeepalive" for this.
		#   Similarly, one has to force some clients to use HTTP/1.0 to workaround
		#   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
		#   "force-response-1.0" for this.
		# BrowserMatch "MSIE [2-6]" \
		#		nokeepalive ssl-unclean-shutdown \
		#		downgrade-1.0 force-response-1.0


		# ******************************************
		# ******************************************
		# Added part
		# Git

		# Path to the Git directory (inside the OS)
		SetEnv GIT_PROJECT_ROOT /git

		# Allows all projects to be served
		# If commented a file must exist in each available repository via Apache, file name: git-daemon-export-ok
		SetEnv GIT_HTTP_EXPORT_ALL

		# Defines the URL path where git is located, as seen via http
		# First param is path, second is os path to git-http-backend, don't forget the last slash
		ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

		# Access configuration
		<Files "git-http-backend">
			# Enable Basic HTTP Authentication
			AuthType Basic
			AuthName "Git Access"
			AuthUserFile /git/.htpasswd
			# The following line allows to obtain a repository (pull/fetch) without having a user/pass combo
			# Comment it if user/pass are needed to obtain info as well
		#	Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
			Require valid-user
			# END Enable Basic HTTP Authentication
		</Files>
		# END Git

	</VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Client based authentication using certificates in Apache

Apache configuration

To force Apache to serve only to clients that have a valid certificate add the following lines to /etc/apache2/sites-available/default-ssl.conf:



	# To allow certificate based authentication for clients
	# Clients must have a certificate to login
	SSLCACertificateFile /etc/apache2/ssl/selfsigned.crt
	SSLVerifyClient require

The file should look like this:

/etc/apache2/sites-available/default-ssl.conf



<IfModule mod_ssl.c>
	<VirtualHost _default_:443>
		ServerAdmin webmaster@localhost

		DocumentRoot /var/www/html

		# Available loglevels: trace8, ..., trace1, debug, info, notice, warn,
		# error, crit, alert, emerg.
		# It is also possible to configure the loglevel for particular
		# modules, e.g.
		#LogLevel info ssl:warn

		ErrorLog ${APACHE_LOG_DIR}/error.log
		CustomLog ${APACHE_LOG_DIR}/access.log combined

		# For most configuration files from conf-available/, which are
		# enabled or disabled at a global level, it is possible to
		# include a line for only one particular virtual host. For example the
		# following line enables the CGI configuration for this host only
		# after it has been globally disabled with "a2disconf".
		#Include conf-available/serve-cgi-bin.conf

		#   SSL Engine Switch:
		#   Enable/Disable SSL for this virtual host.
		SSLEngine on

		#   A self-signed (snakeoil) certificate can be created by installing
		#   the ssl-cert package. See
		#   /usr/share/doc/apache2/README.Debian.gz for more info.
		#   If both key and certificate are stored in the same file, only the
		#   SSLCertificateFile directive is needed.
		SSLCertificateFile	/etc/apache2/ssl/selfsigned.crt
		SSLCertificateKeyFile /etc/apache2/ssl/selfsigned.key

		#   Server Certificate Chain:
		#   Point SSLCertificateChainFile at a file containing the
		#   concatenation of PEM encoded CA certificates which form the
		#   certificate chain for the server certificate. Alternatively
		#   the referenced file can be the same as SSLCertificateFile
		#   when the CA certificates are directly appended to the server
		#   certificate for convinience.
		#SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt

		#   Certificate Authority (CA):
		#   Set the CA certificate verification path where to find CA
		#   certificates for client authentication or alternatively one
		#   huge file containing all of them (file must be PEM encoded)
		#   Note: Inside SSLCACertificatePath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCACertificatePath /etc/ssl/certs/
		#SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt

		#   Certificate Revocation Lists (CRL):
		#   Set the CA revocation path where to find CA CRLs for client
		#   authentication or alternatively one huge file containing all
		#   of them (file must be PEM encoded)
		#   Note: Inside SSLCARevocationPath you need hash symlinks
		#		 to point to the certificate files. Use the provided
		#		 Makefile to update the hash symlinks after changes.
		#SSLCARevocationPath /etc/apache2/ssl.crl/
		#SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl

		#   Client Authentication (Type):
		#   Client certificate verification type and depth.  Types are
		#   none, optional, require and optional_no_ca.  Depth is a
		#   number which specifies how deeply to verify the certificate
		#   issuer chain before deciding the certificate is not valid.
		#SSLVerifyClient require
		#SSLVerifyDepth  10

		#   SSL Engine Options:
		#   Set various options for the SSL engine.
		#   o FakeBasicAuth:
		#	 Translate the client X.509 into a Basic Authorisation.  This means that
		#	 the standard Auth/DBMAuth methods can be used for access control.  The
		#	 user name is the `one line' version of the client's X.509 certificate.
		#	 Note that no password is obtained from the user. Every entry in the user
		#	 file needs this password: `xxj31ZMTZzkVA'.
		#   o ExportCertData:
		#	 This exports two additional environment variables: SSL_CLIENT_CERT and
		#	 SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
		#	 server (always existing) and the client (only existing when client
		#	 authentication is used). This can be used to import the certificates
		#	 into CGI scripts.
		#   o StdEnvVars:
		#	 This exports the standard SSL/TLS related `SSL_*' environment variables.
		#	 Per default this exportation is switched off for performance reasons,
		#	 because the extraction step is an expensive operation and is usually
		#	 useless for serving static content. So one usually enables the
		#	 exportation for CGI and SSI requests only.
		#   o OptRenegotiate:
		#	 This enables optimized SSL connection renegotiation handling when SSL
		#	 directives are used in per-directory context.
		#SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
		<FilesMatch "\.(cgi|shtml|phtml|php)$">
				SSLOptions +StdEnvVars
		</FilesMatch>
		<Directory /usr/lib/cgi-bin>
				SSLOptions +StdEnvVars
		</Directory>

		#   SSL Protocol Adjustments:
		#   The safe and default but still SSL/TLS standard compliant shutdown
		#   approach is that mod_ssl sends the close notify alert but doesn't wait for
		#   the close notify alert from client. When you need a different shutdown
		#   approach you can use one of the following variables:
		#   o ssl-unclean-shutdown:
		#	 This forces an unclean shutdown when the connection is closed, i.e. no
		#	 SSL close notify alert is send or allowed to received.  This violates
		#	 the SSL/TLS standard but is needed for some brain-dead browsers. Use
		#	 this when you receive I/O errors because of the standard approach where
		#	 mod_ssl sends the close notify alert.
		#   o ssl-accurate-shutdown:
		#	 This forces an accurate shutdown when the connection is closed, i.e. a
		#	 SSL close notify alert is send and mod_ssl waits for the close notify
		#	 alert of the client. This is 100% SSL/TLS standard compliant, but in
		#	 practice often causes hanging connections with brain-dead browsers. Use
		#	 this only for browsers where you know that their SSL implementation
		#	 works correctly.
		#   Notice: Most problems of broken clients are also related to the HTTP
		#   keep-alive facility, so you usually additionally want to disable
		#   keep-alive for those clients, too. Use variable "nokeepalive" for this.
		#   Similarly, one has to force some clients to use HTTP/1.0 to workaround
		#   their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
		#   "force-response-1.0" for this.
		# BrowserMatch "MSIE [2-6]" \
		#		nokeepalive ssl-unclean-shutdown \
		#		downgrade-1.0 force-response-1.0


		# ******************************************
		# ******************************************
		# Added part
		# Git

		# Path to the Git directory (inside the OS)
		SetEnv GIT_PROJECT_ROOT /git

		# Allows all projects to be served
		# If commented a file must exist in each available repository via Apache, file name: git-daemon-export-ok
		SetEnv GIT_HTTP_EXPORT_ALL

		# Defines the URL path where git is located, as seen via http
		# First param is path, second is os path to git-http-backend, don't forget the last slash
		ScriptAlias /git/ /usr/lib/git-core/git-http-backend/

		# Access configuration
		<Files "git-http-backend">
			# Enable Basic HTTP Authentication
			AuthType Basic
			AuthName "Git Access"
			AuthUserFile /git/.htpasswd
			# The following line allows to obtain a repository (pull/fetch) without having a user/pass combo
			# Comment it if user/pass are needed to obtain info as well
		#	Require expr !(%{QUERY_STRING} -strmatch '*service=git-receive-pack*' || %{REQUEST_URI} =~ m#/git-receive-pack$#)
			Require valid-user
			# END Enable Basic HTTP Authentication
		</Files>
		# END Git

	</VirtualHost>
</IfModule>

# vim: syntax=apache ts=4 sw=4 sts=4 sr noet

Client certificate

The client certificate generation works like this:

  • Setup a root CA key and certificate, in our case the file selfsigned.crt acts as a root CA.
  • The client generates his private key and certificate request, since we control both the server and the client this can be done in either machine.
  • Generate the client certificate using the cliente certificate request, the root certificate and the root key.

Steps:

# Generate the client key
openssl genrsa -out client.key 2048
# Generate the client csr (Certificate Signing Request)
openssl req -new -key client.key -out client.csr
# Generate the client certificate, change serial number for every new certificate
openssl x509 -req -in client.csr -CA selfsigned.crt -CAkey selfsigned.key -set_serial 01 -out client.crt

# Generate a p12 file, this can be used for a browser but will probably have to be installed in the OS or the Browser
openssl pkcs12 -export -out client.p12 -inkey client.key -in client.crt -chain -CAfile ../oneline/selfsigned.crt

Source:

Git using a Client Certificate

If we configured Apache for client based authentication then Git needs a certificate to use to communicate with Apache.

Steps:

  1. Transfer the client key and certificate to the client. This means client.key and client.csr.
  2. Follow steps from the previos section: Git using the Self-Signed Certificate.
  3. Configure Git to use the transferred files:
    git config http.sslCert [client os location]/client.crt
    git config http.sslKey [client os location]/client.key

Further reading