Recently I came across a problem of forwarding a certificate Id to backend service for the authentication purposes. I also do not want to handle SSL at services.
Let’s say I have a server setup as follows: There is an Angular website on port 4200 and REST/Websocket services on port 3000. REST services are accessible over endpoint /kumuluz
and Websocket connections via /v1/devices. As a common facade to access these services I set up Apache as a reverse proxy as in an example configuration below.
To extract a field from a client certificate (e.g. CN in my case) and forward request to a backend REST server with an additional header field is not a problem. I just extract property %{SSL_CLIENT_S_DN_CN}s
and set a header field clientId
.
The problem comes, when you would like to do the same for the Websocket connections – you cannot set header for these type of connections. But you can do a workaround (the point of this post): Tell clients to connect to the endpoint /v1/devices/CLIENT_ID
and then check if the parameter matches the client id of underlying client certificate. Now you forced the client to use the correct ids in URL, which you can use for authentication as Apache forwards only requests where SSLRequire successes.
ServerName portal.zitnik.si
Redirect permanent / https://portal.zitnik.si/
ServerAdmin slavko@zitnik.si
ServerName portal.zitnik.si
ServerAlias portal.zitnik.si
DocumentRoot /var/www
ProxyPreserveHost On
ProxyRequests Off
ProxyPass /images !
ProxyPass /v1/devices ws://localhost:3000/v1/devices
ProxyPassReverse /v1/devices ws://localhost:3000/v1/devices
ProxyPass /kumuluz http://localhost:3000
ProxyPassReverse /kumuluz http://localhost:3000
ProxyPass / http://localhost:4200/
ProxyPassReverse / http://localhost:4200/
RedirectMatch ^/$ https://portal.zitnik.si
SSLEngine on
SSLCertificateFile /home/slavkoz/certs/portal.zitnik.si.crt
SSLCertificateKeyFile /home/slavkoz/certs/portal.zitnik.si.key
SSLCACertificateFile /home/slavkoz/certs/CA.pem
SSLVerifyClient none
RequestHeader set clientId ""
SSLVerifyClient require
SSLVerifyDepth 1
RequestHeader set clientId "%{SSL_CLIENT_S_DN_CN}s"
SSLVerifyClient require
SSLVerifyDepth 1
SetEnvIf Request_URI "/v1/devices/(.*)$" CLIENT_ID=$1
SSLRequire %{SSL_CLIENT_S_DN_CN} eq %{ENV:CLIENT_ID}