CAC Authentication with Go and HAproxy

There are two methods that I’m aware of to run a FIPS 140-2 compliant Go web server. See the first post in this series to see why this might be necessary.

One approach is to use a FIPS 140-2 compliant SSL terminating proxy and place it in front of the Go application. I wrote an earlier post that covers how to do this and provides a Docker container for demonstration.

Building on top of this to add authentication of users via their CAC (common access card) just requires configuring HAProxy with the DOD certificate authorities and CRL. From there, HTTP headers can be used to pass the CAC information to the Go app where it can be used for authentication.

frontend http
    bind :443 ssl crt /usr/local/etc/haproxy/sample.pem ca-file /usr/local/etc/haproxy/cacerts.cer crl-file /usr/local/etc/haproxy/dod.crl verify required
    mode http
    http-request set-header X-SSL-Client-DN        %{+Q}[ssl_c_s_dn]
    http-request set-header X-SSL-Client-CN        %{+Q}[ssl_c_s_dn(cn)]
    http-request set-header X-SSL-Issuer           %{+Q}[ssl_c_i_dn]
    http-request set-header X-SSL-Client-NotBefore %{+Q}[ssl_c_notbefore]
    http-request set-header X-SSL-Client-NotAfter  %{+Q}[ssl_c_notafter]
    default_backend go-app

I’ve put together a Docker container showing how to build/configure HAproxy and your app. If you run it, it should request and only allow access with a CAC at which point it will display your name and other information from your CAC.

There are some downsides to this method. While I love HAproxy, being required to use it isn’t ideal. Also, though the Go app should listen on the local interface only, if someone were to access that machine they could impersonate other users via just sending the appropriate HTTP headers.

I was going to look into calling into OpenSSL with cgo, but Space Monkey already maintains a full featured wrapper. I plan on investigating using the wrapper to perform authentication using the FIPS validated module from Go directly.

comments powered by Disqus