github.com/wuhuizuo/gomplate@v3.5.0+incompatible/tests/integration/datasources_vault_test.go (about)

     1  //+build integration
     2  //+build !windows
     3  
     4  package integration
     5  
     6  import (
     7  	"io/ioutil"
     8  	"os"
     9  	"os/user"
    10  	"path"
    11  	"strconv"
    12  
    13  	. "gopkg.in/check.v1"
    14  
    15  	"github.com/gotestyourself/gotestyourself/fs"
    16  	"github.com/gotestyourself/gotestyourself/icmd"
    17  	vaultapi "github.com/hashicorp/vault/api"
    18  )
    19  
    20  type VaultDatasourcesSuite struct {
    21  	tmpDir      *fs.Dir
    22  	pidDir      *fs.Dir
    23  	vaultAddr   string
    24  	vaultResult *icmd.Result
    25  	v           *vaultClient
    26  }
    27  
    28  var _ = Suite(&VaultDatasourcesSuite{})
    29  
    30  const vaultRootToken = "00000000-1111-2222-3333-444455556666"
    31  
    32  func (s *VaultDatasourcesSuite) SetUpSuite(c *C) {
    33  	s.pidDir, s.tmpDir, s.vaultAddr, s.vaultResult = startVault(c)
    34  
    35  	var err error
    36  	s.v, err = createVaultClient(s.vaultAddr, vaultRootToken)
    37  	handle(c, err)
    38  
    39  	err = s.v.vc.Sys().PutPolicy("writepol", `path "*" {
    40    capabilities = ["create","update","delete"]
    41  }`)
    42  	handle(c, err)
    43  	err = s.v.vc.Sys().PutPolicy("readpol", `path "*" {
    44    capabilities = ["read","delete"]
    45  }`)
    46  	handle(c, err)
    47  	err = s.v.vc.Sys().PutPolicy("listPol", `path "*" {
    48    capabilities = ["read","list","delete"]
    49  }`)
    50  	handle(c, err)
    51  }
    52  
    53  func startVault(c *C) (pidDir, tmpDir *fs.Dir, vaultAddr string, vaultResult *icmd.Result) {
    54  	pidDir = fs.NewDir(c, "gomplate-inttests-vaultpid")
    55  	tmpDir = fs.NewDir(c, "gomplate-inttests",
    56  		fs.WithFile("config.json", `{
    57  		"pid_file": "`+pidDir.Join("vault.pid")+`"
    58  		}`),
    59  	)
    60  
    61  	// rename any existing token so it doesn't get overridden
    62  	u, _ := user.Current()
    63  	homeDir := u.HomeDir
    64  	tokenFile := path.Join(homeDir, ".vault-token")
    65  	info, err := os.Stat(tokenFile)
    66  	if err == nil && info.Mode().IsRegular() {
    67  		os.Rename(tokenFile, path.Join(homeDir, ".vault-token.bak"))
    68  	}
    69  
    70  	_, vaultAddr = freeport()
    71  	vault := icmd.Command("vault", "server",
    72  		"-dev",
    73  		"-dev-root-token-id="+vaultRootToken,
    74  		"-dev-leased-kv",
    75  		"-log-level=err",
    76  		"-dev-listen-address="+vaultAddr,
    77  		"-config="+tmpDir.Join("config.json"),
    78  	)
    79  	vaultResult = icmd.StartCmd(vault)
    80  
    81  	c.Logf("Fired up Vault: %v", vault)
    82  
    83  	err = waitForURL(c, "http://"+vaultAddr+"/v1/sys/health")
    84  	handle(c, err)
    85  
    86  	return pidDir, tmpDir, vaultAddr, vaultResult
    87  }
    88  
    89  func (s *VaultDatasourcesSuite) TearDownSuite(c *C) {
    90  	defer s.tmpDir.Remove()
    91  	defer s.pidDir.Remove()
    92  
    93  	p, err := ioutil.ReadFile(s.pidDir.Join("vault.pid"))
    94  	handle(c, err)
    95  	pid, err := strconv.Atoi(string(p))
    96  	handle(c, err)
    97  	process, err := os.FindProcess(pid)
    98  	handle(c, err)
    99  	err = process.Kill()
   100  	handle(c, err)
   101  
   102  	// restore old token if it was backed up
   103  	u, _ := user.Current()
   104  	homeDir := u.HomeDir
   105  	tokenFile := path.Join(homeDir, ".vault-token.bak")
   106  	info, err := os.Stat(tokenFile)
   107  	if err == nil && info.Mode().IsRegular() {
   108  		os.Rename(tokenFile, path.Join(homeDir, ".vault-token"))
   109  	}
   110  }
   111  
   112  func (s *VaultDatasourcesSuite) TestTokenAuth(c *C) {
   113  	s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
   114  	defer s.v.vc.Logical().Delete("secret/foo")
   115  	tok, err := s.v.tokenCreate("readpol", 5)
   116  	handle(c, err)
   117  
   118  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   119  		"-d", "vault=vault:///secret",
   120  		"-i", `{{(ds "vault" "foo").value}}`,
   121  	), func(c *icmd.Cmd) {
   122  		c.Env = []string{
   123  			"VAULT_ADDR=http://" + s.v.addr,
   124  			"VAULT_TOKEN=" + tok,
   125  		}
   126  	})
   127  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   128  
   129  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   130  		"-d", "vault=vault+http://"+s.v.addr+"/secret",
   131  		"-i", `{{(ds "vault" "foo").value}}`,
   132  	), func(c *icmd.Cmd) {
   133  		c.Env = []string{
   134  			"VAULT_TOKEN=" + tok,
   135  		}
   136  	})
   137  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   138  
   139  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   140  		"-d", "vault=vault:///secret",
   141  		"-i", `{{(ds "vault" "bar").value}}`,
   142  	), func(c *icmd.Cmd) {
   143  		c.Env = []string{
   144  			"VAULT_ADDR=http://" + s.v.addr,
   145  			"VAULT_TOKEN=" + tok,
   146  		}
   147  	})
   148  	result.Assert(c, icmd.Expected{ExitCode: 1, Err: "error calling ds: Couldn't read datasource 'vault': no value found for path /secret/bar"})
   149  
   150  	tokFile := fs.NewFile(c, "test-vault-token", fs.WithContent(tok))
   151  	defer tokFile.Remove()
   152  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   153  		"-d", "vault=vault:///secret",
   154  		"-i", `{{(ds "vault" "foo").value}}`,
   155  	), func(c *icmd.Cmd) {
   156  		c.Env = []string{
   157  			"VAULT_ADDR=http://" + s.v.addr,
   158  			"VAULT_TOKEN_FILE=" + tokFile.Path(),
   159  		}
   160  	})
   161  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   162  }
   163  
   164  func (s *VaultDatasourcesSuite) TestUserPassAuth(c *C) {
   165  	s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
   166  	defer s.v.vc.Logical().Delete("secret/foo")
   167  	err := s.v.vc.Sys().EnableAuth("userpass", "userpass", "")
   168  	handle(c, err)
   169  	err = s.v.vc.Sys().EnableAuth("userpass2", "userpass", "")
   170  	handle(c, err)
   171  	defer s.v.vc.Sys().DisableAuth("userpass")
   172  	defer s.v.vc.Sys().DisableAuth("userpass2")
   173  	_, err = s.v.vc.Logical().Write("auth/userpass/users/dave", map[string]interface{}{
   174  		"password": "foo", "ttl": "10s", "policies": "readpol"})
   175  	handle(c, err)
   176  	_, err = s.v.vc.Logical().Write("auth/userpass2/users/dave", map[string]interface{}{
   177  		"password": "bar", "ttl": "10s", "policies": "readpol"})
   178  	handle(c, err)
   179  
   180  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   181  		"-d", "vault=vault:///secret",
   182  		"-i", `{{(ds "vault" "foo").value}}`,
   183  	), func(c *icmd.Cmd) {
   184  		c.Env = []string{
   185  			"VAULT_ADDR=http://" + s.v.addr,
   186  			"VAULT_AUTH_USERNAME=dave", "VAULT_AUTH_PASSWORD=foo",
   187  		}
   188  	})
   189  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   190  
   191  	userFile := fs.NewFile(c, "test-vault-user", fs.WithContent("dave"))
   192  	passFile := fs.NewFile(c, "test-vault-pass", fs.WithContent("foo"))
   193  	defer userFile.Remove()
   194  	defer passFile.Remove()
   195  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   196  		"-d", "vault=vault:///secret",
   197  		"-i", `{{(ds "vault" "foo").value}}`,
   198  	), func(c *icmd.Cmd) {
   199  		c.Env = []string{
   200  			"VAULT_ADDR=http://" + s.v.addr,
   201  			"VAULT_AUTH_USERNAME_FILE=" + userFile.Path(),
   202  			"VAULT_AUTH_PASSWORD_FILE=" + passFile.Path(),
   203  		}
   204  	})
   205  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   206  
   207  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   208  		"-d", "vault=vault:///secret",
   209  		"-i", `{{(ds "vault" "foo").value}}`,
   210  	), func(c *icmd.Cmd) {
   211  		c.Env = []string{
   212  			"VAULT_ADDR=http://" + s.v.addr,
   213  			"VAULT_AUTH_USERNAME=dave", "VAULT_AUTH_PASSWORD=bar",
   214  			"VAULT_AUTH_USERPASS_MOUNT=userpass2",
   215  		}
   216  	})
   217  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   218  }
   219  
   220  func (s *VaultDatasourcesSuite) TestAppRoleAuth(c *C) {
   221  	s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
   222  	defer s.v.vc.Logical().Delete("secret/foo")
   223  	err := s.v.vc.Sys().EnableAuth("approle", "approle", "")
   224  	handle(c, err)
   225  	err = s.v.vc.Sys().EnableAuth("approle2", "approle", "")
   226  	handle(c, err)
   227  	defer s.v.vc.Sys().DisableAuth("approle")
   228  	defer s.v.vc.Sys().DisableAuth("approle2")
   229  	_, err = s.v.vc.Logical().Write("auth/approle/role/testrole", map[string]interface{}{
   230  		"secret_id_ttl": "10s", "token_ttl": "20s",
   231  		"secret_id_num_uses": "1", "policies": "readpol",
   232  	})
   233  	handle(c, err)
   234  	_, err = s.v.vc.Logical().Write("auth/approle2/role/testrole", map[string]interface{}{
   235  		"secret_id_ttl": "10s", "token_ttl": "20s",
   236  		"secret_id_num_uses": "1", "policies": "readpol",
   237  	})
   238  	handle(c, err)
   239  
   240  	rid, _ := s.v.vc.Logical().Read("auth/approle/role/testrole/role-id")
   241  	roleID := rid.Data["role_id"].(string)
   242  	sid, _ := s.v.vc.Logical().Write("auth/approle/role/testrole/secret-id", nil)
   243  	secretID := sid.Data["secret_id"].(string)
   244  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   245  		"-d", "vault=vault:///secret",
   246  		"-i", `{{(ds "vault" "foo").value}}`,
   247  	), func(c *icmd.Cmd) {
   248  		c.Env = []string{
   249  			"VAULT_ADDR=http://" + s.v.addr,
   250  			"VAULT_ROLE_ID=" + roleID,
   251  			"VAULT_SECRET_ID=" + secretID,
   252  		}
   253  	})
   254  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   255  
   256  	rid, _ = s.v.vc.Logical().Read("auth/approle2/role/testrole/role-id")
   257  	roleID = rid.Data["role_id"].(string)
   258  	sid, _ = s.v.vc.Logical().Write("auth/approle2/role/testrole/secret-id", nil)
   259  	secretID = sid.Data["secret_id"].(string)
   260  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   261  		"-d", "vault=vault:///secret",
   262  		"-i", `{{(ds "vault" "foo").value}}`,
   263  	), func(c *icmd.Cmd) {
   264  		c.Env = []string{
   265  			"VAULT_ADDR=http://" + s.v.addr,
   266  			"VAULT_ROLE_ID=" + roleID,
   267  			"VAULT_SECRET_ID=" + secretID,
   268  			"VAULT_AUTH_APPROLE_MOUNT=approle2",
   269  		}
   270  	})
   271  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   272  }
   273  
   274  func (s *VaultDatasourcesSuite) TestAppIDAuth(c *C) {
   275  	s.v.vc.Logical().Write("secret/foo", map[string]interface{}{"value": "bar"})
   276  	defer s.v.vc.Logical().Delete("secret/foo")
   277  	err := s.v.vc.Sys().EnableAuth("app-id", "app-id", "")
   278  	handle(c, err)
   279  	err = s.v.vc.Sys().EnableAuth("app-id2", "app-id", "")
   280  	handle(c, err)
   281  	defer s.v.vc.Sys().DisableAuth("app-id")
   282  	defer s.v.vc.Sys().DisableAuth("app-id2")
   283  	_, err = s.v.vc.Logical().Write("auth/app-id/map/app-id/testappid", map[string]interface{}{
   284  		"display_name": "test_app_id", "value": "readpol",
   285  	})
   286  	handle(c, err)
   287  	_, err = s.v.vc.Logical().Write("auth/app-id/map/user-id/testuserid", map[string]interface{}{
   288  		"value": "testappid",
   289  	})
   290  	handle(c, err)
   291  	_, err = s.v.vc.Logical().Write("auth/app-id2/map/app-id/testappid", map[string]interface{}{
   292  		"display_name": "test_app_id", "value": "readpol",
   293  	})
   294  	handle(c, err)
   295  	_, err = s.v.vc.Logical().Write("auth/app-id2/map/user-id/testuserid", map[string]interface{}{
   296  		"value": "testappid",
   297  	})
   298  	handle(c, err)
   299  
   300  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   301  		"-d", "vault=vault:///secret",
   302  		"-i", `{{(ds "vault" "foo").value}}`,
   303  	), func(c *icmd.Cmd) {
   304  		c.Env = []string{
   305  			"VAULT_ADDR=http://" + s.v.addr,
   306  			"VAULT_APP_ID=testappid",
   307  			"VAULT_USER_ID=testuserid",
   308  		}
   309  	})
   310  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   311  
   312  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   313  		"-d", "vault=vault:///secret",
   314  		"-i", `{{(ds "vault" "foo").value}}`,
   315  	), func(c *icmd.Cmd) {
   316  		c.Env = []string{
   317  			"VAULT_ADDR=http://" + s.v.addr,
   318  			"VAULT_APP_ID=testappid",
   319  			"VAULT_USER_ID=testuserid",
   320  			"VAULT_AUTH_APP_ID_MOUNT=app-id2",
   321  		}
   322  	})
   323  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar"})
   324  }
   325  
   326  func (s *VaultDatasourcesSuite) TestDynamicAuth(c *C) {
   327  	err := s.v.vc.Sys().Mount("ssh/", &vaultapi.MountInput{Type: "ssh"})
   328  	handle(c, err)
   329  	defer s.v.vc.Sys().Unmount("ssh")
   330  
   331  	_, err = s.v.vc.Logical().Write("ssh/roles/test", map[string]interface{}{
   332  		"key_type": "otp", "default_user": "user", "cidr_list": "10.0.0.0/8",
   333  	})
   334  	handle(c, err)
   335  	testCommands := []icmd.Cmd{
   336  		icmd.Command(GomplateBin,
   337  			"-d", "vault=vault:///",
   338  			"-i", `{{(ds "vault" "ssh/creds/test?ip=10.1.2.3&username=user").ip}}`,
   339  		),
   340  		icmd.Command(GomplateBin,
   341  			"-d", "vault=vault:///ssh/creds/test",
   342  			"-i", `{{(ds "vault" "?ip=10.1.2.3&username=user").ip}}`,
   343  		),
   344  		icmd.Command(GomplateBin,
   345  			"-d", "vault=vault:///ssh/creds/test?ip=10.1.2.3&username=user",
   346  			"-i", `{{(ds "vault").ip}}`,
   347  		),
   348  		icmd.Command(GomplateBin,
   349  			"-d", "vault=vault:///?ip=10.1.2.3&username=user",
   350  			"-i", `{{(ds "vault" "ssh/creds/test").ip}}`,
   351  		),
   352  	}
   353  	tok, err := s.v.tokenCreate("writepol", len(testCommands)*2)
   354  	handle(c, err)
   355  
   356  	for _, v := range testCommands {
   357  		result := icmd.RunCmd(v, func(c *icmd.Cmd) {
   358  			c.Env = []string{
   359  				"VAULT_ADDR=http://" + s.v.addr,
   360  				"VAULT_TOKEN=" + tok,
   361  			}
   362  		})
   363  		result.Assert(c, icmd.Expected{ExitCode: 0, Out: "10.1.2.3"})
   364  	}
   365  }
   366  
   367  func (s *VaultDatasourcesSuite) TestList(c *C) {
   368  	s.v.vc.Logical().Write("secret/dir/foo", map[string]interface{}{"value": "one"})
   369  	s.v.vc.Logical().Write("secret/dir/bar", map[string]interface{}{"value": "two"})
   370  	defer s.v.vc.Logical().Delete("secret/dir/foo")
   371  	defer s.v.vc.Logical().Delete("secret/dir/bar")
   372  	tok, err := s.v.tokenCreate("listpol", 5)
   373  	handle(c, err)
   374  
   375  	result := icmd.RunCmd(icmd.Command(GomplateBin,
   376  		"-d", "vault=vault:///secret/dir/",
   377  		"-i", `{{ range (ds "vault" ) }}{{ . }}: {{ (ds "vault" .).value }} {{end}}`,
   378  	), func(c *icmd.Cmd) {
   379  		c.Env = []string{
   380  			"VAULT_ADDR=http://" + s.v.addr,
   381  			"VAULT_TOKEN=" + tok,
   382  		}
   383  	})
   384  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar: two foo: one"})
   385  
   386  	result = icmd.RunCmd(icmd.Command(GomplateBin,
   387  		"-d", "vault=vault+http://"+s.v.addr+"/secret",
   388  		"-i", `{{ range (ds "vault" "dir/" ) }}{{ . }} {{end}}`,
   389  	), func(c *icmd.Cmd) {
   390  		c.Env = []string{
   391  			"VAULT_TOKEN=" + tok,
   392  		}
   393  	})
   394  	result.Assert(c, icmd.Expected{ExitCode: 0, Out: "bar foo"})
   395  }