Skip to content

Commit 8732386

Browse files
Merge pull request #94 from barbacbd/CORS-4264-openshift-clone
CORS-4264: Update the GCP provider to allow users to manage their own firewall rules
2 parents e9159d6 + 7f2fae4 commit 8732386

File tree

8 files changed

+217
-32
lines changed

8 files changed

+217
-32
lines changed

cluster/gce/gci/configure-helper.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -958,6 +958,14 @@ EOF
958958
use_cloud_config="true"
959959
cat <<EOF >>/etc/gce.conf
960960
regional = ${MULTIMASTER}
961+
EOF
962+
fi
963+
# FirewallRulesManagement indicates whethere the firewall rules are
964+
# managed (enabled) or not (disabled) for the provider.
965+
if [[ -n "${FIREWALLRULESMANAGEMENT:-}" ]]; then
966+
use_cloud_config="true"
967+
cat <<EOF >>/etc/gce.conf
968+
firewall-rules-management = ${FIREWALLRULESMANAGEMENT}
961969
EOF
962970
fi
963971
if [[ -n "${GCE_ALPHA_FEATURES:-}" ]]; then

cluster/gce/util.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,7 @@ KUBE_DOCKER_REGISTRY: $(yaml-quote "${KUBE_DOCKER_REGISTRY:-}")
11901190
KUBE_ADDON_REGISTRY: $(yaml-quote "${KUBE_ADDON_REGISTRY:-}")
11911191
MULTIZONE: $(yaml-quote "${MULTIZONE:-}")
11921192
MULTIMASTER: $(yaml-quote "${MULTIMASTER:-}")
1193+
FIREWALLRULESMANAGEMENT: $(yaml-quote "${FIREWALLRULESMANAGEMENT:-}")
11931194
NON_MASQUERADE_CIDR: $(yaml-quote "${NON_MASQUERADE_CIDR:-}")
11941195
ENABLE_DEFAULT_STORAGE_CLASS: $(yaml-quote "${ENABLE_DEFAULT_STORAGE_CLASS:-}")
11951196
# (TODO/cloud-provider-gcp): Need to figure out how to inject this

providers/gce/gce.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,17 @@ const clusterStackIPV4 StackType = "IPV4"
116116
// The underlying VPC's stack type could be either IPV6 or dual stack IPV4_IPV6.
117117
const clusterStackIPV6 StackType = "IPV6"
118118

