lua.ingress_rbac_logging.lua Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of envoy-control-core Show documentation
Show all versions of envoy-control-core Show documentation
Production-ready Control Plane for Service Mesh based on Envoy Proxy.
function envoy_on_request(handle)
local metadata = handle:metadata()
local client_identity_header_names = metadata:get('client_identity_headers') or {}
local clients_allowed_to_all_endpoints = metadata:get('clients_allowed_to_all_endpoints') or {}
local request_id_header_names = metadata:get('request_id_headers') or {}
local trusted_header_name = metadata:get('trusted_client_identity_header') or ''
local headers = handle:headers()
local path = headers:get(':path')
local method = headers:get(':method')
local authority = headers:get(':authority') or ''
local lua_destination_authority = headers:get('x-lua-destination-authority') or ''
local xff_header = headers:get('x-forwarded-for')
local request_id = first_header_value_from_list(request_id_header_names, headers)
local client_name = ''
local allowed_client = false
local trusted_client = false
if trusted_header_name ~= '' then
client_name = headers:get(trusted_header_name) or ''
allowed_client = is_allowed_client(client_name, clients_allowed_to_all_endpoints)
if client_name ~= '' then
trusted_client = true
end
end
if client_name == '' then
client_name = first_header_value_from_list(client_identity_header_names, headers)
allowed_client = is_allowed_client(client_name, clients_allowed_to_all_endpoints)
if trusted_header_name ~= '' and client_name ~= '' and handle:connection():ssl() ~= nil then
client_name = client_name .. ' (not trusted)'
end
end
local dynamic_metadata = handle:streamInfo():dynamicMetadata()
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.path', path)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.method', method)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.xff_header', xff_header)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.client_name', client_name)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.trusted_client', trusted_client)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.allowed_client', allowed_client)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.request_id', request_id)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.authority', authority)
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.lua_destination_authority', lua_destination_authority)
local headers_to_log = metadata:get('rbac_headers_to_log') or {}
for _, header in ipairs(headers_to_log) do
dynamic_metadata:set('envoy.filters.http.lua', 'request.info.headers.'..header, headers:get(header))
end
end
function first_header_value_from_list(header_list, headers)
for _,h in ipairs(header_list) do
local value = headers:get(h) or ''
if value ~= '' then
return value
end
end
return ''
end
function is_allowed_client(client_name, clients_allowed_to_all_endpoints)
if client_name == '' then
return false
end
for _,h in ipairs(clients_allowed_to_all_endpoints) do
if h ~= '' and client_name == h then
return true
end
end
return false
end
function envoy_on_response(handle)
local dynamic_metadata = handle:streamInfo():dynamicMetadata()
local rbacMetadata = dynamic_metadata:get('envoy.filters.http.rbac') or {}
local is_shadow_denied = (rbacMetadata['shadow_engine_result'] or '') == 'denied'
if is_shadow_denied then
local headers = handle:headers()
local lua_metadata = dynamic_metadata:get('envoy.filters.http.lua') or {}
local jwt_status = (dynamic_metadata:get('envoy.filters.http.header_to_metadata') or {})['jwt-status'] or 'missing'
local jwt_metadata = dynamic_metadata:get('envoy.filters.http.jwt_authn') or {}
if jwt_metadata['jwt_failure_reason'] then
jwt_status = jwt_metadata['jwt_failure_reason']['message']
end
local upstream_request_time = headers:get('x-envoy-upstream-service-time')
local status_code = headers:get(':status')
local rbac_action = 'shadow_denied'
if upstream_request_time == nil and status_code == '403' then
rbac_action = 'denied'
end
log_request(handle, lua_metadata, jwt_status, rbac_action)
end
end
function log_request(handle, lua_metadata, jwt_status, rbac_action)
local client_name = lua_metadata['request.info.client_name'] or ''
local trusted_client = lua_metadata['request.info.trusted_client'] or false
local path = lua_metadata['request.info.path'] or ''
local protocol = handle:connection():ssl() == nil and 'http' or 'https'
local method = lua_metadata['request.info.method'] or ''
local xff_header = lua_metadata['request.info.xff_header'] or ''
local source_ip = string.match(xff_header, '[^,]+$') or ''
local request_id = lua_metadata['request.info.request_id'] or ''
local status_code = handle:headers():get(':status') or '0'
local allowed_client = lua_metadata['request.info.allowed_client'] or false
local authority = lua_metadata['request.info.authority'] or ''
local lua_destination_authority = lua_metadata['request.info.lua_destination_authority'] or ''
local message = {
'\nINCOMING_PERMISSIONS {"method":"', method,
'","path":"', path,
'","clientIp":"', source_ip,
'","clientName":"', escape(client_name),
'","trustedClient":', tostring(trusted_client),
',"authority":"', escape(authority),
'","luaDestinationAuthority":"', escape(lua_destination_authority),
'","clientAllowedToAllEndpoints":', tostring(allowed_client),
',"protocol":"', protocol,
'","requestId":"', escape(request_id),
'","statusCode":', status_code,
',"rbacAction":"', rbac_action, '"' ,
',"jwtTokenStatus":"' , jwt_status, '"',
}
local headers_to_log = handle:metadata():get('rbac_headers_to_log') or {}
for _, header in ipairs(headers_to_log) do
local value = lua_metadata['request.info.headers.'..header]
if value then
table.insert(message, ',"')
table.insert(message, header)
table.insert(message, '":"')
table.insert(message, tostring(escape(value)))
table.insert(message, '"')
end
end
table.insert(message, '}')
handle:logInfo(table.concat(message, ''))
end
escapeList = {
['\\'] = '\\\\',
['\"'] = '\\\"',
['\b'] = '\\b',
['\f'] = '\\f',
['\n'] = '\\n',
['\r'] = '\\r',
['\t'] = '\\t',
}
function escape(val)
return string.gsub(val, '[\\\"\b\f\n\r\t]', escapeList)
end