feat(firewall): add tenant and system rule scopes

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-07-30 21:38:19 -04:00
parent b8afd75b77
commit 63d91ca7fa
5 changed files with 352 additions and 37 deletions
+38 -30
View File
@@ -36,8 +36,8 @@ class FirewallService
private const CONFIG_AUTO_BLOCK_DURATION = 'firewall.autoBlockDuration';
private const CONFIG_ENABLED = 'firewall.enabled';
/** @var FirewallRuleObject[]|null */
private ?array $rulesCache = null;
/** @var array<string, FirewallRuleObject[]> */
private array $rulesCache = [];
public function __construct(
private readonly FirewallStore $store,
@@ -83,24 +83,25 @@ class FirewallService
$rules = $this->getActiveRules();
// First check for explicit allow rules (whitelist takes precedence)
foreach ($rules as $rule) {
if ($rule->getAction() !== FirewallRuleObject::ACTION_ALLOW) {
continue;
}
if ($this->ruleMatchesRequest($rule, $ipAddress, $deviceFingerprint)) {
return new FirewallAnalyzeResult(true, $rule->getId(), 'Explicitly allowed');
}
}
foreach ([
[FirewallRuleObject::SCOPE_SYSTEM, FirewallRuleObject::ACTION_BLOCK],
[FirewallRuleObject::SCOPE_TENANT, FirewallRuleObject::ACTION_ALLOW],
[FirewallRuleObject::SCOPE_TENANT, FirewallRuleObject::ACTION_BLOCK],
[FirewallRuleObject::SCOPE_SYSTEM, FirewallRuleObject::ACTION_ALLOW],
] as [$scope, $action]) {
foreach ($rules as $rule) {
if ($rule->getScope() !== $scope || $rule->getAction() !== $action) {
continue;
}
if (!$this->ruleMatchesRequest($rule, $ipAddress, $deviceFingerprint)) {
continue;
}
if ($action === FirewallRuleObject::ACTION_ALLOW) {
return new FirewallAnalyzeResult(true, $rule->getId(), 'Explicitly allowed');
}
// Then check for block rules
foreach ($rules as $rule) {
if ($rule->getAction() !== FirewallRuleObject::ACTION_BLOCK) {
continue;
}
if ($this->ruleMatchesRequest($rule, $ipAddress, $deviceFingerprint)) {
$this->publishAccessDenied($ipAddress, $deviceFingerprint, $rule);
return new FirewallAnalyzeResult(false, $rule->getId(), $rule->getReason());
}
@@ -293,7 +294,8 @@ class FirewallService
}
$rule = new FirewallRuleObject();
$rule->setTenantId($tenantId)
$rule->setScope(FirewallRuleObject::SCOPE_TENANT)
->setTenantId($tenantId)
->setType(FirewallRuleObject::TYPE_IP)
->setAction(FirewallRuleObject::ACTION_BLOCK)
->setValue($ipAddress)
@@ -335,7 +337,8 @@ class FirewallService
}
$rule = new FirewallRuleObject();
$rule->setTenantId($tenantId)
$rule->setScope(FirewallRuleObject::SCOPE_TENANT)
->setTenantId($tenantId)
->setType(FirewallRuleObject::TYPE_IP)
->setAction(FirewallRuleObject::ACTION_ALLOW)
->setValue($ipAddress)
@@ -371,7 +374,8 @@ class FirewallService
}
$rule = new FirewallRuleObject();
$rule->setTenantId($tenantId)
$rule->setScope(FirewallRuleObject::SCOPE_TENANT)
->setTenantId($tenantId)
->setType(FirewallRuleObject::TYPE_IP_RANGE)
->setAction(FirewallRuleObject::ACTION_BLOCK)
->setValue($cidr)
@@ -401,7 +405,8 @@ class FirewallService
}
$rule = new FirewallRuleObject();
$rule->setTenantId($tenantId)
$rule->setScope(FirewallRuleObject::SCOPE_TENANT)
->setTenantId($tenantId)
->setType(FirewallRuleObject::TYPE_DEVICE)
->setAction(FirewallRuleObject::ACTION_BLOCK)
->setValue($fingerprint)
@@ -551,13 +556,16 @@ class FirewallService
*/
private function getActiveRules(): array
{
if ($this->rulesCache === null) {
$tenantId = $this->tenantContext->identifier();
$this->rulesCache = $tenantId
? $this->store->listRules($tenantId, true)
: [];
$tenantId = $this->tenantContext->identifier();
if (!$tenantId) {
return [];
}
return $this->rulesCache;
if (!array_key_exists($tenantId, $this->rulesCache)) {
$this->rulesCache[$tenantId] = $this->store->listApplicableRules($tenantId);
}
return $this->rulesCache[$tenantId];
}
/**
@@ -565,7 +573,7 @@ class FirewallService
*/
private function clearRulesCache(): void
{
$this->rulesCache = null;
$this->rulesCache = [];
}
/**