Apache HTTP Server as Reverse Proxy

This section contains examples of how the Apache Web Server (version 2.2.20) can be used as a proxy in front of SignServer. The guide is only informative, please consult the current Apache documentation for the modules used.

The proxy can for example be used to:

  • Use standard ports (80, 443) instead of unprivileged ports used by the application server.
  • Make workers accessible through more nice looking URLs. For example, "http://tsa.example.com" instead of "http://example.com:8080/signserver/tsa?workerName=TimeStampSigner1".
  • Usie any of the access control and authentication mechanism available in Apache.
  • Redirect HTTP traffic to HTTPS.
  • Only accept requests to specified locations.

Since the requests should go through the proxy, it is recommended to configure the application server to only listen to localhost, and/or use a firewall blocking the application server ports from external requests. To configure JBoss to only listen to localhost, set the following properties in signserver_deploy.properties:

httpsserver.bindaddress.pubhttp=127.0.0.1
httpsserver.bindaddress.pubhttps=127.0.0.1
httpsserver.bindaddress.privhttps=127.0.0.1

Install the Apache web server and enable required modules (the following commands are for Ubuntu but should be similar in other distributions as well):

$ sudo apt-get install apache2
$ cd /etc/apache2/mods-enabled/
$ sudo ln -s ../mods-available/proxy.load proxy.load
$ sudo ln -s ../mods-available/proxy_http.load proxy_http.load
$ sudo ln -s ../mods-available/proxy_ajp.load proxy_ajp.load
$ sudo ln -s ../mods-available/proxy_balancer.load proxy_balancer.load
$ sudo ln -s ../mods-available/rewrite.load rewrite.load
$ sudo ln -s ../mods-available/ssl.load ssl.load


Example: Rewrite URLs for TSA (using mod_proxy and mod_rewrite)

The following sample configuration allows rendering nice URLs for time-stamping so that you can point your TSA clients to http://tsa.example.com/ instead of http://tsa.example.com:8080/signserver/process?workerName=TimeStampSigner1.

This configuration combines mod_proxy with mod_rewrite to enable setting the workerName or workerId, allowing different TSAs available on different URLs.

<VirtualHost tsa.example.com:80>
    ServerName tsa.example.com
    ServerAlias tsa.example.com
    CustomLog /var/log/apache2/access.log combined

    RewriteEngine on
    RewriteLogLevel 5
    RewriteLog "/var/log/apache2/rewrite.log
    RewriteRule ^/$ /?workerName=TimeStampSigner1 [PT]

    ProxyRequests Off
    <Proxy *>
        Order deny,allow
        Allow from all
    </Proxy>
    ProxyPass / http://127.0.0.1:8080/signserver/process
    ProxyPassReverse / http://127.0.0.1:8080/signserver/process
</VirtualHost>

Example: Rewrite URLs and redirect to HTTPS (using AJP)

The following example configures three virtual hosts.

The first signserver.example.com:80 redirects all requests to use HTTPS and thus the virtual host signserver.example.com:443.

The second virtual host is configured to proxy requests to the /signserver path on the application server using the AJP protocol. It is also configured to use HTTPS with a server certificate.

The last virtual hosts auth.signserver.example.com using an additional IP address is configured to require client certificate authentication.

Some application servers (for example, JBoss 4) might have problems writing the correct port number in the endpoint URL in the web services WSDL file when using a proxy (that is, writing 8443 instead of 443).

<VirtualHost signserver.example.com:80>
    ServerName signserver.example.com
    ServerAlias signserver.example.com

    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}

    # Configure log
    LogLevel warn
    ErrorLog /var/log/apache2/error.log
    CustomLog /var/log/apache2/access.log combined

</VirtualHost>

<VirtualHost signserver.example.com:443>
    ServerName signserver.example.com
    ServerAlias signserver.example.com

    ProxyRequests Off
    <Proxy balancer://mycluster-3>
        BalancerMember ajp://localhost:8009/signserver
    </Proxy>
    ProxyPass / balancer://mycluster-3/

    RewriteEngine   On

    # Treat requests to / and /signserver/ as the same for web services endpoints to work.
    RewriteCond     %{THE_REQUEST}  /signserver/
    RewriteRule     ^/signserver/(.*)$ /$1 [PT]

    # Configure secure SSL for this server using SSL certificate generated by EJBCA
    SSLEngine on
    SSLCipherSuite HIGH
    SSLProtocol all -SSLv2
    SSLCertificateFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/signserver.example.com-cert.pem
    SSLCertificateKeyFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/signserver.example.com-key.pem

    # Configure log
    LogLevel warn
    ErrorLog /var/log/apache2/error.log
    CustomLog /var/log/apache2/access.log combined
