@@ -2,12 +2,15 @@ package linode
22
33import (
44 "context"
5- "encoding/base64"
65 "encoding/json"
76 "fmt"
87 "strconv"
98 "strings"
109
10+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11+ "k8s.io/client-go/kubernetes"
12+ "k8s.io/client-go/rest"
13+
1114 "github.com/linode/linodego"
1215 "github.com/pkg/errors"
1316 v1 "k8s.io/api/core/v1"
@@ -20,25 +23,15 @@ const (
2023 // is overwritten to https. Options are tcp, http and https. Defaults to tcp.
2124 annLinodeProtocol = "service.beta.kubernetes.io/linode-loadbalancer-protocol"
2225
23- // annLinodeTLSPorts is the annotation used to specify which ports of the loadbalancer
24- // should use the https protocol. This is a comma separated list of ports
25- // (e.g. 443,6443,7443).
26- annLinodeTLSPorts = "service.beta.kubernetes.io/linode-loadbalancer-tls-ports"
27-
2826 annLinodeCheckPath = "service.beta.kubernetes.io/linode-loadbalancer-check-path"
2927 annLinodeCheckBody = "service.beta.kubernetes.io/linode-loadbalancer-check-body"
3028 annLinodeHealthCheckType = "service.beta.kubernetes.io/linode-loadbalancer-check-type"
3129
32- // annLinodeCertificateID is the annotation specifying the certificate ID
33- // used for https protocol. This annotation is required if annLinodeTLSPorts
34- // is passed.
35- annLinodeSSLCertificate = "service.beta.kubernetes.io/linode-loadbalancer-ssl-cert"
36- annLinodeSSLKey = "service.beta.kubernetes.io/linode-loadbalancer-ssl-key"
37-
3830 annLinodeHealthCheckInterval = "service.beta.kubernetes.io/linode-loadbalancer-check-interval"
3931 annLinodeHealthCheckTimeout = "service.beta.kubernetes.io/linode-loadbalancer-check-timeout"
4032 annLinodeHealthCheckAttempts = "service.beta.kubernetes.io/linode-loadbalancer-check-attempts"
4133 annLinodeHealthCheckPassive = "service.beta.kubernetes.io/linode-loadbalancer-check-passive"
34+ annLinodeLoadBalancerTLS = "service.beta.kubernetes.io/linode-loadbalancer-tls"
4235
4336 annLinodeSessionPersistence = "service.beta.kubernetes.io/linode-loadbalancer-stickiness"
4437
@@ -58,6 +51,13 @@ var lbNotFound = errors.New("loadbalancer not found")
5851type loadbalancers struct {
5952 client * linodego.Client
6053 zone string
54+
55+ kubeClient kubernetes.Interface
56+ }
57+
58+ type tlsAnnotation struct {
59+ TlsSecretName string `json:"tls-secret-name"`
60+ Port int `json:"port"`
6161}
6262
6363// newLoadbalancers returns a cloudprovider.LoadBalancer whose concrete type is a *loadbalancer.
@@ -346,27 +346,34 @@ func (l *loadbalancers) buildNodeBalancerConfig(service *v1.Service, port int) (
346346 config .CheckPassive = checkPassive
347347
348348 if protocol == linodego .ProtocolHTTPS {
349- isTLS , err := isTLSPort (service , port )
350- if err != nil {
349+ if err = l .processHTTPS (service , & config , port ); err != nil {
351350 return config , err
352351 }
353- if isTLS {
354- cert , key := getSSLCertInfo (service )
355- if cert == "" && key == "" {
356- return config , fmt .Errorf ("must set %v and %v annotation for https protocol" , annLinodeSSLCertificate , annLinodeSSLKey )
357- }
358- if cert != "" {
359- config .SSLCert = cert
360- }
361- if key != "" {
362- config .SSLKey = key
363- }
364- }
365352 }
366353
367354 return config , nil
368355}
369356
357+ func (l * loadbalancers ) processHTTPS (service * v1.Service , nbConfig * linodego.NodeBalancerConfig , port int ) error {
358+ if err := l .retrieveKubeClient (); err != nil {
359+ return err
360+ }
361+ tlsAnnotations , err := getTLSAnnotations (service )
362+ if err != nil {
363+ return err
364+ }
365+
366+ tlsPorts := getTLSPorts (tlsAnnotations )
367+ isTLS := isTLSPort (tlsPorts , port )
368+ if isTLS {
369+ nbConfig .SSLCert , nbConfig .SSLKey , err = getTLSCertInfo (l .kubeClient , tlsAnnotations , service .Namespace , port )
370+ if err != nil {
371+ return err
372+ }
373+ }
374+ return nil
375+ }
376+
370377// buildLoadBalancerRequest returns a linodego.NodeBalancer
371378// requests for service across nodes.
372379func (l * loadbalancers ) buildLoadBalancerRequest (ctx context.Context , service * v1.Service , nodes []* v1.Node ) (* linodego.NodeBalancer , error ) {
@@ -402,6 +409,22 @@ func (l *loadbalancers) buildNodeBalancerNodeCreateOptions(node *v1.Node, nodePo
402409 }
403410}
404411
412+ func (l * loadbalancers ) retrieveKubeClient () error {
413+ if l .kubeClient == nil {
414+ kubeConfig , err := rest .InClusterConfig ()
415+ if err != nil {
416+ return err
417+ }
418+
419+ l .kubeClient , err = kubernetes .NewForConfig (kubeConfig )
420+ if err != nil {
421+ return err
422+ }
423+ }
424+
425+ return nil
426+ }
427+
405428// getProtocol returns the desired protocol of service.
406429func getProtocol (service * v1.Service ) (linodego.ConfigProtocol , error ) {
407430 protocol , ok := service .Annotations [annLinodeProtocol ]
@@ -427,39 +450,36 @@ func getHealthCheckType(service *v1.Service) (linodego.ConfigCheck, error) {
427450 return linodego .ConfigCheck (hType ), nil
428451}
429452
430- func isTLSPort (service * v1.Service , port int ) (bool , error ) {
431- tlsPortsSlice , err := getTLSPorts (service )
432- if err != nil {
433- return false , err
434- }
453+ func isTLSPort (tlsPortsSlice []int , port int ) bool {
435454 for _ , tlsPort := range tlsPortsSlice {
436455 if port == tlsPort {
437- return true , nil
456+ return true
438457 }
439458 }
440- return false , nil
459+ return false
441460}
442461
443462// getTLSPorts returns the ports of service that are set to use TLS.
444- func getTLSPorts (service * v1. Service ) ( []int , error ) {
445- tlsPorts , ok := service . Annotations [ annLinodeTLSPorts ]
446- if ! ok {
447- return nil , nil
463+ func getTLSPorts (tlsAnnotations [] * tlsAnnotation ) []int {
464+ tlsPortsInt := make ([] int , 0 )
465+ for _ , tlsAnnotation := range tlsAnnotations {
466+ tlsPortsInt = append ( tlsPortsInt , tlsAnnotation . Port )
448467 }
449468
450- tlsPortsSlice := strings .Split (tlsPorts , "," )
451-
452- tlsPortsInt := make ([]int , len (tlsPortsSlice ))
453- for i , tlsPort := range tlsPortsSlice {
454- port , err := strconv .Atoi (tlsPort )
455- if err != nil {
456- return nil , err
457- }
469+ return tlsPortsInt
470+ }
458471
459- tlsPortsInt [i ] = port
472+ func getTLSAnnotations (service * v1.Service ) ([]* tlsAnnotation , error ) {
473+ annotationJSON , ok := service .Annotations [annLinodeLoadBalancerTLS ]
474+ if ! ok {
475+ return nil , fmt .Errorf ("annotation %v must be specified" , annLinodeLoadBalancerTLS )
460476 }
461-
462- return tlsPortsInt , nil
477+ tlsAnnotations := make ([]* tlsAnnotation , 0 )
478+ err := json .Unmarshal ([]byte (annotationJSON ), & tlsAnnotations )
479+ if err != nil {
480+ return nil , err
481+ }
482+ return tlsAnnotations , nil
463483}
464484
465485func getNodeInternalIp (node * v1.Node ) string {
@@ -503,18 +523,26 @@ func getStickiness(service *v1.Service) linodego.ConfigStickiness {
503523 }
504524}
505525
506- func getSSLCertInfo (service * v1.Service ) (string , string ) {
507- cert := service .Annotations [annLinodeSSLCertificate ]
508- if cert != "" {
509- cb , _ := base64 .StdEncoding .DecodeString (cert )
510- cert = strings .TrimSpace (string (cb ))
511- }
512- key := service .Annotations [annLinodeSSLKey ]
513- if key != "" {
514- kb , _ := base64 .StdEncoding .DecodeString (key )
515- key = strings .TrimSpace (string (kb ))
526+ func getTLSCertInfo (kubeClient kubernetes.Interface , tlsAnnotations []* tlsAnnotation , namespace string , port int ) (string , string , error ) {
527+ for _ , tlsAnnotation := range tlsAnnotations {
528+ if tlsAnnotation .Port == port {
529+ secret , err := kubeClient .CoreV1 ().Secrets (namespace ).Get (tlsAnnotation .TlsSecretName , metav1.GetOptions {})
530+ if err != nil {
531+ return "" , "" , err
532+ }
533+
534+ cert := string (secret .Data [v1 .TLSCertKey ])
535+ cert = strings .TrimSpace (cert )
536+
537+ key := string (secret .Data [v1 .TLSPrivateKeyKey ])
538+
539+ key = strings .TrimSpace (key )
540+
541+ return cert , key , nil
542+ }
516543 }
517- return cert , key
544+
545+ return "" , "" , fmt .Errorf ("cert & key for port %v is not specified in annotation %v" , port , annLinodeLoadBalancerTLS )
518546}
519547
520548func getConnectionThrottle (service * v1.Service ) int {
0 commit comments