github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/atc/creds/vault/manager_test.go (about)

     1  package vault_test
     2  
     3  import (
     4  	"crypto/tls"
     5  	"encoding/json"
     6  	"net"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"time"
    10  
    11  	"code.cloudfoundry.org/lager/lagertest"
    12  	"github.com/pf-qiu/concourse/v6/atc/creds/vault"
    13  	"github.com/hashicorp/vault/api"
    14  	"github.com/jessevdk/go-flags"
    15  	"github.com/square/certstrap/pkix"
    16  
    17  	. "github.com/onsi/ginkgo"
    18  	. "github.com/onsi/ginkgo/extensions/table"
    19  	. "github.com/onsi/gomega"
    20  )
    21  
    22  var _ = Describe("VaultManager", func() {
    23  	var manager vault.VaultManager
    24  
    25  	Describe("IsConfigured()", func() {
    26  		JustBeforeEach(func() {
    27  			_, err := flags.ParseArgs(&manager, []string{})
    28  			Expect(err).To(BeNil())
    29  		})
    30  
    31  		It("fails on empty Manager", func() {
    32  			Expect(manager.IsConfigured()).To(BeFalse())
    33  		})
    34  
    35  		It("passes if URL is set", func() {
    36  			manager.URL = "http://vault"
    37  			Expect(manager.IsConfigured()).To(BeTrue())
    38  		})
    39  	})
    40  
    41  	Describe("Validate()", func() {
    42  		JustBeforeEach(func() {
    43  			manager = vault.VaultManager{URL: "http://vault", Auth: vault.AuthConfig{ClientToken: "xxx"}}
    44  			_, err := flags.ParseArgs(&manager, []string{})
    45  			Expect(err).To(BeNil())
    46  			Expect(manager.SharedPath).To(Equal(""))
    47  			Expect(manager.PathPrefix).To(Equal("/concourse"))
    48  			Expect(manager.LookupTemplates).To(Equal([]string{
    49  				"/{{.Team}}/{{.Pipeline}}/{{.Secret}}",
    50  				"/{{.Team}}/{{.Secret}}",
    51  			}))
    52  			Expect(manager.Namespace).To(Equal(""))
    53  		})
    54  
    55  		It("passes on default parameters", func() {
    56  			Expect(manager.Validate()).To(BeNil())
    57  		})
    58  
    59  		DescribeTable("passes if all vault credentials are specified",
    60  			func(backend, clientToken string) {
    61  				manager.Auth.Backend = backend
    62  				manager.Auth.ClientToken = clientToken
    63  				Expect(manager.Validate()).To(BeNil())
    64  			},
    65  			Entry("all values", "backend", "clientToken"),
    66  			Entry("only clientToken", "", "clientToken"),
    67  		)
    68  
    69  		It("fails on missing vault auth credentials", func() {
    70  			manager.Auth = vault.AuthConfig{}
    71  			Expect(manager.Validate()).ToNot(BeNil())
    72  		})
    73  	})
    74  
    75  	Describe("Config", func() {
    76  		var config map[string]interface{}
    77  		var fakeVault *httptest.Server
    78  
    79  		var configErr error
    80  
    81  		BeforeEach(func() {
    82  			key, err := pkix.CreateRSAKey(1024)
    83  			Expect(err).ToNot(HaveOccurred())
    84  
    85  			ca, err := pkix.CreateCertificateAuthority(key, "", time.Now().Add(time.Hour), "", "", "", "", "vault-ca")
    86  			Expect(err).ToNot(HaveOccurred())
    87  
    88  			serverKey, err := pkix.CreateRSAKey(1024)
    89  			Expect(err).ToNot(HaveOccurred())
    90  
    91  			serverKeyBytes, err := serverKey.ExportPrivate()
    92  			Expect(err).ToNot(HaveOccurred())
    93  
    94  			serverName := "vault"
    95  
    96  			serverCSR, err := pkix.CreateCertificateSigningRequest(serverKey, "", []net.IP{net.ParseIP("127.0.0.1")}, []string{serverName}, "", "", "", "", "")
    97  			Expect(err).ToNot(HaveOccurred())
    98  
    99  			serverCert, err := pkix.CreateCertificateHost(ca, key, serverCSR, time.Now().Add(time.Hour))
   100  			Expect(err).ToNot(HaveOccurred())
   101  
   102  			clientKey, err := pkix.CreateRSAKey(1024)
   103  			Expect(err).ToNot(HaveOccurred())
   104  
   105  			clientKeyBytes, err := clientKey.ExportPrivate()
   106  			Expect(err).ToNot(HaveOccurred())
   107  
   108  			clientCSR, err := pkix.CreateCertificateSigningRequest(clientKey, "", nil, nil, "", "", "", "", "concourse")
   109  			Expect(err).ToNot(HaveOccurred())
   110  
   111  			clientCert, err := pkix.CreateCertificateHost(ca, key, clientCSR, time.Now().Add(time.Hour))
   112  			Expect(err).ToNot(HaveOccurred())
   113  
   114  			serverCertBytes, err := serverCert.Export()
   115  			Expect(err).ToNot(HaveOccurred())
   116  
   117  			clientCertBytes, err := clientCert.Export()
   118  			Expect(err).ToNot(HaveOccurred())
   119  
   120  			caBytes, err := ca.Export()
   121  			Expect(err).ToNot(HaveOccurred())
   122  
   123  			fakeVault = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   124  				err := json.NewEncoder(w).Encode(api.Secret{
   125  					Data: map[string]interface{}{"value": "foo"},
   126  				})
   127  				Expect(err).ToNot(HaveOccurred())
   128  			}))
   129  
   130  			tlsCert, err := tls.X509KeyPair(serverCertBytes, serverKeyBytes)
   131  			Expect(err).ToNot(HaveOccurred())
   132  
   133  			fakeVault.TLS = &tls.Config{
   134  				Certificates: []tls.Certificate{tlsCert},
   135  			}
   136  
   137  			fakeVault.StartTLS()
   138  
   139  			config = map[string]interface{}{
   140  				"url":                  fakeVault.URL,
   141  				"path_prefix":          "/path-prefix",
   142  				"lookup_templates": []string{
   143  					"/what/{{.Team}}/blah/{{.Pipeline}}/{{.Secret}}",
   144  					"/thing/{{.Team}}/{{.Secret}}",
   145  				},
   146  				"shared_path":          "/shared-path",
   147  				"namespace":            "some-namespace",
   148  				"ca_cert":              string(caBytes),
   149  				"client_cert":          string(clientCertBytes),
   150  				"client_key":           string(clientKeyBytes),
   151  				"server_name":          serverName,
   152  				"insecure_skip_verify": true,
   153  				"client_token":         "some-client-token",
   154  				"auth_backend_max_ttl": "5m",
   155  				"auth_retry_max":       "15m",
   156  				"auth_retry_initial":   "10s",
   157  				"auth_backend":         "approle",
   158  				"auth_params": map[string]string{
   159  					"role_id":   "some-role-id",
   160  					"secret_id": "some-secret-id",
   161  				},
   162  			}
   163  
   164  			manager = vault.VaultManager{}
   165  		})
   166  
   167  		JustBeforeEach(func() {
   168  			configErr = manager.Config(config)
   169  		})
   170  
   171  		It("configures TLS appropriately", func() {
   172  			Expect(configErr).ToNot(HaveOccurred())
   173  
   174  			err := manager.Init(lagertest.NewTestLogger("test"))
   175  			Expect(err).ToNot(HaveOccurred())
   176  
   177  			secret, err := manager.Client.Read("some/path")
   178  			Expect(err).ToNot(HaveOccurred())
   179  			Expect(secret).ToNot(BeNil())
   180  			Expect(secret.Data).To(Equal(map[string]interface{}{"value": "foo"}))
   181  		})
   182  
   183  		It("configures all attributes appropriately", func() {
   184  			Expect(configErr).ToNot(HaveOccurred())
   185  
   186  			Expect(manager.URL).To(Equal(fakeVault.URL))
   187  			Expect(manager.PathPrefix).To(Equal("/path-prefix"))
   188  			Expect(manager.LookupTemplates).To(Equal([]string{
   189  				"/what/{{.Team}}/blah/{{.Pipeline}}/{{.Secret}}",
   190  				"/thing/{{.Team}}/{{.Secret}}",
   191  			}))
   192  			Expect(manager.SharedPath).To(Equal("/shared-path"))
   193  			Expect(manager.Namespace).To(Equal("some-namespace"))
   194  
   195  			Expect(manager.TLS.Insecure).To(BeTrue())
   196  
   197  			Expect(manager.Auth.ClientToken).To(Equal("some-client-token"))
   198  			Expect(manager.Auth.BackendMaxTTL).To(Equal(5 * time.Minute))
   199  			Expect(manager.Auth.RetryMax).To(Equal(15 * time.Minute))
   200  			Expect(manager.Auth.RetryInitial).To(Equal(10 * time.Second))
   201  			Expect(manager.Auth.Backend).To(Equal("approle"))
   202  			Expect(manager.Auth.Params).To(Equal(map[string]string{
   203  				"role_id":   "some-role-id",
   204  				"secret_id": "some-secret-id",
   205  			}))
   206  		})
   207  
   208  		Context("with optional configs omitted", func() {
   209  			BeforeEach(func() {
   210  				delete(config, "path_prefix")
   211  				delete(config, "auth_retry_max")
   212  				delete(config, "auth_retry_initial")
   213  				delete(config, "lookup_templates")
   214  			})
   215  
   216  			It("has sane defaults", func() {
   217  				Expect(configErr).ToNot(HaveOccurred())
   218  
   219  				Expect(manager.PathPrefix).To(Equal("/concourse"))
   220  				Expect(manager.Auth.RetryMax).To(Equal(5 * time.Minute))
   221  				Expect(manager.Auth.RetryInitial).To(Equal(time.Second))
   222  				Expect(manager.LookupTemplates).To(Equal([]string{
   223  					"/{{.Team}}/{{.Pipeline}}/{{.Secret}}",
   224  					"/{{.Team}}/{{.Secret}}",
   225  				}))
   226  			})
   227  		})
   228  
   229  		Context("with extra keys in the config", func() {
   230  			BeforeEach(func() {
   231  				config["unknown_key"] = "whambam"
   232  			})
   233  
   234  			It("returns an error", func() {
   235  				Expect(configErr).To(HaveOccurred())
   236  				Expect(configErr.Error()).To(ContainSubstring("unknown_key"))
   237  			})
   238  		})
   239  	})
   240  })