From 2086be7fd25388ac1aefc9ba801284af35f31fa3 Mon Sep 17 00:00:00 2001 From: Rohith Date: Thu, 25 Feb 2016 14:28:14 +0000 Subject: [PATCH] - adding the bundle format option - this needs a clean really - shifting to version v0.0.4 - fixing the govet error --- config.go | 2 +- main.go | 2 +- utils.go | 22 +++++++- vault.go | 136 ++++++++++++++++++++++++++-------------------- vault_resource.go | 2 +- 5 files changed, 100 insertions(+), 64 deletions(-) diff --git a/config.go b/config.go index 716bf62..b3891f5 100644 --- a/config.go +++ b/config.go @@ -59,7 +59,7 @@ func init() { flag.BoolVar(&options.dryRun, "dryrun", false, "perform a dry run, printing the content to screen") flag.BoolVar(&options.tlsVerify, "tls-skip-verify", false, "whether to check and verify the vault service certificate") flag.StringVar(&options.vaultCaFile, "ca-cert", "", "the path to the file container the CA used to verify the vault service") - flag.DurationVar(&options.statsInterval, "stats", time.Duration(5)*time.Minute, "the interval to produce statistics on the accessed resources") + flag.DurationVar(&options.statsInterval, "stats", time.Duration(1)*time.Hour, "the interval to produce statistics on the accessed resources") flag.Var(options.resources, "cn", "a resource to retrieve and monitor from vault") } diff --git a/main.go b/main.go index 4527581..5766952 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,7 @@ import ( const ( Prog = "vault-sidekick" - Version = "v0.0.3" + Version = "v0.0.4" ) func main() { diff --git a/utils.go b/utils.go index 3459454..ae594c1 100644 --- a/utils.go +++ b/utils.go @@ -30,6 +30,7 @@ import ( "github.com/golang/glog" "gopkg.in/yaml.v2" + "path/filepath" ) func init() { @@ -79,7 +80,7 @@ func readConfigFile(filename string) (map[string]string, error) { suffix := path.Ext(filename) switch suffix { case ".yaml": - return readYAMLFile(filename) + fallthrough case ".yml": return readYAMLFile(filename) default: @@ -163,7 +164,7 @@ func writeResource(rn *VaultResource, data map[string]interface{}) error { // step: determine the resource path resourcePath := rn.GetFilename() if !strings.HasPrefix(resourcePath, "/") { - resourcePath = fmt.Sprintf("%s/%s", options.outputDir, resourcePath) + resourcePath = fmt.Sprintf("%s/%s", options.outputDir, filepath.Base(resourcePath)) } glog.V(10).Infof("writing the resource: %s, format: %s", resourcePath, rn.format) @@ -187,6 +188,23 @@ func writeResource(rn *VaultResource, data map[string]interface{}) error { return writeFile(resourcePath, content) } + if rn.format == "bundle" { + certificateFile := fmt.Sprintf("%s.crt", resourcePath) + caFile := fmt.Sprintf("%s.ca", resourcePath) + certificate := fmt.Sprintf("%s\n\n%s", data["certificate"], data["private_key"]) + ca := fmt.Sprintf("%s", data["issuing_ca"]) + + if err := writeFile(certificateFile, []byte(certificate)); err != nil { + glog.Errorf("failed to write the bundled certificate file, error: %s", err) + return err + } + + if err := writeFile(caFile, []byte(ca)); err != nil { + glog.Errorf("failed to write the ca certificate file, errro: %s", err) + return err + } + } + if rn.format == "cert" { files := map[string]string{ "certificate": "crt", diff --git a/vault.go b/vault.go index 756e7dc..c9fcc3a 100644 --- a/vault.go +++ b/vault.go @@ -21,6 +21,7 @@ import ( "crypto/x509" "fmt" "io/ioutil" + "net" "net/http" "time" @@ -42,6 +43,7 @@ type AuthInterface interface { // VaultService is the main interface into the vault API - placing into a structure // allows one to easily mock it and two to simplify the interface for us type VaultService struct { + vaultURL string // the vault client client *api.Client // the vault config @@ -69,59 +71,24 @@ func NewVaultService(url string) (*VaultService, error) { // step: create the config for client service := new(VaultService) - service.config = api.DefaultConfig() - service.config.Address = url + service.vaultURL = url service.listeners = make([]chan VaultEvent, 0) - service.config.HttpClient.Transport, err = service.buildHTTPTransport() - if err != nil { - return nil, err - } // step: create the service processor channels service.resourceChannel = make(chan *watchedResource, 20) - // step: create the actual client - if service.client, err = api.NewClient(service.config); err != nil { + // step: retrieve a vault client + service.client, err = newVaultClient(&options) + if err != nil { return nil, err } - // step: are we using a token? or do we need to authenticate and grab a token - if service.token, err = service.authenticate(options.vaultAuthOptions); err != nil { - return nil, err - } - - // step: set the token for the client - service.client.SetToken(service.token) - // step: start the service processor off service.vaultServiceProcessor() return service, nil } -func (r *VaultService) buildHTTPTransport() (*http.Transport, error) { - transport := &http.Transport{} - - // step: are we skip the tls verify? - if options.tlsVerify { - transport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - } - // step: are we loading a CA file - if options.vaultCaFile != "" { - // step: load the ca file - caCert, err := ioutil.ReadFile(options.vaultCaFile) - if err != nil { - return nil, fmt.Errorf("unable to read in the ca: %s, reason: %s", options.vaultCaFile, err) - } - caCertPool := x509.NewCertPool() - caCertPool.AppendCertsFromPEM(caCert) - // step: add the ca to the root - transport.TLSClientConfig.RootCAs = caCertPool - } - - return transport, nil -} - // AddListener ... add a listener to the events listeners func (r *VaultService) AddListener(ch chan VaultEvent) { glog.V(10).Infof("adding the listener: %v", ch) @@ -267,26 +234,6 @@ func (r *VaultService) vaultServiceProcessor() { }() } -// authenticate ... we need to authenticate to teh vault to grab a toke -// auth : a map containing the options required for authentication -func (r VaultService) authenticate(auth map[string]string) (string, error) { - var secret string - var err error - - plugin, _ := auth[VaultAuth] - switch plugin { - case "userpass": - secret, err = NewUserPassPlugin(r.client).Create(auth) - case "token": - auth["filename"] = options.vaultAuthFile - secret, err = NewUserTokenPlugin(r.client).Create(auth) - default: - return "", fmt.Errorf("unsupported authentication plugin: %s", plugin) - } - - return secret, err -} - // scheduleNow ... a helper method to perform an immediate reschedule into a channel // rn : a pointer to the watched resource you wish to reschedule // ch : the channel the resource should be placed into @@ -403,3 +350,74 @@ func (r VaultService) get(rn *watchedResource) (err error) { return err } + +// newVaultClient creates and authenticates a vault client +func newVaultClient(opts *config) (*api.Client, error) { + var err error + var token string + + config := api.DefaultConfig() + config.Address = opts.vaultURL + + config.HttpClient.Transport, err = buildHTTPTransport(opts) + if err != nil { + return nil, err + } + + // step: create the actual client + client, err := api.NewClient(config) + if err != nil { + return nil, err + } + + plugin, _ := opts.vaultAuthOptions[VaultAuth] + switch plugin { + case "userpass": + token, err = NewUserPassPlugin(client).Create(opts.vaultAuthOptions) + case "token": + opts.vaultAuthOptions["filename"] = options.vaultAuthFile + token, err = NewUserTokenPlugin(client).Create(opts.vaultAuthOptions) + default: + return nil, fmt.Errorf("unsupported authentication plugin: %s", plugin) + } + + // step: set the token for the client + client.SetToken(token) + + return client, nil +} + +// buildHTTPTransport constructs a http transport for the http client +func buildHTTPTransport(opts *config) (*http.Transport, error) { + // step: create the vault sidekick + transport := &http.Transport{ + Proxy: http.ProxyFromEnvironment, + Dial: (&net.Dialer{ + Timeout: 30 * time.Second, + KeepAlive: 30 * time.Second, + }).Dial, + TLSHandshakeTimeout: 10 * time.Second, + } + + // step: are we skip the tls verify? + if options.tlsVerify { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + } + } + + // step: are we loading a CA file + if opts.vaultCaFile != "" { + // step: load the ca file + caCert, err := ioutil.ReadFile(opts.vaultCaFile) + if err != nil { + return nil, fmt.Errorf("unable to read in the ca: %s, reason: %s", opts.vaultCaFile, err) + } + caCertPool := x509.NewCertPool() + caCertPool.AppendCertsFromPEM(caCert) + // step: add the ca to the root + transport.TLSClientConfig.RootCAs = caCertPool + } + + return transport, nil +} diff --git a/vault_resource.go b/vault_resource.go index 270f4c8..f228a3c 100644 --- a/vault_resource.go +++ b/vault_resource.go @@ -43,7 +43,7 @@ const ( ) var ( - resourceFormatRegex = regexp.MustCompile("^(yaml|json|ini|txt|cert|csv)$") + resourceFormatRegex = regexp.MustCompile("^(yaml|json|ini|txt|cert|bundle|csv)$") // a map of valid resource to retrieve from vault validResources = map[string]bool{