Skip to content

Commit 8b85b40

Browse files
authored
feat: configure firewalld (#1892)
* feat: configure firewalld * f * f * f * f * f * f * f * f * f * f * f * f * f
1 parent ccf5a68 commit 8b85b40

File tree

22 files changed

+746
-8
lines changed

22 files changed

+746
-8
lines changed

.github/workflows/distros.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ jobs:
4141

4242
- name: Set up QEMU
4343
uses: docker/setup-qemu-action@v3
44+
with:
45+
# see https://github.com/tonistiigi/binfmt/issues/215
46+
image: tonistiigi/binfmt:qemu-v7.0.0
4447

4548
- name: Set up Docker Buildx
4649
uses: docker/setup-buildx-action@v3

cmd/installer/cli/firewalld.go

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/replicatedhq/embedded-cluster/pkg/helpers/firewalld"
8+
"github.com/sirupsen/logrus"
9+
"go.uber.org/multierr"
10+
)
11+
12+
// configureFirewalld configures firewalld for the cluster. It adds the ec-net zone for pod and
13+
// service communication with default target ACCEPT, and opens the necessary ports in the default
14+
// zone for k0s and k8s components on the host network.
15+
func configureFirewalld(ctx context.Context, podNetwork, serviceNetwork string) error {
16+
isActive, err := firewalld.IsFirewalldActive(ctx)
17+
if err != nil {
18+
return fmt.Errorf("check if firewalld is active: %w", err)
19+
}
20+
if !isActive {
21+
logrus.Debugf("firewalld is not active, skipping configuration")
22+
return nil
23+
}
24+
25+
logrus.Debugf("firewalld is active, configuring")
26+
27+
cmdExists, err := firewalld.FirewallCmdExists(ctx)
28+
if err != nil {
29+
return fmt.Errorf("check if firewall-cmd exists: %w", err)
30+
}
31+
if !cmdExists {
32+
logrus.Debugf("firewall-cmd not found but firewalld is active, skipping firewalld configuration")
33+
return nil
34+
}
35+
36+
err = ensureFirewalldECNetZone(ctx, podNetwork, serviceNetwork)
37+
if err != nil {
38+
return fmt.Errorf("ensure ec-net zone: %w", err)
39+
}
40+
41+
err = ensureFirewalldDefaultZone(ctx)
42+
if err != nil {
43+
return fmt.Errorf("ensure default zone: %w", err)
44+
}
45+
46+
err = firewalld.Reload(ctx)
47+
if err != nil {
48+
return fmt.Errorf("reload firewalld: %w", err)
49+
}
50+
51+
return nil
52+
}
53+
54+
// resetFirewalld removes all firewalld configuration added by the installer.
55+
func resetFirewalld(ctx context.Context) (finalErr error) {
56+
cmdExists, err := firewalld.FirewallCmdExists(ctx)
57+
if err != nil {
58+
return fmt.Errorf("check if firewall-cmd exists: %w", err)
59+
}
60+
if !cmdExists {
61+
return nil
62+
}
63+
64+
err = resetFirewalldECNetZone(ctx)
65+
if err != nil {
66+
finalErr = multierr.Append(finalErr, fmt.Errorf("reset ec-net zone: %w", err))
67+
}
68+
69+
err = resetFirewalldDefaultZone(ctx)
70+
if err != nil {
71+
finalErr = multierr.Append(finalErr, fmt.Errorf("reset default zone: %w", err))
72+
}
73+
74+
err = firewalld.Reload(ctx)
75+
if err != nil {
76+
return fmt.Errorf("reload firewalld: %w", err)
77+
}
78+
79+
return
80+
}
81+
82+
func ensureFirewalldECNetZone(ctx context.Context, podNetwork, serviceNetwork string) error {
83+
opts := []firewalld.Option{
84+
firewalld.IsPermanent(),
85+
firewalld.WithZone("ec-net"),
86+
}
87+
88+
exists, err := firewalld.ZoneExists(ctx, "ec-net")
89+
if err != nil {
90+
return fmt.Errorf("check if ec-net zone exists: %w", err)
91+
} else if !exists {
92+
err = firewalld.NewZone(ctx, "ec-net", opts...)
93+
if err != nil {
94+
return fmt.Errorf("create ec-net zone: %w", err)
95+
}
96+
}
97+
98+
// Set the default target to ACCEPT for pod and service networks
99+
err = firewalld.SetZoneTarget(ctx, "ACCEPT", opts...)
100+
if err != nil {
101+
return fmt.Errorf("set target to ACCEPT: %w", err)
102+
}
103+
104+
err = firewalld.AddSourceToZone(ctx, podNetwork, opts...)
105+
if err != nil {
106+
return fmt.Errorf("add pod network source: %w", err)
107+
}
108+
109+
err = firewalld.AddSourceToZone(ctx, serviceNetwork, opts...)
110+
if err != nil {
111+
return fmt.Errorf("add service network source: %w", err)
112+
}
113+
114+
// Add the calico interfaces
115+
// This is redundant and overlaps with the pod network but we add it anyway
116+
calicoIfaces := []string{"cali+", "tunl+", "vxlan-v6.calico", "vxlan.calico", "wg-v6.cali", "wireguard.cali"}
117+
for _, iface := range calicoIfaces {
118+
err = firewalld.AddInterfaceToZone(ctx, iface, opts...)
119+
if err != nil {
120+
return fmt.Errorf("add %s interface: %w", iface, err)
121+
}
122+
}
123+
124+
return nil
125+
}
126+
127+
func resetFirewalldECNetZone(ctx context.Context) (finalErr error) {
128+
opts := []firewalld.Option{
129+
firewalld.IsPermanent(),
130+
}
131+
132+
exists, err := firewalld.ZoneExists(ctx, "ec-net")
133+
if err != nil {
134+
return fmt.Errorf("check if ec-net zone exists: %w", err)
135+
} else if !exists {
136+
return nil
137+
}
138+
139+
err = firewalld.DeleteZone(ctx, "ec-net", opts...)
140+
if err != nil {
141+
return fmt.Errorf("delete ec-net zone: %w", err)
142+
}
143+
144+
return
145+
}
146+
147+
func ensureFirewalldDefaultZone(ctx context.Context) error {
148+
opts := []firewalld.Option{
149+
firewalld.IsPermanent(),
150+
}
151+
152+
// Allow other nodes to connect to k0s core components
153+
ports := []string{"6443/tcp", "10250/tcp", "9443/tcp", "2380/tcp", "4789/udp"}
154+
for _, port := range ports {
155+
err := firewalld.AddPortToZone(ctx, port, opts...)
156+
if err != nil {
157+
return fmt.Errorf("add %s port: %w", port, err)
158+
}
159+
}
160+
161+
return nil
162+
}
163+
164+
func resetFirewalldDefaultZone(ctx context.Context) (finalErr error) {
165+
opts := []firewalld.Option{
166+
firewalld.IsPermanent(),
167+
}
168+
169+
ports := []string{"6443/tcp", "10250/tcp", "9443/tcp", "2380/tcp", "4789/udp"}
170+
for _, port := range ports {
171+
err := firewalld.RemovePortFromZone(ctx, port, opts...)
172+
if err != nil {
173+
finalErr = multierr.Append(finalErr, fmt.Errorf("remove %s port: %w", port, err))
174+
}
175+
}
176+
177+
return
178+
}

