Record the forward policies before disabling ufw, so a retried retirement restores them (hq ADR 0100)
This commit is contained in:
@@ -30,6 +30,7 @@ func foundFirewall(ctx context.Context, d *declaration.Declaration, known *store
|
||||
return "", err
|
||||
}
|
||||
rec.DisabledByMesh = false
|
||||
rec.Forward = nil
|
||||
log(" enabled ufw again: this node is adopted, and the firewall found on it is in force")
|
||||
}
|
||||
kind, name, err := firewall.Detect(ctx, run)
|
||||
@@ -68,7 +69,12 @@ func retireFirewall(ctx context.Context, d *declaration.Declaration, origin stri
|
||||
rec.DisabledByMesh {
|
||||
return nil
|
||||
}
|
||||
if err := firewall.Disable(ctx, run); err != nil {
|
||||
if rec.Forward == nil {
|
||||
// Recorded before ufw is touched: disabling it opens the forward policy, and a retry
|
||||
// must know what it was (novox/hq ADR 0100).
|
||||
rec.Forward = firewall.ForwardPolicies(ctx, run)
|
||||
}
|
||||
if err := firewall.Disable(ctx, run, rec.Forward); err != nil {
|
||||
return err
|
||||
}
|
||||
rec.DisabledByMesh = true
|
||||
|
||||
@@ -21,6 +21,23 @@ type ufwMachine struct {
|
||||
rules []string
|
||||
ruleset string
|
||||
asked []string
|
||||
|
||||
// forward is iptables' forward policy when set; empty is a machine without iptables. failP
|
||||
// is how many -P calls fail before one succeeds.
|
||||
forward string
|
||||
failP int
|
||||
}
|
||||
|
||||
func (u *ufwMachine) iptables(args []string) (string, error) {
|
||||
if len(args) == 3 && args[0] == "-P" {
|
||||
if u.failP > 0 {
|
||||
u.failP--
|
||||
return "", errors.New("iptables: resource temporarily unavailable")
|
||||
}
|
||||
u.forward = args[2]
|
||||
return "", nil
|
||||
}
|
||||
return "-P FORWARD " + u.forward + "\n-A FORWARD -j DOCKER-USER\n", nil
|
||||
}
|
||||
|
||||
func (u *ufwMachine) run(_ context.Context, name string, args ...string) (string, error) {
|
||||
@@ -28,6 +45,11 @@ func (u *ufwMachine) run(_ context.Context, name string, args ...string) (string
|
||||
switch name {
|
||||
case "nft":
|
||||
return u.ruleset, nil
|
||||
case "iptables":
|
||||
if u.forward == "" {
|
||||
return "", &exec.Error{Name: name, Err: exec.ErrNotFound}
|
||||
}
|
||||
return u.iptables(args)
|
||||
case "ufw":
|
||||
if !u.installed {
|
||||
return "", &exec.Error{Name: name, Err: exec.ErrNotFound}
|
||||
@@ -52,6 +74,9 @@ func (u *ufwMachine) run(_ context.Context, name string, args ...string) (string
|
||||
return "", nil
|
||||
case "disable":
|
||||
u.active = false
|
||||
if u.forward != "" {
|
||||
u.forward = "ACCEPT" // as measured: ufw disable opens the forward policy
|
||||
}
|
||||
return "", nil
|
||||
case "delete":
|
||||
want := strings.Join(args[1:], " ")
|
||||
@@ -370,3 +395,27 @@ func TestAStaleOpeningOnAnAdoptedNodeIsRemovedAsAnyOrphan(t *testing.T) {
|
||||
t.Errorf("the stale opening was not removed before the new one was added: %v", u.asked)
|
||||
}
|
||||
}
|
||||
|
||||
func TestARetiredFirewallRetriedStillPutsBackTheForwardPolicy(t *testing.T) {
|
||||
// The forward policy is recorded before ufw is disabled, so a retirement that failed after
|
||||
// the disable restores what the machine had, not what the disable left (novox/hq ADR 0100).
|
||||
dir := t.TempDir()
|
||||
u := &ufwMachine{installed: true, active: true, forward: "DROP", failP: 1}
|
||||
_, state, err := applyWith(t, adopted(t, `{"taken":[]}`, withConf(dir)), store.State{}, u.run)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
converged := parse(t, `{"declaration":1,"resources":[`+withConf(dir)+`]}`)
|
||||
if _, state, err = applyWith(t, converged, state, u.run); err == nil {
|
||||
t.Fatal("the failed restore was not reported")
|
||||
}
|
||||
if u.active || u.forward != "ACCEPT" || state.Firewall.Forward["iptables"] != "DROP" {
|
||||
t.Fatalf("after the failed attempt: active %v, forward %s, recorded %+v", u.active, u.forward, state.Firewall)
|
||||
}
|
||||
if _, state, err = applyWith(t, converged, state, u.run); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if u.forward != "DROP" || !state.Firewall.DisabledByMesh {
|
||||
t.Errorf("the retry did not put the forward policy back: %s, %+v", u.forward, state.Firewall)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user