github.com/wynshop-open-source/gomplate@v3.5.0+incompatible/libkv/consul.go (about)

     1  package libkv
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"os"
     7  	"time"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	// XXX: replace once https://github.com/go-yaml/yaml/issues/139 is solved
    12  	yaml "gopkg.in/hairyhenderson/yaml.v2"
    13  
    14  	"github.com/docker/libkv"
    15  	"github.com/docker/libkv/store"
    16  	"github.com/docker/libkv/store/consul"
    17  	"github.com/hairyhenderson/gomplate/conv"
    18  	"github.com/hairyhenderson/gomplate/env"
    19  	"github.com/hairyhenderson/gomplate/vault"
    20  	consulapi "github.com/hashicorp/consul/api"
    21  )
    22  
    23  const (
    24  	http  = "http"
    25  	https = "https"
    26  )
    27  
    28  // NewConsul - instantiate a new Consul datasource handler
    29  func NewConsul(u *url.URL) (*LibKV, error) {
    30  	consul.Register()
    31  	c, err := consulURL(u)
    32  	if err != nil {
    33  		return nil, err
    34  	}
    35  	config, err := consulConfig(c.Scheme == https)
    36  	if err != nil {
    37  		return nil, err
    38  	}
    39  	if role := env.Getenv("CONSUL_VAULT_ROLE", ""); role != "" {
    40  		mount := env.Getenv("CONSUL_VAULT_MOUNT", "consul")
    41  
    42  		var client *vault.Vault
    43  		client, err = vault.New(nil)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  		err = client.Login()
    48  		defer client.Logout()
    49  		if err != nil {
    50  			return nil, err
    51  		}
    52  
    53  		path := fmt.Sprintf("%s/creds/%s", mount, role)
    54  
    55  		var data []byte
    56  		data, err = client.Read(path)
    57  		if err != nil {
    58  			return nil, errors.Wrapf(err, "vault consul auth failed")
    59  		}
    60  
    61  		decoded := make(map[string]interface{})
    62  		err = yaml.Unmarshal(data, &decoded)
    63  		if err != nil {
    64  			return nil, errors.Wrapf(err, "Unable to unmarshal object")
    65  		}
    66  
    67  		token := decoded["token"].(string)
    68  
    69  		// nolint: gosec
    70  		_ = os.Setenv("CONSUL_HTTP_TOKEN", token)
    71  	}
    72  	var kv store.Store
    73  	kv, err = libkv.NewStore(store.CONSUL, []string{c.String()}, config)
    74  	if err != nil {
    75  		return nil, errors.Wrapf(err, "Consul setup failed")
    76  	}
    77  	return &LibKV{kv}, nil
    78  }
    79  
    80  // -- converts a gomplate datasource URL into a usable Consul URL
    81  func consulURL(u *url.URL) (*url.URL, error) {
    82  	addrEnv := env.Getenv("CONSUL_HTTP_ADDR")
    83  	c, err := url.Parse(addrEnv)
    84  	if err != nil {
    85  		return nil, errors.Wrapf(err, "invalid URL '%s' in CONSUL_HTTP_ADDR", addrEnv)
    86  	}
    87  	if c.Scheme == "" {
    88  		c.Scheme = u.Scheme
    89  	}
    90  	switch c.Scheme {
    91  	case "consul+http", http:
    92  		c.Scheme = http
    93  	case "consul+https", https:
    94  		c.Scheme = https
    95  	case "consul":
    96  		if conv.Bool(env.Getenv("CONSUL_HTTP_SSL")) {
    97  			c.Scheme = https
    98  		} else {
    99  			c.Scheme = http
   100  		}
   101  	}
   102  
   103  	if c.Host == "" && u.Host == "" {
   104  		c.Host = "localhost:8500"
   105  	} else if c.Host == "" {
   106  		c.Host = u.Host
   107  	}
   108  
   109  	return c, nil
   110  }
   111  
   112  func consulConfig(useTLS bool) (*store.Config, error) {
   113  	t := conv.MustAtoi(env.Getenv("CONSUL_TIMEOUT"))
   114  	config := &store.Config{
   115  		ConnectionTimeout: time.Duration(t) * time.Second,
   116  	}
   117  	if useTLS {
   118  		tconf := setupTLS("CONSUL")
   119  		var err error
   120  		config.TLS, err = consulapi.SetupTLSConfig(tconf)
   121  		if err != nil {
   122  			return nil, errors.Wrapf(err, "TLS Config setup failed")
   123  		}
   124  	}
   125  	return config, nil
   126  }
   127  
   128  func setupTLS(prefix string) *consulapi.TLSConfig {
   129  	tlsConfig := &consulapi.TLSConfig{
   130  		Address:  env.Getenv(prefix + "_TLS_SERVER_NAME"),
   131  		CAFile:   env.Getenv(prefix + "_CACERT"),
   132  		CAPath:   env.Getenv(prefix + "_CAPATH"),
   133  		CertFile: env.Getenv(prefix + "_CLIENT_CERT"),
   134  		KeyFile:  env.Getenv(prefix + "_CLIENT_KEY"),
   135  	}
   136  	if v := env.Getenv(prefix + "_HTTP_SSL_VERIFY"); v != "" {
   137  		verify := conv.Bool(v)
   138  		tlsConfig.InsecureSkipVerify = !verify
   139  	}
   140  	return tlsConfig
   141  }