cmd/installer/cli/install.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,6 +270,11 @@ func runInstall(ctx context.Context, name string, flags InstallCmdFlags, metrics
270270
return fmt.Errorf("unable to configure network manager: %w", err)
271271
}
272272

273+
logrus.Debugf("configuring firewalld")
274+
if err := configureFirewalld(ctx, flags.cidrCfg.PodCIDR, flags.cidrCfg.ServiceCIDR); err != nil {
275+
logrus.Debugf("unable to configure firewalld: %v", err)
276+
}
277+
273278
logrus.Debugf("running install preflights")
274279
if err := runInstallPreflights(ctx, flags, metricsReporter); err != nil {
275280
if errors.Is(err, preflights.ErrPreflightsHaveFail) {

cmd/installer/cli/join.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ func runJoin(ctx context.Context, name string, flags JoinCmdFlags, jcmd *kotsadm
158158
return fmt.Errorf("unable to get join CIDR config: %w", err)
159159
}
160160

161+
logrus.Debugf("configuring firewalld")
162+
if err := configureFirewalld(ctx, cidrCfg.PodCIDR, cidrCfg.ServiceCIDR); err != nil {
163+
logrus.Debugf("unable to configure firewalld: %v", err)
164+
}
165+
161166
logrus.Debugf("running join preflights")
162167
if err := runJoinPreflights(ctx, jcmd, flags, cidrCfg, metricsReporter); err != nil {
163168
if errors.Is(err, preflights.ErrPreflightsHaveFail) {

cmd/installer/cli/reset.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,12 @@ func ResetCmd(ctx context.Context, name string) *cobra.Command {
142142
return err
143143
}
144144

145+
logrus.Debugf("Resetting firewalld...")
146+
err = resetFirewalld(ctx)
147+
if !checkErrPrompt(assumeYes, force, err) {
148+
return fmt.Errorf("failed to reset firewalld: %w", err)
149+
}
150+
145151
if err := helpers.RemoveAll(runtimeconfig.PathToK0sConfig()); err != nil {
146152
return fmt.Errorf("failed to remove k0s config: %w", err)
147153
}
@@ -214,6 +220,8 @@ func ResetCmd(ctx context.Context, name string) *cobra.Command {
214220
cmd.Flags().BoolVar(&assumeYes, "yes", false, "Assume yes to all prompts.")
215221
cmd.Flags().SetNormalizeFunc(normalizeNoPromptToYes)
216222

223+
cmd.AddCommand(ResetFirewalldCmd(ctx, name))
224+
217225
return cmd
218226
}
219227

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package cli
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig"
9+
rcutil "github.com/replicatedhq/embedded-cluster/pkg/runtimeconfig/util"
10+
"github.com/sirupsen/logrus"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
func ResetFirewalldCmd(ctx context.Context, name string) *cobra.Command {
15+
cmd := &cobra.Command{
16+
Use: "firewalld",
17+
Short: "Remove %s firewalld configuration from the current node",
18+
Hidden: true,
19+
PreRunE: func(cmd *cobra.Command, args []string) error {
20+
if os.Getuid() != 0 {
21+
return fmt.Errorf("reset firewalld command must be run as root")
22+
}
23+
24+
rcutil.InitBestRuntimeConfig(cmd.Context())
25+
26+
os.Setenv("KUBECONFIG", runtimeconfig.PathToKubeConfig())
27+
os.Setenv("TMPDIR", runtimeconfig.EmbeddedClusterTmpSubDir())
28+
29+
return nil
30+
},
31+
RunE: func(cmd *cobra.Command, args []string) error {
32+
err := resetFirewalld(cmd.Context())
33+
if err != nil {
34+
return fmt.Errorf("failed to reset firewalld: %w", err)
35+
}
36+
37+
logrus.Infof("Firewalld reset successfully")
38+
39+
return nil
40+
},
41+
}
42+
43+
return cmd
44+
}

cmd/installer/cli/restore.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,11 @@ func runRestoreStepNew(ctx context.Context, name string, flags InstallCmdFlags,
374374
return fmt.Errorf("unable to configure network manager: %w", err)
375375
}
376376

377+
logrus.Debugf("configuring firewalld")
378+
if err := configureFirewalld(ctx, flags.cidrCfg.PodCIDR, flags.cidrCfg.ServiceCIDR); err != nil {
379+
logrus.Debugf("unable to configure firewalld: %v", err)
380+
}
381+
377382
logrus.Debugf("materializing binaries")
378383
if err := materializeFiles(flags.airgapBundle); err != nil {
379384
return fmt.Errorf("unable to materialize binaries: %w", err)

dev/distros/dockerfiles/almalinux-8.Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ RUN dnf install -y \
2020
systemd-timesyncd \
2121
expect \
2222
vim \
23+
firewalld \
2324
--allowerasing
2425

2526
# Entrypoint for runtime configurations

e2e/install_test.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ func TestSingleNodeInstallationAlmaLinux8(t *testing.T) {
9595
t.Fatalf("fail to check postupgrade state: %v: %s: %s", err, stdout, stderr)
9696
}
9797

98+
t.Logf("%s: configuring firewalld", time.Now().Format(time.RFC3339))
99+
line = []string{"firewalld-configure.sh"}
100+
if stdout, stderr, err := tc.RunCommandOnNode(0, line); err != nil {
101+
t.Fatalf("fail to configure firewalld: %v: %s: %s", err, stdout, stderr)
102+
}
103+
98104
t.Logf("%s: installing embedded-cluster on node 0", time.Now().Format(time.RFC3339))
99105
line = []string{"single-node-install.sh", "ui", os.Getenv("SHORT_SHA")}
100106
if stdout, stderr, err := tc.RunCommandOnNode(0, line); err != nil {
@@ -111,6 +117,12 @@ func TestSingleNodeInstallationAlmaLinux8(t *testing.T) {
111117
t.Fatalf("fail to check installation state: %v: %s: %s", err, stdout, stderr)
112118
}
113119

120+
t.Logf("%s: validating firewalld", time.Now().Format(time.RFC3339))
121+
line = []string{"firewalld-validate.sh"}
122+
if stdout, stderr, err := tc.RunCommandOnNode(0, line); err != nil {
123+
t.Fatalf("fail to validate firewalld: %v: %s: %s", err, stdout, stderr)
124+
}
125+
114126
appUpgradeVersion := fmt.Sprintf("appver-%s-upgrade", os.Getenv("SHORT_SHA"))
115127
testArgs := []string{appUpgradeVersion}
116128

@@ -125,6 +137,12 @@ func TestSingleNodeInstallationAlmaLinux8(t *testing.T) {
125137
t.Fatalf("fail to check postupgrade state: %v: %s: %s", err, stdout, stderr)
126138
}
127139

140+
t.Logf("%s: resetting firewalld", time.Now().Format(time.RFC3339))
141+
line = []string{"firewalld-reset.sh"}
142+
if stdout, stderr, err := tc.RunCommandOnNode(0, line); err != nil {
143+
t.Fatalf("fail to reset firewalld: %v: %s: %s", err, stdout, stderr)
144+
}
145+
128146
t.Logf("%s: test complete", time.Now().Format(time.RFC3339))
129147
}
130148

e2e/scripts/firewalld-configure.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#!/usr/bin/env bash
2+
set -euxo pipefail
3+
4+
systemctl enable --now firewalld
5+
6+
firewall-cmd --set-default-zone=drop
7+
firewall-cmd --reload

0 commit comments

Comments
 (0)