feat(fw): Renderer-Rewrite + auto-apply + Anti-Lockout
internal/firewall/firewall.go komplett neu: joint zone-iface-mapping
(network_interfaces.role), address objects + groups (members
expandiert), services + groups, rules, nat-rules. Output: einheitliche
View mit Legs (rule × service cross-product) damit das Template kein
sub-template/dict braucht.
Template:
* Anti-Lockout-Block am input-chain-Top (SSH+443 immer erlaubt,
KANN nicht von Custom-Rules overruled werden — User-Wunsch).
* Rules: pro Leg eine nft-Zeile mit iif/oif sets, ip saddr/daddr,
proto+dport, optional log-prefix.
* prerouting_nat: iteriert dnat-Rules.
* postrouting_nat: snat + masquerade.
Auto-apply: FirewallHandler bekommt einen Reloader-Hook der nach
jedem POST/PUT/DELETE aufgerufen wird. main.go injected
firewall.New(pool).Render — schreibt + sudo nft -f.
Sudoers (/etc/sudoers.d/edgeguard): NOPASSWD für 'nft -f
/etc/edgeguard/nftables.d/ruleset.nft'. configgen.ReloadService
nutzt jetzt sudo (haproxy reload klappte vorher nicht aus dem
edgeguard-User).
Frontend (Sweep): style={{ marginBottom: 16 }} → className="mb-16"
in allen 7 Firewall-Tabs — User-Feedback "globales CSS statt inline".
Live auf 89.163.205.6: nft list table inet edgeguard zeigt
Anti-Lockout + Baseline + Cluster-Peer-Set + (jetzt noch leere)
Custom-Rules-Sektion. render-config postinst-mäßig sauber.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -85,7 +85,7 @@ export default function AddressGroupsTab() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" style={{ marginBottom: 16 }} onClick={() => {
|
||||
<Button type="primary" className="mb-16" onClick={() => {
|
||||
setCreating(true); form.resetFields()
|
||||
form.setFieldsValue({ member_ids: [] })
|
||||
}}>
|
||||
|
||||
@@ -78,7 +78,7 @@ export default function AddressObjectsTab() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" style={{ marginBottom: 16 }} onClick={() => {
|
||||
<Button type="primary" className="mb-16" onClick={() => {
|
||||
setCreating(true); form.resetFields()
|
||||
form.setFieldsValue({ kind: 'host' })
|
||||
}}>
|
||||
|
||||
@@ -122,7 +122,7 @@ export default function NATRulesTab() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" style={{ marginBottom: 16 }} onClick={() => {
|
||||
<Button type="primary" className="mb-16" onClick={() => {
|
||||
setCreating(true); form.resetFields()
|
||||
form.setFieldsValue({ priority: 100, enabled: true, kind: 'dnat' })
|
||||
}}>
|
||||
|
||||
@@ -185,7 +185,7 @@ export default function RulesTab() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" style={{ marginBottom: 16 }} onClick={() => {
|
||||
<Button type="primary" className="mb-16" onClick={() => {
|
||||
setCreating(true); form.resetFields()
|
||||
form.setFieldsValue({
|
||||
priority: 100, enabled: true, action: 'accept', log: false,
|
||||
@@ -213,7 +213,7 @@ export default function RulesTab() {
|
||||
<Input placeholder="SSH von Office" />
|
||||
</Form.Item>
|
||||
|
||||
<Space size="middle" style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Space size="middle" className="flex-wrap">
|
||||
<Form.Item label={t('fw.rule.priority')} name="priority" rules={[{ required: true }]}>
|
||||
<InputNumber min={0} max={9999} />
|
||||
</Form.Item>
|
||||
@@ -262,7 +262,7 @@ export default function RulesTab() {
|
||||
</Space>
|
||||
))}
|
||||
|
||||
<Space size="middle" style={{ display: 'flex', flexWrap: 'wrap' }}>
|
||||
<Space size="middle" className="flex-wrap">
|
||||
<Form.Item label={t('fw.rule.serviceKind')} name="service_kind" rules={[{ required: true }]}>
|
||||
<Select style={{ width: 120 }} options={(['any','object','group'] as const).map(k => ({ value: k, label: k }))} />
|
||||
</Form.Item>
|
||||
|
||||
@@ -85,7 +85,7 @@ export default function ServiceGroupsTab() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" style={{ marginBottom: 16 }} onClick={() => {
|
||||
<Button type="primary" className="mb-16" onClick={() => {
|
||||
setCreating(true); form.resetFields()
|
||||
form.setFieldsValue({ member_ids: [] })
|
||||
}}>
|
||||
|
||||
@@ -89,7 +89,7 @@ export default function ServicesTab() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button type="primary" style={{ marginBottom: 16 }} onClick={() => {
|
||||
<Button type="primary" className="mb-16" onClick={() => {
|
||||
setCreating(true); form.resetFields()
|
||||
form.setFieldsValue({ proto: 'tcp' })
|
||||
}}>
|
||||
|
||||
Reference in New Issue
Block a user