@@ -50,6 +50,8 @@ const (
5050 lbApiPort = 8081
5151 lbAlgorithmKey = "serviceloadbalancer/lb.algorithm"
5252 lbHostKey = "serviceloadbalancer/lb.host"
53+ lbSslTerm = "serviceloadbalancer/lb.sslTerm"
54+ lbAclMatch = "serviceloadbalancer/lb.aclMatch"
5355 lbCookieStickySessionKey = "serviceloadbalancer/lb.cookie-sticky-session"
5456 defaultErrorPage = "file:///etc/haproxy/errors/404.http"
5557)
@@ -72,31 +74,31 @@ var (
7274 supportedAlgorithms = []string {"roundrobin" , "leastconn" , "first" , "source" }
7375
7476 config = flags .String ("cfg" , "loadbalancer.json" , `path to load balancer json config.
75- Note that this is *not* the path to the configuration file for the load balancer
76- itself, but rather, the path to the json configuration of how you would like the
77- load balancer to behave in the kubernetes cluster.` )
77+ Note that this is *not* the path to the configuration file for the load balancer
78+ itself, but rather, the path to the json configuration of how you would like the
79+ load balancer to behave in the kubernetes cluster.` )
7880
7981 dry = flags .Bool ("dry" , false , `if set, a single dry run of configuration
80- parsing is executed. Results written to stdout.` )
82+ parsing is executed. Results written to stdout.` )
8183
8284 cluster = flags .Bool ("use-kubernetes-cluster-service" , true , `If true, use the built in kubernetes
83- cluster for creating the client` )
85+ cluster for creating the client` )
8486
8587 // If you have pure tcp services or https services that need L3 routing, you
8688 // must specify them by name. Note that you are responsible for:
8789 // 1. Making sure there is no collision between the service ports of these services.
88- // - You can have multiple <mysql svc name>:3306 specifications in this map, and as
89- // long as the service ports of your mysql service don't clash, you'll get
90- // loadbalancing for each one.
90+ // - You can have multiple <mysql svc name>:3306 specifications in this map, and as
91+ // long as the service ports of your mysql service don't clash, you'll get
92+ // loadbalancing for each one.
9193 // 2. Exposing the service ports as node ports on a pod.
9294 // 3. Adding firewall rules so these ports can ingress traffic.
9395 //
9496 // Any service not specified in this map is treated as an http:80 service,
9597 // unless TargetService dictates otherwise.
9698
9799 tcpServices = flags .String ("tcp-services" , "" , `Comma separated list of tcp/https
98- serviceName:servicePort pairings. This assumes you've opened up the right
99- hostPorts for each service that serves ingress traffic.` )
100+ serviceName:servicePort pairings. This assumes you've opened up the right
101+ hostPorts for each service that serves ingress traffic.` )
100102
101103 targetService = flags .String (
102104 "target-service" , "" , `Restrict loadbalancing to a single target service.` )
@@ -115,21 +117,25 @@ var (
115117 // backend svc_p2: pod1:tp2, pod2:tp2
116118
117119 forwardServices = flags .Bool ("forward-services" , false , `Forward to service vip
118- instead of endpoints. This will use kube-proxy's inbuilt load balancing.` )
120+ instead of endpoints. This will use kube-proxy's inbuilt load balancing.` )
119121
120122 httpPort = flags .Int ("http-port" , 80 , `Port to expose http services.` )
121123 statsPort = flags .Int ("stats-port" , 1936 , `Port for loadbalancer stats,
122- Used in the loadbalancer liveness probe.` )
124+ Used in the loadbalancer liveness probe.` )
123125
124126 startSyslog = flags .Bool ("syslog" , false , `if set, it will start a syslog server
125- that will forward haproxy logs to stdout.` )
127+ that will forward haproxy logs to stdout.` )
128+
129+ sslCert = flags .String ("ssl-cert" , "" , `if set, it will load the certificate.` )
130+ sslCaCert = flags .String ("ssl-ca-cert" , "" , `if set, it will load the certificate from which
131+ to load CA certificates used to verify client's certificate.` )
126132
127133 errorPage = flags .String ("error-page" , "" , `if set, it will try to load the content
128- as a web page and use the content as error page. Is required that the URL returns
129- 200 as a status code` )
134+ as a web page and use the content as error page. Is required that the URL returns
135+ 200 as a status code` )
130136
131137 lbDefAlgorithm = flags .String ("balance-algorithm" , "roundrobin" , `if set, it allows a custom
132- default balance algorithm.` )
138+ default balance algorithm.` )
133139)
134140
135141// service encapsulates a single backend entry in the load balancer config.
@@ -152,6 +158,12 @@ type service struct {
152158 // host header inside the http request. It only applies to http traffic.
153159 Host string
154160
161+ // if true, terminate ssl using the loadbalancers certificates.
162+ SslTerm bool
163+
164+ // if set use this to match the path rule
165+ AclMatch string
166+
155167 // Algorithm
156168 Algorithm string
157169
@@ -193,6 +205,8 @@ type loadBalancerConfig struct {
193205 Template string `json:"template" description:"template for the load balancer config."`
194206 Algorithm string `json:"algorithm" description:"loadbalancing algorithm."`
195207 startSyslog bool `description:"indicates if the load balancer uses syslog."`
208+ sslCert string `json:"sslCert" description:"PEM for ssl."`
209+ sslCaCert string `json:"sslCaCert" description:"PEM to verify client's certificate."`
196210 lbDefAlgorithm string `description:"custom default load balancer algorithm".`
197211}
198212
@@ -219,6 +233,16 @@ func (s serviceAnnotations) getCookieStickySession() (string, bool) {
219233 return val , ok
220234}
221235
236+ func (s serviceAnnotations ) getSslTerm () (string , bool ) {
237+ val , ok := s [lbSslTerm ]
238+ return val , ok
239+ }
240+
241+ func (s serviceAnnotations ) getAclMatch () (string , bool ) {
242+ val , ok := s [lbAclMatch ]
243+ return val , ok
244+ }
245+
222246// Get serves the error page
223247func (s * staticPageHandler ) Getfunc (w http.ResponseWriter , r * http.Request ) {
224248 w .WriteHeader (404 )
@@ -277,6 +301,15 @@ func (cfg *loadBalancerConfig) write(services map[string][]service, dryRun bool)
277301 conf ["startSyslog" ] = strconv .FormatBool (cfg .startSyslog )
278302 conf ["services" ] = services
279303
304+ var sslConfig string
305+ if cfg .sslCert != "" {
306+ sslConfig = "crt " + cfg .sslCert
307+ }
308+ if cfg .sslCaCert != "" {
309+ sslConfig += " ca-file " + cfg .sslCaCert
310+ }
311+ conf ["sslCert" ] = sslConfig
312+
280313 // default load balancer algorithm is roundrobin
281314 conf ["defLbAlgorithm" ] = lbDefAlgorithm
282315 if cfg .lbDefAlgorithm != "" {
@@ -367,7 +400,7 @@ func getServiceNameForLBRule(s *api.Service, servicePort int) string {
367400}
368401
369402// getServices returns a list of services and their endpoints.
370- func (lbc * loadBalancerController ) getServices () (httpSvc []service , tcpSvc []service ) {
403+ func (lbc * loadBalancerController ) getServices () (httpSvc []service , httpsTermSvc [] service , tcpSvc []service ) {
371404 ep := []string {}
372405 services , _ := lbc .svcLister .List ()
373406 for _ , s := range services .Items {
@@ -422,6 +455,19 @@ func (lbc *loadBalancerController) getServices() (httpSvc []service, tcpSvc []se
422455 newSvc .SessionAffinity = true
423456 }
424457
458+ // By default sslTerm is disabled
459+ newSvc .SslTerm = false
460+ if val , ok := serviceAnnotations (s .ObjectMeta .Annotations ).getSslTerm (); ok {
461+ b , err := strconv .ParseBool (val )
462+ if err == nil {
463+ newSvc .SslTerm = b
464+ }
465+ }
466+
467+ if val , ok := serviceAnnotations (s .ObjectMeta .Annotations ).getAclMatch (); ok {
468+ newSvc .AclMatch = val
469+ }
470+
425471 if port , ok := lbc .tcpServices [sName ]; ok && port == servicePort .Port {
426472 newSvc .FrontendPort = servicePort .Port
427473 tcpSvc = append (tcpSvc , newSvc )
@@ -434,13 +480,18 @@ func (lbc *loadBalancerController) getServices() (httpSvc []service, tcpSvc []se
434480 }
435481
436482 newSvc .FrontendPort = lbc .httpPort
437- httpSvc = append (httpSvc , newSvc )
483+ if newSvc .SslTerm == true {
484+ httpsTermSvc = append (httpsTermSvc , newSvc )
485+ } else {
486+ httpSvc = append (httpSvc , newSvc )
487+ }
438488 }
439489 glog .Infof ("Found service: %+v" , newSvc )
440490 }
441491 }
442492
443493 sort .Sort (serviceByName (httpSvc ))
494+ sort .Sort (serviceByName (httpsTermSvc ))
444495 sort .Sort (serviceByName (tcpSvc ))
445496
446497 return
@@ -452,18 +503,15 @@ func (lbc *loadBalancerController) sync(dryRun bool) error {
452503 time .Sleep (100 * time .Millisecond )
453504 return errDeferredSync
454505 }
455-
456- lbc .reloadRateLimiter .Accept ()
457-
458- httpSvc , tcpSvc := lbc .getServices ()
459- if len (httpSvc ) == 0 && len (tcpSvc ) == 0 {
460- glog .Info ("There is no available services to be used in the load balancer" )
506+ httpSvc , httpsTermSvc , tcpSvc := lbc .getServices ()
507+ if len (httpSvc ) == 0 && len (httpsTermSvc ) == 0 && len (tcpSvc ) == 0 {
461508 return nil
462509 }
463510 if err := lbc .cfg .write (
464511 map [string ][]service {
465- "http" : httpSvc ,
466- "tcp" : tcpSvc ,
512+ "http" : httpSvc ,
513+ "httpsTerm" : httpsTermSvc ,
514+ "tcp" : tcpSvc ,
467515 }, dryRun ); err != nil {
468516 return err
469517 }
@@ -533,7 +581,7 @@ func newLoadBalancerController(cfg *loadBalancerConfig, kubeClient *unversioned.
533581
534582// parseCfg parses the given configuration file.
535583// cmd line params take precedence over config directives.
536- func parseCfg (configPath string , defLbAlgorithm string ) * loadBalancerConfig {
584+ func parseCfg (configPath string , defLbAlgorithm string , sslCert string , sslCaCert string ) * loadBalancerConfig {
537585 jsonBlob , err := ioutil .ReadFile (configPath )
538586 if err != nil {
539587 glog .Fatalf ("Could not parse lb config: %v" , err )
@@ -543,7 +591,8 @@ func parseCfg(configPath string, defLbAlgorithm string) *loadBalancerConfig {
543591 if err != nil {
544592 glog .Fatalf ("Unable to unmarshal json blob: %v" , string (jsonBlob ))
545593 }
546-
594+ cfg .sslCert = sslCert
595+ cfg .sslCaCert = sslCaCert
547596 cfg .lbDefAlgorithm = defLbAlgorithm
548597 glog .Infof ("Creating new loadbalancer: %+v" , cfg )
549598 return & cfg
@@ -612,7 +661,7 @@ func dryRun(lbc *loadBalancerController) {
612661func main () {
613662 clientConfig := kubectl_util .DefaultClientConfig (flags )
614663 flags .Parse (os .Args )
615- cfg := parseCfg (* config , * lbDefAlgorithm )
664+ cfg := parseCfg (* config , * lbDefAlgorithm , * sslCert , * sslCaCert )
616665
617666 var kubeClient * unversioned.Client
618667 var err error
@@ -660,6 +709,7 @@ func main() {
660709
661710 // TODO: Handle multiple namespaces
662711 lbc := newLoadBalancerController (cfg , kubeClient , namespace , tcpSvcs )
712+
663713 go lbc .epController .Run (util .NeverStop )
664714 go lbc .svcController .Run (util .NeverStop )
665715 if * dry {
@@ -668,4 +718,5 @@ func main() {
668718 lbc .cfg .reload ()
669719 util .Until (lbc .worker , time .Second , util .NeverStop )
670720 }
721+
671722}
0 commit comments