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 }