</VirtualHost>

# Note: auth.signserver.example.com must have a different IP address
<VirtualHost auth.signserver.example.com:443>
    ServerName auth.signserver.example.com
    ServerAlias auth.signserver.example.com

    ProxyRequests Off
    <Proxy balancer://mycluster-4>
        BalancerMember ajp://localhost:8009/signserver
    </Proxy>
    ProxyPass / balancer://mycluster-4/

    RewriteEngine   On
    # Treat requests to / and /signserver/ as the same for web services endpoints to work.
    RewriteCond     %{THE_REQUEST}  /signserver/
    RewriteRule     ^/signserver/(.*)$ /$1 [PT]

    # Configure secure SSL for this server using SSL certificate generated by EJBCA
    SSLEngine on
    SSLCipherSuite HIGH
    SSLProtocol all -SSLv2
    SSLCertificateFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/auth.signserver.example.com-cert.pem
    SSLCertificateKeyFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/auth.signserver.example.com-key.pem

    SSLVerifyClient require
    SSLVerifyDepth 1
    SSLCACertificateFile /home/markus/Documents/PrimeKey/MarkusCA/example.com/truststore.pem

    # Configure log
    LogLevel warn
    ErrorLog /var/log/apache2/error.log
    CustomLog /var/log/apache2/access.log combined
</VirtualHost>

Example: Granting access to specific workers only

This example shows how to limit access to specified resources only.

If you are going to grant different users access to different workers, always remember to first deny access from the root location since there are other ways to access a worker than the "/worker/*" or "/sodworker/*" pattern. For instance, /process, /tsa, /pdf and /sod etc, as well as using the web services interfaces /signserverws, /SignServerWSService, /validationws, /ValidationWSService, and /ClientWSService, all can be used to invoke any worker.

If you instead relay on SignServer to do the authentication/authorization, it is recommended to only grant access to the locations you intend to use. In that case you will probably want to also give access to the web services interfaces, /worker and /process etc.

Also remember that if you are proxying from multiple virtual hosts (for example, if you have one with and one without client authentication as in the example above), you might want to add the access restrictions to all of them.

 ...
    # First, deny access globally and then only give access to resources explicitly
    <Location />
    	Order Deny,Allow
    	Deny from all
    </Location>

    # Allow index page
    <LocationMatch "^/$">
	Order Allow,Deny
	Allow from all
    </LocationMatch>

    # Allow Client Web
    <Location /clientweb/>
	Order Allow,Deny
	Allow from all
    </Location>

    # Allow documentation
    <Location /doc/>
	Order Allow,Deny
	Allow from all
    </Location>

    # Allow web page resources
    <LocationMatch "\.(css|js|jpg|png)$">
	Order Allow,Deny
	Allow from all
    </LocationMatch>
    
    # Allow the Admin interface
    <Location /AdminWSService/>
	Order Allow,Deny
	Allow from all
    </Location>

    # Grant everybody access to the XMLSigner
    <Location /worker/XMLSigner>
	Order Allow,Deny
	Allow from all
    </Location>
                        
    # Grant everybody access to the MRTDSODSigner
    <Location /sodworker/MRTDSODSigner>
        Order Allow,Deny
        Allow from all
    </Location>

    # Grant valid users access to the CMSSigner
    <Location /worker/CMSSigner>
	Order Allow,Deny
        Allow from all
        AuthType Basic
        AuthName "Restricted CMSSigner access"
    	AuthUserFile /home/markus/.htpasswd
    	Require valid-user
    </Location>
    ...

Additional Configuration

Custom Private HTTPS port

For example, if a reverse proxy is used to change the ports used by SignServer, the links in the Administration Web interface might not be correct (for example, if the standard port 443 is used instead of 8443). In that case, configure the following in conf/signserver_deploy.properties:

httpserver.external.privhttps=443

Custom Context Root

With a reverse proxy, it is also possible to use a different beginning of the URL for accessing SignServer than the default "/signserver". If for example the reverse proxy instead serves SignServer under "/myservice/signserver" this might have to be configured in conf/signserver_deploy.properties so that the URLs in the Administration Web interface, as well as the Web Services endpoints, work as expected:

httpserver.context.root=/myservice/signserver