-
Notifications
You must be signed in to change notification settings - Fork 145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle firewall rule creation for load balancers #70
Conversation
Hey @ghubcoder apologies for the delay, I've been getting ramped up on the controller code. Taking a look now. |
do/loadbalancers.go
Outdated
var ruleExists bool | ||
var rulesToAdd []firewallRequest | ||
var alreadyAdded bool | ||
//var completedFirewalls []string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused variable
do/loadbalancers.go
Outdated
// the load balancer. | ||
// | ||
// EnsureFirewall will not modify service or nodes. | ||
func (l *loadbalancers) EnsureFirewall(lb *godo.LoadBalancer) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name isn't really describing what this function does. It's ensuring that the firewall rules allow a load balancer. Not that a firewall exists.
do/loadbalancers.go
Outdated
var alreadyAdded bool | ||
//var completedFirewalls []string | ||
|
||
for _, dropletid := range lb.DropletIDs { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Variable should be dropletID
do/loadbalancers.go
Outdated
return fmt.Errorf("Error listing firewalls for droplet %d", dropletid) | ||
} | ||
|
||
if len(firewalls) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if len(firewalls) == 0 { continue }
would reduce nesting.
do/loadbalancers.go
Outdated
@@ -179,6 +184,126 @@ func (l *loadbalancers) EnsureLoadBalancer(clusterName string, service *v1.Servi | |||
|
|||
} | |||
|
|||
func checkIfPortInRange(port int, fwPortRange string) bool { | |||
|
|||
fwPortList := strings.Split(fwPortRange, "-") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Create one function that convert the port range into two integers and use the two integers as arguments for these helper functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had a look at this, the only issue is that the first value can sometimes be a string containing "all", rather than just two integers. Need to think about how to clean this up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kind : Service
apiVersion : v1
metadata :
name : bonjour
annotations :
service.beta.kubernetes.io/do-loadbalancer-certificate-id : " 1234-5678-9012-3456 "
service.beta.kubernetes.io/do-loadbalancer- protocole : " https "
# Décommentez une fois que hello.example.com pointe vers l'adresse IP externe de l'équilibreur de charge DO.
# service.beta.kubernetes.io/do-loadbalancer-hostname: "hello.example.com"
spec :
type : LoadBalancer
sélecteur :
app : hello
ports :
- Nom : https
protocole : TCP
Port : 443
targetPort : 80
apiVersion : apps / v1
kind : Métadonnées de déploiement
:
nom : bonjour spec :
répliques : 3 sélecteur :
matchLabels :
app : bonjour modèle :
metadata :
labels :
app : bonjour spec :
conteneurs :
- nom : bonjour
image : ports snormore / bonjour
:
- protocole containerPort : 80
: TCP
do/loadbalancers.go
Outdated
_, err = l.client.LoadBalancers.Delete(ctx, lb.ID) | ||
return err | ||
} | ||
|
||
func (l *loadbalancers) EnsureFirewallDeleted(lb *godo.LoadBalancer) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Function name is misleading. Perhaps FirewallRuleDeleted
.
do/loadbalancers.go
Outdated
//check each firewall to see if rule already exists | ||
for _, firewall := range firewalls { | ||
for _, fwInboundRule := range firewall.InboundRules { | ||
for _, fwSourcelbs := range fwInboundRule.Sources.LoadBalancerUIDs { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic can be broken up into functions. Checking if the rule exists, deleting the rule, creating the rule.
do/loadbalancers.go
Outdated
return fmt.Errorf("Error listing firewalls for droplet %d", dropletid) | ||
} | ||
|
||
if len(firewalls) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similar comments to the ones noted above.
It would make things cleaner if they were moved to a firewall.go file. |
Thanks for the submission. I'm excited to use this. |
@cagedmantis thanks for this, I'll take a look at making the changes. |
do/firewalls.go
Outdated
|
||
// Check if a single port rule exists for a load balancer | ||
// forwarding rule ( will not remove ranges defined by ports or ALL ) | ||
func lbfwRuleRequiresDeletion(lbID string, lbRule godo.ForwardingRule, firewalls []godo.Firewall) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is pretty much the same as lbfwRuleExists, only difference is it makes a call to checkIfPortRequiresDeletion, rather than checkIfPortInRange. These are slightly different as we only delete a port if it's not included in a range of ports. Whereas we only add a port if it's not contained within a list of ranges.
These two functions (lbfwRuleExists, lbfwRuleRequiresDeletion) could be replaced by one function, and the checking function required could be passed in as a parameter. Although I'm not sure if that is good practice.
I've tested it once more, seems to work ok after the changes. Need to think about adding some tests now for the firewalls.go code. |
I wonder what the status of this PR is? @ghubcoder, seems like you added the remaining tests, is that correct? |
For what it is worth, I have merged this PR locally and am running it on a K8S cluster. It seems to work. Creating a Service creates a LB and updates the Firewalls for the relevant droplets. Upon deletion of the service the LB is deleted and the Firewall rules are removed too. Not sure if there is anything else left to do here to get this over the line. |
@pritpal-sabharwal thanks for giving this a try, very much appreciated ! |
I'm going to close this PR. Apart from the question of whether there's still interest, we have pending PR #332 to take a different approach to opening up and closing down ports dynamically through a dedicated, managed firewall. While the PR targets NodePorts, theoretically it can be extended for LB ports as well. |
This adds the ability for digitalocean-cloud-controller-manager to inspect the droplets which are part of a newly created load balancer and check whether they have an attached firewall.
If a firewall is present, it then checks to see if a firewall rule is required to allow the load balancer to communicate with the droplet on the target port.
Upon deletion of the load balancer, the reverse happens and the firewall rules are removed.
I've tested this and it does appear to work. I think perhaps the firewall function mocks need pulling out into their own file and more tests need adding.
There also needs to be some cleanup of the error handling/logging messages. Would be good to see if this works for anyone else.