1package awsauth
2
3import (
4	"context"
5	"encoding/base64"
6	"encoding/json"
7	"fmt"
8	"io/ioutil"
9	"net/http"
10	"os"
11	"strings"
12	"testing"
13	"time"
14
15	"github.com/aws/aws-sdk-go/aws/session"
16	"github.com/aws/aws-sdk-go/service/sts"
17	"github.com/hashicorp/vault/helper/policyutil"
18	"github.com/hashicorp/vault/logical"
19	"github.com/hashicorp/vault/logical/framework"
20	logicaltest "github.com/hashicorp/vault/logical/testing"
21)
22
23const testVaultHeaderValue = "VaultAcceptanceTesting"
24const testValidRoleName = "valid-role"
25const testInvalidRoleName = "invalid-role"
26
27func TestBackend_CreateParseVerifyRoleTag(t *testing.T) {
28	// create a backend
29	config := logical.TestBackendConfig()
30	storage := &logical.InmemStorage{}
31	config.StorageView = storage
32
33	b, err := Backend(config)
34	if err != nil {
35		t.Fatal(err)
36	}
37
38	err = b.Setup(context.Background(), config)
39	if err != nil {
40		t.Fatal(err)
41	}
42
43	// create a role entry
44	data := map[string]interface{}{
45		"auth_type":    "ec2",
46		"policies":     "p,q,r,s",
47		"bound_ami_id": "abcd-123",
48	}
49	resp, err := b.HandleRequest(context.Background(), &logical.Request{
50		Operation: logical.CreateOperation,
51		Path:      "role/abcd-123",
52		Storage:   storage,
53		Data:      data,
54	})
55	if resp != nil && resp.IsError() {
56		t.Fatalf("failed to create role")
57	}
58	if err != nil {
59		t.Fatal(err)
60	}
61
62	// read the created role entry
63	roleEntry, err := b.lockedAWSRole(context.Background(), storage, "abcd-123")
64	if err != nil {
65		t.Fatal(err)
66	}
67
68	// create a nonce for the role tag
69	nonce, err := createRoleTagNonce()
70	if err != nil {
71		t.Fatal(err)
72	}
73	rTag1 := &roleTag{
74		Version:  "v1",
75		Role:     "abcd-123",
76		Nonce:    nonce,
77		Policies: []string{"p", "q", "r"},
78		MaxTTL:   200000000000, // 200s
79	}
80
81	// create a role tag against the role entry
82	val, err := createRoleTagValue(rTag1, roleEntry)
83	if err != nil {
84		t.Fatal(err)
85	}
86	if val == "" {
87		t.Fatalf("failed to create role tag")
88	}
89
90	// parse the created role tag
91	rTag2, err := b.parseAndVerifyRoleTagValue(context.Background(), storage, val)
92	if err != nil {
93		t.Fatal(err)
94	}
95
96	// check the values in parsed role tag
97	if rTag2.Version != "v1" ||
98		rTag2.Nonce != nonce ||
99		rTag2.Role != "abcd-123" ||
100		rTag2.MaxTTL != 200000000000 || // 200s
101		!policyutil.EquivalentPolicies(rTag2.Policies, []string{"p", "q", "r"}) ||
102		len(rTag2.HMAC) == 0 {
103		t.Fatalf("parsed role tag is invalid")
104	}
105
106	// verify the tag contents using role specific HMAC key
107	verified, err := verifyRoleTagValue(rTag2, roleEntry)
108	if err != nil {
109		t.Fatal(err)
110	}
111	if !verified {
112		t.Fatalf("failed to verify the role tag")
113	}
114
115	// register a different role
116	resp, err = b.HandleRequest(context.Background(), &logical.Request{
117		Operation: logical.CreateOperation,
118		Path:      "role/ami-6789",
119		Storage:   storage,
120		Data:      data,
121	})
122	if resp != nil && resp.IsError() {
123		t.Fatalf("failed to create role")
124	}
125	if err != nil {
126		t.Fatal(err)
127	}
128
129	// get the entry of the newly created role entry
130	roleEntry2, err := b.lockedAWSRole(context.Background(), storage, "ami-6789")
131	if err != nil {
132		t.Fatal(err)
133	}
134
135	// try to verify the tag created with previous role's HMAC key
136	// with the newly registered entry's HMAC key
137	verified, err = verifyRoleTagValue(rTag2, roleEntry2)
138	if err != nil {
139		t.Fatal(err)
140	}
141	if verified {
142		t.Fatalf("verification of role tag should have failed")
143	}
144
145	// modify any value in role tag and try to verify it
146	rTag2.Version = "v2"
147	verified, err = verifyRoleTagValue(rTag2, roleEntry)
148	if err != nil {
149		t.Fatal(err)
150	}
151	if verified {
152		t.Fatalf("verification of role tag should have failed: invalid Version")
153	}
154}
155
156func TestBackend_prepareRoleTagPlaintextValue(t *testing.T) {
157	// create a nonce for the role tag
158	nonce, err := createRoleTagNonce()
159	if err != nil {
160		t.Fatal(err)
161	}
162	rTag := &roleTag{
163		Version: "v1",
164		Nonce:   nonce,
165		Role:    "abcd-123",
166	}
167
168	rTag.Version = ""
169	// try to create plaintext part of role tag
170	// without specifying version
171	val, err := prepareRoleTagPlaintextValue(rTag)
172	if err == nil {
173		t.Fatalf("expected error for missing version")
174	}
175	rTag.Version = "v1"
176
177	rTag.Nonce = ""
178	// try to create plaintext part of role tag
179	// without specifying nonce
180	val, err = prepareRoleTagPlaintextValue(rTag)
181	if err == nil {
182		t.Fatalf("expected error for missing nonce")
183	}
184	rTag.Nonce = nonce
185
186	rTag.Role = ""
187	// try to create plaintext part of role tag
188	// without specifying role
189	val, err = prepareRoleTagPlaintextValue(rTag)
190	if err == nil {
191		t.Fatalf("expected error for missing role")
192	}
193	rTag.Role = "abcd-123"
194
195	// create the plaintext part of the tag
196	val, err = prepareRoleTagPlaintextValue(rTag)
197	if err != nil {
198		t.Fatal(err)
199	}
200
201	// verify if it contains known fields
202	if !strings.Contains(val, "r=") ||
203		!strings.Contains(val, "d=") ||
204		!strings.Contains(val, "m=") ||
205		!strings.HasPrefix(val, "v1") {
206		t.Fatalf("incorrect information in role tag plaintext value")
207	}
208
209	rTag.InstanceID = "instance-123"
210	// create the role tag with instance_id specified
211	val, err = prepareRoleTagPlaintextValue(rTag)
212	if err != nil {
213		t.Fatal(err)
214	}
215	// verify it
216	if !strings.Contains(val, "i=") {
217		t.Fatalf("missing instance ID in role tag plaintext value")
218	}
219
220	rTag.MaxTTL = 200000000000
221	// create the role tag with max_ttl specified
222	val, err = prepareRoleTagPlaintextValue(rTag)
223	if err != nil {
224		t.Fatal(err)
225	}
226	// verify it
227	if !strings.Contains(val, "t=") {
228		t.Fatalf("missing max_ttl field in role tag plaintext value")
229	}
230}
231
232func TestBackend_CreateRoleTagNonce(t *testing.T) {
233	// create a nonce for the role tag
234	nonce, err := createRoleTagNonce()
235	if err != nil {
236		t.Fatal(err)
237	}
238	if nonce == "" {
239		t.Fatalf("failed to create role tag nonce")
240	}
241
242	// verify that the value returned is base64 encoded
243	nonceBytes, err := base64.StdEncoding.DecodeString(nonce)
244	if err != nil {
245		t.Fatal(err)
246	}
247	if len(nonceBytes) == 0 {
248		t.Fatalf("length of role tag nonce is zero")
249	}
250}
251
252func TestBackend_ConfigTidyIdentities(t *testing.T) {
253	// create a backend
254	config := logical.TestBackendConfig()
255	storage := &logical.InmemStorage{}
256	config.StorageView = storage
257
258	b, err := Backend(config)
259	if err != nil {
260		t.Fatal(err)
261	}
262
263	err = b.Setup(context.Background(), config)
264	if err != nil {
265		t.Fatal(err)
266	}
267
268	// test update operation
269	tidyRequest := &logical.Request{
270		Operation: logical.UpdateOperation,
271		Path:      "config/tidy/identity-whitelist",
272		Storage:   storage,
273	}
274	data := map[string]interface{}{
275		"safety_buffer":         "60",
276		"disable_periodic_tidy": true,
277	}
278	tidyRequest.Data = data
279	_, err = b.HandleRequest(context.Background(), tidyRequest)
280	if err != nil {
281		t.Fatal(err)
282	}
283
284	// test read operation
285	tidyRequest.Operation = logical.ReadOperation
286	resp, err := b.HandleRequest(context.Background(), tidyRequest)
287	if err != nil {
288		t.Fatal(err)
289	}
290	if resp == nil || resp.IsError() {
291		t.Fatalf("failed to read config/tidy/identity-whitelist endpoint")
292	}
293	if resp.Data["safety_buffer"].(int) != 60 || !resp.Data["disable_periodic_tidy"].(bool) {
294		t.Fatalf("bad: expected: safety_buffer:60 disable_periodic_tidy:true actual: safety_buffer:%d disable_periodic_tidy:%t\n", resp.Data["safety_buffer"].(int), resp.Data["disable_periodic_tidy"].(bool))
295	}
296
297	// test delete operation
298	tidyRequest.Operation = logical.DeleteOperation
299	resp, err = b.HandleRequest(context.Background(), tidyRequest)
300	if err != nil {
301		t.Fatal(err)
302	}
303	if resp != nil {
304		t.Fatalf("failed to delete config/tidy/identity-whitelist")
305	}
306}
307
308func TestBackend_ConfigTidyRoleTags(t *testing.T) {
309	config := logical.TestBackendConfig()
310	storage := &logical.InmemStorage{}
311	config.StorageView = storage
312
313	b, err := Backend(config)
314	if err != nil {
315		t.Fatal(err)
316	}
317
318	err = b.Setup(context.Background(), config)
319	if err != nil {
320		t.Fatal(err)
321	}
322
323	// test update operation
324	tidyRequest := &logical.Request{
325		Operation: logical.UpdateOperation,
326		Path:      "config/tidy/roletag-blacklist",
327		Storage:   storage,
328	}
329	data := map[string]interface{}{
330		"safety_buffer":         "60",
331		"disable_periodic_tidy": true,
332	}
333	tidyRequest.Data = data
334	_, err = b.HandleRequest(context.Background(), tidyRequest)
335	if err != nil {
336		t.Fatal(err)
337	}
338
339	// test read operation
340	tidyRequest.Operation = logical.ReadOperation
341	resp, err := b.HandleRequest(context.Background(), tidyRequest)
342	if err != nil {
343		t.Fatal(err)
344	}
345	if resp == nil || resp.IsError() {
346		t.Fatalf("failed to read config/tidy/roletag-blacklist endpoint")
347	}
348	if resp.Data["safety_buffer"].(int) != 60 || !resp.Data["disable_periodic_tidy"].(bool) {
349		t.Fatalf("bad: expected: safety_buffer:60 disable_periodic_tidy:true actual: safety_buffer:%d disable_periodic_tidy:%t\n", resp.Data["safety_buffer"].(int), resp.Data["disable_periodic_tidy"].(bool))
350	}
351
352	// test delete operation
353	tidyRequest.Operation = logical.DeleteOperation
354	resp, err = b.HandleRequest(context.Background(), tidyRequest)
355	if err != nil {
356		t.Fatal(err)
357	}
358	if resp != nil {
359		t.Fatalf("failed to delete config/tidy/roletag-blacklist")
360	}
361}
362
363func TestBackend_TidyIdentities(t *testing.T) {
364	config := logical.TestBackendConfig()
365	storage := &logical.InmemStorage{}
366	config.StorageView = storage
367
368	b, err := Backend(config)
369	if err != nil {
370		t.Fatal(err)
371	}
372
373	err = b.Setup(context.Background(), config)
374	if err != nil {
375		t.Fatal(err)
376	}
377
378	expiredIdentityWhitelist := &whitelistIdentity{
379		ExpirationTime: time.Now().Add(-1 * 24 * 365 * time.Hour),
380	}
381	entry, err := logical.StorageEntryJSON("whitelist/identity/id1", expiredIdentityWhitelist)
382	if err != nil {
383		t.Fatal(err)
384	}
385	if err := storage.Put(context.Background(), entry); err != nil {
386		t.Fatal(err)
387	}
388
389	// test update operation
390	_, err = b.HandleRequest(context.Background(), &logical.Request{
391		Operation: logical.UpdateOperation,
392		Path:      "tidy/identity-whitelist",
393		Storage:   storage,
394	})
395	if err != nil {
396		t.Fatal(err)
397	}
398
399	// let tidy finish in the background
400	time.Sleep(1 * time.Second)
401
402	entry, err = storage.Get(context.Background(), "whitelist/identity/id1")
403	if err != nil {
404		t.Fatal(err)
405	}
406	if entry != nil {
407		t.Fatal("wl tidy did not remove expired entry")
408	}
409}
410
411func TestBackend_TidyRoleTags(t *testing.T) {
412	config := logical.TestBackendConfig()
413	storage := &logical.InmemStorage{}
414	config.StorageView = storage
415
416	b, err := Backend(config)
417	if err != nil {
418		t.Fatal(err)
419	}
420
421	err = b.Setup(context.Background(), config)
422	if err != nil {
423		t.Fatal(err)
424	}
425
426	expiredIdentityWhitelist := &roleTagBlacklistEntry{
427		ExpirationTime: time.Now().Add(-1 * 24 * 365 * time.Hour),
428	}
429	entry, err := logical.StorageEntryJSON("blacklist/roletag/id1", expiredIdentityWhitelist)
430	if err != nil {
431		t.Fatal(err)
432	}
433	if err := storage.Put(context.Background(), entry); err != nil {
434		t.Fatal(err)
435	}
436
437	// test update operation
438	_, err = b.HandleRequest(context.Background(), &logical.Request{
439		Operation: logical.UpdateOperation,
440		Path:      "tidy/roletag-blacklist",
441		Storage:   storage,
442	})
443	if err != nil {
444		t.Fatal(err)
445	}
446
447	// let tidy finish in the background
448	time.Sleep(1 * time.Second)
449
450	entry, err = storage.Get(context.Background(), "blacklist/roletag/id1")
451	if err != nil {
452		t.Fatal(err)
453	}
454	if entry != nil {
455		t.Fatal("bl tidy did not remove expired entry")
456	}
457}
458
459func TestBackend_ConfigClient(t *testing.T) {
460	config := logical.TestBackendConfig()
461	storage := &logical.InmemStorage{}
462	config.StorageView = storage
463
464	b, err := Backend(config)
465	if err != nil {
466		t.Fatal(err)
467	}
468
469	err = b.Setup(context.Background(), config)
470	if err != nil {
471		t.Fatal(err)
472	}
473
474	data := map[string]interface{}{"access_key": "AKIAJBRHKV6EVTTNXDHA",
475		"secret_key": "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",
476	}
477
478	stepCreate := logicaltest.TestStep{
479		Operation: logical.CreateOperation,
480		Path:      "config/client",
481		Data:      data,
482	}
483
484	stepUpdate := logicaltest.TestStep{
485		Operation: logical.UpdateOperation,
486		Path:      "config/client",
487		Data:      data,
488	}
489
490	data3 := map[string]interface{}{"access_key": "",
491		"secret_key": "mCtSM8ZUEQ3mOFVZYPBQkf2sO6F/W7a5TVzrl3Oj",
492	}
493	stepInvalidAccessKey := logicaltest.TestStep{
494		Operation: logical.UpdateOperation,
495		Path:      "config/client",
496		Data:      data3,
497		ErrorOk:   true,
498	}
499
500	data4 := map[string]interface{}{"access_key": "accesskey",
501		"secret_key": "",
502	}
503	stepInvalidSecretKey := logicaltest.TestStep{
504		Operation: logical.UpdateOperation,
505		Path:      "config/client",
506		Data:      data4,
507		ErrorOk:   true,
508	}
509
510	logicaltest.Test(t, logicaltest.TestCase{
511		AcceptanceTest:    false,
512		CredentialBackend: b,
513		Steps: []logicaltest.TestStep{
514			stepCreate,
515			stepInvalidAccessKey,
516			stepInvalidSecretKey,
517			stepUpdate,
518		},
519	})
520
521	// test existence check returning false
522	checkFound, exists, err := b.HandleExistenceCheck(context.Background(), &logical.Request{
523		Operation: logical.CreateOperation,
524		Path:      "config/client",
525		Storage:   storage,
526	})
527	if err != nil {
528		t.Fatal(err)
529	}
530	if !checkFound {
531		t.Fatal("existence check not found for path 'config/client'")
532	}
533	if exists {
534		t.Fatal("existence check should have returned 'false' for 'config/client'")
535	}
536
537	// create an entry
538	configClientCreateRequest := &logical.Request{
539		Operation: logical.UpdateOperation,
540		Path:      "config/client",
541		Data:      data,
542		Storage:   storage,
543	}
544	_, err = b.HandleRequest(context.Background(), configClientCreateRequest)
545	if err != nil {
546		t.Fatal(err)
547	}
548
549	//test existence check returning true
550	checkFound, exists, err = b.HandleExistenceCheck(context.Background(), &logical.Request{
551		Operation: logical.CreateOperation,
552		Path:      "config/client",
553		Storage:   storage,
554	})
555	if err != nil {
556		t.Fatal(err)
557	}
558	if !checkFound {
559		t.Fatal("existence check not found for path 'config/client'")
560	}
561	if !exists {
562		t.Fatal("existence check should have returned 'true' for 'config/client'")
563	}
564
565	endpointData := map[string]interface{}{
566		"secret_key": "secretkey",
567		"access_key": "accesskey",
568		"endpoint":   "endpointvalue",
569	}
570
571	endpointReq := &logical.Request{
572		Operation: logical.UpdateOperation,
573		Path:      "config/client",
574		Storage:   storage,
575		Data:      endpointData,
576	}
577	_, err = b.HandleRequest(context.Background(), endpointReq)
578	if err != nil {
579		t.Fatal(err)
580	}
581
582	endpointReq.Operation = logical.ReadOperation
583	resp, err := b.HandleRequest(context.Background(), endpointReq)
584	if err != nil {
585		t.Fatal(err)
586	}
587	if resp == nil ||
588		resp.IsError() {
589		t.Fatalf("")
590	}
591	actual := resp.Data["endpoint"].(string)
592	if actual != "endpointvalue" {
593		t.Fatalf("bad: endpoint: expected:endpointvalue actual:%s\n", actual)
594	}
595}
596
597func TestBackend_pathConfigCertificate(t *testing.T) {
598	config := logical.TestBackendConfig()
599	storage := &logical.InmemStorage{}
600	config.StorageView = storage
601
602	b, err := Backend(config)
603	if err != nil {
604		t.Fatal(err)
605	}
606
607	err = b.Setup(context.Background(), config)
608	if err != nil {
609		t.Fatal(err)
610	}
611
612	certReq := &logical.Request{
613		Operation: logical.CreateOperation,
614		Storage:   storage,
615		Path:      "config/certificate/cert1",
616	}
617	checkFound, exists, err := b.HandleExistenceCheck(context.Background(), certReq)
618	if err != nil {
619		t.Fatal(err)
620	}
621	if !checkFound {
622		t.Fatal("existence check not found for path 'config/certificate/cert1'")
623	}
624	if exists {
625		t.Fatal("existence check should have returned 'false' for 'config/certificate/cert1'")
626	}
627
628	data := map[string]interface{}{
629		"type": "pkcs7",
630		"aws_public_cert": `LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM3VENDQXEwQ0NRQ1d1a2paNVY0YVp6QUpC
631Z2NxaGtqT09BUURNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Sa3cKRndZRFZRUUlFeEJYWVhOb2FXNW5k
632Rzl1SUZOMFlYUmxNUkF3RGdZRFZRUUhFd2RUWldGMGRHeGxNU0F3SGdZRApWUVFLRXhkQmJXRjZi
633MjRnVjJWaUlGTmxjblpwWTJWeklFeE1RekFlRncweE1qQXhNRFV4TWpVMk1USmFGdzB6Ck9EQXhN
634RFV4TWpVMk1USmFNRnd4Q3pBSkJnTlZCQVlUQWxWVE1Sa3dGd1lEVlFRSUV4QlhZWE5vYVc1bmRH
635OXUKSUZOMFlYUmxNUkF3RGdZRFZRUUhFd2RUWldGMGRHeGxNU0F3SGdZRFZRUUtFeGRCYldGNmIy
636NGdWMlZpSUZObApjblpwWTJWeklFeE1RekNDQWJjd2dnRXNCZ2NxaGtqT09BUUJNSUlCSHdLQmdR
637Q2prdmNTMmJiMVZRNHl0LzVlCmloNU9PNmtLL24xTHpsbHI3RDhad3RRUDhmT0VwcDVFMm5nK0Q2
638VWQxWjFnWWlwcjU4S2ozbnNzU05wSTZiWDMKVnlJUXpLN3dMY2xuZC9Zb3pxTk5tZ0l5WmVjTjdF
639Z2xLOUlUSEpMUCt4OEZ0VXB0M1FieVlYSmRtVk1lZ042UApodmlZdDVKSC9uWWw0aGgzUGExSEpk
640c2tnUUlWQUxWSjNFUjExK0tvNHRQNm53dkh3aDYrRVJZUkFvR0JBSTFqCmsrdGtxTVZIdUFGY3ZB
641R0tvY1Rnc2pKZW02LzVxb216SnVLRG1iSk51OVF4dzNyQW90WGF1OFFlK01CY0psL1UKaGh5MUtI
642VnBDR2w5ZnVlUTJzNklMMENhTy9idXljVTFDaVlRazQwS05IQ2NIZk5pWmJkbHgxRTlycFVwN2Ju
643RgpsUmEydjFudE1YM2NhUlZEZGJ0UEVXbWR4U0NZc1lGRGs0bVpyT0xCQTRHRUFBS0JnRWJtZXZl
644NWY4TElFL0dmCk1ObVA5Q001ZW92UU9HeDVobzhXcUQrYVRlYnMrazJ0bjkyQkJQcWVacXBXUmE1
645UC8ranJkS21sMXF4NGxsSFcKTVhyczNJZ0liNitoVUlCK1M4ZHo4L21tTzBicHI3NlJvWlZDWFlh
646YjJDWmVkRnV0N3FjM1dVSDkrRVVBSDVtdwp2U2VEQ09VTVlRUjdSOUxJTll3b3VISXppcVFZTUFr
647R0J5cUdTTTQ0QkFNREx3QXdMQUlVV1hCbGs0MHhUd1N3CjdIWDMyTXhYWXJ1c2U5QUNGQk5HbWRY
648MlpCclZOR3JOOU4yZjZST2swazlLCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K
649`,
650	}
651
652	certReq.Data = data
653	// test create operation
654	resp, err := b.HandleRequest(context.Background(), certReq)
655	if err != nil || (resp != nil && resp.IsError()) {
656		t.Fatalf("resp: %#v, err: %v", resp, err)
657	}
658
659	certReq.Data = nil
660	// test existence check
661	checkFound, exists, err = b.HandleExistenceCheck(context.Background(), certReq)
662	if err != nil {
663		t.Fatal(err)
664	}
665	if !checkFound {
666		t.Fatal("existence check not found for path 'config/certificate/cert1'")
667	}
668	if !exists {
669		t.Fatal("existence check should have returned 'true' for 'config/certificate/cert1'")
670	}
671
672	certReq.Operation = logical.ReadOperation
673	// test read operation
674	resp, err = b.HandleRequest(context.Background(), certReq)
675	if err != nil {
676		t.Fatal(err)
677	}
678	expectedCert := `-----BEGIN CERTIFICATE-----
679MIIC7TCCAq0CCQCWukjZ5V4aZzAJBgcqhkjOOAQDMFwxCzAJBgNVBAYTAlVTMRkw
680FwYDVQQIExBXYXNoaW5ndG9uIFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYD
681VQQKExdBbWF6b24gV2ViIFNlcnZpY2VzIExMQzAeFw0xMjAxMDUxMjU2MTJaFw0z
682ODAxMDUxMjU2MTJaMFwxCzAJBgNVBAYTAlVTMRkwFwYDVQQIExBXYXNoaW5ndG9u
683IFN0YXRlMRAwDgYDVQQHEwdTZWF0dGxlMSAwHgYDVQQKExdBbWF6b24gV2ViIFNl
684cnZpY2VzIExMQzCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQCjkvcS2bb1VQ4yt/5e
685ih5OO6kK/n1Lzllr7D8ZwtQP8fOEpp5E2ng+D6Ud1Z1gYipr58Kj3nssSNpI6bX3
686VyIQzK7wLclnd/YozqNNmgIyZecN7EglK9ITHJLP+x8FtUpt3QbyYXJdmVMegN6P
687hviYt5JH/nYl4hh3Pa1HJdskgQIVALVJ3ER11+Ko4tP6nwvHwh6+ERYRAoGBAI1j
688k+tkqMVHuAFcvAGKocTgsjJem6/5qomzJuKDmbJNu9Qxw3rAotXau8Qe+MBcJl/U
689hhy1KHVpCGl9fueQ2s6IL0CaO/buycU1CiYQk40KNHCcHfNiZbdlx1E9rpUp7bnF
690lRa2v1ntMX3caRVDdbtPEWmdxSCYsYFDk4mZrOLBA4GEAAKBgEbmeve5f8LIE/Gf
691MNmP9CM5eovQOGx5ho8WqD+aTebs+k2tn92BBPqeZqpWRa5P/+jrdKml1qx4llHW
692MXrs3IgIb6+hUIB+S8dz8/mmO0bpr76RoZVCXYab2CZedFut7qc3WUH9+EUAH5mw
693vSeDCOUMYQR7R9LINYwouHIziqQYMAkGByqGSM44BAMDLwAwLAIUWXBlk40xTwSw
6947HX32MxXYruse9ACFBNGmdX2ZBrVNGrN9N2f6ROk0k9K
695-----END CERTIFICATE-----
696`
697	if resp.Data["aws_public_cert"].(string) != expectedCert {
698		t.Fatalf("bad: expected:%s\n got:%s\n", expectedCert, resp.Data["aws_public_cert"].(string))
699	}
700
701	certReq.Operation = logical.CreateOperation
702	certReq.Path = "config/certificate/cert2"
703	certReq.Data = data
704	// create another entry to test the list operation
705	_, err = b.HandleRequest(context.Background(), certReq)
706	if err != nil {
707		t.Fatal(err)
708	}
709
710	certReq.Operation = logical.ListOperation
711	certReq.Path = "config/certificates"
712	// test list operation
713	resp, err = b.HandleRequest(context.Background(), certReq)
714	if err != nil {
715		t.Fatal(err)
716	}
717	if resp == nil || resp.IsError() {
718		t.Fatalf("failed to list config/certificates")
719	}
720	keys := resp.Data["keys"].([]string)
721	if len(keys) != 2 {
722		t.Fatalf("invalid keys listed: %#v\n", keys)
723	}
724
725	certReq.Operation = logical.DeleteOperation
726	certReq.Path = "config/certificate/cert1"
727	_, err = b.HandleRequest(context.Background(), certReq)
728	if err != nil {
729		t.Fatal(err)
730	}
731
732	certReq.Path = "config/certificate/cert2"
733	_, err = b.HandleRequest(context.Background(), certReq)
734	if err != nil {
735		t.Fatal(err)
736	}
737
738	certReq.Operation = logical.ListOperation
739	certReq.Path = "config/certificates"
740	// test list operation
741	resp, err = b.HandleRequest(context.Background(), certReq)
742	if err != nil {
743		t.Fatal(err)
744	}
745	if resp == nil || resp.IsError() {
746		t.Fatalf("failed to list config/certificates")
747	}
748	if resp.Data["keys"] != nil {
749		t.Fatalf("no entries should be present")
750	}
751}
752
753func TestBackend_parseAndVerifyRoleTagValue(t *testing.T) {
754	// create a backend
755	config := logical.TestBackendConfig()
756	storage := &logical.InmemStorage{}
757	config.StorageView = storage
758	b, err := Backend(config)
759	if err != nil {
760		t.Fatal(err)
761	}
762
763	err = b.Setup(context.Background(), config)
764	if err != nil {
765		t.Fatal(err)
766	}
767
768	// create a role
769	data := map[string]interface{}{
770		"auth_type":    "ec2",
771		"policies":     "p,q,r,s",
772		"max_ttl":      "120s",
773		"role_tag":     "VaultRole",
774		"bound_ami_id": "abcd-123",
775	}
776	resp, err := b.HandleRequest(context.Background(), &logical.Request{
777		Operation: logical.CreateOperation,
778		Path:      "role/abcd-123",
779		Storage:   storage,
780		Data:      data,
781	})
782	if resp != nil && resp.IsError() {
783		t.Fatalf("failed to create role")
784	}
785	if err != nil {
786		t.Fatal(err)
787	}
788
789	// verify that the entry is created
790	resp, err = b.HandleRequest(context.Background(), &logical.Request{
791		Operation: logical.ReadOperation,
792		Path:      "role/abcd-123",
793		Storage:   storage,
794	})
795	if err != nil {
796		t.Fatal(err)
797	}
798	if resp == nil {
799		t.Fatalf("expected an role entry for abcd-123")
800	}
801
802	// create a role tag
803	data2 := map[string]interface{}{
804		"policies": "p,q,r,s",
805	}
806	resp, err = b.HandleRequest(context.Background(), &logical.Request{
807		Operation: logical.UpdateOperation,
808		Path:      "role/abcd-123/tag",
809		Storage:   storage,
810		Data:      data2,
811	})
812	if err != nil {
813		t.Fatal(err)
814	}
815	if resp.Data["tag_key"].(string) == "" ||
816		resp.Data["tag_value"].(string) == "" {
817		t.Fatalf("invalid tag response: %#v\n", resp)
818	}
819	tagValue := resp.Data["tag_value"].(string)
820
821	// parse the value and check if the verifiable values match
822	rTag, err := b.parseAndVerifyRoleTagValue(context.Background(), storage, tagValue)
823	if err != nil {
824		t.Fatalf("err: %s", err)
825	}
826	if rTag == nil {
827		t.Fatalf("failed to parse role tag")
828	}
829	if rTag.Version != "v1" ||
830		!policyutil.EquivalentPolicies(rTag.Policies, []string{"p", "q", "r", "s"}) ||
831		rTag.Role != "abcd-123" {
832		t.Fatalf("bad: parsed role tag contains incorrect values. Got: %#v\n", rTag)
833	}
834}
835
836func TestBackend_PathRoleTag(t *testing.T) {
837	config := logical.TestBackendConfig()
838	storage := &logical.InmemStorage{}
839	config.StorageView = storage
840	b, err := Backend(config)
841	if err != nil {
842		t.Fatal(err)
843	}
844
845	err = b.Setup(context.Background(), config)
846	if err != nil {
847		t.Fatal(err)
848	}
849
850	data := map[string]interface{}{
851		"auth_type":    "ec2",
852		"policies":     "p,q,r,s",
853		"max_ttl":      "120s",
854		"role_tag":     "VaultRole",
855		"bound_ami_id": "abcd-123",
856	}
857	resp, err := b.HandleRequest(context.Background(), &logical.Request{
858		Operation: logical.CreateOperation,
859		Path:      "role/abcd-123",
860		Storage:   storage,
861		Data:      data,
862	})
863	if resp != nil && resp.IsError() {
864		t.Fatalf("failed to create role")
865	}
866	if err != nil {
867		t.Fatal(err)
868	}
869
870	resp, err = b.HandleRequest(context.Background(), &logical.Request{
871		Operation: logical.ReadOperation,
872		Path:      "role/abcd-123",
873		Storage:   storage,
874	})
875	if err != nil {
876		t.Fatal(err)
877	}
878	if resp == nil {
879		t.Fatalf("failed to find a role entry for abcd-123")
880	}
881
882	resp, err = b.HandleRequest(context.Background(), &logical.Request{
883		Operation: logical.UpdateOperation,
884		Path:      "role/abcd-123/tag",
885		Storage:   storage,
886	})
887	if err != nil {
888		t.Fatal(err)
889	}
890	if resp == nil || resp.Data == nil {
891		t.Fatalf("failed to create a tag on role: abcd-123")
892	}
893	if resp.IsError() {
894		t.Fatalf("failed to create a tag on role: abcd-123: %s\n", resp.Data["error"])
895	}
896	if resp.Data["tag_value"].(string) == "" {
897		t.Fatalf("role tag not present in the response data: %#v\n", resp.Data)
898	}
899}
900
901func TestBackend_PathBlacklistRoleTag(t *testing.T) {
902	// create the backend
903	storage := &logical.InmemStorage{}
904	config := logical.TestBackendConfig()
905	config.StorageView = storage
906	b, err := Backend(config)
907	if err != nil {
908		t.Fatal(err)
909	}
910
911	err = b.Setup(context.Background(), config)
912	if err != nil {
913		t.Fatal(err)
914	}
915
916	// create an role entry
917	data := map[string]interface{}{
918		"auth_type":    "ec2",
919		"policies":     "p,q,r,s",
920		"role_tag":     "VaultRole",
921		"bound_ami_id": "abcd-123",
922	}
923	resp, err := b.HandleRequest(context.Background(), &logical.Request{
924		Operation: logical.CreateOperation,
925		Path:      "role/abcd-123",
926		Storage:   storage,
927		Data:      data,
928	})
929	if resp != nil && resp.IsError() {
930		t.Fatalf("failed to create role")
931	}
932	if err != nil {
933		t.Fatal(err)
934	}
935
936	// create a role tag against an role registered before
937	data2 := map[string]interface{}{
938		"policies": "p,q,r,s",
939	}
940	resp, err = b.HandleRequest(context.Background(), &logical.Request{
941		Operation: logical.UpdateOperation,
942		Path:      "role/abcd-123/tag",
943		Storage:   storage,
944		Data:      data2,
945	})
946	if err != nil {
947		t.Fatal(err)
948	}
949	if resp == nil || resp.Data == nil {
950		t.Fatalf("failed to create a tag on role: abcd-123")
951	}
952	if resp.IsError() {
953		t.Fatalf("failed to create a tag on role: abcd-123: %s\n", resp.Data["error"])
954	}
955	tag := resp.Data["tag_value"].(string)
956	if tag == "" {
957		t.Fatalf("role tag not present in the response data: %#v\n", resp.Data)
958	}
959
960	// blacklist that role tag
961	resp, err = b.HandleRequest(context.Background(), &logical.Request{
962		Operation: logical.UpdateOperation,
963		Path:      "roletag-blacklist/" + tag,
964		Storage:   storage,
965	})
966	if err != nil {
967		t.Fatal(err)
968	}
969	if resp != nil {
970		t.Fatalf("failed to blacklist the roletag: %s\n", tag)
971	}
972
973	// read the blacklist entry
974	resp, err = b.HandleRequest(context.Background(), &logical.Request{
975		Operation: logical.ReadOperation,
976		Path:      "roletag-blacklist/" + tag,
977		Storage:   storage,
978	})
979	if err != nil {
980		t.Fatal(err)
981	}
982	if resp == nil || resp.Data == nil {
983		t.Fatalf("failed to read the blacklisted role tag: %s\n", tag)
984	}
985	if resp.IsError() {
986		t.Fatalf("failed to read the blacklisted role tag:%s. Err: %s\n", tag, resp.Data["error"])
987	}
988
989	// delete the blacklisted entry
990	_, err = b.HandleRequest(context.Background(), &logical.Request{
991		Operation: logical.DeleteOperation,
992		Path:      "roletag-blacklist/" + tag,
993		Storage:   storage,
994	})
995	if err != nil {
996		t.Fatal(err)
997	}
998
999	// try to read the deleted entry
1000	tagEntry, err := b.lockedBlacklistRoleTagEntry(context.Background(), storage, tag)
1001	if err != nil {
1002		t.Fatal(err)
1003	}
1004	if tagEntry != nil {
1005		t.Fatalf("role tag should not have been present: %s\n", tag)
1006	}
1007}
1008
1009/* This is an acceptance test.
1010   Requires the following env vars:
1011   TEST_AWS_EC2_PKCS7
1012   TEST_AWS_EC2_IDENTITY_DOCUMENT
1013   TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG
1014   TEST_AWS_EC2_AMI_ID
1015   TEST_AWS_EC2_ACCOUNT_ID
1016   TEST_AWS_EC2_IAM_ROLE_ARN
1017
1018   If this is being run on an EC2 instance, you can set the environment vars using this bash snippet:
1019
1020   export TEST_AWS_EC2_PKCS7=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/pkcs7)
1021   export TEST_AWS_EC2_IDENTITY_DOCUMENT=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/document | base64 -w 0)
1022   export TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG=$(curl -s http://169.254.169.254/latest/dynamic/instance-identity/signature | tr -d '\n')
1023   export TEST_AWS_EC2_AMI_ID=$(curl -s http://169.254.169.254/latest/meta-data/ami-id)
1024   export TEST_AWS_EC2_IAM_ROLE_ARN=$(aws iam get-role --role-name $(curl -q http://169.254.169.254/latest/meta-data/iam/security-credentials/ -S -s) --query Role.Arn --output text)
1025   export TEST_AWS_EC2_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
1026
1027   If the test is not being run on an EC2 instance that has access to
1028   credentials using EC2RoleProvider, on top of the above vars, following
1029   needs to be set:
1030   TEST_AWS_SECRET_KEY
1031   TEST_AWS_ACCESS_KEY
1032*/
1033func TestBackendAcc_LoginWithInstanceIdentityDocAndWhitelistIdentity(t *testing.T) {
1034	// This test case should be run only when certain env vars are set and
1035	// executed as an acceptance test.
1036	if os.Getenv(logicaltest.TestEnvVar) == "" {
1037		t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar))
1038		return
1039	}
1040
1041	pkcs7 := os.Getenv("TEST_AWS_EC2_PKCS7")
1042	if pkcs7 == "" {
1043		t.Skipf("env var TEST_AWS_EC2_PKCS7 not set, skipping test")
1044	}
1045
1046	identityDoc := os.Getenv("TEST_AWS_EC2_IDENTITY_DOCUMENT")
1047	if identityDoc == "" {
1048		t.Skipf("env var TEST_AWS_EC2_IDENTITY_DOCUMENT not set, skipping test")
1049	}
1050
1051	identityDocSig := os.Getenv("TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG")
1052	if identityDocSig == "" {
1053		t.Skipf("env var TEST_AWS_EC2_IDENTITY_DOCUMENT_SIG not set, skipping test")
1054	}
1055
1056	amiID := os.Getenv("TEST_AWS_EC2_AMI_ID")
1057	if amiID == "" {
1058		t.Skipf("env var TEST_AWS_EC2_AMI_ID not set, skipping test")
1059	}
1060
1061	iamARN := os.Getenv("TEST_AWS_EC2_IAM_ROLE_ARN")
1062	if iamARN == "" {
1063		t.Skipf("env var TEST_AWS_EC2_IAM_ROLE_ARN not set, skipping test")
1064	}
1065
1066	accountID := os.Getenv("TEST_AWS_EC2_ACCOUNT_ID")
1067	if accountID == "" {
1068		t.Skipf("env var TEST_AWS_EC2_ACCOUNT_ID not set, skipping test")
1069	}
1070
1071	roleName := amiID
1072
1073	// create the backend
1074	storage := &logical.InmemStorage{}
1075	config := logical.TestBackendConfig()
1076	config.StorageView = storage
1077	b, err := Backend(config)
1078	if err != nil {
1079		t.Fatal(err)
1080	}
1081
1082	err = b.Setup(context.Background(), config)
1083	if err != nil {
1084		t.Fatal(err)
1085	}
1086
1087	accessKey := os.Getenv("TEST_AWS_ACCESS_KEY")
1088	secretKey := os.Getenv("TEST_AWS_SECRET_KEY")
1089
1090	// In case of problems with making API calls using the credentials (2FA enabled,
1091	// for instance), the keys need not be set if the test is running on an EC2
1092	// instance with permissions to get the credentials using EC2RoleProvider.
1093	if accessKey != "" && secretKey != "" {
1094		// get the API credentials from env vars
1095		clientConfig := map[string]interface{}{
1096			"access_key": accessKey,
1097			"secret_key": secretKey,
1098		}
1099		if clientConfig["access_key"] == "" ||
1100			clientConfig["secret_key"] == "" {
1101			t.Fatalf("credentials not configured")
1102		}
1103
1104		// store the credentials
1105		_, err = b.HandleRequest(context.Background(), &logical.Request{
1106			Operation: logical.UpdateOperation,
1107			Storage:   storage,
1108			Path:      "config/client",
1109			Data:      clientConfig,
1110		})
1111		if err != nil {
1112			t.Fatal(err)
1113		}
1114	}
1115
1116	loginInput := map[string]interface{}{
1117		"pkcs7": pkcs7,
1118		"nonce": "vault-client-nonce",
1119	}
1120
1121	parsedIdentityDoc, err := b.parseIdentityDocument(context.Background(), storage, pkcs7)
1122	if err != nil {
1123		t.Fatal(err)
1124	}
1125
1126	// Perform the login operation with a AMI ID that is not matching
1127	// the bound on the role.
1128	loginRequest := &logical.Request{
1129		Operation: logical.UpdateOperation,
1130		Path:      "login",
1131		Storage:   storage,
1132		Data:      loginInput,
1133	}
1134
1135	// Baseline role data that should succeed permit login
1136	data := map[string]interface{}{
1137		"auth_type":             "ec2",
1138		"policies":              "root",
1139		"max_ttl":               "120s",
1140		"bound_ami_id":          []string{"wrong_ami_id", amiID, "wrong_ami_id2"},
1141		"bound_account_id":      accountID,
1142		"bound_iam_role_arn":    iamARN,
1143		"bound_ec2_instance_id": []string{parsedIdentityDoc.InstanceID, "i-1234567"},
1144	}
1145
1146	roleReq := &logical.Request{
1147		Operation: logical.CreateOperation,
1148		Path:      "role/" + roleName,
1149		Storage:   storage,
1150		Data:      data,
1151	}
1152
1153	updateRoleExpectLoginFail := func(roleRequest, loginRequest *logical.Request) error {
1154		resp, err := b.HandleRequest(context.Background(), roleRequest)
1155		if err != nil || (resp != nil && resp.IsError()) {
1156			return fmt.Errorf("bad: failed to create role: resp:%#v\nerr:%v", resp, err)
1157		}
1158		resp, err = b.HandleRequest(context.Background(), loginRequest)
1159		if err != nil || resp == nil || (resp != nil && !resp.IsError()) {
1160			return fmt.Errorf("bad: expected login failure: resp:%#v\nerr:%v", resp, err)
1161		}
1162		return nil
1163	}
1164
1165	// Test a role with the wrong AMI ID
1166	data["bound_ami_id"] = []string{"ami-1234567", "ami-7654321"}
1167	if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil {
1168		t.Fatal(err)
1169	}
1170
1171	roleReq.Operation = logical.UpdateOperation
1172	// Place the correct AMI ID in one of the values, but make the AccountID wrong
1173	data["bound_ami_id"] = []string{"wrong_ami_id_1", amiID, "wrong_ami_id_2"}
1174	data["bound_account_id"] = []string{"wrong-account-id", "wrong-account-id-2"}
1175	if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil {
1176		t.Fatal(err)
1177	}
1178
1179	// Place the correct AccountID in one of the values, but make the wrong IAMRoleARN
1180	data["bound_account_id"] = []string{"wrong-account-id-1", accountID, "wrong-account-id-2"}
1181	data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn", "wrong_iam_role_arn_2"}
1182	if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil {
1183		t.Fatal(err)
1184	}
1185
1186	// Place correct IAM role ARN, but incorrect instance ID
1187	data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn_1", iamARN, "wrong_iam_role_arn_2"}
1188	data["bound_ec2_instance_id"] = "i-1234567"
1189	if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil {
1190		t.Fatal(err)
1191	}
1192
1193	// Place correct instance ID, but substring of the IAM role ARN
1194	data["bound_ec2_instance_id"] = []string{parsedIdentityDoc.InstanceID, "i-1234567"}
1195	data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn", iamARN[:len(iamARN)-2], "wrong_iam_role_arn_2"}
1196	if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil {
1197		t.Fatal(err)
1198	}
1199
1200	// place a wildcard in the middle of the role ARN
1201	// The :31 gets arn:aws:iam::123456789012:role/
1202	// This test relies on the role name having at least two characters
1203	data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn", fmt.Sprintf("%s*%s", iamARN[:31], iamARN[32:])}
1204	if err := updateRoleExpectLoginFail(roleReq, loginRequest); err != nil {
1205		t.Fatal(err)
1206	}
1207
1208	// globbed IAM role ARN
1209	data["bound_iam_role_arn"] = []string{"wrong_iam_role_arn_1", fmt.Sprintf("%s*", iamARN[:len(iamARN)-2]), "wrong_iam_role_arn_2"}
1210	resp, err := b.HandleRequest(context.Background(), roleReq)
1211	if err != nil || (resp != nil && resp.IsError()) {
1212		t.Fatalf("bad: failed to create role: resp:%#v\nerr:%v", resp, err)
1213	}
1214
1215	// Now, the login attempt should succeed
1216	resp, err = b.HandleRequest(context.Background(), loginRequest)
1217	if err != nil {
1218		t.Fatal(err)
1219	}
1220	if resp == nil || resp.Auth == nil || resp.IsError() {
1221		t.Fatalf("bad: failed to login: resp:%#v\nerr:%v", resp, err)
1222	}
1223
1224	// Attempt to re-login with the identity signature
1225	delete(loginInput, "pkcs7")
1226	loginInput["identity"] = identityDoc
1227	loginInput["signature"] = identityDocSig
1228	resp, err = b.HandleRequest(context.Background(), loginRequest)
1229	if err != nil {
1230		t.Fatal(err)
1231	}
1232	if resp == nil || resp.Auth == nil || resp.IsError() {
1233		t.Fatalf("bad: failed to login: resp:%#v\nerr:%v", resp, err)
1234	}
1235
1236	// verify the presence of instance_id in the response object.
1237	instanceID := resp.Auth.Metadata["instance_id"]
1238	if instanceID == "" {
1239		t.Fatalf("instance ID not present in the response object")
1240	}
1241	if instanceID != parsedIdentityDoc.InstanceID {
1242		t.Fatalf("instance ID in response (%q) did not match instance ID from identity document (%q)", instanceID, parsedIdentityDoc.InstanceID)
1243	}
1244
1245	_, ok := resp.Auth.Metadata["nonce"]
1246	if ok {
1247		t.Fatalf("client nonce should not have been returned")
1248	}
1249
1250	loginInput["nonce"] = "changed-vault-client-nonce"
1251	// try to login again with changed nonce
1252	resp, err = b.HandleRequest(context.Background(), loginRequest)
1253	if err != nil {
1254		t.Fatal(err)
1255	}
1256	if resp == nil || !resp.IsError() {
1257		t.Fatalf("login attempt should have failed due to client nonce mismatch")
1258	}
1259
1260	// Check if a whitelist identity entry is created after the login.
1261	wlRequest := &logical.Request{
1262		Operation: logical.ReadOperation,
1263		Path:      "identity-whitelist/" + instanceID,
1264		Storage:   storage,
1265	}
1266	resp, err = b.HandleRequest(context.Background(), wlRequest)
1267	if err != nil {
1268		t.Fatal(err)
1269	}
1270	if resp == nil || resp.Data == nil || resp.Data["role"] != roleName {
1271		t.Fatalf("failed to read whitelist identity")
1272	}
1273
1274	// Delete the whitelist identity entry.
1275	wlRequest.Operation = logical.DeleteOperation
1276	resp, err = b.HandleRequest(context.Background(), wlRequest)
1277	if err != nil {
1278		t.Fatal(err)
1279	}
1280	if resp.IsError() {
1281		t.Fatalf("failed to delete whitelist identity")
1282	}
1283
1284	// Allow a fresh login without supplying the nonce
1285	delete(loginInput, "nonce")
1286
1287	resp, err = b.HandleRequest(context.Background(), loginRequest)
1288	if err != nil {
1289		t.Fatal(err)
1290	}
1291	if resp == nil || resp.Auth == nil || resp.IsError() {
1292		t.Fatalf("login attempt failed")
1293	}
1294
1295	_, ok = resp.Auth.Metadata["nonce"]
1296	if !ok {
1297		t.Fatalf("expected nonce to be returned")
1298	}
1299}
1300
1301func TestBackend_pathStsConfig(t *testing.T) {
1302	config := logical.TestBackendConfig()
1303	storage := &logical.InmemStorage{}
1304	config.StorageView = storage
1305	b, err := Backend(config)
1306	if err != nil {
1307		t.Fatal(err)
1308	}
1309
1310	err = b.Setup(context.Background(), config)
1311	if err != nil {
1312		t.Fatal(err)
1313	}
1314	stsReq := &logical.Request{
1315		Operation: logical.CreateOperation,
1316		Storage:   storage,
1317		Path:      "config/sts/account1",
1318	}
1319	checkFound, exists, err := b.HandleExistenceCheck(context.Background(), stsReq)
1320	if err != nil {
1321		t.Fatal(err)
1322	}
1323	if !checkFound {
1324		t.Fatal("existence check not found for path 'config/sts/account1'")
1325	}
1326	if exists {
1327		t.Fatal("existence check should have returned 'false' for 'config/sts/account1'")
1328	}
1329
1330	data := map[string]interface{}{
1331		"sts_role": "arn:aws:iam:account1:role/myRole",
1332	}
1333
1334	stsReq.Data = data
1335	// test create operation
1336	resp, err := b.HandleRequest(context.Background(), stsReq)
1337	if err != nil || (resp != nil && resp.IsError()) {
1338		t.Fatalf("resp: %#v, err: %v", resp, err)
1339	}
1340
1341	stsReq.Data = nil
1342	// test existence check
1343	checkFound, exists, err = b.HandleExistenceCheck(context.Background(), stsReq)
1344	if err != nil {
1345		t.Fatal(err)
1346	}
1347	if !checkFound {
1348		t.Fatal("existence check not found for path 'config/sts/account1'")
1349	}
1350	if !exists {
1351		t.Fatal("existence check should have returned 'true' for 'config/sts/account1'")
1352	}
1353
1354	stsReq.Operation = logical.ReadOperation
1355	// test read operation
1356	resp, err = b.HandleRequest(context.Background(), stsReq)
1357	if err != nil {
1358		t.Fatal(err)
1359	}
1360	expectedStsRole := "arn:aws:iam:account1:role/myRole"
1361	if resp.Data["sts_role"].(string) != expectedStsRole {
1362		t.Fatalf("bad: expected:%s\n got:%s\n", expectedStsRole, resp.Data["sts_role"].(string))
1363	}
1364
1365	stsReq.Operation = logical.CreateOperation
1366	stsReq.Path = "config/sts/account2"
1367	stsReq.Data = data
1368	// create another entry to test the list operation
1369	resp, err = b.HandleRequest(context.Background(), stsReq)
1370	if err != nil || (resp != nil && resp.IsError()) {
1371		t.Fatal(err)
1372	}
1373
1374	stsReq.Operation = logical.ListOperation
1375	stsReq.Path = "config/sts"
1376	// test list operation
1377	resp, err = b.HandleRequest(context.Background(), stsReq)
1378	if err != nil {
1379		t.Fatal(err)
1380	}
1381	if resp == nil || resp.IsError() {
1382		t.Fatalf("failed to list config/sts")
1383	}
1384	keys := resp.Data["keys"].([]string)
1385	if len(keys) != 2 {
1386		t.Fatalf("invalid keys listed: %#v\n", keys)
1387	}
1388
1389	stsReq.Operation = logical.DeleteOperation
1390	stsReq.Path = "config/sts/account1"
1391	resp, err = b.HandleRequest(context.Background(), stsReq)
1392	if err != nil || (resp != nil && resp.IsError()) {
1393		t.Fatal(err)
1394	}
1395
1396	stsReq.Path = "config/sts/account2"
1397	resp, err = b.HandleRequest(context.Background(), stsReq)
1398	if err != nil || (resp != nil && resp.IsError()) {
1399		t.Fatal(err)
1400	}
1401
1402	stsReq.Operation = logical.ListOperation
1403	stsReq.Path = "config/sts"
1404	// test list operation
1405	resp, err = b.HandleRequest(context.Background(), stsReq)
1406	if err != nil {
1407		t.Fatal(err)
1408	}
1409	if resp == nil || resp.IsError() {
1410		t.Fatalf("failed to list config/sts")
1411	}
1412	if resp.Data["keys"] != nil {
1413		t.Fatalf("no entries should be present")
1414	}
1415}
1416
1417func buildCallerIdentityLoginData(request *http.Request, roleName string) (map[string]interface{}, error) {
1418	headersJson, err := json.Marshal(request.Header)
1419	if err != nil {
1420		return nil, err
1421	}
1422	requestBody, err := ioutil.ReadAll(request.Body)
1423	if err != nil {
1424		return nil, err
1425	}
1426	return map[string]interface{}{
1427		"iam_http_request_method": request.Method,
1428		"iam_request_url":         base64.StdEncoding.EncodeToString([]byte(request.URL.String())),
1429		"iam_request_headers":     base64.StdEncoding.EncodeToString(headersJson),
1430		"iam_request_body":        base64.StdEncoding.EncodeToString(requestBody),
1431		"request_role":            roleName,
1432	}, nil
1433}
1434
1435// This is an acceptance test.
1436// If the test is NOT being run on an AWS EC2 instance in an instance profile,
1437// it requires the following environment variables to be set:
1438// TEST_AWS_ACCESS_KEY_ID
1439// TEST_AWS_SECRET_ACCESS_KEY
1440// TEST_AWS_SECURITY_TOKEN or TEST_AWS_SESSION_TOKEN (optional, if you are using short-lived creds)
1441// These are intentionally NOT the "standard" variables to prevent accidentally
1442// using prod creds in acceptance tests
1443func TestBackendAcc_LoginWithCallerIdentity(t *testing.T) {
1444	// This test case should be run only when certain env vars are set and
1445	// executed as an acceptance test.
1446	if os.Getenv(logicaltest.TestEnvVar) == "" {
1447		t.Skip(fmt.Sprintf("Acceptance tests skipped unless env '%s' set", logicaltest.TestEnvVar))
1448		return
1449	}
1450
1451	storage := &logical.InmemStorage{}
1452	config := logical.TestBackendConfig()
1453	config.StorageView = storage
1454	b, err := Backend(config)
1455	if err != nil {
1456		t.Fatal(err)
1457	}
1458
1459	err = b.Setup(context.Background(), config)
1460	if err != nil {
1461		t.Fatal(err)
1462	}
1463
1464	// Override the default AWS env vars (if set) with our test creds
1465	// so that the credential provider chain will pick them up
1466	// NOTE that I'm not bothing to override the shared config file location,
1467	// so if creds are specified there, they will be used before IAM
1468	// instance profile creds
1469	// This doesn't provide perfect leakage protection (e.g., it will still
1470	// potentially pick up credentials from the ~/.config files), but probably
1471	// good enough rather than having to muck around in the low-level details
1472	for _, envvar := range []string{
1473		"AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_SECURITY_TOKEN", "AWS_SESSION_TOKEN"} {
1474		// Skip test if any of the required env vars are missing
1475		testEnvVar := os.Getenv("TEST_" + envvar)
1476		if testEnvVar == "" {
1477			t.Skipf("env var %s not set, skipping test", "TEST_"+envvar)
1478		}
1479
1480		// restore existing environment variables (in case future tests need them)
1481		defer os.Setenv(envvar, os.Getenv(envvar))
1482
1483		os.Setenv(envvar, testEnvVar)
1484	}
1485	awsSession, err := session.NewSession()
1486	if err != nil {
1487		fmt.Println("failed to create session,", err)
1488		return
1489	}
1490
1491	stsService := sts.New(awsSession)
1492	stsInputParams := &sts.GetCallerIdentityInput{}
1493
1494	testIdentity, err := stsService.GetCallerIdentity(stsInputParams)
1495	if err != nil {
1496		t.Fatalf("Received error retrieving identity: %s", err)
1497	}
1498	entity, err := parseIamArn(*testIdentity.Arn)
1499	if err != nil {
1500		t.Fatal(err)
1501	}
1502
1503	// Test setup largely done
1504	// At this point, we're going to:
1505	// 1. Configure the client to require our test header value
1506	// 2. Configure identity to use the ARN for the alias
1507	// 3. Configure two different roles:
1508	//    a. One bound to our test user
1509	//    b. One bound to a garbage ARN
1510	// 4. Pass in a request that doesn't have the signed header, ensure
1511	//    we're not allowed to login
1512	// 5. Passin a request that has a validly signed header, but the wrong
1513	//    value, ensure it doesn't allow login
1514	// 6. Pass in a request that has a validly signed request, ensure
1515	//    it allows us to login to our role
1516	// 7. Pass in a request that has a validly signed request, asking for
1517	//    the other role, ensure it fails
1518
1519	clientConfigData := map[string]interface{}{
1520		"iam_server_id_header_value": testVaultHeaderValue,
1521	}
1522	clientRequest := &logical.Request{
1523		Operation: logical.UpdateOperation,
1524		Path:      "config/client",
1525		Storage:   storage,
1526		Data:      clientConfigData,
1527	}
1528	_, err = b.HandleRequest(context.Background(), clientRequest)
1529	if err != nil {
1530		t.Fatal(err)
1531	}
1532
1533	configIdentityData := map[string]interface{}{
1534		"iam_alias": identityAliasIAMFullArn,
1535	}
1536	configIdentityRequest := &logical.Request{
1537		Operation: logical.UpdateOperation,
1538		Path:      "config/identity",
1539		Storage:   storage,
1540		Data:      configIdentityData,
1541	}
1542	resp, err := b.HandleRequest(context.Background(), configIdentityRequest)
1543	if err != nil {
1544		t.Fatal(err)
1545	}
1546	if resp != nil && resp.IsError() {
1547		t.Fatalf("received error response when configuring identity: %#v", resp)
1548	}
1549
1550	// configuring the valid role we'll be able to login to
1551	roleData := map[string]interface{}{
1552		"bound_iam_principal_arn": []string{entity.canonicalArn(), "arn:aws:iam::123456789012:role/FakeRoleArn1*"}, // Fake ARN MUST be wildcard terminated because we're resolving unique IDs, and the wildcard termination prevents unique ID resolution
1553		"policies":                "root",
1554		"auth_type":               iamAuthType,
1555	}
1556	roleRequest := &logical.Request{
1557		Operation: logical.CreateOperation,
1558		Path:      "role/" + testValidRoleName,
1559		Storage:   storage,
1560		Data:      roleData,
1561	}
1562	resp, err = b.HandleRequest(context.Background(), roleRequest)
1563	if err != nil || (resp != nil && resp.IsError()) {
1564		t.Fatalf("bad: failed to create role: resp:%#v\nerr:%v", resp, err)
1565	}
1566
1567	// configuring a valid role we won't be able to login to
1568	roleDataEc2 := map[string]interface{}{
1569		"auth_type":    "ec2",
1570		"policies":     "root",
1571		"bound_ami_id": "ami-1234567",
1572	}
1573	roleRequestEc2 := &logical.Request{
1574		Operation: logical.CreateOperation,
1575		Path:      "role/ec2only",
1576		Storage:   storage,
1577		Data:      roleDataEc2,
1578	}
1579	resp, err = b.HandleRequest(context.Background(), roleRequestEc2)
1580	if err != nil || (resp != nil && resp.IsError()) {
1581		t.Fatalf("bad: failed to create role; resp:%#v\nerr:%v", resp, err)
1582	}
1583
1584	fakeArn := "arn:aws:iam::123456789012:role/somePath/FakeRole"
1585	fakeArn2 := "arn:aws:iam::123456789012:role/somePath/FakeRole2"
1586	fakeArnResolverCount := 0
1587	fakeArnResolver := func(ctx context.Context, s logical.Storage, arn string) (string, error) {
1588		if strings.HasPrefix(arn, fakeArn) {
1589			fakeArnResolverCount++
1590			return fmt.Sprintf("FakeUniqueIdFor%s%d", arn, fakeArnResolverCount), nil
1591		}
1592		return b.resolveArnToRealUniqueId(context.Background(), s, arn)
1593	}
1594	b.resolveArnToUniqueIDFunc = fakeArnResolver
1595
1596	// now we're creating the invalid role we won't be able to login to
1597	roleData["bound_iam_principal_arn"] = []string{fakeArn, fakeArn2}
1598	roleRequest.Path = "role/" + testInvalidRoleName
1599	resp, err = b.HandleRequest(context.Background(), roleRequest)
1600	if err != nil || (resp != nil && resp.IsError()) {
1601		t.Fatalf("bad: didn't fail to create role: resp:%#v\nerr:%v", resp, err)
1602	}
1603
1604	// now, create the request without the signed header
1605	stsRequestNoHeader, _ := stsService.GetCallerIdentityRequest(stsInputParams)
1606	stsRequestNoHeader.Sign()
1607	loginData, err := buildCallerIdentityLoginData(stsRequestNoHeader.HTTPRequest, testValidRoleName)
1608	if err != nil {
1609		t.Fatal(err)
1610	}
1611	loginRequest := &logical.Request{
1612		Operation: logical.UpdateOperation,
1613		Path:      "login",
1614		Storage:   storage,
1615		Data:      loginData,
1616	}
1617	resp, err = b.HandleRequest(context.Background(), loginRequest)
1618	if err != nil || resp == nil || !resp.IsError() {
1619		t.Errorf("bad: expected failed login due to missing header: resp:%#v\nerr:%v", resp, err)
1620	}
1621
1622	// create the request with the invalid header value
1623
1624	// Not reusing stsRequestNoHeader because the process of signing the request
1625	// and reading the body modifies the underlying request, so it's just cleaner
1626	// to get new requests.
1627	stsRequestInvalidHeader, _ := stsService.GetCallerIdentityRequest(stsInputParams)
1628	stsRequestInvalidHeader.HTTPRequest.Header.Add(iamServerIdHeader, "InvalidValue")
1629	stsRequestInvalidHeader.Sign()
1630	loginData, err = buildCallerIdentityLoginData(stsRequestInvalidHeader.HTTPRequest, testValidRoleName)
1631	if err != nil {
1632		t.Fatal(err)
1633	}
1634	loginRequest = &logical.Request{
1635		Operation: logical.UpdateOperation,
1636		Path:      "login",
1637		Storage:   storage,
1638		Data:      loginData,
1639	}
1640	resp, err = b.HandleRequest(context.Background(), loginRequest)
1641	if err != nil || resp == nil || !resp.IsError() {
1642		t.Errorf("bad: expected failed login due to invalid header: resp:%#v\nerr:%v", resp, err)
1643	}
1644
1645	// Now, valid request against invalid role
1646	stsRequestValid, _ := stsService.GetCallerIdentityRequest(stsInputParams)
1647	stsRequestValid.HTTPRequest.Header.Add(iamServerIdHeader, testVaultHeaderValue)
1648	stsRequestValid.Sign()
1649	loginData, err = buildCallerIdentityLoginData(stsRequestValid.HTTPRequest, testInvalidRoleName)
1650	if err != nil {
1651		t.Fatal(err)
1652	}
1653	loginRequest = &logical.Request{
1654		Operation: logical.UpdateOperation,
1655		Path:      "login",
1656		Storage:   storage,
1657		Data:      loginData,
1658	}
1659	resp, err = b.HandleRequest(context.Background(), loginRequest)
1660	if err != nil || resp == nil || !resp.IsError() {
1661		t.Errorf("bad: expected failed login due to invalid role: resp:%#v\nerr:%v", resp, err)
1662	}
1663
1664	loginData["role"] = "ec2only"
1665	resp, err = b.HandleRequest(context.Background(), loginRequest)
1666	if err != nil || resp == nil || !resp.IsError() {
1667		t.Errorf("bad: expected failed login due to bad auth type: resp:%#v\nerr:%v", resp, err)
1668	}
1669
1670	// finally, the happy path test :)
1671
1672	loginData["role"] = testValidRoleName
1673	resp, err = b.HandleRequest(context.Background(), loginRequest)
1674	if err != nil {
1675		t.Fatal(err)
1676	}
1677	if resp == nil || resp.Auth == nil || resp.IsError() {
1678		t.Fatalf("bad: expected valid login: resp:%#v", resp)
1679	}
1680	if resp.Auth.Alias == nil {
1681		t.Fatalf("bad: nil auth Alias")
1682	}
1683	if resp.Auth.Alias.Name != *testIdentity.Arn {
1684		t.Fatalf("bad: expected identity alias of %q, got %q instead", *testIdentity.Arn, resp.Auth.Alias.Name)
1685	}
1686
1687	renewReq := generateRenewRequest(storage, resp.Auth)
1688	// dump a fake ARN into the metadata to ensure that we ONLY look
1689	// at the unique ID that has been generated
1690	renewReq.Auth.Metadata["canonical_arn"] = "fake_arn"
1691	empty_login_fd := &framework.FieldData{
1692		Raw:    map[string]interface{}{},
1693		Schema: pathLogin(b).Fields,
1694	}
1695	// ensure we can renew
1696	resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd)
1697	if err != nil {
1698		t.Fatal(err)
1699	}
1700	if resp == nil {
1701		t.Fatal("got nil response from renew")
1702	}
1703	if resp.IsError() {
1704		t.Fatalf("got error when renewing: %#v", *resp)
1705	}
1706
1707	// Now, fake out the unique ID resolver to ensure we fail login if the unique ID
1708	// changes from under us
1709	b.resolveArnToUniqueIDFunc = resolveArnToFakeUniqueId
1710	// First, we need to update the role to force Vault to use our fake resolver to
1711	// pick up the fake user ID
1712	roleData["bound_iam_principal_arn"] = entity.canonicalArn()
1713	roleRequest.Path = "role/" + testValidRoleName
1714	resp, err = b.HandleRequest(context.Background(), roleRequest)
1715	if err != nil || (resp != nil && resp.IsError()) {
1716		t.Fatalf("bad: failed to recreate role: resp:%#v\nerr:%v", resp, err)
1717	}
1718	resp, err = b.HandleRequest(context.Background(), loginRequest)
1719	if err != nil || resp == nil || !resp.IsError() {
1720		t.Errorf("bad: expected failed login due to changed AWS role ID: resp: %#v\nerr:%v", resp, err)
1721	}
1722
1723	// and ensure a renew no longer works
1724	resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd)
1725	if err == nil || (resp != nil && !resp.IsError()) {
1726		t.Errorf("bad: expected failed renew due to changed AWS role ID: resp: %#v", resp)
1727	}
1728	// Undo the fake resolver...
1729	b.resolveArnToUniqueIDFunc = b.resolveArnToRealUniqueId
1730
1731	// Now test that wildcard matching works
1732	wildcardRoleName := "valid_wildcard"
1733	wildcardEntity := *entity
1734	wildcardEntity.FriendlyName = "*"
1735	roleData["bound_iam_principal_arn"] = []string{wildcardEntity.canonicalArn(), "arn:aws:iam::123456789012:role/DoesNotExist/Vault_Fake_Role*"}
1736	roleRequest.Path = "role/" + wildcardRoleName
1737	resp, err = b.HandleRequest(context.Background(), roleRequest)
1738	if err != nil || (resp != nil && resp.IsError()) {
1739		t.Fatalf("bad: failed to create wildcard roles: resp:%#v\nerr:%v", resp, err)
1740	}
1741
1742	loginData["role"] = wildcardRoleName
1743	resp, err = b.HandleRequest(context.Background(), loginRequest)
1744	if err != nil {
1745		t.Fatal(err)
1746	}
1747	if resp == nil || resp.Auth == nil || resp.IsError() {
1748		t.Fatalf("bad: expected valid login: resp:%#v", resp)
1749	}
1750	// and ensure we can renew
1751	renewReq = generateRenewRequest(storage, resp.Auth)
1752	resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd)
1753	if err != nil {
1754		t.Fatal(err)
1755	}
1756	if resp == nil {
1757		t.Fatal("got nil response from renew")
1758	}
1759	if resp.IsError() {
1760		t.Fatalf("got error when renewing: %#v", *resp)
1761	}
1762	// ensure the cache is populated
1763	cachedArn := b.getCachedUserId(resp.Auth.Metadata["client_user_id"])
1764	if cachedArn == "" {
1765		t.Errorf("got empty ARN back from user ID cache; expected full arn")
1766	}
1767
1768	// Test for renewal with period
1769	period := 600 * time.Second
1770	roleData["period"] = period.String()
1771	roleRequest.Path = "role/" + testValidRoleName
1772	resp, err = b.HandleRequest(context.Background(), roleRequest)
1773	if err != nil || (resp != nil && resp.IsError()) {
1774		t.Fatalf("bad: failed to create wildcard role: resp:%#v\nerr:%v", resp, err)
1775	}
1776
1777	loginData["role"] = testValidRoleName
1778	resp, err = b.HandleRequest(context.Background(), loginRequest)
1779	if err != nil {
1780		t.Fatal(err)
1781	}
1782	if resp == nil || resp.Auth == nil || resp.IsError() {
1783		t.Fatalf("bad: expected valid login: resp:%#v", resp)
1784	}
1785
1786	renewReq = generateRenewRequest(storage, resp.Auth)
1787	resp, err = b.pathLoginRenew(context.Background(), renewReq, empty_login_fd)
1788	if err != nil {
1789		t.Fatal(err)
1790	}
1791	if resp == nil {
1792		t.Fatal("got nil response from renew")
1793	}
1794	if resp.IsError() {
1795		t.Fatalf("got error when renewing: %#v", *resp)
1796	}
1797
1798	if resp.Auth.Period != period {
1799		t.Fatalf("expected a period value of %s in the response, got: %s", period, resp.Auth.Period)
1800	}
1801}
1802
1803func generateRenewRequest(s logical.Storage, auth *logical.Auth) *logical.Request {
1804	renewReq := &logical.Request{
1805		Storage: s,
1806		Auth:    &logical.Auth{},
1807	}
1808	renewReq.Auth.InternalData = auth.InternalData
1809	renewReq.Auth.Metadata = auth.Metadata
1810	renewReq.Auth.LeaseOptions = auth.LeaseOptions
1811	renewReq.Auth.Policies = auth.Policies
1812	renewReq.Auth.Period = auth.Period
1813
1814	return renewReq
1815}
1816