Skip to main content
Version: Next

Lua Policy Plugins

Nauthilus Lua plugins can emit typed policy attributes directly into the active request decision context. This lets a plugin collect a signal once and then let auth.policy.policies decide what the final effect should be.

Enable the Bundled Registry

The bundled policy-aware plugins emit attributes below lua.plugin.*. Register these attributes before using them in policies:

auth:
policy:
registry_scripts:
- "/etc/nauthilus/lua-plugins.d/policy/registry.lua"

The registry is loaded when the policy snapshot is built. If a plugin emits an unknown attribute, the Lua execution fails instead of silently creating a loose fact.

Plugin Helper

Bundled plugins use nauthilus_policy_facts:

local policy_facts = require("nauthilus_policy_facts")

policy_facts.emit("soft_delay", "risky", true)
policy_facts.emit_public("geoip", "rejected", true, {
status_message = "Policy violation",
})
policy_facts.status_message("geoip", "Policy violation")
  • emit and emit_many write policy attributes and request-local policy_facts.
  • emit_public and emit_many_public also write policy_fact_<namespace>_<key> custom logs.
  • status_message sets the normal Nauthilus status message and emits lua.plugin.<namespace>.status_message.
  • set stores only request-local Lua context data and does not emit a policy attribute.

Attribute Reference

All attributes below are registered by lua-plugins.d/policy/registry.lua.

Environment Source Plugins

PluginAttributeTypeMeaning
account_longwindow_metrics.lualua.plugin.account_longwindow.usernamestringAccount name used by the long-window collector.
account_longwindow_metrics.lualua.plugin.account_longwindow.authenticatedboolWhether the request was authenticated when metrics were collected.
account_longwindow_metrics.lualua.plugin.account_longwindow.uniq_ips_24hnumberUnique account IP estimate over 24 hours.
account_longwindow_metrics.lualua.plugin.account_longwindow.uniq_ips_7dnumberUnique account IP estimate over 7 days.
account_longwindow_metrics.lualua.plugin.account_longwindow.fails_24hnumberFailed account attempts over 24 hours.
account_longwindow_metrics.lualua.plugin.account_longwindow.fails_7dnumberFailed account attempts over 7 days.
account_longwindow_metrics.lualua.plugin.account_longwindow.has_pw_tokenboolWhether the request produced a sprayed-password token.
global_pattern_monitoring.lualua.plugin.global_pattern.attemptsnumberGlobal attempts in the current window.
global_pattern_monitoring.lualua.plugin.global_pattern.unique_ipsnumberGlobal unique IP estimate.
global_pattern_monitoring.lualua.plugin.global_pattern.unique_usersnumberGlobal unique user estimate.
global_pattern_monitoring.lualua.plugin.global_pattern.attempts_per_ipnumberAttempts-per-IP ratio.
global_pattern_monitoring.lualua.plugin.global_pattern.attempts_per_usernumberAttempts-per-user ratio.
global_pattern_monitoring.lualua.plugin.global_pattern.ips_per_usernumberIPs-per-user ratio.
security_metrics.lualua.plugin.security_metrics.global_ips_per_user_24hnumberGlobal IPs-per-user ratio over 24 hours.
security_metrics.lualua.plugin.security_metrics.global_ips_per_user_7dnumberGlobal IPs-per-user ratio over 7 days.
security_metrics.lualua.plugin.security_metrics.protected_accountsnumberNumber of accounts currently in protection mode.
failed_login_hotspot.lualua.plugin.failed_login_hotspot.usernamestringUsername evaluated against the failed-login hotspot set.
failed_login_hotspot.lualua.plugin.failed_login_hotspot.countnumberFailed-login hotspot score.
failed_login_hotspot.lualua.plugin.failed_login_hotspot.ranknumberFailed-login hotspot rank.
failed_login_hotspot.lualua.plugin.failed_login_hotspot.triggeredboolWhether the hotspot threshold matched.
blocklist.lualua.plugin.blocklist.matchedboolWhether the remote client matched the blocklist.
blocklist.lualua.plugin.blocklist.client_ipipClient IP sent to the blocklist service.
blocklist.lualua.plugin.blocklist.status_messagestringClient-visible blocklist message.

lua.plugin.blocklist.matched carries a public status_message detail when it is emitted.

Subject Source Plugins

