Skip to content

Commit 16fa486

Browse files
committed
Open egress firewall for UDP and ICMP too
Signed-off-by: Hans Rakers <[email protected]>
1 parent 4e33b4a commit 16fa486

File tree

4 files changed

+77
-18
lines changed

4 files changed

+77
-18
lines changed

docs/book/src/clustercloudstack/configuration.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ cmk list zones listall=true | jq '.zone[] | {name, id}'
6161

6262
The network must be declared as an environment variable `CLOUDSTACK_NETWORK_NAME` and is a mandatory parameter.
6363
As of now, only isolated and shared networks are supported.
64-
If the specified network does not exist, a new isolated network will be created.
64+
65+
If the specified network does not exist, a new isolated network will be created. The newly created network will have a default egress firewall policy that allows all TCP, UDP and ICMP traffic from the cluster to the outside world.
6566

6667
The list of networks for the specific zone can be fetched using the cmk cli as follows :
6768
```

pkg/cloud/isolated_network.go

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,12 +110,26 @@ func (c *client) CreateIsolatedNetwork(fd *infrav1.CloudStackFailureDomain, isoN
110110
return c.AddCreatedByCAPCTag(ResourceTypeNetwork, isoNet.Spec.ID)
111111
}
112112

113-
// OpenFirewallRules opens a CloudStack firewall for an isolated network.
113+
// OpenFirewallRules opens a CloudStack egress firewall for an isolated network.
114114
func (c *client) OpenFirewallRules(isoNet *infrav1.CloudStackIsolatedNetwork) (retErr error) {
115-
p := c.cs.Firewall.NewCreateEgressFirewallRuleParams(isoNet.Spec.ID, NetworkProtocolTCP)
116-
_, retErr = c.cs.Firewall.CreateEgressFirewallRule(p)
117-
if retErr != nil && strings.Contains(strings.ToLower(retErr.Error()), "there is already") { // Already a firewall rule here.
118-
retErr = nil
115+
protocols := []string{NetworkProtocolTCP, NetworkProtocolUDP, NetworkProtocolICMP}
116+
for _, proto := range protocols {
117+
p := c.cs.Firewall.NewCreateEgressFirewallRuleParams(isoNet.Spec.ID, proto)
118+
119+
if proto == "icmp" {
120+
p.SetIcmptype(-1)
121+
p.SetIcmpcode(-1)
122+
}
123+
124+
_, err := c.cs.Firewall.CreateEgressFirewallRule(p)
125+
if err != nil &&
126+
// Ignore errors regarding already existing fw rules for TCP/UDP
127+
!strings.Contains(strings.ToLower(err.Error()), "there is already") &&
128+
// Ignore errors regarding already existing fw rule for ICMP
129+
!strings.Contains(strings.ToLower(err.Error()), "new rule conflicts with existing rule") {
130+
retErr = multierror.Append(retErr, errors.Wrapf(
131+
err, "failed creating egress firewall rule for network ID %s protocol %s", isoNet.Spec.ID, proto))
132+
}
119133
}
120134
c.customMetrics.EvaluateErrorAndIncrementAcsReconciliationErrorCounter(retErr)
121135
return retErr

pkg/cloud/isolated_network_test.go

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,24 @@ var _ = Describe("Network", func() {
8484
PublicIpAddresses: []*csapi.PublicIpAddress{{Id: dummies.PublicIPID, Ipaddress: "fakeIP"}}}, nil)
8585
as.EXPECT().NewAssociateIpAddressParams().Return(&csapi.AssociateIpAddressParams{})
8686
as.EXPECT().AssociateIpAddress(gomock.Any())
87-
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, cloud.NetworkProtocolTCP).
88-
Return(&csapi.CreateEgressFirewallRuleParams{})
89-
fs.EXPECT().CreateEgressFirewallRule(&csapi.CreateEgressFirewallRuleParams{}).
90-
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil)
87+
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, gomock.Any()).
88+
DoAndReturn(func(networkid string, protocol string) *csapi.CreateEgressFirewallRuleParams {
89+
p := &csapi.CreateEgressFirewallRuleParams{}
90+
if protocol == "icmp" {
91+
p.SetIcmptype(-1)
92+
p.SetIcmpcode(-1)
93+
}
94+
return p
95+
}).Times(3)
96+
97+
ruleParamsICMP := &csapi.CreateEgressFirewallRuleParams{}
98+
ruleParamsICMP.SetIcmptype(-1)
99+
ruleParamsICMP.SetIcmpcode(-1)
100+
gomock.InOrder(
101+
fs.EXPECT().CreateEgressFirewallRule(&csapi.CreateEgressFirewallRuleParams{}).
102+
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil).Times(2),
103+
fs.EXPECT().CreateEgressFirewallRule(ruleParamsICMP).
104+
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil))
91105

92106
// Will add cluster tag once to Network and once to PublicIP.
93107
createdByResponse := &csapi.ListTagsResponse{Tags: []*csapi.Tag{{Key: cloud.CreatedByCAPCTagName, Value: "1"}}}
@@ -124,10 +138,24 @@ var _ = Describe("Network", func() {
124138
Context("for a closed firewall", func() {
125139
It("OpenFirewallRule asks CloudStack to open the firewall", func() {
126140
dummies.Zone1.Network = dummies.ISONet1
127-
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, cloud.NetworkProtocolTCP).
128-
Return(&csapi.CreateEgressFirewallRuleParams{})
129-
fs.EXPECT().CreateEgressFirewallRule(&csapi.CreateEgressFirewallRuleParams{}).
130-
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil)
141+
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, gomock.Any()).
142+
DoAndReturn(func(networkid string, protocol string) *csapi.CreateEgressFirewallRuleParams {
143+
p := &csapi.CreateEgressFirewallRuleParams{}
144+
if protocol == "icmp" {
145+
p.SetIcmptype(-1)
146+
p.SetIcmpcode(-1)
147+
}
148+
return p
149+
}).Times(3)
150+
151+
ruleParamsICMP := &csapi.CreateEgressFirewallRuleParams{}
152+
ruleParamsICMP.SetIcmptype(-1)
153+
ruleParamsICMP.SetIcmpcode(-1)
154+
gomock.InOrder(
155+
fs.EXPECT().CreateEgressFirewallRule(&csapi.CreateEgressFirewallRuleParams{}).
156+
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil).Times(2),
157+
fs.EXPECT().CreateEgressFirewallRule(ruleParamsICMP).
158+
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil))
131159

132160
Ω(client.OpenFirewallRules(dummies.CSISONet1)).Should(Succeed())
133161
})
@@ -137,10 +165,24 @@ var _ = Describe("Network", func() {
137165
It("OpenFirewallRule asks CloudStack to open the firewall anyway, but doesn't fail", func() {
138166
dummies.Zone1.Network = dummies.ISONet1
139167

140-
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, "tcp").
141-
Return(&csapi.CreateEgressFirewallRuleParams{})
142-
fs.EXPECT().CreateEgressFirewallRule(&csapi.CreateEgressFirewallRuleParams{}).
143-
Return(&csapi.CreateEgressFirewallRuleResponse{}, errors.New("there is already a rule like this"))
168+
fs.EXPECT().NewCreateEgressFirewallRuleParams(dummies.ISONet1.ID, gomock.Any()).
169+
DoAndReturn(func(networkid string, protocol string) *csapi.CreateEgressFirewallRuleParams {
170+
p := &csapi.CreateEgressFirewallRuleParams{}
171+
if protocol == "icmp" {
172+
p.SetIcmptype(-1)
173+
p.SetIcmpcode(-1)
174+
}
175+
return p
176+
}).Times(3)
177+
178+
ruleParamsICMP := &csapi.CreateEgressFirewallRuleParams{}
179+
ruleParamsICMP.SetIcmptype(-1)
180+
ruleParamsICMP.SetIcmpcode(-1)
181+
gomock.InOrder(
182+
fs.EXPECT().CreateEgressFirewallRule(&csapi.CreateEgressFirewallRuleParams{}).
183+
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil).Times(2),
184+
fs.EXPECT().CreateEgressFirewallRule(ruleParamsICMP).
185+
Return(&csapi.CreateEgressFirewallRuleResponse{}, nil))
144186

145187
Ω(client.OpenFirewallRules(dummies.CSISONet1)).Should(Succeed())
146188
})

pkg/cloud/network.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const (
3333
NetworkTypeIsolated = "Isolated"
3434
NetworkTypeShared = "Shared"
3535
NetworkProtocolTCP = "tcp"
36+
NetworkProtocolUDP = "udp"
37+
NetworkProtocolICMP = "icmp"
3638
)
3739

3840
// NetworkExists checks that the network already exists based on the presence of all fields.

0 commit comments

Comments
 (0)