Add TLS support for k8s middleware (#289)

* Added TLS to k8s client

Added options for TLS kubernetes client connection.

* Fix k8s TLS config option parsing

Brings config option parsing for kubernetes TLS in line with recent changes.

* Put TLS config on one line

Put kubernetes tls config on one line to match style established in etcd tls config.

* Add tls option to README
This commit is contained in:
Chris O'Haver
2016-09-23 18:07:06 -04:00
committed by Miek Gieben
parent b9cf32f7a9
commit 15297c8e63
3 changed files with 43 additions and 12 deletions

View File

@@ -40,7 +40,9 @@ This is the default kubernetes setup, with everything specified in full:
# Example values: 60s, 5m, 1h # Example values: 60s, 5m, 1h
resyncperiod 5m resyncperiod 5m
# Use url for k8s API endpoint # Use url for k8s API endpoint
endpoint http://localhost:8080 endpoint https://k8sendpoint:8080
# The tls cert, key and the CA cert filenames
tls cert key cacert
# Assemble k8s record names with the template # Assemble k8s record names with the template
template {service}.{namespace}.{zone} template {service}.{namespace}.{zone}
# Only expose the k8s namespace "demo" # Only expose the k8s namespace "demo"

View File

@@ -18,6 +18,7 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
unversionedapi "k8s.io/kubernetes/pkg/api/unversioned" unversionedapi "k8s.io/kubernetes/pkg/api/unversioned"
unversionedclient "k8s.io/kubernetes/pkg/client/unversioned" unversionedclient "k8s.io/kubernetes/pkg/client/unversioned"
"k8s.io/kubernetes/pkg/client/restclient"
"k8s.io/kubernetes/pkg/client/unversioned/clientcmd" "k8s.io/kubernetes/pkg/client/unversioned/clientcmd"
clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api" clientcmdapi "k8s.io/kubernetes/pkg/client/unversioned/clientcmd/api"
"k8s.io/kubernetes/pkg/labels" "k8s.io/kubernetes/pkg/labels"
@@ -29,6 +30,9 @@ type Kubernetes struct {
Zones []string Zones []string
Proxy proxy.Proxy // Proxy for looking up names during the resolution process Proxy proxy.Proxy // Proxy for looking up names during the resolution process
APIEndpoint string APIEndpoint string
APICertAuth string
APIClientCert string
APIClientKey string
APIConn *dnsController APIConn *dnsController
ResyncPeriod time.Duration ResyncPeriod time.Duration
NameTemplate *nametemplate.NameTemplate NameTemplate *nametemplate.NameTemplate
@@ -37,23 +41,41 @@ type Kubernetes struct {
Selector *labels.Selector Selector *labels.Selector
} }
// InitKubeCache initializes a new Kubernetes cache. func (k *Kubernetes) getClientConfig() (*restclient.Config, error) {
// TODO(miek): is this correct?
func (k *Kubernetes) InitKubeCache() error {
// For a custom api server or running outside a k8s cluster // For a custom api server or running outside a k8s cluster
// set URL in env.KUBERNETES_MASTER or set endpoint in Corefile // set URL in env.KUBERNETES_MASTER or set endpoint in Corefile
loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
overrides := &clientcmd.ConfigOverrides{} overrides := &clientcmd.ConfigOverrides{}
clusterinfo := clientcmdapi.Cluster{}
authinfo := clientcmdapi.AuthInfo{}
if len(k.APIEndpoint) > 0 { if len(k.APIEndpoint) > 0 {
overrides.ClusterInfo = clientcmdapi.Cluster{Server: k.APIEndpoint} clusterinfo.Server = k.APIEndpoint
} }
if len(k.APICertAuth) > 0 {
clusterinfo.CertificateAuthority = k.APICertAuth
}
if len(k.APIClientCert) > 0 {
authinfo.ClientCertificate = k.APIClientCert
}
if len(k.APIClientKey) > 0 {
authinfo.ClientKey = k.APIClientKey
}
overrides.ClusterInfo = clusterinfo
overrides.AuthInfo = authinfo
clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides)
config, err := clientConfig.ClientConfig() return clientConfig.ClientConfig()
}
// InitKubeCache initializes a new Kubernetes cache.
// TODO(miek): is this correct?
func (k *Kubernetes) InitKubeCache() error {
config, err := k.getClientConfig()
if err != nil { if err != nil {
return err return err
} }
kubeClient, err := unversionedclient.New(config)
kubeClient, err := unversionedclient.New(config)
if err != nil { if err != nil {
log.Printf("[ERROR] Failed to create kubernetes notification controller: %v", err) log.Printf("[ERROR] Failed to create kubernetes notification controller: %v", err)
return err return err

View File

@@ -75,7 +75,7 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
switch c.Val() { switch c.Val() {
case "template": case "template":
args := c.RemainingArgs() args := c.RemainingArgs()
if len(args) != 0 { if len(args) > 0 {
template := strings.Join(args, "") template := strings.Join(args, "")
err := k8s.NameTemplate.SetTemplate(template) err := k8s.NameTemplate.SetTemplate(template)
if err != nil { if err != nil {
@@ -86,21 +86,28 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
return nil, c.ArgErr() return nil, c.ArgErr()
case "namespaces": case "namespaces":
args := c.RemainingArgs() args := c.RemainingArgs()
if len(args) != 0 { if len(args) > 0 {
k8s.Namespaces = append(k8s.Namespaces, args...) k8s.Namespaces = append(k8s.Namespaces, args...)
continue continue
} }
return nil, c.ArgErr() return nil, c.ArgErr()
case "endpoint": case "endpoint":
args := c.RemainingArgs() args := c.RemainingArgs()
if len(args) != 0 { if len(args) > 0 {
k8s.APIEndpoint = args[0] k8s.APIEndpoint = args[0]
continue continue
} }
return nil, c.ArgErr() return nil, c.ArgErr()
case "tls": // cert key cacertfile
args := c.RemainingArgs()
if len(args) == 3 {
k8s.APIClientCert, k8s.APIClientKey, k8s.APICertAuth = args[0], args[1], args[2]
continue
}
return nil, c.ArgErr()
case "resyncperiod": case "resyncperiod":
args := c.RemainingArgs() args := c.RemainingArgs()
if len(args) != 0 { if len(args) > 0 {
rp, err := time.ParseDuration(args[0]) rp, err := time.ParseDuration(args[0])
if err != nil { if err != nil {
return nil, fmt.Errorf("Unable to parse resync duration value. Value provided was '%v'. Example valid values: '15s', '5m', '1h'. Error was: %v", args[0], err) return nil, fmt.Errorf("Unable to parse resync duration value. Value provided was '%v'. Example valid values: '15s', '5m', '1h'. Error was: %v", args[0], err)
@@ -111,7 +118,7 @@ func kubernetesParse(c *caddy.Controller) (*Kubernetes, error) {
return nil, c.ArgErr() return nil, c.ArgErr()
case "labels": case "labels":
args := c.RemainingArgs() args := c.RemainingArgs()
if len(args) != 0 { if len(args) > 0 {
labelSelectorString := strings.Join(args, " ") labelSelectorString := strings.Join(args, " ")
ls, err := unversionedapi.ParseToLabelSelector(labelSelectorString) ls, err := unversionedapi.ParseToLabelSelector(labelSelectorString)
if err != nil { if err != nil {