PluginAttributeTypeMeaning
account_centric_monitoring.lualua.plugin.account_monitoring.attack_detectedboolWhether account-centric monitoring detected an attack pattern.
account_centric_monitoring.lualua.plugin.account_monitoring.usernamestringUsername evaluated by the monitor.
account_centric_monitoring.lualua.plugin.account_monitoring.uniq_ips_1hnumberUnique account IP estimate over 1 hour.
account_centric_monitoring.lualua.plugin.account_monitoring.uniq_ips_24hnumberUnique account IP estimate over 24 hours.
account_centric_monitoring.lualua.plugin.account_monitoring.uniq_ips_7dnumberUnique account IP estimate over 7 days.
account_centric_monitoring.lualua.plugin.account_monitoring.failed_24hnumberFailed account attempts over 24 hours.
account_centric_monitoring.lualua.plugin.account_monitoring.ratio_24hnumberAccount IP-to-failure ratio over 24 hours.
account_protection_mode.lualua.plugin.account_protection.activeboolWhether account protection mode is active.
account_protection_mode.lualua.plugin.account_protection.reasonstringComma-separated protection reason codes.
account_protection_mode.lualua.plugin.account_protection.backoff_levelnumberCurrent protection backoff level.
account_protection_mode.lualua.plugin.account_protection.delay_msnumberDelay applied in milliseconds.
account_protection_mode.lualua.plugin.account_protection.enforce_rejectboolWhether protection mode rejects unauthenticated traffic.
account_protection_mode.lualua.plugin.account_protection.status_messagestringClient-visible protection message.
geoip.lualua.plugin.geoip.guidstringGeoIP service request identifier.
geoip.lualua.plugin.geoip.current_country_codestringCurrent ISO-3166 alpha-2 country code.
geoip.lualua.plugin.geoip.country_codesstring_listCountry codes observed by the GeoIP service.
geoip.lualua.plugin.geoip.rejectedboolWhether the GeoIP service requested rejection.
geoip.lualua.plugin.geoip.errorboolWhether the GeoIP service returned an error.
geoip.lualua.plugin.geoip.status_messagestringClient-visible GeoIP message.
idp_policy.lualua.plugin.idp_policy.rejectedboolWhether the IdP Lua policy rejected the request.
idp_policy.lualua.plugin.idp_policy.reasonstringReason returned by the IdP Lua policy.
idp_policy.lualua.plugin.idp_policy.oidc_cidstringOIDC client identifier evaluated by the plugin.
idp_policy.lualua.plugin.idp_policy.grant_typestringOIDC grant type evaluated by the plugin.
idp_policy.lualua.plugin.idp_policy.status_messagestringClient-visible IdP policy message.
monitoring.lualua.plugin.director.backend_serverstringBackend server selected by the director subject source.
soft_delay.lualua.plugin.soft_delay.riskyboolWhether the soft-delay subject source considered the request risky.
soft_delay.lualua.plugin.soft_delay.applied_msnumberDelay applied in milliseconds.

lua.plugin.account_protection.active, lua.plugin.geoip.rejected, and lua.plugin.idp_policy.rejected carry a public status_message detail when emitted with a client-visible message.

Policy Example

auth:
policy:
registry_scripts:
- "/etc/nauthilus/lua-plugins.d/policy/registry.lua"

checks:
- name: lua_subject_geoip
type: lua.subject
stage: subject_analysis
operations: [authenticate]
config_ref: auth.policy.attribute_sources.lua.subject.geoip

policies:
- name: deny_geoip_rejection
stage: auth_decision
operations: [authenticate]
require_checks: [lua_subject_geoip]
if:
attribute: lua.plugin.geoip.rejected
is: true
then:
decision: deny
reason: geoip_policy_rejected
response_marker: auth.response.fail
response_message:
from: attribute_detail
attribute: lua.plugin.geoip.rejected
detail: status_message
fallback: "Invalid login or password"

Writing Your Own Emitter

Register the attribute:

nauthilus_policy.register_attribute({
id = "lua.plugin.example.risky",
stage = "subject_analysis",
operations = { "authenticate" },
category = "environment",
type = "bool",
description = "Example risk flag",
})

Emit it from a request-time Lua plugin:

local policy = require("nauthilus_policy")

policy.emit_attribute({
id = "lua.plugin.example.risky",
value = true,
})

The emitted type, operation, and stage must match the registry definition.