Skip to content
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

Closed
wants to merge 9 commits into from

Conversation

ghubcoder
Copy link

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.

@ghubcoder ghubcoder changed the title Handle firelwall rule creation for load balancers Handle firewall rule creation for load balancers Apr 1, 2018
@cagedmantis
Copy link
Contributor

Hey @ghubcoder apologies for the delay, I've been getting ramped up on the controller code. Taking a look now.

var ruleExists bool
var rulesToAdd []firewallRequest
var alreadyAdded bool
//var completedFirewalls []string
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove unused variable

// the load balancer.
//
// EnsureFirewall will not modify service or nodes.
func (l *loadbalancers) EnsureFirewall(lb *godo.LoadBalancer) error {
Copy link
Contributor

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.

var alreadyAdded bool
//var completedFirewalls []string

for _, dropletid := range lb.DropletIDs {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable should be dropletID

return fmt.Errorf("Error listing firewalls for droplet %d", dropletid)
}

if len(firewalls) > 0 {
Copy link
Contributor

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.

@@ -179,6 +184,126 @@ func (l *loadbalancers) EnsureLoadBalancer(clusterName string, service *v1.Servi

}

func checkIfPortInRange(port int, fwPortRange string) bool {

fwPortList := strings.Split(fwPortRange, "-")
Copy link
Contributor

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.

Copy link
Author

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.

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

_, err = l.client.LoadBalancers.Delete(ctx, lb.ID)
return err
}

func (l *loadbalancers) EnsureFirewallDeleted(lb *godo.LoadBalancer) error {
Copy link
Contributor

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.

//check each firewall to see if rule already exists
for _, firewall := range firewalls {
for _, fwInboundRule := range firewall.InboundRules {
for _, fwSourcelbs := range fwInboundRule.Sources.LoadBalancerUIDs {
Copy link
Contributor

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.

return fmt.Errorf("Error listing firewalls for droplet %d", dropletid)
}

if len(firewalls) > 0 {
Copy link
Contributor

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.

@cagedmantis
Copy link
Contributor

It would make things cleaner if they were moved to a firewall.go file.

@cagedmantis
Copy link
Contributor

Thanks for the submission. I'm excited to use this.

@ghubcoder
Copy link
Author

@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 {
Copy link
Author

@ghubcoder ghubcoder Apr 19, 2018

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.

@ghubcoder
Copy link
Author

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.

@timoreimann
Copy link
Collaborator

I wonder what the status of this PR is? @ghubcoder, seems like you added the remaining tests, is that correct?

@pritpal-sabharwal
Copy link

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.

@ghubcoder
Copy link
Author

@pritpal-sabharwal thanks for giving this a try, very much appreciated !

@timoreimann
Copy link
Collaborator

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants