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

feat(lb): add ssl bridging annotations #164

Merged
merged 2 commits into from
Aug 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/loadbalancer-annotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@ This is the annotation to set the forward protocol of the LB to HTTP.
The possible values are `false`, `true` or `*` for all ports or a comma delimited list of the service port (for instance `80,443`).
NB: forwarding HTTPS traffic with HTTP protocol enabled will work only if using a certificate, and the LB will send HTTP traffic to the backend.

### `service.beta.kubernetes.io/scw-loadbalancer-http-backend-tls`
This is the annotation to enable tls towards the backend when using http forward protocol
The possible values are `false`, `true` or `*` for all ports or a comma delimited list of the service port (for instance `80,443`)

### `service.beta.kubernetes.io/scw-loadbalancer-http-backend-tls-skip-verify`
This is the annotation to skip tls verification on backends when using http forward protocol with TLS enabled
The possible values are `false`, `true` or `*` for all ports or a comma delimited list of the service port (for instance `80,443`)

### `service.beta.kubernetes.io/scw-loadbalancer-certificate-ids`
This is the annotation to choose the the certificate IDs to associate with this LoadBalancer.
The possible format are:
Expand Down
43 changes: 36 additions & 7 deletions scaleway/loadbalancers.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,6 +978,16 @@ func servicePortToBackend(service *v1.Service, loadbalancer *scwlb.LB, port v1.S
return nil, err
}

sslBridging, err := getSSLBridging(service, port.NodePort)
if err != nil {
return nil, err
}

sslSkipVerify, err := getSSLBridgingSkipVerify(service, port.NodePort)
if err != nil {
return nil, err
}

