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 https://docs.authelia.com.
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
typed_config:
"@type": type.googleapis.com/envoy.config.filter.http.lua.v2.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
address:
socket_address: { address: ************, port_value: 443 }
listener_filters:
- name: "envoy.filters.listener.tls_inspector"
typed_config: {}
filter_chains:
- filter_chain_match:
server_names: ["************"]
transport_socket:
name: envoy.transport_sockets.tls
typed_config:
"@type": type.googleapis.com/envoy.extensions.transport_sockets.tls.v3.DownstreamTlsContext
common_tls_context:
tls_certificates:
- certificate_chain: { filename: "************.cert" }
private_key: { filename: "************.key" }
tls_params:
tls_minimum_protocol_version: TLSv1_2
filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
use_remote_address: true
stat_prefix: ingress_http
route_config:
virtual_hosts:
- name: default
domains: "*"
routes:
- match: { prefix: "/" }
route: { cluster: my_cluster }
response_headers_to_add:
- header:
key: "Strict-Transport-Security"
value: "max-age=31536000; includeSubDomains"
append: true
http_filters:
- name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.config.filter.http.lua.v2.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(
"auth-service",
auth_headers,
"nothing here",
5000
)
local status = headers[":status"]
local user = headers["remote-user"]
if ( status == "302" or status == "401" ) then
request_handle:logDebug("LUA:redirect 302")
request_handle:respond(headers,body)
end
if status ~= "200" then
request_handle:respond(
{[":status"] = "500"},"authservice error"
)
else
if (user ~= nil or user ~= '') then
request_handle:headers():add("x-webobjects-remote-user", user)
end
end
end
- name: envoy.filters.http.router
typed_config: {}
Want to comment or know more then please...