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. 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 cleaner URLs. For example,
http://tsa.example.cominstead ofhttp://example.com:8080/signserver/tsa?workerName=TimeStampSigner1. -
Use 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)
From WildFly 40, the usage of AJP is deprecated in favor of proxying with HTTP and, from WildFly 41, AJP fails with the error message:
UT000220: The AJP listener is configured with -Dio.undertow.ajp.REQUIRE_AJP_SECRET=true by default, which enables secret enforcement, but the secret property -Dio.undertow.ajp.AJP_SECRET either wasn't defined or was empty. Such combination is forbidden.
It is recommend to switch away from AJP. Alternatively, configure WildFly with -Dio.undertow.ajp.REQUIRE_AJP_SECRET=false or with the required secrets.
The following example configures three virtual hosts:
-
Set the first
signserver.example.com:80redirects all requests to use HTTPS and thus the virtual hostsignserver.example.com:443. -
The second virtual host is configured to proxy requests to the
/signserverpath 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.comusing an additional IP address is configured to require client certificate authentication.
<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>
You might need to add the AJP listener to your WildFly 32+ and restart it:
$JBOSS_HOME/bin/jboss-cli.sh -c '/subsystem=undertow/server=default-server/ajp-listener=myListener:add(socket-binding=ajp, scheme=http, enabled=true)'
$JBOSS_HOME/bin/jboss-cli.sh -c ':reload'
It is recommended to use a firewall as an extra layer of security, to drop malformed packages and prevent future services from being exploited.
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, using /process, /tsa, /pdf, and /sod, 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 rely on SignServer to do the authentication or authorization, it is recommended to only grant access to the locations you intend to use. In this situation, also give access to the web services interfaces, /worker, /process, and so on.
Also, 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. For example, if the reverse proxy serves SignServer under /myservice/signserver, you may need to configure 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