forwardPortAlgorithm, err := getForwardPortAlgorithm(service)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1107,8 +1117,10 @@ func servicePortToBackend(service *v1.Service, loadbalancer *scwlb.LB, port v1.S
backend := &scwlb.Backend{
Name: fmt.Sprintf("%s_tcp_%d", string(service.UID), port.NodePort),
Pool: nodeIPs,
ForwardPort: port.NodePort,
ForwardProtocol: protocol,
SslBridging: sslBridging,
IgnoreSslServerVerify: sslSkipVerify,
ForwardPort: port.NodePort,
ForwardPortAlgorithm: forwardPortAlgorithm,
StickySessions: stickySessions,
ProxyProtocol: proxyProtocol,
Expand Down Expand Up @@ -1196,14 +1208,22 @@ func backendEquals(got, want *scwlb.Backend) bool {
klog.V(3).Infof("backend.Name: %s - %s", got.Name, want.Name)
return false
}
if got.ForwardPort != want.ForwardPort {
klog.V(3).Infof("backend.ForwardPort: %d - %d", got.ForwardPort, want.ForwardPort)
return false
}
if got.ForwardProtocol != want.ForwardProtocol {
klog.V(3).Infof("backend.ForwardProtocol: %s - %s", got.ForwardProtocol, want.ForwardProtocol)
return false
}
if !reflect.DeepEqual(got.SslBridging, want.SslBridging) {
klog.V(3).Infof("backend.SslBridging: %s - %s", ptrBoolToString(got.SslBridging), ptrBoolToString(want.SslBridging))
return false
}
if !reflect.DeepEqual(got.IgnoreSslServerVerify, want.IgnoreSslServerVerify) {
klog.V(3).Infof("backend.IgnoreSslServerVerify: %s - %s", ptrBoolToString(got.IgnoreSslServerVerify), ptrBoolToString(want.IgnoreSslServerVerify))
return false
}
if got.ForwardPort != want.ForwardPort {
klog.V(3).Infof("backend.ForwardPort: %d - %d", got.ForwardPort, want.ForwardPort)
return false
}
if got.ForwardPortAlgorithm != want.ForwardPortAlgorithm {
klog.V(3).Infof("backend.ForwardPortAlgorithm: %s - %s", got.ForwardPortAlgorithm, want.ForwardPortAlgorithm)
return false
Expand Down Expand Up @@ -1410,6 +1430,7 @@ func (l *loadbalancers) createBackend(service *v1.Service, loadbalancer *scwlb.L
LBID: loadbalancer.ID,
Name: backend.Name,
ForwardProtocol: backend.ForwardProtocol,
SslBridging: backend.SslBridging,
ForwardPort: backend.ForwardPort,
ForwardPortAlgorithm: backend.ForwardPortAlgorithm,
StickySessions: backend.StickySessions,
Expand Down Expand Up @@ -1438,6 +1459,7 @@ func (l *loadbalancers) updateBackend(service *v1.Service, loadbalancer *scwlb.L
BackendID: backend.ID,
Name: backend.Name,
ForwardProtocol: backend.ForwardProtocol,
SslBridging: backend.SslBridging,
ForwardPort: backend.ForwardPort,
ForwardPortAlgorithm: backend.ForwardPortAlgorithm,
StickySessions: backend.StickySessions,
Expand Down Expand Up @@ -1477,7 +1499,7 @@ func (l *loadbalancers) updateBackend(service *v1.Service, loadbalancer *scwlb.L
return b, nil
}

// createBackend creates a frontend on the load balancer
// createFrontend creates a frontend on the load balancer
func (l *loadbalancers) createFrontend(service *v1.Service, loadbalancer *scwlb.LB, frontend *scwlb.Frontend, backend *scwlb.Backend) (*scwlb.Frontend, error) {
f, err := l.api.CreateFrontend(&scwlb.ZonedAPICreateFrontendRequest{
Zone: loadbalancer.Zone,
Expand All @@ -1493,7 +1515,7 @@ func (l *loadbalancers) createFrontend(service *v1.Service, loadbalancer *scwlb.
return f, err
}

// updateBackend updates a frontend on the load balancer
// updateFrontend updates a frontend on the load balancer
func (l *loadbalancers) updateFrontend(service *v1.Service, loadbalancer *scwlb.LB, frontend *scwlb.Frontend, backend *scwlb.Backend) (*scwlb.Frontend, error) {
f, err := l.api.UpdateFrontend(&scwlb.ZonedAPIUpdateFrontendRequest{
Zone: loadbalancer.Zone,
Expand Down Expand Up @@ -1638,3 +1660,10 @@ func ptrInt32ToString(i *int32) string {
}
return fmt.Sprintf("%d", *i)
}

func ptrBoolToString(b *bool) string {
if b == nil {
return "<nil>"
}
return fmt.Sprintf("%t", *b)
}
62 changes: 62 additions & 0 deletions scaleway/loadbalancers_annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,16 @@ const (
// (for instance "80,443")
serviceAnnotationLoadBalancerProtocolHTTP = "service.beta.kubernetes.io/scw-loadbalancer-protocol-http"

// serviceAnnotationLoadBalancerHTTPBackendTLS is the annotation to enable tls towards the backend when using http forward protocol
// The possible values are "false", "true" or "*" for all ports or a comma delimited list of the service port
// (for instance "80,443")
serviceAnnotationLoadBalancerHTTPBackendTLS = "service.beta.kubernetes.io/scw-loadbalancer-http-backend-tls"

// serviceAnnotationLoadBalancerHTTPBackendTLSSkipVerify is the annotation to skip tls verification on backends when using http forward protocol with TLS enabled
// The possible values are "false", "true" or "*" for all ports or a comma delimited list of the service port
// (for instance "80,443")
serviceAnnotationLoadBalancerHTTPBackendTLSSkipVerify = "service.beta.kubernetes.io/scw-loadbalancer-http-backend-tls-skip-verify"

// serviceAnnotationLoadBalancerCertificateIDs is the annotation to choose the certificate IDS to associate
// with this LoadBalancer.
// The possible format are:
Expand Down Expand Up @@ -543,6 +553,58 @@ func getForwardProtocol(service *v1.Service, nodePort int32) (scwlb.Protocol, er
return scwlb.ProtocolTCP, nil
}

func getSSLBridging(service *v1.Service, nodePort int32) (*bool, error) {
tlsEnabled, found := service.Annotations[serviceAnnotationLoadBalancerHTTPBackendTLS]
if !found {
return nil, nil
Copy link
Collaborator

Choose a reason for hiding this comment

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

just wondering, this return just does nothing ?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

same pattern as the other, if no annotation set, we return the default (unset)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but agreed that passing an empty string to isPortInRange would render the same result.
I'll keep the check as it's more explicit

}

var svcPort int32 = -1
for _, p := range service.Spec.Ports {
if p.NodePort == nodePort {
svcPort = p.Port
}
}
if svcPort == -1 {
klog.Errorf("no valid port found")
return nil, errLoadBalancerInvalidAnnotation
}

isTLSEnabled, err := isPortInRange(tlsEnabled, svcPort)
if err != nil {
klog.Errorf("unable to check if port %d is in range %s", svcPort, tlsEnabled)
return nil, err
}

return scw.BoolPtr(isTLSEnabled), nil
}

func getSSLBridgingSkipVerify(service *v1.Service, nodePort int32) (*bool, error) {
skipTLSVerify, found := service.Annotations[serviceAnnotationLoadBalancerHTTPBackendTLSSkipVerify]
if !found {
return nil, nil
}

var svcPort int32 = -1
for _, p := range service.Spec.Ports {
if p.NodePort == nodePort {
svcPort = p.Port
}
}
if svcPort == -1 {
klog.Errorf("no valid port found")
return nil, errLoadBalancerInvalidAnnotation
}

isSkipTLSVerify, err := isPortInRange(skipTLSVerify, svcPort)
if err != nil {
klog.Errorf("unable to check if port %d is in range %s", svcPort, skipTLSVerify)
return nil, err
}

return scw.BoolPtr(isSkipTLSVerify), nil
}

func getCertificateIDs(service *v1.Service, port int32) ([]string, error) {
certificates := service.Annotations[serviceAnnotationLoadBalancerCertificateIDs]
ids := []string{}
Expand Down
Loading