Browse Source

Add support for TLS between flannel and etcd

Fixes #63
Eugene Yakubovich 10 years ago
parent
commit
6fb790c50b
3 changed files with 62 additions and 18 deletions
  1. 15 1
      main.go
  2. 42 15
      subnet/registry.go
  3. 5 2
      subnet/subnet.go

+ 15 - 1
main.go

@@ -27,6 +27,9 @@ import (
 type CmdLineOpts struct {
 	etcdEndpoints string
 	etcdPrefix    string
+	etcdKeyfile   string
+	etcdCertfile  string
+	etcdCAFile    string
 	help          bool
 	version       bool
 	ipMasq        bool
@@ -39,6 +42,9 @@ var opts CmdLineOpts
 func init() {
 	flag.StringVar(&opts.etcdEndpoints, "etcd-endpoints", "http://127.0.0.1:4001", "a comma-delimited list of etcd endpoints")
 	flag.StringVar(&opts.etcdPrefix, "etcd-prefix", "/coreos.com/network", "etcd prefix")
+	flag.StringVar(&opts.etcdKeyfile, "etcd-keyfile", "", "SSL key file used to secure etcd communication")
+	flag.StringVar(&opts.etcdCertfile, "etcd-certfile", "", "SSL certification file used to secure etcd communication")
+	flag.StringVar(&opts.etcdCAFile, "etcd-cafile", "", "SSL Certificate Authority file used to secure etcd communication")
 	flag.StringVar(&opts.subnetFile, "subnet-file", "/run/flannel/subnet.env", "filename where env variables (subnet and MTU values) will be written to")
 	flag.StringVar(&opts.iface, "iface", "", "interface to use (IP or name) for inter-host communication")
 	flag.BoolVar(&opts.ipMasq, "ip-masq", false, "setup IP masquerade rule for traffic destined outside of overlay network")
@@ -128,8 +134,16 @@ func lookupIface() (*net.Interface, net.IP, error) {
 func makeSubnetManager() *subnet.SubnetManager {
 	peers := strings.Split(opts.etcdEndpoints, ",")
 
+	cfg := &subnet.EtcdConfig{
+		Endpoints: peers,
+		Keyfile:   opts.etcdKeyfile,
+		Certfile:  opts.etcdCertfile,
+		CAFile:    opts.etcdCAFile,
+		Prefix:    opts.etcdPrefix,
+	}
+
 	for {
-		sm, err := subnet.NewSubnetManager(peers, opts.etcdPrefix)
+		sm, err := subnet.NewSubnetManager(cfg)
 		if err == nil {
 			return sm
 		}

+ 42 - 15
subnet/registry.go

@@ -1,6 +1,7 @@
 package subnet
 
 import (
+	"fmt"
 	"path"
 	"sync"
 	"time"
@@ -17,23 +18,44 @@ type subnetRegistry interface {
 	watchSubnets(since uint64, stop chan bool) (*etcd.Response, error)
 }
 
+type EtcdConfig struct {
+	Endpoints []string
+	Keyfile   string
+	Certfile  string
+	CAFile    string
+	Prefix    string
+}
+
 type etcdSubnetRegistry struct {
-	mux      sync.Mutex
-	cli      *etcd.Client
-	endpoint []string
-	prefix   string
+	mux     sync.Mutex
+	cli     *etcd.Client
+	etcdCfg *EtcdConfig
 }
 
-func newEtcdSubnetRegistry(endpoint []string, prefix string) subnetRegistry {
-	return &etcdSubnetRegistry{
-		cli:      etcd.NewClient(endpoint),
-		endpoint: endpoint,
-		prefix:   prefix,
+func newEtcdClient(c *EtcdConfig) (*etcd.Client, error) {
+	if c.Keyfile != "" || c.Certfile != "" || c.CAFile != "" {
+		return etcd.NewTLSClient(c.Endpoints, c.Certfile, c.Keyfile, c.CAFile)
+	} else {
+		return etcd.NewClient(c.Endpoints), nil
 	}
 }
 
+func newEtcdSubnetRegistry(config *EtcdConfig) (subnetRegistry, error) {
+	r := &etcdSubnetRegistry{
+		etcdCfg: config,
+	}
+
+	var err error
+	r.cli, err = newEtcdClient(config)
+	if err != nil {
+		return nil, err
+	}
+
+	return r, nil
+}
+
 func (esr *etcdSubnetRegistry) getConfig() (*etcd.Response, error) {
-	key := path.Join(esr.prefix, "config")
+	key := path.Join(esr.etcdCfg.Prefix, "config")
 	resp, err := esr.client().Get(key, false, false)
 	if err != nil {
 		return nil, err
@@ -42,12 +64,12 @@ func (esr *etcdSubnetRegistry) getConfig() (*etcd.Response, error) {
 }
 
 func (esr *etcdSubnetRegistry) getSubnets() (*etcd.Response, error) {
-	key := path.Join(esr.prefix, "subnets")
+	key := path.Join(esr.etcdCfg.Prefix, "subnets")
 	return esr.client().Get(key, false, true)
 }
 
 func (esr *etcdSubnetRegistry) createSubnet(sn, data string, ttl uint64) (*etcd.Response, error) {
-	key := path.Join(esr.prefix, "subnets", sn)
+	key := path.Join(esr.etcdCfg.Prefix, "subnets", sn)
 	resp, err := esr.client().Create(key, data, ttl)
 	if err != nil {
 		return nil, err
@@ -58,7 +80,7 @@ func (esr *etcdSubnetRegistry) createSubnet(sn, data string, ttl uint64) (*etcd.
 }
 
 func (esr *etcdSubnetRegistry) updateSubnet(sn, data string, ttl uint64) (*etcd.Response, error) {
-	key := path.Join(esr.prefix, "subnets", sn)
+	key := path.Join(esr.etcdCfg.Prefix, "subnets", sn)
 	resp, err := esr.client().Set(key, data, ttl)
 	if err != nil {
 		return nil, err
@@ -70,7 +92,7 @@ func (esr *etcdSubnetRegistry) updateSubnet(sn, data string, ttl uint64) (*etcd.
 
 func (esr *etcdSubnetRegistry) watchSubnets(since uint64, stop chan bool) (*etcd.Response, error) {
 	for {
-		key := path.Join(esr.prefix, "subnets")
+		key := path.Join(esr.etcdCfg.Prefix, "subnets")
 		resp, err := esr.client().RawWatch(key, since, true, nil, stop)
 
 		if err != nil {
@@ -101,7 +123,12 @@ func (esr *etcdSubnetRegistry) client() *etcd.Client {
 func (esr *etcdSubnetRegistry) resetClient() {
 	esr.mux.Lock()
 	defer esr.mux.Unlock()
-	esr.cli = etcd.NewClient(esr.endpoint)
+
+	var err error
+	esr.cli, err = newEtcdClient(esr.etcdCfg)
+	if err != nil {
+		panic(fmt.Errorf("resetClient: error recreating etcd client: %v", err))
+	}
 }
 
 func ensureExpiration(resp *etcd.Response, ttl uint64) {

+ 5 - 2
subnet/subnet.go

@@ -67,8 +67,11 @@ type Event struct {
 
 type EventBatch []Event
 
-func NewSubnetManager(etcdEndpoint []string, prefix string) (*SubnetManager, error) {
-	esr := newEtcdSubnetRegistry(etcdEndpoint, prefix)
+func NewSubnetManager(config *EtcdConfig) (*SubnetManager, error) {
+	esr, err := newEtcdSubnetRegistry(config)
+	if err != nil {
+		return nil, err
+	}
 	return newSubnetManager(esr)
 }