1package awsauth
2
3import (
4	"context"
5	"reflect"
6	"strings"
7	"testing"
8
9	"github.com/go-test/deep"
10	"github.com/hashicorp/vault/sdk/helper/policyutil"
11	"github.com/hashicorp/vault/sdk/helper/strutil"
12	"github.com/hashicorp/vault/sdk/logical"
13)
14
15func TestBackend_pathRoleEc2(t *testing.T) {
16	config := logical.TestBackendConfig()
17	storage := &logical.InmemStorage{}
18	config.StorageView = storage
19
20	b, err := Backend(config)
21	if err != nil {
22		t.Fatal(err)
23	}
24
25	err = b.Setup(context.Background(), config)
26	if err != nil {
27		t.Fatal(err)
28	}
29
30	data := map[string]interface{}{
31		"auth_type":    "ec2",
32		"policies":     "p,q,r,s",
33		"max_ttl":      "2h",
34		"bound_ami_id": "ami-abcd123",
35	}
36	resp, err := b.HandleRequest(context.Background(), &logical.Request{
37		Operation: logical.CreateOperation,
38		Path:      "role/ami-abcd123",
39		Data:      data,
40		Storage:   storage,
41	})
42	if resp != nil && resp.IsError() {
43		t.Fatalf("failed to create role")
44	}
45	if err != nil {
46		t.Fatal(err)
47	}
48
49	resp, err = b.HandleRequest(context.Background(), &logical.Request{
50		Operation: logical.ReadOperation,
51		Path:      "role/ami-abcd123",
52		Storage:   storage,
53	})
54	if err != nil {
55		t.Fatal(err)
56	}
57	if resp == nil || resp.IsError() {
58		t.Fatal("failed to read the role entry")
59	}
60	if !policyutil.EquivalentPolicies(strings.Split(data["policies"].(string), ","), resp.Data["policies"].([]string)) {
61		t.Fatalf("bad: policies: expected: %#v\ngot: %#v\n", data, resp.Data)
62	}
63
64	data["allow_instance_migration"] = true
65	data["disallow_reauthentication"] = true
66	resp, err = b.HandleRequest(context.Background(), &logical.Request{
67		Operation: logical.UpdateOperation,
68		Path:      "role/ami-abcd123",
69		Data:      data,
70		Storage:   storage,
71	})
72	if err != nil {
73		t.Fatal(err)
74	}
75	if resp == nil || !resp.IsError() {
76		t.Fatalf("expected failure to create role with both allow_instance_migration true and disallow_reauthentication true")
77	}
78	data["disallow_reauthentication"] = false
79	resp, err = b.HandleRequest(context.Background(), &logical.Request{
80		Operation: logical.UpdateOperation,
81		Path:      "role/ami-abcd123",
82		Data:      data,
83		Storage:   storage,
84	})
85	if err != nil {
86		t.Fatal(err)
87	}
88	if resp != nil && resp.IsError() {
89		t.Fatalf("failure to update role: %v", resp.Data["error"])
90	}
91	resp, err = b.HandleRequest(context.Background(), &logical.Request{
92		Operation: logical.ReadOperation,
93		Path:      "role/ami-abcd123",
94		Storage:   storage,
95	})
96	if err != nil {
97		t.Fatal(err)
98	}
99	if !resp.Data["allow_instance_migration"].(bool) {
100		t.Fatal("bad: expected allow_instance_migration:true got:false\n")
101	}
102
103	if resp.Data["disallow_reauthentication"].(bool) {
104		t.Fatal("bad: expected disallow_reauthentication: false got:true\n")
105	}
106
107	// add another entry, to test listing of role entries
108	data["bound_ami_id"] = "ami-abcd456"
109	resp, err = b.HandleRequest(context.Background(), &logical.Request{
110		Operation: logical.CreateOperation,
111		Path:      "role/ami-abcd456",
112		Data:      data,
113		Storage:   storage,
114	})
115	if resp != nil && resp.IsError() {
116		t.Fatalf("failed to create role: %s", resp.Data["error"])
117	}
118	if err != nil {
119		t.Fatal(err)
120	}
121
122	data["bound_iam_principal_arn"] = ""
123	resp, err = b.HandleRequest(context.Background(), &logical.Request{
124		Operation: logical.UpdateOperation,
125		Path:      "role/ami-abcd456",
126		Data:      data,
127		Storage:   storage,
128	})
129	if err != nil {
130		t.Fatal(err)
131	}
132	if resp != nil && resp.IsError() {
133		t.Fatalf("failed to update role with empty bound_iam_principal_arn: %s", resp.Data["error"])
134	}
135
136	resp, err = b.HandleRequest(context.Background(), &logical.Request{
137		Operation: logical.ListOperation,
138		Path:      "roles",
139		Storage:   storage,
140	})
141	if err != nil {
142		t.Fatal(err)
143	}
144	if resp == nil || resp.Data == nil || resp.IsError() {
145		t.Fatalf("failed to list the role entries")
146	}
147	keys := resp.Data["keys"].([]string)
148	if len(keys) != 2 {
149		t.Fatalf("bad: keys: %#v\n", keys)
150	}
151
152	_, err = b.HandleRequest(context.Background(), &logical.Request{
153		Operation: logical.DeleteOperation,
154		Path:      "role/ami-abcd123",
155		Storage:   storage,
156	})
157	if err != nil {
158		t.Fatal(err)
159	}
160
161	resp, err = b.HandleRequest(context.Background(), &logical.Request{
162		Operation: logical.ReadOperation,
163		Path:      "role/ami-abcd123",
164		Storage:   storage,
165	})
166	if err != nil {
167		t.Fatal(err)
168	}
169	if resp != nil {
170		t.Fatalf("bad: response: expected:nil actual:%#v\n", resp)
171	}
172}
173
174func Test_enableIamIDResolution(t *testing.T) {
175	config := logical.TestBackendConfig()
176	storage := &logical.InmemStorage{}
177	config.StorageView = storage
178
179	b, err := Backend(config)
180	if err != nil {
181		t.Fatal(err)
182	}
183	err = b.Setup(context.Background(), config)
184	if err != nil {
185		t.Fatal(err)
186	}
187	roleName := "upgradable_role"
188
189	b.resolveArnToUniqueIDFunc = resolveArnToFakeUniqueId
190
191	boundIamRoleARNs := []string{"arn:aws:iam::123456789012:role/MyRole", "arn:aws:iam::123456789012:role/path/*"}
192	data := map[string]interface{}{
193		"auth_type":               iamAuthType,
194		"policies":                "p,q",
195		"bound_iam_principal_arn": boundIamRoleARNs,
196		"resolve_aws_unique_ids":  false,
197	}
198
199	submitRequest := func(roleName string, op logical.Operation) (*logical.Response, error) {
200		return b.HandleRequest(context.Background(), &logical.Request{
201			Operation: op,
202			Path:      "role/" + roleName,
203			Data:      data,
204			Storage:   storage,
205		})
206	}
207
208	resp, err := submitRequest(roleName, logical.CreateOperation)
209	if err != nil {
210		t.Fatal(err)
211	}
212	if resp != nil && resp.IsError() {
213		t.Fatalf("failed to create role: %#v", resp)
214	}
215
216	resp, err = submitRequest(roleName, logical.ReadOperation)
217	if err != nil {
218		t.Fatal(err)
219	}
220	if resp == nil || resp.IsError() {
221		t.Fatalf("failed to read role: resp:%#v,\nerr:%#v", resp, err)
222	}
223	if resp.Data["bound_iam_principal_id"] != nil && len(resp.Data["bound_iam_principal_id"].([]string)) > 0 {
224		t.Fatalf("expected to get no unique ID in role, but got %q", resp.Data["bound_iam_principal_id"])
225	}
226
227	data = map[string]interface{}{
228		"resolve_aws_unique_ids": true,
229	}
230	resp, err = submitRequest(roleName, logical.UpdateOperation)
231	if err != nil {
232		t.Fatal(err)
233	}
234	if resp != nil && resp.IsError() {
235		t.Fatalf("unable to upgrade role to resolve internal IDs: resp:%#v", resp)
236	}
237
238	resp, err = submitRequest(roleName, logical.ReadOperation)
239	if err != nil {
240		t.Fatal(err)
241	}
242	if resp == nil || resp.IsError() {
243		t.Fatalf("failed to read role: resp:%#v,\nerr:%#v", resp, err)
244	}
245	principalIDs := resp.Data["bound_iam_principal_id"].([]string)
246	if len(principalIDs) != 1 || principalIDs[0] != "FakeUniqueId1" {
247		t.Fatalf("bad: expected upgrade of role resolve principal ID to %q, but got %q instead", "FakeUniqueId1", resp.Data["bound_iam_principal_id"])
248	}
249	returnedARNs := resp.Data["bound_iam_principal_arn"].([]string)
250	if !strutil.EquivalentSlices(returnedARNs, boundIamRoleARNs) {
251		t.Fatalf("bad: expected to return bound_iam_principal_arn of %q, but got %q instead", boundIamRoleARNs, returnedARNs)
252	}
253}
254
255func TestBackend_pathIam(t *testing.T) {
256	config := logical.TestBackendConfig()
257	storage := &logical.InmemStorage{}
258	config.StorageView = storage
259
260	b, err := Backend(config)
261	if err != nil {
262		t.Fatal(err)
263	}
264	err = b.Setup(context.Background(), config)
265	if err != nil {
266		t.Fatal(err)
267	}
268
269	// make sure we start with empty roles, which gives us confidence that the read later
270	// actually is the two roles we created
271	resp, err := b.HandleRequest(context.Background(), &logical.Request{
272		Operation: logical.ListOperation,
273		Path:      "roles",
274		Storage:   storage,
275	})
276	if err != nil {
277		t.Fatal(err)
278	}
279	if resp == nil || resp.Data == nil || resp.IsError() {
280		t.Fatalf("failed to list role entries")
281	}
282	if resp.Data["keys"] != nil {
283		t.Fatalf("Received roles when expected none")
284	}
285
286	data := map[string]interface{}{
287		"auth_type":               iamAuthType,
288		"policies":                "p,q,r,s",
289		"max_ttl":                 "2h",
290		"bound_iam_principal_arn": "n:aws:iam::123456789012:user/MyUserName",
291		"resolve_aws_unique_ids":  false,
292	}
293	resp, err = b.HandleRequest(context.Background(), &logical.Request{
294		Operation: logical.CreateOperation,
295		Path:      "role/MyRoleName",
296		Data:      data,
297		Storage:   storage,
298	})
299
300	if err != nil {
301		t.Fatal(err)
302	}
303	if resp != nil && resp.IsError() {
304		t.Fatalf("failed to create the role entry; resp: %#v", resp)
305	}
306
307	resp, err = b.HandleRequest(context.Background(), &logical.Request{
308		Operation: logical.ReadOperation,
309		Path:      "role/MyRoleName",
310		Storage:   storage,
311	})
312	if err != nil {
313		t.Fatal(err)
314	}
315	if resp == nil || resp.IsError() {
316		t.Fatal("failed to read the role entry")
317	}
318	if !policyutil.EquivalentPolicies(strings.Split(data["policies"].(string), ","), resp.Data["policies"].([]string)) {
319		t.Fatalf("bad: policies: expected %#v\ngot: %#v\n", data, resp.Data)
320	}
321
322	data["inferred_entity_type"] = "invalid"
323	resp, err = b.HandleRequest(context.Background(), &logical.Request{
324		Operation: logical.CreateOperation,
325		Path:      "role/ShouldNeverExist",
326		Data:      data,
327		Storage:   storage,
328	})
329	if resp == nil || !resp.IsError() {
330		t.Fatalf("Created role with invalid inferred_entity_type")
331	}
332	if err != nil {
333		t.Fatal(err)
334	}
335
336	data["inferred_entity_type"] = ec2EntityType
337	resp, err = b.HandleRequest(context.Background(), &logical.Request{
338		Operation: logical.CreateOperation,
339		Path:      "role/ShouldNeverExist",
340		Data:      data,
341		Storage:   storage,
342	})
343	if resp == nil || !resp.IsError() {
344		t.Fatalf("Created role without necessary inferred_aws_region")
345	}
346	if err != nil {
347		t.Fatal(err)
348	}
349
350	delete(data, "bound_iam_principal_arn")
351	data["inferred_aws_region"] = "us-east-1"
352	resp, err = b.HandleRequest(context.Background(), &logical.Request{
353		Operation: logical.CreateOperation,
354		Path:      "role/ShouldNeverExist",
355		Data:      data,
356		Storage:   storage,
357	})
358	if resp == nil || !resp.IsError() {
359		t.Fatalf("Created role without anything bound")
360	}
361	if err != nil {
362		t.Fatal(err)
363	}
364
365	// generate a second role, ensure we're able to list both
366	data["bound_ami_id"] = "ami-abcd123"
367	secondRole := &logical.Request{
368		Operation: logical.CreateOperation,
369		Path:      "role/MyOtherRoleName",
370		Data:      data,
371		Storage:   storage,
372	}
373	resp, err = b.HandleRequest(context.Background(), secondRole)
374	if err != nil {
375		t.Fatal(err)
376	}
377	if resp != nil && resp.IsError() {
378		t.Fatalf("failed to create additional role: %v", *secondRole)
379	}
380
381	resp, err = b.HandleRequest(context.Background(), &logical.Request{
382		Operation: logical.ListOperation,
383		Path:      "roles",
384		Storage:   storage,
385	})
386	if err != nil {
387		t.Fatal(err)
388	}
389	if resp == nil || resp.Data == nil || resp.IsError() {
390		t.Fatalf("failed to list role entries")
391	}
392	keys := resp.Data["keys"].([]string)
393	if len(keys) != 2 {
394		t.Fatalf("bad: keys %#v\n", keys)
395	}
396
397	resp, err = b.HandleRequest(context.Background(), &logical.Request{
398		Operation: logical.DeleteOperation,
399		Path:      "role/MyOtherRoleName",
400		Storage:   storage,
401	})
402	if err != nil {
403		t.Fatal(err)
404	}
405
406	resp, err = b.HandleRequest(context.Background(), &logical.Request{
407		Operation: logical.ReadOperation,
408		Path:      "role/MyOtherRoleName",
409		Storage:   storage,
410	})
411	if err != nil {
412		t.Fatal(err)
413	}
414	if resp != nil {
415		t.Fatalf("bad: response: expected: nil actual:%3v\n", resp)
416	}
417}
418
419func TestBackend_pathRoleMixedTypes(t *testing.T) {
420	config := logical.TestBackendConfig()
421	storage := &logical.InmemStorage{}
422	config.StorageView = storage
423
424	b, err := Backend(config)
425	if err != nil {
426		t.Fatal(err)
427	}
428	err = b.Setup(context.Background(), config)
429	if err != nil {
430		t.Fatal(err)
431	}
432
433	data := map[string]interface{}{
434		"policies":     "p,q,r,s",
435		"bound_ami_id": "ami-abc1234",
436		"auth_type":    "ec2,invalid",
437	}
438
439	submitRequest := func(roleName string, op logical.Operation) (*logical.Response, error) {
440		return b.HandleRequest(context.Background(), &logical.Request{
441			Operation: op,
442			Path:      "role/" + roleName,
443			Data:      data,
444			Storage:   storage,
445		})
446	}
447
448	resp, err := submitRequest("shouldNeverExist", logical.CreateOperation)
449	if resp == nil || !resp.IsError() {
450		t.Fatalf("created role with invalid auth_type; resp: %#v", resp)
451	}
452	if err != nil {
453		t.Fatal(err)
454	}
455
456	data["auth_type"] = "ec2,,iam"
457	resp, err = submitRequest("shouldNeverExist", logical.CreateOperation)
458	if resp == nil || !resp.IsError() {
459		t.Fatalf("created role mixed auth types")
460	}
461	if err != nil {
462		t.Fatal(err)
463	}
464
465	data["auth_type"] = ec2AuthType
466	resp, err = submitRequest("ec2_to_iam", logical.CreateOperation)
467	if resp != nil && resp.IsError() {
468		t.Fatalf("failed to create valid role; resp: %#v", resp)
469	}
470	if err != nil {
471		t.Fatal(err)
472	}
473
474	data["auth_type"] = iamAuthType
475	delete(data, "bound_ami_id")
476	boundIamPrincipalARNs := []string{"arn:aws:iam::123456789012:role/MyRole", "arn:aws:iam::123456789012:role/path/*"}
477	data["bound_iam_principal_arn"] = boundIamPrincipalARNs
478	resp, err = submitRequest("ec2_to_iam", logical.UpdateOperation)
479	if resp == nil || !resp.IsError() {
480		t.Fatalf("changed auth type on the role")
481	}
482	if err != nil {
483		t.Fatal(err)
484	}
485
486	data["inferred_entity_type"] = ec2EntityType
487	data["inferred_aws_region"] = "us-east-1"
488	data["resolve_aws_unique_ids"] = false
489	resp, err = submitRequest("multipleTypesInferred", logical.CreateOperation)
490	if err != nil {
491		t.Fatal(err)
492	}
493	if resp.IsError() {
494		t.Fatalf("didn't allow creation of roles with only inferred bindings")
495	}
496
497	b.resolveArnToUniqueIDFunc = resolveArnToFakeUniqueId
498	data["resolve_aws_unique_ids"] = true
499	resp, err = submitRequest("withInternalIdResolution", logical.CreateOperation)
500	if err != nil {
501		t.Fatal(err)
502	}
503	if resp.IsError() {
504		t.Fatalf("didn't allow creation of role resolving unique IDs")
505	}
506	resp, err = submitRequest("withInternalIdResolution", logical.ReadOperation)
507	if err != nil {
508		t.Fatal(err)
509	}
510	principalIDs := resp.Data["bound_iam_principal_id"].([]string)
511	if len(principalIDs) != 1 || principalIDs[0] != "FakeUniqueId1" {
512		t.Fatalf("expected fake unique ID of FakeUniqueId1, got %q", resp.Data["bound_iam_principal_id"])
513	}
514	returnedARNs := resp.Data["bound_iam_principal_arn"].([]string)
515	if !strutil.EquivalentSlices(returnedARNs, boundIamPrincipalARNs) {
516		t.Fatalf("bad: expected to return bound_iam_principal_arn of %q, but got %q instead", boundIamPrincipalARNs, returnedARNs)
517	}
518	data["resolve_aws_unique_ids"] = false
519	resp, err = submitRequest("withInternalIdResolution", logical.UpdateOperation)
520	if err != nil {
521		t.Fatal(err)
522	}
523	if !resp.IsError() {
524		t.Fatalf("allowed changing resolve_aws_unique_ids from true to false")
525	}
526
527}
528
529func TestAwsEc2_RoleCrud(t *testing.T) {
530	var err error
531	var resp *logical.Response
532	config := logical.TestBackendConfig()
533	storage := &logical.InmemStorage{}
534	config.StorageView = storage
535
536	b, err := Backend(config)
537	if err != nil {
538		t.Fatal(err)
539	}
540
541	err = b.Setup(context.Background(), config)
542	if err != nil {
543		t.Fatal(err)
544	}
545
546	role1Data := map[string]interface{}{
547		"auth_type":                "ec2",
548		"bound_vpc_id":             "testvpcid",
549		"allow_instance_migration": true,
550		"policies":                 "testpolicy1,testpolicy2",
551	}
552	roleReq := &logical.Request{
553		Operation: logical.UpdateOperation,
554		Storage:   storage,
555		Path:      "role/role1",
556		Data:      role1Data,
557	}
558
559	resp, err = b.HandleRequest(context.Background(), roleReq)
560	if err != nil || (resp != nil && resp.IsError()) {
561		t.Fatalf("resp: %#v, err: %v", resp, err)
562	}
563
564	roleData := map[string]interface{}{
565		"auth_type":                      "ec2",
566		"bound_ami_id":                   "testamiid",
567		"bound_account_id":               "testaccountid",
568		"bound_region":                   "testregion",
569		"bound_iam_role_arn":             "arn:aws:iam::123456789012:role/MyRole",
570		"bound_iam_instance_profile_arn": "arn:aws:iam::123456789012:instance-profile/MyInstancePro*",
571		"bound_subnet_id":                "testsubnetid",
572		"bound_vpc_id":                   "testvpcid",
573		"bound_ec2_instance_id":          "i-12345678901234567,i-76543210987654321",
574		"role_tag":                       "testtag",
575		"resolve_aws_unique_ids":         false,
576		"allow_instance_migration":       true,
577		"ttl":                            "10m",
578		"max_ttl":                        "20m",
579		"policies":                       "testpolicy1,testpolicy2",
580		"disallow_reauthentication":      false,
581		"hmac_key":                       "testhmackey",
582		"period":                         "1m",
583	}
584
585	roleReq.Path = "role/testrole"
586	roleReq.Data = roleData
587	resp, err = b.HandleRequest(context.Background(), roleReq)
588	if err != nil || (resp != nil && resp.IsError()) {
589		t.Fatalf("resp: %#v, err: %v", resp, err)
590	}
591
592	roleReq.Operation = logical.ReadOperation
593	resp, err = b.HandleRequest(context.Background(), roleReq)
594	if err != nil || (resp != nil && resp.IsError()) {
595		t.Fatalf("resp: %#v, err: %v", resp, err)
596	}
597
598	expected := map[string]interface{}{
599		"auth_type":                      ec2AuthType,
600		"bound_ami_id":                   []string{"testamiid"},
601		"bound_account_id":               []string{"testaccountid"},
602		"bound_region":                   []string{"testregion"},
603		"bound_ec2_instance_id":          []string{"i-12345678901234567", "i-76543210987654321"},
604		"bound_iam_principal_arn":        []string{},
605		"bound_iam_principal_id":         []string{},
606		"bound_iam_role_arn":             []string{"arn:aws:iam::123456789012:role/MyRole"},
607		"bound_iam_instance_profile_arn": []string{"arn:aws:iam::123456789012:instance-profile/MyInstancePro*"},
608		"bound_subnet_id":                []string{"testsubnetid"},
609		"bound_vpc_id":                   []string{"testvpcid"},
610		"inferred_entity_type":           "",
611		"inferred_aws_region":            "",
612		"resolve_aws_unique_ids":         false,
613		"role_tag":                       "testtag",
614		"allow_instance_migration":       true,
615		"ttl":                            int64(600),
616		"token_ttl":                      int64(600),
617		"max_ttl":                        int64(1200),
618		"token_max_ttl":                  int64(1200),
619		"token_explicit_max_ttl":         int64(0),
620		"policies":                       []string{"testpolicy1", "testpolicy2"},
621		"token_policies":                 []string{"testpolicy1", "testpolicy2"},
622		"disallow_reauthentication":      false,
623		"period":                         int64(60),
624		"token_period":                   int64(60),
625		"token_bound_cidrs":              []string{},
626		"token_no_default_policy":        false,
627		"token_num_uses":                 0,
628		"token_type":                     "default",
629	}
630
631	if resp.Data["role_id"] == nil {
632		t.Fatal("role_id not found in repsonse")
633	}
634	expected["role_id"] = resp.Data["role_id"]
635	if diff := deep.Equal(expected, resp.Data); diff != nil {
636		t.Fatal(diff)
637	}
638
639	roleData["bound_vpc_id"] = "newvpcid"
640	roleReq.Operation = logical.UpdateOperation
641	resp, err = b.HandleRequest(context.Background(), roleReq)
642	if err != nil || (resp != nil && resp.IsError()) {
643		t.Fatalf("resp: %#v, err: %v", resp, err)
644	}
645
646	roleReq.Operation = logical.ReadOperation
647	resp, err = b.HandleRequest(context.Background(), roleReq)
648	if err != nil || (resp != nil && resp.IsError()) {
649		t.Fatalf("resp: %#v, err: %v", resp, err)
650	}
651	expected["bound_vpc_id"] = []string{"newvpcid"}
652	if !reflect.DeepEqual(expected, resp.Data) {
653		t.Fatalf("bad: role data: expected: %#v\n actual: %#v", expected, resp.Data)
654	}
655
656	// Create a new backend so we have a new cache (thus populating from disk).
657	// Then test reading (reading from disk + lock), writing, reading,
658	// deleting, reading.
659	b, err = Backend(config)
660	if err != nil {
661		t.Fatal(err)
662	}
663
664	err = b.Setup(context.Background(), config)
665	if err != nil {
666		t.Fatal(err)
667	}
668
669	// Read again, make sure things are what we expect
670	resp, err = b.HandleRequest(context.Background(), roleReq)
671	if err != nil || (resp != nil && resp.IsError()) {
672		t.Fatalf("resp: %#v, err: %v", resp, err)
673	}
674	if !reflect.DeepEqual(expected, resp.Data) {
675		t.Fatalf("bad: role data: expected: %#v\n actual: %#v", expected, resp.Data)
676	}
677
678	roleReq.Operation = logical.UpdateOperation
679	roleData["bound_ami_id"] = "testamiid2"
680	resp, err = b.HandleRequest(context.Background(), roleReq)
681	if err != nil || (resp != nil && resp.IsError()) {
682		t.Fatalf("resp: %#v, err: %v", resp, err)
683	}
684
685	roleReq.Operation = logical.ReadOperation
686	resp, err = b.HandleRequest(context.Background(), roleReq)
687	if err != nil || (resp != nil && resp.IsError()) {
688		t.Fatalf("resp: %#v, err: %v", resp, err)
689	}
690
691	expected["bound_ami_id"] = []string{"testamiid2"}
692	if diff := deep.Equal(expected, resp.Data); diff != nil {
693		t.Fatal(diff)
694	}
695
696	// Delete which should remove from disk and also cache
697	roleReq.Operation = logical.DeleteOperation
698	resp, err = b.HandleRequest(context.Background(), roleReq)
699	if err != nil || (resp != nil && resp.IsError()) {
700		t.Fatalf("resp: %#v, err: %v", resp, err)
701	}
702	if resp != nil {
703		t.Fatalf("failed to delete role entry")
704	}
705
706	// Verify it was deleted, e.g. it isn't found in the role cache
707	roleReq.Operation = logical.ReadOperation
708	resp, err = b.HandleRequest(context.Background(), roleReq)
709	if err != nil || (resp != nil && resp.IsError()) {
710		t.Fatalf("resp: %#v, err: %v", resp, err)
711	}
712	if resp != nil {
713		t.Fatal("expected nil")
714	}
715}
716
717func TestAwsEc2_RoleDurationSeconds(t *testing.T) {
718	config := logical.TestBackendConfig()
719	storage := &logical.InmemStorage{}
720	config.StorageView = storage
721
722	b, err := Backend(config)
723	if err != nil {
724		t.Fatal(err)
725	}
726
727	err = b.Setup(context.Background(), config)
728	if err != nil {
729		t.Fatal(err)
730	}
731
732	roleData := map[string]interface{}{
733		"auth_type":                      "ec2",
734		"bound_iam_instance_profile_arn": "arn:aws:iam::123456789012:instance-profile/test-profile-name",
735		"resolve_aws_unique_ids":         false,
736		"ttl":                            "10s",
737		"max_ttl":                        "20s",
738		"period":                         "30s",
739	}
740
741	roleReq := &logical.Request{
742		Operation: logical.CreateOperation,
743		Storage:   storage,
744		Path:      "role/testrole",
745		Data:      roleData,
746	}
747
748	resp, err := b.HandleRequest(context.Background(), roleReq)
749	if err != nil || (resp != nil && resp.IsError()) {
750		t.Fatalf("resp: %#v, err: %v", resp, err)
751	}
752
753	roleReq.Operation = logical.ReadOperation
754
755	resp, err = b.HandleRequest(context.Background(), roleReq)
756	if err != nil || (resp != nil && resp.IsError()) {
757		t.Fatalf("resp: %#v, err: %v", resp, err)
758	}
759
760	if int64(resp.Data["ttl"].(int64)) != 10 {
761		t.Fatalf("bad: period; expected: 10, actual: %d", resp.Data["ttl"])
762	}
763	if int64(resp.Data["max_ttl"].(int64)) != 20 {
764		t.Fatalf("bad: period; expected: 20, actual: %d", resp.Data["max_ttl"])
765	}
766	if int64(resp.Data["period"].(int64)) != 30 {
767		t.Fatalf("bad: period; expected: 30, actual: %d", resp.Data["period"])
768	}
769}
770
771func TestRoleEntryUpgradeV(t *testing.T) {
772	config := logical.TestBackendConfig()
773	storage := &logical.InmemStorage{}
774	config.StorageView = storage
775	b, err := Backend(config)
776	if err != nil {
777		t.Fatal(err)
778	}
779
780	err = b.Setup(context.Background(), config)
781	if err != nil {
782		t.Fatal(err)
783	}
784
785	roleEntryToUpgrade := &awsRoleEntry{
786		BoundIamRoleARNs:            []string{"arn:aws:iam::123456789012:role/my_role_prefix"},
787		BoundIamInstanceProfileARNs: []string{"arn:aws:iam::123456789012:instance-profile/my_profile-prefix"},
788		Version:                     1,
789	}
790	expected := &awsRoleEntry{
791		BoundIamRoleARNs:            []string{"arn:aws:iam::123456789012:role/my_role_prefix*"},
792		BoundIamInstanceProfileARNs: []string{"arn:aws:iam::123456789012:instance-profile/my_profile-prefix*"},
793		Version:                     currentRoleStorageVersion,
794	}
795
796	upgraded, err := b.upgradeRole(context.Background(), storage, roleEntryToUpgrade)
797	if err != nil {
798		t.Fatalf("error upgrading role entry: %#v", err)
799	}
800	if !upgraded {
801		t.Fatalf("expected to upgrade role entry %#v but got no upgrade", roleEntryToUpgrade)
802	}
803	if roleEntryToUpgrade.RoleID == "" {
804		t.Fatal("expected role ID to be populated")
805	}
806	expected.RoleID = roleEntryToUpgrade.RoleID
807	if diff := deep.Equal(*roleEntryToUpgrade, *expected); diff != nil {
808		t.Fatal(diff)
809	}
810}
811
812func TestRoleInitialize(t *testing.T) {
813
814	config := logical.TestBackendConfig()
815	storage := &logical.InmemStorage{}
816	config.StorageView = storage
817	b, err := Backend(config)
818	if err != nil {
819		t.Fatal(err)
820	}
821
822	ctx := context.Background()
823	err = b.Setup(ctx, config)
824	if err != nil {
825		t.Fatal(err)
826	}
827
828	// create some role entries, some of which will need to be upgraded
829	type testData struct {
830		name  string
831		entry *awsRoleEntry
832	}
833
834	before := []testData{
835		{
836			name: "role1",
837			entry: &awsRoleEntry{
838				BoundIamRoleARNs:            []string{"arn:aws:iam::000000000001:role/my_role_prefix"},
839				BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000001:instance-profile/my_profile-prefix"},
840				Version:                     1,
841			},
842		},
843		{
844			name: "role2",
845			entry: &awsRoleEntry{
846				BoundIamRoleARNs:            []string{"arn:aws:iam::000000000002:role/my_role_prefix"},
847				BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000002:instance-profile/my_profile-prefix"},
848				Version:                     2,
849			},
850		},
851		{
852			name: "role3",
853			entry: &awsRoleEntry{
854				BoundIamRoleARNs:            []string{"arn:aws:iam::000000000003:role/my_role_prefix"},
855				BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000003:instance-profile/my_profile-prefix"},
856				Version:                     currentRoleStorageVersion,
857			},
858		},
859	}
860
861	// put the entries in storage
862	for _, role := range before {
863		err = b.setRole(ctx, storage, role.name, role.entry)
864		if err != nil {
865			t.Fatal(err)
866		}
867	}
868
869	// upgrade all the entries
870	upgraded, err := b.upgrade(ctx, storage)
871	if err != nil {
872		t.Fatal(err)
873	}
874	if !upgraded {
875		t.Fatalf("expected upgrade")
876	}
877
878	// read the entries from storage
879	after := make([]testData, 0)
880	names, err := storage.List(ctx, "role/")
881	if err != nil {
882		t.Fatal(err)
883	}
884	for _, name := range names {
885		entry, err := b.role(ctx, storage, name)
886		if err != nil {
887			t.Fatal(err)
888		}
889		after = append(after, testData{name: name, entry: entry})
890	}
891
892	// make sure each entry is at the current version
893	expected := []testData{
894		{
895			name: "role1",
896			entry: &awsRoleEntry{
897				BoundIamRoleARNs:            []string{"arn:aws:iam::000000000001:role/my_role_prefix"},
898				BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000001:instance-profile/my_profile-prefix"},
899				Version:                     currentRoleStorageVersion,
900			},
901		},
902		{
903			name: "role2",
904			entry: &awsRoleEntry{
905				BoundIamRoleARNs:            []string{"arn:aws:iam::000000000002:role/my_role_prefix"},
906				BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000002:instance-profile/my_profile-prefix"},
907				Version:                     currentRoleStorageVersion,
908			},
909		},
910		{
911			name: "role3",
912			entry: &awsRoleEntry{
913				BoundIamRoleARNs:            []string{"arn:aws:iam::000000000003:role/my_role_prefix"},
914				BoundIamInstanceProfileARNs: []string{"arn:aws:iam::000000000003:instance-profile/my_profile-prefix"},
915				Version:                     currentRoleStorageVersion,
916			},
917		},
918	}
919	if diff := deep.Equal(expected, after); diff != nil {
920		t.Fatal(diff)
921	}
922
923	// run it again -- nothing will happen
924	upgraded, err = b.upgrade(ctx, storage)
925	if err != nil {
926		t.Fatal(err)
927	}
928	if upgraded {
929		t.Fatalf("expected no upgrade")
930	}
931
932	// make sure saved role version is correct
933	entry, err := storage.Get(ctx, "config/version")
934	if err != nil {
935		t.Fatal(err)
936	}
937	var version awsVersion
938	err = entry.DecodeJSON(&version)
939	if err != nil {
940		t.Fatal(err)
941	}
942	if version.Version != currentAwsVersion {
943		t.Fatalf("expected version %d, got  %d", currentAwsVersion, version.Version)
944	}
945
946	// stomp on the saved version
947	version.Version = 0
948	e2, err := logical.StorageEntryJSON("config/version", version)
949	if err != nil {
950		t.Fatal(err)
951	}
952	err = storage.Put(ctx, e2)
953	if err != nil {
954		t.Fatal(err)
955	}
956
957	// run it again -- now an upgrade will happen
958	upgraded, err = b.upgrade(ctx, storage)
959	if err != nil {
960		t.Fatal(err)
961	}
962	if !upgraded {
963		t.Fatalf("expected upgrade")
964	}
965}
966
967func TestAwsVersion(t *testing.T) {
968
969	before := awsVersion{
970		Version: 42,
971	}
972
973	entry, err := logical.StorageEntryJSON("config/version", &before)
974	if err != nil {
975		t.Fatal(err)
976	}
977
978	var after awsVersion
979	err = entry.DecodeJSON(&after)
980	if err != nil {
981		t.Fatal(err)
982	}
983
984	if diff := deep.Equal(before, after); diff != nil {
985		t.Fatal(diff)
986	}
987}
988
989func resolveArnToFakeUniqueId(ctx context.Context, s logical.Storage, arn string) (string, error) {
990	return "FakeUniqueId1", nil
991}
992