Closed remy-tiitre closed 2 years ago
Currently, DFP does not support this use case. This would take a little bit of thinking to iron out the edge cases to implement this feature.
How and when are these backend templates used in /cfg/tmpl folder? I understand that haproxy.tmpl is the base for everything else. All other templates are merged together there. But what about those service based templates? I see a convention that for every service theres servise-[be|fe]*.cfg file. All fe files are empty. when I manually create files there, will they be picked up? Lets say that I add docker configuration object that maps to /cfg/tmpl/some_service_name-be.cfg, will it be added to haproxy? And why are there those -fe files? I'm trying to figure out if I could get away with be/fe config file templates or I have to modify this haproxy.tmpl. Last one would be a little more annoing as I would have to check your modifications to it every time I update the docker image.
How and when are these backend templates used in /cfg/tmpl folder?
The templates are used during startup and every-time a service is updated or removed.
when I manually create files there, will they be picked up?
If you create the files there with a configuration object, DFP would try to write to these paths, which may error out, since usually configuration files are not writable.
And why are there those -fe files?
From my understanding, they are not normally empty. In http mode these should contain the use_backend
to direct request to the corresponding backend.
I'm trying to figure out if I could get away with be/fe config file templates or I have to modify this haproxy.tmpl.
I am open to changing how DFP does templating to open it up to your use case. You can already add your desired binding by setting DEFAULT_PORTS=443 ssl crt /etc/haproxy/cert/server.pem ca-file /etc/haproxy/cert/ca.pem verify optional crt-ignore-err all crl-file /etc/haproxy/cert/root_crl.pem
, and service specific backends by setting com.df.backendExtra
. What is missing is allow the user to define a custom use_backend
for each service, in your case you need use_backend ssl-error unless { ssl_c_verify 0 }
. This would involve updating DFP to support com.df.useBackendRules=unless { ssl_c_verify 0 }
.
My usecase is probably too complicated for DFP to handle with environment variables and service labels only. Though, if the approach were like OpenShift is doing it, then probably it would be a little easier. First they have 3 different frontends -> http, https and custom ports. But what I ended up is modifying the template to something like this:
...
listen https_in
bind *:443
mode tcp
acl clienthello req_ssl_hello_type 1
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
# Deny clients not sending an SNI header in 5 seconds
tcp-request content reject
acl require_client_certificate req.ssl_sni -i some.domain.where.i.want.client.certificate
use-server tls_client_certificate if require_client_certificate
use-server tls_default unless require_client_certificate
server tls_client_certificate abns@tls_client_certificate send-proxy-v2
server tls_default abns@tls_default send-proxy-v2
frontend tls_client_certificate
bind abns@tls_client_certificate accept-proxy ssl strict-sni crt-list /cfg/crt-list.txt ca-file /cfg/cert.some.nice-ca.pem verify optional crt-ignore-err all alpn h2,http/1.1
mode {{.DefaultReqMode}}
{{- if eq .DefaultReqMode "http" }}
option forwardfor
{{- end}}
acl client_cert_verified ssl_c_used ssl_c_verify 0
use_backend some_backend_with_client_cert-be if client_cert_verified
default_backend some_backend_when_cert_fails-be
frontend tls_default{{.DefaultBinds}}
bind abns@tls_default accept-proxy ssl strict-sni crt-list /cfg/crt-list.txt alpn h2,http/1.1
mode {{.DefaultReqMode}}
{{- if eq .DefaultReqMode "http" }}
option forwardfor
{{- end}}
{{.ExtraFrontend}}{{.ContentFrontend}}{{.ContentFrontendTcp}}{{.ContentFrontendSNI}}{{.ContentListen}}
backend some_backend_with_client_cert-be
http-request set-header X-Forwarded-Host some.domain.where.i.want.client.certificate
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-SSL-Client-Verify %[ssl_c_verify]
http-request set-header X-Client-Certificate %[ssl_c_der,base64]
http-request set-header X-Real-IP %[src]
server some_nice_backend some_nice_backend:8080
backend some_backend_when_cert_fails-be
option http-server-close
http-request set-header X-Forwarded-Host authid.lhv.ee.prelive
http-request set-header X-Forwarded-Port %[dst_port]
http-request set-header X-Forwarded-Proto https if { ssl_fc }
http-request set-header X-SSL-Client-Verify %[ssl_c_verify]
http-request set-header X-Real-IP %[src]
server some_nice_backend some_nice_backend:8080
Main problem is with {{.DefaultBinds}} variable, as it has all the different bind information in one variable. So I was forced to add DEFAULT_PORTS=80 environment variable and hardcode the CA_FILE location.
This project needs adoption. I moved to Kubernetes and cannot dedicate time to this project anymore. Similarly, involvement from other contributors dropped as well. Please consider contributing yourself if you think this project is useful.
Dear @remy-tiitre
If this issue is still relevant, please feel free to leave a comment here.
Closed due to inactivity
It is probably not possible right now. First 2 things that pop into mind is that verifyClientSsl and addReqHeader, setReqHeader do not support indexes. So either all services require client sertificate or none of them do.
But I have a deeper problem, what if I want to implement it like its done in plain HAProxy frontend https-in bind *:443 ssl crt /etc/haproxy/cert/server.pem ca-file /etc/haproxy/cert/ca.pem verify optional crt-ignore-err all crl-file /etc/haproxy/cert/root_crl.pem use_backend ssl-error unless { ssl_c_verify 0 } use_backend sso-with-ca-cert if { ssl_fc_has_crt } default_backend sso-no-ca-cert
backend sso-with-ca-cert http-request set-header X-SSL-Client-Verify %[ssl_c_verify] http-request set-header X-Client-Certificate %[ssl_c_der,base64] http-request set-header X-Forwarded-Host %[dst] http-request set-header X-Forwarded-Port %[dst_port] http-request set-header X-Forwarded-Proto https ... backend sso-no-ca-cert ...
backend ssl-error option http-server-close redirect location /certificate-expired.html if { ssl_c_verify 10 } ! { path /certificate-expired.html } redirect location /certificate-revoked.html if { ssl_c_verify 23 } ! { path /certificate-revoked.html } redirect location /other-certificate-error.html unless { ssl_c_verify 0 } ! { path //other-certificate-error.html } ...
Example https://raymii.org/s/tutorials/haproxy_client_side_ssl_certificates.html Notice how theres different options depending how the client certification validation went.