Skip to main content

Envoy Proxy front end using Authelia

Q: So what is Authelia and why would I want to do this?
A: Add 2FA to an existing web service, behind Envoy Proxy as an edge proxy, with the backend unaware.

Authelia is an open-source authentication and authorization server providing 2-factor authentication and single sign-on (SSO) for your applications via a web portal. It acts as a companion of reverse proxies like nginx, Traefik or HAProxy to let them know whether queries should pass through. Unauthenticated users are redirected to Authelia Sign-in portal instead.

Documentation is available at

The Solution

So the proxy authentication hook that is in Envoy doesn't match what is required for Authelia to work, but reading the manual gets us to a working configuration. What we need to do is process the request on the way in, call the Authelia service and if we don't get back an "OK" redirect the request to the Authelia service.

The Lua hook to the rescue to allow processing, adding headers and calling another service in the middle of processing the request.

         - name: envoy.filters.http.lua
             inline_code: |

 When the request comes in we build a GET request to send to Authelia, and based on the result allow the request to go through. If we get a 302or a 401 from Authelia then return the Authelia response to this request.
If we get a 200 and user is set then tuck it away in a header.

Sample code snippet

 - name: listener_1
     socket_address: { address: ************, port_value: 443 }
   - name: "envoy.filters.listener.tls_inspector"
     typed_config: {}
   - filter_chain_match:
       server_names: ["************"]
       name: envoy.transport_sockets.tls
           - certificate_chain: { filename: "************.cert" }
             private_key: { filename: "************.key" }
             tls_minimum_protocol_version: TLSv1_2
     - name:
         use_remote_address: true
         stat_prefix: ingress_http
           - name: default
             domains: "*"
             - match: { prefix: "/" }
               route: { cluster: my_cluster }
           - header:
               key: "Strict-Transport-Security"
               value: "max-age=31536000; includeSubDomains"
             append: true      
         - name: envoy.filters.http.lua
             inline_code: |
               function envoy_on_request(request_handle)
                 local request_headers = request_handle:headers()  
                 local auth_headers = {}                   
                 auth_headers[":method"] = "GET"
                 auth_headers["X-Original-URL"] = "https://************.com"..request_headers:get(":path")
                 auth_headers[":path"] = "/api/verify?rd=https://************.com"
                 auth_headers[":authority"] = "auth-service"
                 auth_headers["cookie"] = request_headers:get("cookie")                                
                 local headers, body = request_handle:httpCall(
                   "nothing here",
                 local status = headers[":status"]
                 local user   = headers["remote-user"]
                 if ( status == "302" or status == "401" ) then                      
                    request_handle:logDebug("LUA:redirect 302")
                 if status ~= "200" then                      
                      {[":status"] = "500"},"authservice error"
                    if (user ~= nil or user ~= '') then
                       request_handle:headers():add("x-webobjects-remote-user", user)

         - name: envoy.filters.http.router
           typed_config: {}


Want to comment or know more then please...

Contact Me