feat(firewall): Auto-FW-Rule-Generator + UI-Anzeige
Renderer berechnet inbound-accept-Rules aus dem laufenden
Service-State — Operator legt keine FW-Rule mehr für DNS/Squid/WG-
Listen-Sockets manuell an.
internal/firewall:
* View.AutoRules + AutoFWRule struct (proto, port, optional dst-IP,
comment).
* loadAutoRules quert cross-service:
- DNS: dns_settings.listen_addresses ohne 127.x/::1 → udp+tcp 53
pro IP (mit ip daddr X-match).
- Squid: count(active forward_proxy_acls) > 0 → tcp 3128 (any IP,
squid bindet 0.0.0.0).
- WireGuard: server-mode + listen_port → udp <port> pro Iface.
* nft-Template emittiert eigene "Service-Auto-Rules"-Section vor
Operator-Rules. Comment im nft-Output zeigt source-service.
* LoadAutoRules exportiert für Handler-Endpoint.
Handler:
* GET /api/v1/firewall/auto-rules — gibt die berechnete Liste
zurück damit die UI sie anzeigen kann.
* FirewallHandler.Pool field + ctor-arg dazugekommen.
UI:
* SystemRulesCard fetcht /firewall/auto-rules + merged sie unter
die statischen Anti-Lockout-Rows. 30s-Polling. Operator sieht
jetzt im /firewall/Rules-Tab oben warum z.B. udp/53 offen ist
(auto: DNS auf 10.10.20.1).
Cleanup: alte manuelle DNS+WG-Rules per SQL gelöscht — Auto-Rules
übernehmen.
Version 1.0.38.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "edgeguard-management-ui",
|
||||
"private": true,
|
||||
"version": "1.0.36",
|
||||
"version": "1.0.38",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -73,7 +73,7 @@ const NAV: NavSection[] = [
|
||||
},
|
||||
]
|
||||
|
||||
const VERSION = '1.0.36'
|
||||
const VERSION = '1.0.38'
|
||||
|
||||
export default function Sidebar({ isOpen, onClose }: SidebarProps) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
import { Alert, Card, Space, Table, Tag, Typography } from 'antd'
|
||||
import type { ColumnsType } from 'antd/es/table'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import apiClient, { isEnvelope } from '../../api/client'
|
||||
|
||||
interface AutoRule {
|
||||
Proto: string
|
||||
Port: number
|
||||
DstIP?: string
|
||||
Comment: string
|
||||
}
|
||||
|
||||
async function listAutoRules(): Promise<AutoRule[]> {
|
||||
try {
|
||||
const r = await apiClient.get('/firewall/auto-rules')
|
||||
if (!isEnvelope(r.data)) return []
|
||||
return (r.data.data as { rules?: AutoRule[] }).rules ?? []
|
||||
} catch { return [] }
|
||||
}
|
||||
|
||||
// SystemRulesCard documents the baseline nftables ruleset that
|
||||
// EdgeGuard installs unconditionally — anti-lockout, stateful
|
||||
// session handling, public ingress, cluster mTLS. These rules sit
|
||||
@@ -36,6 +54,18 @@ const ACTION_COLORS: Record<string, string> = {
|
||||
|
||||
export default function SystemRulesCard() {
|
||||
const { t } = useTranslation()
|
||||
const { data: autoRules } = useQuery({ queryKey: ['fw', 'auto-rules'], queryFn: listAutoRules, refetchInterval: 30_000 })
|
||||
|
||||
// Static system rules + dynamic auto-rules zu einer Liste mergen.
|
||||
const dynamic: SystemRule[] = (autoRules ?? []).map((r, i) => ({
|
||||
key: `auto-${i}`,
|
||||
chain: 'input',
|
||||
match: `${r.DstIP ? `ip daddr ${r.DstIP} ` : ''}${r.Proto} dport ${r.Port}`,
|
||||
action: 'accept',
|
||||
note: `auto: ${r.Comment}`,
|
||||
}))
|
||||
const allRows = [...ROWS, ...dynamic]
|
||||
|
||||
const cols: ColumnsType<SystemRule> = [
|
||||
{ title: t('fw.sys.chain'), dataIndex: 'chain', key: 'chain', width: 80, render: (s: string) => <Tag>{s}</Tag> },
|
||||
{ title: t('fw.sys.match'), dataIndex: 'match', key: 'match', render: (s: string) => <code>{s}</code> },
|
||||
@@ -63,7 +93,7 @@ export default function SystemRulesCard() {
|
||||
size="small"
|
||||
rowKey="key"
|
||||
columns={cols}
|
||||
dataSource={ROWS}
|
||||
dataSource={allRows}
|
||||
pagination={false}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
Reference in New Issue
Block a user