119+
// FirewallRulesManagement indicates how firewall rules are managed by the provider.
120+
type FirewallRulesManagement string
121+
122+
// firewallRulesManagementEnabled indicates that the firewall rules should be managed by the provider.
123+
// This includes firewall rule creation, deletion, and updates.
124+
const firewallRulesManagementEnabled FirewallRulesManagement = "Enabled"
125+
126+
// firewallRulesManagementDisabled indicates that the firewall rules should not be managed by the provider.
127+
// This includes firewall rule creation, deletion, and updates.
128+
const firewallRulesManagementDisabled FirewallRulesManagement = "Disabled"
129+
119130
// Cloud is an implementation of Interface, LoadBalancer and Instances for Google Compute Engine.
120131
type Cloud struct {
121132
// ClusterID contains functionality for getting (and initializing) the ingress-uid. Call Cloud.Initialize()
@@ -213,6 +224,8 @@ type Cloud struct {
213224

214225
// enableRBSDefaultForL4NetLB disable Service controller from picking up services by default
215226
enableRBSDefaultForL4NetLB bool
227+
228+
firewallRulesManagement FirewallRulesManagement
216229
}
217230

218231
// ConfigGlobal is the in memory representation of the gce.conf config data
@@ -254,6 +267,10 @@ type ConfigGlobal struct {
254267
// ExternalInstanceGroupsPrefix, when not-empty, is used to filter instance groups (from an external GCP Project)
255268
// and include them in the backend for ILB.
256269
ExternalInstanceGroupsPrefix string `gcfg:"external-instance-groups-prefix"`
270+
271+
// FirewallRulesManagement indicates whether the provider should handle all firewall
272+
// operations, such as creation, deletion, and updates.
273+
FirewallRulesManagement string `gcfg:"firewall-rules-management"`
257274
}
258275

259276
// ConfigFile is the struct used to parse the /etc/gce.conf configuration file.
@@ -289,6 +306,7 @@ type CloudConfig struct {
289306
AlphaFeatureGate *AlphaFeatureGate
290307
StackType string
291308
ExternalInstanceGroupsPrefix string
309+
FirewallRulesManagement string
292310
}
293311

294312
func init() {
@@ -380,6 +398,7 @@ func generateCloudConfig(configFile *ConfigFile) (cloudConfig *CloudConfig, err
380398
cloudConfig.NodeInstancePrefix = configFile.Global.NodeInstancePrefix
381399
cloudConfig.AlphaFeatureGate = NewAlphaFeatureGate(configFile.Global.AlphaFeatures)
382400
cloudConfig.ExternalInstanceGroupsPrefix = configFile.Global.ExternalInstanceGroupsPrefix
401+
cloudConfig.FirewallRulesManagement = configFile.Global.FirewallRulesManagement
383402
}
384403

385404
// retrieve projectID and zone
@@ -584,6 +603,7 @@ func CreateGCECloud(config *CloudConfig) (*Cloud, error) {
584603
projectsBasePath: getProjectsBasePath(service.BasePath),
585604
stackType: StackType(config.StackType),
586605
externalInstanceGroupsPrefix: config.ExternalInstanceGroupsPrefix,
606+
firewallRulesManagement: FirewallRulesManagement(config.FirewallRulesManagement),
587607
}
588608

589609
gce.manager = &gceServiceManager{gce}

providers/gce/gce_fake.go

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,32 @@ import (
3030

3131
// TestClusterValues holds the config values for the fake/test gce cloud object.
3232
type TestClusterValues struct {
33-
ProjectID string
34-
Region string
35-
ZoneName string
36-
SecondaryZoneName string
37-
ClusterID string
38-
ClusterName string
39-
OnXPN bool
40-
Regional bool
41-
NetworkURL string
42-
SubnetworkURL string
43-
StackType StackType
33+
ProjectID string
34+
Region string
35+
ZoneName string
36+
SecondaryZoneName string
37+
ClusterID string
38+
ClusterName string
39+
OnXPN bool
40+
Regional bool
41+
NetworkURL string
42+
SubnetworkURL string
43+
StackType StackType
44+
FirewallRulesManagement FirewallRulesManagement
4445
}
4546

4647
// DefaultTestClusterValues Creates a reasonable set of default cluster values
4748
// for generating a new test fake GCE cloud instance.
4849
func DefaultTestClusterValues() TestClusterValues {
4950
return TestClusterValues{
50-
ProjectID: "test-project",
51-
Region: "us-central1",
52-
ZoneName: "us-central1-b",
53-
SecondaryZoneName: "us-central1-c",
54-
ClusterID: "test-cluster-id",
55-
ClusterName: "Test-Cluster-Name",
56-
StackType: clusterStackIPV4,
51+
ProjectID: "test-project",
52+
Region: "us-central1",
53+
ZoneName: "us-central1-b",
54+
SecondaryZoneName: "us-central1-c",
55+
ClusterID: "test-cluster-id",
56+
ClusterName: "Test-Cluster-Name",
57+
StackType: clusterStackIPV4,
58+
FirewallRulesManagement: firewallRulesManagementEnabled,
5759
}
5860
}
5961

@@ -75,20 +77,21 @@ func NewFakeGCECloud(vals TestClusterValues) *Cloud {
7577
panic(err)
7678
}
7779
gce := &Cloud{
78-
region: vals.Region,
79-
service: service,
80-
managedZones: []string{vals.ZoneName, vals.SecondaryZoneName},
81-
localZone: vals.ZoneName,
82-
projectID: vals.ProjectID,
83-
networkProjectID: vals.ProjectID,
84-
ClusterID: fakeClusterID(vals.ClusterID),
85-
onXPN: vals.OnXPN,
86-
metricsCollector: newLoadBalancerMetrics(),
87-
projectsBasePath: getProjectsBasePath(service.BasePath),
88-
regional: vals.Regional,
89-
networkURL: vals.NetworkURL,
90-
unsafeSubnetworkURL: vals.SubnetworkURL,
91-
stackType: vals.StackType,
80+
region: vals.Region,
81+
service: service,
82+
managedZones: []string{vals.ZoneName, vals.SecondaryZoneName},
83+
localZone: vals.ZoneName,
84+
projectID: vals.ProjectID,
85+
networkProjectID: vals.ProjectID,
86+
ClusterID: fakeClusterID(vals.ClusterID),
87+
onXPN: vals.OnXPN,
88+
metricsCollector: newLoadBalancerMetrics(),
89+
projectsBasePath: getProjectsBasePath(service.BasePath),
90+
regional: vals.Regional,
91+
networkURL: vals.NetworkURL,
92+
unsafeSubnetworkURL: vals.SubnetworkURL,
93+
stackType: vals.StackType,
94+
firewallRulesManagement: vals.FirewallRulesManagement,
9295
}
9396
c := cloud.NewMockGCE(&gceProjectRouter{gce})
9497
gce.c = c

providers/gce/gce_firewall.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ func newFirewallMetricContext(request string) *metricContext {
3232

3333
// GetFirewall returns the Firewall by name.
3434
func (g *Cloud) GetFirewall(name string) (*compute.Firewall, error) {
35+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
36+
return nil, nil
37+
}
38+
3539
ctx, cancel := cloud.ContextWithCallTimeout()
3640
defer cancel()
3741

@@ -42,6 +46,10 @@ func (g *Cloud) GetFirewall(name string) (*compute.Firewall, error) {
4246

4347
// CreateFirewall creates the passed firewall
4448
func (g *Cloud) CreateFirewall(f *compute.Firewall) error {
49+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
50+
return nil
51+
}
52+
4553
ctx, cancel := cloud.ContextWithCallTimeout()
4654
defer cancel()
4755

@@ -51,6 +59,10 @@ func (g *Cloud) CreateFirewall(f *compute.Firewall) error {
5159

5260
// DeleteFirewall deletes the given firewall rule.
5361
func (g *Cloud) DeleteFirewall(name string) error {
62+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
63+
return nil
64+
}
65+
5466
ctx, cancel := cloud.ContextWithCallTimeout()
5567
defer cancel()
5668

@@ -60,6 +72,10 @@ func (g *Cloud) DeleteFirewall(name string) error {
6072

6173
// UpdateFirewall applies the given firewall as an update to an existing service.
6274
func (g *Cloud) UpdateFirewall(f *compute.Firewall) error {
75+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
76+
return nil
77+
}
78+
6379
ctx, cancel := cloud.ContextWithCallTimeout()
6480
defer cancel()
6581

@@ -69,6 +85,10 @@ func (g *Cloud) UpdateFirewall(f *compute.Firewall) error {
6985

7086
// PatchFirewall applies the given firewall as an update to an existing service.
7187
func (g *Cloud) PatchFirewall(f *compute.Firewall) error {
88+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
89+
return nil
90+
}
91+
7292
ctx, cancel := cloud.ContextWithCallTimeout()
7393
defer cancel()
7494

providers/gce/gce_loadbalancer_external.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,11 @@ func translateAffinityType(affinityType v1.ServiceAffinity) string {
964964
}
965965

966966
func (g *Cloud) firewallNeedsUpdate(name, serviceName, ipAddress string, ports []v1.ServicePort, sourceRanges utilnet.IPNetSet) (exists bool, needsUpdate bool, err error) {
967+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
968+
klog.V(2).Infof("firewallNeedsUpdate(%v): firewall rules are unmanaged", name)
969+
return false, false, nil
970+
}
971+
967972
fw, err := g.GetFirewall(MakeFirewallName(name))
968973
if err != nil {
969974
if isHTTPErrorCode(err, http.StatusNotFound) {
@@ -1009,6 +1014,11 @@ func (g *Cloud) firewallNeedsUpdate(name, serviceName, ipAddress string, ports [
10091014
}
10101015

10111016
func (g *Cloud) ensureHTTPHealthCheckFirewall(svc *v1.Service, serviceName, ipAddress, region, clusterID string, hosts []*gceInstance, hcName string, hcPort int32, isNodesHealthCheck bool) error {
1017+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
1018+
klog.V(2).Infof("ensureHTTPHealthCheckFirewall(%v): firewall rules are unmanaged", hcName)
1019+
return nil
1020+
}
1021+
10121022
// Prepare the firewall params for creating / checking.
10131023
desc := fmt.Sprintf(`{"kubernetes.io/cluster-id":"%s"}`, clusterID)
10141024
if !isNodesHealthCheck {
@@ -1087,6 +1097,17 @@ func (g *Cloud) createFirewall(svc *v1.Service, name, desc, destinationIP string
10871097
if err != nil {
10881098
return err
10891099
}
1100+
1101+
if g.firewallRulesManagement == firewallRulesManagementDisabled {
1102+
klog.V(2).Infof("createFirewall(%v): firewall rules are unmanaged", name)
1103+
project := g.NetworkProjectID()
1104+
if project == "" {
1105+
project = g.ProjectID()
1106+
}
1107+
g.raiseFirewallChangeNeededEvent(svc, FirewallToGCloudCreateCmd(firewall, project))
1108+
return nil
1109+
}
1110+
10901111
if err = g.CreateFirewall(firewall); err != nil {
10911112
if isHTTPErrorCode(err, http.StatusConflict) {
10921113
return nil

providers/gce/gce_loadbalancer_external_test.go

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1902,6 +1902,104 @@ func TestFirewallNeedsUpdate(t *testing.T) {
19021902
}
19031903
}
19041904

1905+
func TestDisabledFirewallOperations(t *testing.T) {
1906+
vals := DefaultTestClusterValues()
1907+
vals.FirewallRulesManagement = firewallRulesManagementDisabled
1908+
gce, err := fakeGCECloud(vals)
1909+
require.NoError(t, err)
1910+
1911+
fw, err := gce.GetFirewall(MakeFirewallName("test"))
1912+
assert.NoError(t, err)
1913+
assert.Nil(t, fw)
1914+
1915+
ipnet, err := utilnet.ParseIPNets("0.0.0.0/0")
1916+
require.NoError(t, err)
1917+
1918+
ports := []v1.ServicePort{
1919+
{Name: "port1", Protocol: v1.ProtocolTCP, Port: int32(80), TargetPort: intstr.FromInt(80)},
1920+
{Name: "port2", Protocol: v1.ProtocolTCP, Port: int32(81), TargetPort: intstr.FromInt(81)},
1921+
{Name: "port3", Protocol: v1.ProtocolTCP, Port: int32(82), TargetPort: intstr.FromInt(82)},
1922+
{Name: "port4", Protocol: v1.ProtocolTCP, Port: int32(84), TargetPort: intstr.FromInt(84)},
1923+
{Name: "port5", Protocol: v1.ProtocolTCP, Port: int32(85), TargetPort: intstr.FromInt(85)},
1924+
{Name: "port6", Protocol: v1.ProtocolTCP, Port: int32(86), TargetPort: intstr.FromInt(86)},
1925+
{Name: "port7", Protocol: v1.ProtocolTCP, Port: int32(88), TargetPort: intstr.FromInt(87)},
1926+
}
1927+
1928+
firewall, err := gce.firewallObject(MakeFirewallName("test"), "Test Description", "0.0.0.0/0", ipnet, ports, nil)
1929+
1930+
err = gce.CreateFirewall(firewall)
1931+
assert.NoError(t, err)
1932+
1933+
err = gce.UpdateFirewall(firewall)
1934+
assert.NoError(t, err)
1935+
1936+
err = gce.PatchFirewall(firewall)
1937+
assert.NoError(t, err)
1938+
1939+
err = gce.DeleteFirewall(MakeFirewallName("test"))
1940+
assert.NoError(t, err)
1941+
}
1942+
1943+
func TestDisabledFirewallNeedsUpdate(t *testing.T) {
1944+
t.Parallel()
1945+
1946+
vals := DefaultTestClusterValues()
1947+
vals.FirewallRulesManagement = firewallRulesManagementDisabled
1948+
gce, err := fakeGCECloud(vals)
1949+
require.NoError(t, err)
1950+
svc := fakeLoadbalancerService("")
1951+
1952+
svc, err = gce.client.CoreV1().Services(svc.Namespace).Create(context.TODO(), svc, metav1.CreateOptions{})
1953+
require.NoError(t, err)
1954+
1955+
svc.Spec.Ports = []v1.ServicePort{
1956+
{Name: "port1", Protocol: v1.ProtocolTCP, Port: int32(80), TargetPort: intstr.FromInt(80)},
1957+
{Name: "port2", Protocol: v1.ProtocolTCP, Port: int32(81), TargetPort: intstr.FromInt(81)},
1958+
{Name: "port3", Protocol: v1.ProtocolTCP, Port: int32(82), TargetPort: intstr.FromInt(82)},
1959+
{Name: "port4", Protocol: v1.ProtocolTCP, Port: int32(84), TargetPort: intstr.FromInt(84)},
1960+
{Name: "port5", Protocol: v1.ProtocolTCP, Port: int32(85), TargetPort: intstr.FromInt(85)},
1961+
{Name: "port6", Protocol: v1.ProtocolTCP, Port: int32(86), TargetPort: intstr.FromInt(86)},
1962+
{Name: "port7", Protocol: v1.ProtocolTCP, Port: int32(88), TargetPort: intstr.FromInt(87)},
1963+
}
1964+
1965+
status, err := createExternalLoadBalancer(gce, svc, []string{"test-node-1"}, vals.ClusterName, vals.ClusterID, vals.ZoneName)
1966+
require.NotNil(t, status)
1967+
require.NoError(t, err)
1968+
svcName := "/" + svc.ObjectMeta.Name
1969+
1970+
ipAddr := status.Ingress[0].IP
1971+
lbName := gce.GetLoadBalancerName(context.TODO(), "", svc)
1972+
1973+
ipnet, err := utilnet.ParseIPNets("0.0.0.0/0")
1974+
require.NoError(t, err)
1975+
1976+
fw, err := gce.GetFirewall(MakeFirewallName(lbName))
1977+
require.NoError(t, err)
1978+
1979+
for desc := range map[string]struct {
1980+
hasErr bool
1981+
}{
1982+
"need to update port-ranges ": {},
1983+
} {
1984+
t.Run(desc, func(t *testing.T) {
1985+
fw, err = gce.GetFirewall(MakeFirewallName(lbName))
1986+
assert.NoError(t, err)
1987+
assert.Nil(t, fw)
1988+
1989+
exists, needsUpdate, err := gce.firewallNeedsUpdate(
1990+
lbName,
1991+
svcName,
1992+
ipAddr,
1993+
svc.Spec.Ports,
1994+
ipnet)
1995+
1996+
assert.Equal(t, false, exists, "firewall should not exist")
1997+
assert.Equal(t, false, needsUpdate, "firewall should not exist, no update needed")
1998+
assert.NoError(t, err)
1999+
})
2000+
}
2001+
}
2002+
19052003
func TestDeleteWrongNetworkTieredResourcesSucceedsWhenNotFound(t *testing.T) {
19062004
t.Parallel()
19072005

0 commit comments

Comments
 (0)