charts/osdu-developer-base/templates/envoy-filter.yaml (116 lines of code) (raw):
{{- $namespace := .Release.Namespace }}
{{- $entraClientId := .Values.azure.clientId }}
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
namespace: {{ $namespace }}
name: microsoft-identity-filter
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: envoy.filters.network.http_connection_manager
subFilter:
name: envoy.filters.http.router
patch:
operation: INSERT_BEFORE
value:
name: envoy.lua.microsoft-identity-filter
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"
inlineCode: |
-- Constants
local AAD_V1_ISSUER = "sts.windows.net"
local AAD_V2_ISSUER = "login.microsoftonline.com"
local entraClientId = "{{ $entraClientId }}"
-- Helper function to log a table
function tableToString(tbl, indent)
if not indent then indent = 0 end
if type(tbl) ~= 'table' then return tostring(tbl) end
local lines = {}
for k, v in pairs(tbl) do
local formatting = string.rep(" ", indent) .. k .. ": "
if type(v) == "table" then
table.insert(lines, formatting)
table.insert(lines, tableToString(v, indent + 1))
else
table.insert(lines, formatting .. tostring(v))
end
end
return table.concat(lines, "\n")
end
-- Function to log all headers
function logAllHeaders(request_handle)
local headers = request_handle:headers()
for key, value in pairs(headers) do
request_handle:logInfo("Header: " .. key .. " = " .. value)
end
end
-- Process AAD v1 tokens
function processAADV1Token(payload, request_handle)
if payload["unique_name"] then
request_handle:headers():add("x-user-id", payload["unique_name"])
request_handle:logWarn("UC1-(AAD v1 User Token (sts.windows.net)): x-user-id set from 'unique_name' claim")
elseif payload["oid"] then
request_handle:headers():add("x-user-id", payload["appid"])
request_handle:logWarn("UC1-(AAD v1 User Token (sts.windows.net)): x-user-id set from 'appid' claim as fallback")
elseif payload["upn"] then
request_handle:headers():add("x-user-id", payload["upn"])
request_handle:logWarn("UC1-(AAD v1 User Token (sts.windows.net)): x-user-id set from 'upn' claim as fallback")
else
request_handle:logError("UC1-(AAD v1 User Token (sts.windows.net)): No valid claim for x-user-id found in AAD v1 token")
end
end
-- Process AAD v2 tokens
function processAADV2Token(payload, request_handle)
if payload["unique_name"] then
request_handle:headers():add("x-user-id", payload["unique_name"])
request_handle:logWarn("UC4-(AAD v2 User Token (login.microsoftonline.com)): x-user-id set from 'unique_name' claim")
elseif payload["oid"] then
request_handle:headers():add("x-user-id", payload["oid"])
request_handle:logWarn("UC4-(AAD v2 User Token (login.microsoftonline.com)): x-user-id set from 'oid' claim as fallback")
elseif payload["azp"] then
request_handle:headers():add("x-user-id", payload["azp"])
request_handle:logWarn("UC4-(AAD v2 User Token (login.microsoftonline.com)): x-user-id set from 'azp' claim as fallback")
else
request_handle:logError("UC4-(AAD v2 User Token (login.microsoftonline.com)): No valid claim for x-user-id found in AAD v2 token")
end
end
-- Main processing function
function envoy_on_request(request_handle)
-- Step 1: Remove existing headers
request_handle:headers():remove("x-user-id")
request_handle:headers():remove("x-app-id")
request_handle:logWarn("x-user-id and x-app-id headers removed")
-- Step 2: Retrieve JWT metadata
local meta = request_handle:streamInfo():dynamicMetadata():get("envoy.filters.http.jwt_authn")
if not meta or not meta["payload"] then
request_handle:logError("No JWT metadata or payload found")
return
end
local payload = meta["payload"]
-- Step 3: Log raw payload for debugging
request_handle:logDebug("JWT payload: " .. tableToString(payload))
-- Step 4: Process audience (aud) claim
local aud = payload["aud"]
if aud then
request_handle:headers():add("x-app-id", aud)
request_handle:logDebug("x-app-id set from 'aud' claim: " .. aud)
-- Special handling for audience "https://management.azure.com/"
if aud == "https://management.azure.com/" then
local managedClientId = payload["appid"]
if managedClientId then
request_handle:headers():add("x-user-id", entraClientId)
request_handle:headers():replace("x-app-id", entraClientId)
request_handle:logWarn("UC7-(Management Audience): x-user-id and x-app-id set to 'appid' claim for management.azure.com audience")
else
request_handle:logError("No 'appid' claim found for management.azure.com audience")
end
return -- Exit early as we don't need further processing for this case
end
else
request_handle:logError("No 'aud' claim found in payload")
end
-- Step 5: Process issuer (iss) for additional logic
local iss = payload["iss"]
if iss and string.find(iss, AAD_V1_ISSUER) then
request_handle:logDebug("Processing AAD v1 token")
processAADV1Token(payload, request_handle)
elseif iss and string.find(iss, AAD_V2_ISSUER) then
request_handle:logDebug("Processing AAD v2 token")
processAADV2Token(payload, request_handle)
else
request_handle:logError("Unknown issuer: " .. (iss or "nil"))
end
-- Step 6: Log all headers before leaving the filter
request_handle:logDebug("Logging all headers before leaving the filter:")
logAllHeaders(request_handle)
end