1package aws 2 3import ( 4 "context" 5 "fmt" 6 "log" 7 "net/http" 8 "os" 9 "reflect" 10 "strings" 11 "sync" 12 "testing" 13 "time" 14 15 "github.com/aws/aws-sdk-go/aws" 16 "github.com/aws/aws-sdk-go/aws/awserr" 17 "github.com/aws/aws-sdk-go/aws/credentials" 18 "github.com/aws/aws-sdk-go/aws/session" 19 "github.com/aws/aws-sdk-go/service/dynamodb" 20 "github.com/aws/aws-sdk-go/service/ec2" 21 "github.com/aws/aws-sdk-go/service/iam" 22 "github.com/aws/aws-sdk-go/service/iam/iamiface" 23 "github.com/aws/aws-sdk-go/service/s3" 24 "github.com/aws/aws-sdk-go/service/sts" 25 cleanhttp "github.com/hashicorp/go-cleanhttp" 26 "github.com/hashicorp/vault/helper/testhelpers" 27 logicaltest "github.com/hashicorp/vault/helper/testhelpers/logical" 28 "github.com/hashicorp/vault/sdk/logical" 29 "github.com/mitchellh/mapstructure" 30) 31 32var initSetup sync.Once 33 34type mockIAMClient struct { 35 iamiface.IAMAPI 36} 37 38func (m *mockIAMClient) CreateUser(input *iam.CreateUserInput) (*iam.CreateUserOutput, error) { 39 return nil, awserr.New("Throttling", "", nil) 40} 41 42func getBackend(t *testing.T) logical.Backend { 43 be, _ := Factory(context.Background(), logical.TestBackendConfig()) 44 return be 45} 46 47func TestBackend_basic(t *testing.T) { 48 t.Parallel() 49 logicaltest.Test(t, logicaltest.TestCase{ 50 AcceptanceTest: true, 51 PreCheck: func() { testAccPreCheck(t) }, 52 LogicalBackend: getBackend(t), 53 Steps: []logicaltest.TestStep{ 54 testAccStepConfig(t), 55 testAccStepWritePolicy(t, "test", testDynamoPolicy), 56 testAccStepRead(t, "creds", "test", []credentialTestFunc{listDynamoTablesTest}), 57 }, 58 }) 59} 60 61func TestBackend_IamUserWithPermissionsBoundary(t *testing.T) { 62 t.Parallel() 63 roleData := map[string]interface{}{ 64 "credential_type": iamUserCred, 65 "policy_arns": adminAccessPolicyArn, 66 "permissions_boundary_arn": iamPolicyArn, 67 } 68 logicaltest.Test(t, logicaltest.TestCase{ 69 AcceptanceTest: true, 70 PreCheck: func() { testAccPreCheck(t) }, 71 LogicalBackend: getBackend(t), 72 Steps: []logicaltest.TestStep{ 73 testAccStepConfig(t), 74 testAccStepWriteRole(t, "test", roleData), 75 testAccStepRead(t, "creds", "test", []credentialTestFunc{listIamUsersTest, describeAzsTestUnauthorized}), 76 }, 77 }) 78} 79 80func TestBackend_basicSTS(t *testing.T) { 81 t.Parallel() 82 awsAccountID, err := getAccountID() 83 if err != nil { 84 t.Logf("Unable to retrive user via sts:GetCallerIdentity: %#v", err) 85 t.Skip("Could not determine AWS account ID from sts:GetCallerIdentity for acceptance tests, skipping") 86 } 87 roleName := generateUniqueName(t.Name()) 88 userName := generateUniqueName(t.Name()) 89 accessKey := &awsAccessKey{} 90 logicaltest.Test(t, logicaltest.TestCase{ 91 AcceptanceTest: true, 92 PreCheck: func() { 93 testAccPreCheck(t) 94 createUser(t, userName, accessKey) 95 createRole(t, roleName, awsAccountID, []string{ec2PolicyArn}) 96 // Sleep sometime because AWS is eventually consistent 97 // Both the createUser and createRole depend on this 98 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 99 time.Sleep(10 * time.Second) 100 }, 101 LogicalBackend: getBackend(t), 102 Steps: []logicaltest.TestStep{ 103 testAccStepConfigWithCreds(t, accessKey), 104 testAccStepRotateRoot(accessKey), 105 testAccStepWritePolicy(t, "test", testDynamoPolicy), 106 testAccStepRead(t, "sts", "test", []credentialTestFunc{listDynamoTablesTest}), 107 testAccStepWriteArnPolicyRef(t, "test", ec2PolicyArn), 108 testAccStepReadSTSWithArnPolicy(t, "test"), 109 testAccStepWriteArnRoleRef(t, "test2", roleName, awsAccountID), 110 testAccStepRead(t, "sts", "test2", []credentialTestFunc{describeInstancesTest}), 111 }, 112 Teardown: func() error { 113 if err := deleteTestRole(roleName); err != nil { 114 return err 115 } 116 return deleteTestUser(accessKey, userName) 117 }, 118 }) 119} 120 121func TestBackend_policyCrud(t *testing.T) { 122 t.Parallel() 123 compacted, err := compactJSON(testDynamoPolicy) 124 if err != nil { 125 t.Fatalf("bad: %s", err) 126 } 127 128 logicaltest.Test(t, logicaltest.TestCase{ 129 AcceptanceTest: true, 130 LogicalBackend: getBackend(t), 131 Steps: []logicaltest.TestStep{ 132 testAccStepConfig(t), 133 testAccStepWritePolicy(t, "test", testDynamoPolicy), 134 testAccStepReadPolicy(t, "test", compacted), 135 testAccStepDeletePolicy(t, "test"), 136 testAccStepReadPolicy(t, "test", ""), 137 }, 138 }) 139} 140 141func TestBackend_throttled(t *testing.T) { 142 t.Parallel() 143 config := logical.TestBackendConfig() 144 config.StorageView = &logical.InmemStorage{} 145 146 b := Backend() 147 if err := b.Setup(context.Background(), config); err != nil { 148 t.Fatal(err) 149 } 150 151 connData := map[string]interface{}{ 152 "credential_type": "iam_user", 153 } 154 155 confReq := &logical.Request{ 156 Operation: logical.UpdateOperation, 157 Path: "roles/something", 158 Storage: config.StorageView, 159 Data: connData, 160 } 161 162 resp, err := b.HandleRequest(context.Background(), confReq) 163 if err != nil || (resp != nil && resp.IsError()) { 164 t.Fatalf("failed to write configuration: resp:%#v err:%s", resp, err) 165 } 166 167 // Mock the IAM API call to return a throttled response to the CreateUser API 168 // call 169 b.iamClient = &mockIAMClient{} 170 171 credReq := &logical.Request{ 172 Operation: logical.UpdateOperation, 173 Path: "creds/something", 174 Storage: config.StorageView, 175 } 176 177 credResp, err := b.HandleRequest(context.Background(), credReq) 178 if err == nil { 179 t.Fatalf("failed to trigger expected throttling error condition: resp:%#v", credResp) 180 } 181 rErr := credResp.Error() 182 expected := "Error creating IAM user: Throttling: " 183 if rErr.Error() != expected { 184 t.Fatalf("error message did not match, expected (%s), got (%s)", expected, rErr.Error()) 185 } 186 187 // verify the error we got back is returned with a http.StatusBadGateway 188 code, err := logical.RespondErrorCommon(credReq, credResp, err) 189 if err == nil { 190 t.Fatal("expected error after running req/resp/err through RespondErrorCommon, got nil") 191 } 192 if code != http.StatusBadGateway { 193 t.Fatalf("expected HTTP status 'bad gateway', got: (%d)", code) 194 } 195} 196 197func testAccPreCheck(t *testing.T) { 198 initSetup.Do(func() { 199 if v := os.Getenv("AWS_DEFAULT_REGION"); v == "" { 200 log.Println("[INFO] Test: Using us-west-2 as test region") 201 os.Setenv("AWS_DEFAULT_REGION", "us-west-2") 202 } 203 }) 204} 205 206func getAccountID() (string, error) { 207 awsConfig := &aws.Config{ 208 Region: aws.String("us-east-1"), 209 HTTPClient: cleanhttp.DefaultClient(), 210 } 211 sess, err := session.NewSession(awsConfig) 212 if err != nil { 213 return "", err 214 } 215 svc := sts.New(sess) 216 217 params := &sts.GetCallerIdentityInput{} 218 res, err := svc.GetCallerIdentity(params) 219 if err != nil { 220 return "", err 221 } 222 if res == nil { 223 return "", fmt.Errorf("got nil response from GetCallerIdentity") 224 } 225 226 return *res.Account, nil 227} 228 229func createRole(t *testing.T, roleName, awsAccountID string, policyARNs []string) { 230 const testRoleAssumePolicy = `{ 231 "Version": "2012-10-17", 232 "Statement": [ 233 { 234 "Effect":"Allow", 235 "Principal": { 236 "AWS": "arn:aws:iam::%s:root" 237 }, 238 "Action": "sts:AssumeRole" 239 } 240 ] 241} 242` 243 awsConfig := &aws.Config{ 244 Region: aws.String("us-east-1"), 245 HTTPClient: cleanhttp.DefaultClient(), 246 } 247 sess, err := session.NewSession(awsConfig) 248 if err != nil { 249 t.Fatal(err) 250 } 251 svc := iam.New(sess) 252 trustPolicy := fmt.Sprintf(testRoleAssumePolicy, awsAccountID) 253 254 params := &iam.CreateRoleInput{ 255 AssumeRolePolicyDocument: aws.String(trustPolicy), 256 RoleName: aws.String(roleName), 257 Path: aws.String("/"), 258 } 259 260 log.Printf("[INFO] AWS CreateRole: %s", roleName) 261 if _, err := svc.CreateRole(params); err != nil { 262 t.Fatalf("AWS CreateRole failed: %v", err) 263 } 264 265 for _, policyARN := range policyARNs { 266 attachment := &iam.AttachRolePolicyInput{ 267 PolicyArn: aws.String(policyARN), 268 RoleName: aws.String(roleName), // Required 269 } 270 _, err = svc.AttachRolePolicy(attachment) 271 272 if err != nil { 273 t.Fatalf("AWS AttachRolePolicy failed: %v", err) 274 } 275 } 276} 277 278func createUser(t *testing.T, userName string, accessKey *awsAccessKey) { 279 // The sequence of user creation actions is carefully chosen to minimize 280 // impact of stolen IAM user credentials 281 // 1. Create user, without any permissions or credentials. At this point, 282 // nobody cares if creds compromised because this user can do nothing. 283 // 2. Attach the timebomb policy. This grants no access but puts a time limit 284 // on validity of compromised credentials. If this fails, nobody cares 285 // because the user has no permissions to do anything anyway 286 // 3. Attach the AdminAccess policy. The IAM user still has no credentials to 287 // do anything 288 // 4. Generate API creds to get an actual access key and secret key 289 timebombPolicyTemplate := `{ 290 "Version": "2012-10-17", 291 "Statement": [ 292 { 293 "Effect": "Deny", 294 "Action": "*", 295 "Resource": "*", 296 "Condition": { 297 "DateGreaterThan": { 298 "aws:CurrentTime": "%s" 299 } 300 } 301 } 302 ] 303 } 304 ` 305 validity := time.Duration(2 * time.Hour) 306 expiry := time.Now().Add(validity) 307 timebombPolicy := fmt.Sprintf(timebombPolicyTemplate, expiry.Format(time.RFC3339)) 308 awsConfig := &aws.Config{ 309 Region: aws.String("us-east-1"), 310 HTTPClient: cleanhttp.DefaultClient(), 311 } 312 sess, err := session.NewSession(awsConfig) 313 if err != nil { 314 t.Fatal(err) 315 } 316 svc := iam.New(sess) 317 createUserInput := &iam.CreateUserInput{ 318 UserName: aws.String(userName), 319 } 320 log.Printf("[INFO] AWS CreateUser: %s", userName) 321 if _, err := svc.CreateUser(createUserInput); err != nil { 322 t.Fatalf("AWS CreateUser failed: %v", err) 323 } 324 325 putPolicyInput := &iam.PutUserPolicyInput{ 326 PolicyDocument: aws.String(timebombPolicy), 327 PolicyName: aws.String("SelfDestructionTimebomb"), 328 UserName: aws.String(userName), 329 } 330 _, err = svc.PutUserPolicy(putPolicyInput) 331 if err != nil { 332 t.Fatalf("AWS PutUserPolicy failed: %v", err) 333 } 334 335 attachUserPolicyInput := &iam.AttachUserPolicyInput{ 336 PolicyArn: aws.String("arn:aws:iam::aws:policy/AdministratorAccess"), 337 UserName: aws.String(userName), 338 } 339 _, err = svc.AttachUserPolicy(attachUserPolicyInput) 340 if err != nil { 341 t.Fatalf("AWS AttachUserPolicy failed, %v", err) 342 } 343 344 createAccessKeyInput := &iam.CreateAccessKeyInput{ 345 UserName: aws.String(userName), 346 } 347 createAccessKeyOutput, err := svc.CreateAccessKey(createAccessKeyInput) 348 if err != nil { 349 t.Fatalf("AWS CreateAccessKey failed: %v", err) 350 } 351 if createAccessKeyOutput == nil { 352 t.Fatalf("AWS CreateAccessKey returned nil") 353 } 354 genAccessKey := createAccessKeyOutput.AccessKey 355 356 accessKey.AccessKeyID = *genAccessKey.AccessKeyId 357 accessKey.SecretAccessKey = *genAccessKey.SecretAccessKey 358} 359 360// Create an IAM Group and add an inline policy and managed policies if specified 361func createGroup(t *testing.T, groupName string, inlinePolicy string, managedPolicies []string) { 362 awsConfig := &aws.Config{ 363 Region: aws.String("us-east-1"), 364 HTTPClient: cleanhttp.DefaultClient(), 365 } 366 sess, err := session.NewSession(awsConfig) 367 if err != nil { 368 t.Fatal(err) 369 } 370 svc := iam.New(sess) 371 createGroupInput := &iam.CreateGroupInput{ 372 GroupName: aws.String(groupName), 373 } 374 log.Printf("[INFO] AWS CreateGroup: %s", groupName) 375 if _, err := svc.CreateGroup(createGroupInput); err != nil { 376 t.Fatalf("AWS CreateGroup failed: %v", err) 377 } 378 379 if len(inlinePolicy) > 0 { 380 putPolicyInput := &iam.PutGroupPolicyInput{ 381 PolicyDocument: aws.String(inlinePolicy), 382 PolicyName: aws.String("InlinePolicy"), 383 GroupName: aws.String(groupName), 384 } 385 _, err = svc.PutGroupPolicy(putPolicyInput) 386 if err != nil { 387 t.Fatalf("AWS PutGroupPolicy failed: %v", err) 388 } 389 } 390 391 for _, mp := range managedPolicies { 392 attachGroupPolicyInput := &iam.AttachGroupPolicyInput{ 393 PolicyArn: aws.String(mp), 394 GroupName: aws.String(groupName), 395 } 396 _, err = svc.AttachGroupPolicy(attachGroupPolicyInput) 397 if err != nil { 398 t.Fatalf("AWS AttachGroupPolicy failed, %v", err) 399 } 400 } 401} 402 403func deleteTestRole(roleName string) error { 404 awsConfig := &aws.Config{ 405 Region: aws.String("us-east-1"), 406 HTTPClient: cleanhttp.DefaultClient(), 407 } 408 sess, err := session.NewSession(awsConfig) 409 if err != nil { 410 return err 411 } 412 svc := iam.New(sess) 413 listAttachmentsInput := &iam.ListAttachedRolePoliciesInput{ 414 RoleName: aws.String(roleName), 415 } 416 detacher := func(result *iam.ListAttachedRolePoliciesOutput, lastPage bool) bool { 417 for _, policy := range result.AttachedPolicies { 418 detachInput := &iam.DetachRolePolicyInput{ 419 PolicyArn: policy.PolicyArn, 420 RoleName: aws.String(roleName), // Required 421 } 422 _, err := svc.DetachRolePolicy(detachInput) 423 if err != nil { 424 log.Printf("[WARN] AWS DetachRolePolicy failed for policy %s: %v", *policy.PolicyArn, err) 425 } 426 } 427 return true 428 } 429 if err := svc.ListAttachedRolePoliciesPages(listAttachmentsInput, detacher); err != nil { 430 log.Printf("[WARN] AWS DetachRolePolicy failed: %v", err) 431 } 432 433 params := &iam.DeleteRoleInput{ 434 RoleName: aws.String(roleName), 435 } 436 437 log.Printf("[INFO] AWS DeleteRole: %s", roleName) 438 _, err = svc.DeleteRole(params) 439 440 if err != nil { 441 log.Printf("[WARN] AWS DeleteRole failed: %v", err) 442 return err 443 } 444 return nil 445} 446 447func deleteTestUser(accessKey *awsAccessKey, userName string) error { 448 awsConfig := &aws.Config{ 449 Region: aws.String("us-east-1"), 450 HTTPClient: cleanhttp.DefaultClient(), 451 } 452 sess, err := session.NewSession(awsConfig) 453 if err != nil { 454 return err 455 } 456 svc := iam.New(sess) 457 userDetachment := &iam.DetachUserPolicyInput{ 458 PolicyArn: aws.String("arn:aws:iam::aws:policy/AdministratorAccess"), 459 UserName: aws.String(userName), 460 } 461 if _, err := svc.DetachUserPolicy(userDetachment); err != nil { 462 log.Printf("[WARN] AWS DetachUserPolicy failed: %v", err) 463 return err 464 } 465 466 deleteAccessKeyInput := &iam.DeleteAccessKeyInput{ 467 AccessKeyId: aws.String(accessKey.AccessKeyID), 468 UserName: aws.String(userName), 469 } 470 _, err = svc.DeleteAccessKey(deleteAccessKeyInput) 471 if err != nil { 472 log.Printf("[WARN] AWS DeleteAccessKey failed: %v", err) 473 return err 474 } 475 476 deleteTestUserPolicyInput := &iam.DeleteUserPolicyInput{ 477 PolicyName: aws.String("SelfDestructionTimebomb"), 478 UserName: aws.String(userName), 479 } 480 _, err = svc.DeleteUserPolicy(deleteTestUserPolicyInput) 481 if err != nil { 482 log.Printf("[WARN] AWS DeleteUserPolicy failed: %v", err) 483 return err 484 } 485 deleteTestUserInput := &iam.DeleteUserInput{ 486 UserName: aws.String(userName), 487 } 488 log.Printf("[INFO] AWS DeleteUser: %s", userName) 489 _, err = svc.DeleteUser(deleteTestUserInput) 490 if err != nil { 491 log.Printf("[WARN] AWS DeleteUser failed: %v", err) 492 return err 493 } 494 495 return nil 496} 497 498func deleteTestGroup(groupName string) error { 499 awsConfig := &aws.Config{ 500 Region: aws.String("us-east-1"), 501 HTTPClient: cleanhttp.DefaultClient(), 502 } 503 sess, err := session.NewSession(awsConfig) 504 if err != nil { 505 return err 506 } 507 svc := iam.New(sess) 508 509 // Detach any managed group policies 510 getGroupsInput := &iam.ListAttachedGroupPoliciesInput{ 511 GroupName: aws.String(groupName), 512 } 513 getGroupsOutput, err := svc.ListAttachedGroupPolicies(getGroupsInput) 514 if err != nil { 515 log.Printf("[WARN] AWS ListAttachedGroupPolicies failed: %v", err) 516 return err 517 } 518 for _, g := range getGroupsOutput.AttachedPolicies { 519 detachGroupInput := &iam.DetachGroupPolicyInput{ 520 GroupName: aws.String(groupName), 521 PolicyArn: g.PolicyArn, 522 } 523 if _, err := svc.DetachGroupPolicy(detachGroupInput); err != nil { 524 log.Printf("[WARN] AWS DetachGroupPolicy failed: %v", err) 525 return err 526 } 527 } 528 529 // Remove any inline policies 530 listGroupPoliciesInput := &iam.ListGroupPoliciesInput{ 531 GroupName: aws.String(groupName), 532 } 533 listGroupPoliciesOutput, err := svc.ListGroupPolicies(listGroupPoliciesInput) 534 if err != nil { 535 log.Printf("[WARN] AWS ListGroupPolicies failed: %v", err) 536 return err 537 } 538 for _, g := range listGroupPoliciesOutput.PolicyNames { 539 deleteGroupPolicyInput := &iam.DeleteGroupPolicyInput{ 540 GroupName: aws.String(groupName), 541 PolicyName: g, 542 } 543 if _, err := svc.DeleteGroupPolicy(deleteGroupPolicyInput); err != nil { 544 log.Printf("[WARN] AWS DeleteGroupPolicy failed: %v", err) 545 return err 546 } 547 } 548 549 // Delete the group 550 deleteTestGroupInput := &iam.DeleteGroupInput{ 551 GroupName: aws.String(groupName), 552 } 553 log.Printf("[INFO] AWS DeleteGroup: %s", groupName) 554 _, err = svc.DeleteGroup(deleteTestGroupInput) 555 if err != nil { 556 log.Printf("[WARN] AWS DeleteGroup failed: %v", err) 557 return err 558 } 559 560 return nil 561} 562 563func testAccStepConfig(t *testing.T) logicaltest.TestStep { 564 return logicaltest.TestStep{ 565 Operation: logical.UpdateOperation, 566 Path: "config/root", 567 Data: map[string]interface{}{ 568 "region": os.Getenv("AWS_DEFAULT_REGION"), 569 }, 570 } 571} 572 573func testAccStepConfigWithCreds(t *testing.T, accessKey *awsAccessKey) logicaltest.TestStep { 574 return logicaltest.TestStep{ 575 Operation: logical.UpdateOperation, 576 Path: "config/root", 577 Data: map[string]interface{}{ 578 "region": os.Getenv("AWS_DEFAULT_REGION"), 579 }, 580 PreFlight: func(req *logical.Request) error { 581 // Values in Data above get eagerly evaluated due to the testing framework. 582 // In particular, they get evaluated before accessKey gets set by CreateUser 583 // and thus would fail. By moving to a closure in a PreFlight, we ensure that 584 // the creds get evaluated lazily after they've been properly set 585 req.Data["access_key"] = accessKey.AccessKeyID 586 req.Data["secret_key"] = accessKey.SecretAccessKey 587 return nil 588 }, 589 } 590} 591 592func testAccStepRotateRoot(oldAccessKey *awsAccessKey) logicaltest.TestStep { 593 return logicaltest.TestStep{ 594 Operation: logical.UpdateOperation, 595 Path: "config/rotate-root", 596 Check: func(resp *logical.Response) error { 597 if resp == nil { 598 return fmt.Errorf("received nil response from config/rotate-root") 599 } 600 newAccessKeyID := resp.Data["access_key"].(string) 601 if newAccessKeyID == oldAccessKey.AccessKeyID { 602 return fmt.Errorf("rotate-root didn't rotate access key") 603 } 604 awsConfig := &aws.Config{ 605 Region: aws.String("us-east-1"), 606 HTTPClient: cleanhttp.DefaultClient(), 607 Credentials: credentials.NewStaticCredentials(oldAccessKey.AccessKeyID, oldAccessKey.SecretAccessKey, ""), 608 } 609 // sigh.... 610 oldAccessKey.AccessKeyID = newAccessKeyID 611 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 612 time.Sleep(10 * time.Second) 613 sess, err := session.NewSession(awsConfig) 614 if err != nil { 615 return err 616 } 617 svc := sts.New(sess) 618 params := &sts.GetCallerIdentityInput{} 619 if _, err := svc.GetCallerIdentity(params); err == nil { 620 return fmt.Errorf("bad: old credentials succeeded after rotate") 621 } 622 if aerr, ok := err.(awserr.Error); ok { 623 if aerr.Code() != "InvalidClientTokenId" { 624 return fmt.Errorf("Unknown error returned from AWS: %#v", aerr) 625 } 626 return nil 627 } 628 return err 629 }, 630 } 631} 632 633func testAccStepRead(t *testing.T, path, name string, credentialTests []credentialTestFunc) logicaltest.TestStep { 634 return logicaltest.TestStep{ 635 Operation: logical.ReadOperation, 636 Path: path + "/" + name, 637 Check: func(resp *logical.Response) error { 638 var d struct { 639 AccessKey string `mapstructure:"access_key"` 640 SecretKey string `mapstructure:"secret_key"` 641 STSToken string `mapstructure:"security_token"` 642 } 643 if err := mapstructure.Decode(resp.Data, &d); err != nil { 644 return err 645 } 646 log.Printf("[WARN] Generated credentials: %v", d) 647 for _, test := range credentialTests { 648 err := test(d.AccessKey, d.SecretKey, d.STSToken) 649 if err != nil { 650 return err 651 } 652 } 653 return nil 654 }, 655 } 656} 657 658func testAccStepReadTTL(name string, maximumTTL time.Duration) logicaltest.TestStep { 659 return logicaltest.TestStep{ 660 Operation: logical.ReadOperation, 661 Path: "creds/" + name, 662 Check: func(resp *logical.Response) error { 663 if resp.Secret == nil { 664 return fmt.Errorf("bad: nil Secret returned") 665 } 666 ttl := resp.Secret.TTL 667 if ttl > maximumTTL { 668 return fmt.Errorf("bad: ttl of %d greater than maximum of %d", ttl/time.Second, maximumTTL/time.Second) 669 } 670 return nil 671 }, 672 } 673} 674 675func describeInstancesTest(accessKey, secretKey, token string) error { 676 creds := credentials.NewStaticCredentials(accessKey, secretKey, token) 677 awsConfig := &aws.Config{ 678 Credentials: creds, 679 Region: aws.String("us-east-1"), 680 HTTPClient: cleanhttp.DefaultClient(), 681 } 682 sess, err := session.NewSession(awsConfig) 683 if err != nil { 684 return err 685 } 686 client := ec2.New(sess) 687 log.Printf("[WARN] Verifying that the generated credentials work with ec2:DescribeInstances...") 688 return retryUntilSuccess(func() error { 689 _, err := client.DescribeInstances(&ec2.DescribeInstancesInput{}) 690 return err 691 }) 692} 693 694func describeAzsTestUnauthorized(accessKey, secretKey, token string) error { 695 creds := credentials.NewStaticCredentials(accessKey, secretKey, token) 696 awsConfig := &aws.Config{ 697 Credentials: creds, 698 Region: aws.String("us-east-1"), 699 HTTPClient: cleanhttp.DefaultClient(), 700 } 701 sess, err := session.NewSession(awsConfig) 702 if err != nil { 703 return err 704 } 705 client := ec2.New(sess) 706 log.Printf("[WARN] Verifying that the generated credentials don't work with ec2:DescribeAvailabilityZones...") 707 return retryUntilSuccess(func() error { 708 _, err := client.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{}) 709 // Need to make sure AWS authenticates the generated credentials but does not authorize the operation 710 if err == nil { 711 return fmt.Errorf("operation succeeded when expected failure") 712 } 713 if aerr, ok := err.(awserr.Error); ok { 714 if aerr.Code() == "UnauthorizedOperation" { 715 return nil 716 } 717 } 718 return err 719 }) 720} 721 722func assertCreatedIAMUser(accessKey, secretKey, token string) error { 723 creds := credentials.NewStaticCredentials(accessKey, secretKey, token) 724 awsConfig := &aws.Config{ 725 Credentials: creds, 726 Region: aws.String("us-east-1"), 727 HTTPClient: cleanhttp.DefaultClient(), 728 } 729 sess, err := session.NewSession(awsConfig) 730 if err != nil { 731 return err 732 } 733 client := iam.New(sess) 734 log.Printf("[WARN] Checking if IAM User is created properly...") 735 userOutput, err := client.GetUser(&iam.GetUserInput{}) 736 if err != nil { 737 return err 738 } 739 740 if *userOutput.User.Path != "/path/" { 741 return fmt.Errorf("bad: got: %#v\nexpected: %#v", userOutput.User.Path, "/path/") 742 } 743 744 return nil 745} 746 747func listIamUsersTest(accessKey, secretKey, token string) error { 748 creds := credentials.NewStaticCredentials(accessKey, secretKey, token) 749 awsConfig := &aws.Config{ 750 Credentials: creds, 751 Region: aws.String("us-east-1"), 752 HTTPClient: cleanhttp.DefaultClient(), 753 } 754 sess, err := session.NewSession(awsConfig) 755 if err != nil { 756 return err 757 } 758 client := iam.New(sess) 759 log.Printf("[WARN] Verifying that the generated credentials work with iam:ListUsers...") 760 return retryUntilSuccess(func() error { 761 _, err := client.ListUsers(&iam.ListUsersInput{}) 762 return err 763 }) 764} 765 766func listDynamoTablesTest(accessKey, secretKey, token string) error { 767 creds := credentials.NewStaticCredentials(accessKey, secretKey, token) 768 awsConfig := &aws.Config{ 769 Credentials: creds, 770 Region: aws.String("us-east-1"), 771 HTTPClient: cleanhttp.DefaultClient(), 772 } 773 sess, err := session.NewSession(awsConfig) 774 if err != nil { 775 return err 776 } 777 client := dynamodb.New(sess) 778 log.Printf("[WARN] Verifying that the generated credentials work with dynamodb:ListTables...") 779 return retryUntilSuccess(func() error { 780 _, err := client.ListTables(&dynamodb.ListTablesInput{}) 781 return err 782 }) 783} 784 785func listS3BucketsTest(accessKey, secretKey, token string) error { 786 creds := credentials.NewStaticCredentials(accessKey, secretKey, token) 787 awsConfig := &aws.Config{ 788 Credentials: creds, 789 Region: aws.String("us-east-1"), 790 HTTPClient: cleanhttp.DefaultClient(), 791 } 792 sess, err := session.NewSession(awsConfig) 793 if err != nil { 794 return err 795 } 796 client := s3.New(sess) 797 log.Printf("[WARN] Verifying that the generated credentials work with s3:ListBuckets...") 798 return retryUntilSuccess(func() error { 799 _, err := client.ListBuckets(&s3.ListBucketsInput{}) 800 return err 801 }) 802} 803 804func retryUntilSuccess(op func() error) error { 805 retryCount := 0 806 success := false 807 var err error 808 for !success && retryCount < 10 { 809 err = op() 810 if err == nil { 811 return nil 812 } 813 time.Sleep(time.Second) 814 retryCount++ 815 } 816 return err 817} 818 819func testAccStepReadSTSWithArnPolicy(t *testing.T, name string) logicaltest.TestStep { 820 return logicaltest.TestStep{ 821 Operation: logical.ReadOperation, 822 Path: "sts/" + name, 823 ErrorOk: true, 824 Check: func(resp *logical.Response) error { 825 if resp.Data["error"] != 826 "attempted to retrieve iam_user credentials through the sts path; this is not allowed for legacy roles" { 827 t.Fatalf("bad: %v", resp) 828 } 829 return nil 830 }, 831 } 832} 833 834func testAccStepWritePolicy(t *testing.T, name string, policy string) logicaltest.TestStep { 835 return logicaltest.TestStep{ 836 Operation: logical.UpdateOperation, 837 Path: "roles/" + name, 838 Data: map[string]interface{}{ 839 "policy": policy, 840 }, 841 } 842} 843 844func testAccStepDeletePolicy(t *testing.T, n string) logicaltest.TestStep { 845 return logicaltest.TestStep{ 846 Operation: logical.DeleteOperation, 847 Path: "roles/" + n, 848 } 849} 850 851func testAccStepReadPolicy(t *testing.T, name string, value string) logicaltest.TestStep { 852 return logicaltest.TestStep{ 853 Operation: logical.ReadOperation, 854 Path: "roles/" + name, 855 Check: func(resp *logical.Response) error { 856 if resp == nil { 857 if value == "" { 858 return nil 859 } 860 861 return fmt.Errorf("bad: %#v", resp) 862 } 863 864 expected := map[string]interface{}{ 865 "policy_arns": []string(nil), 866 "role_arns": []string(nil), 867 "policy_document": value, 868 "credential_type": strings.Join([]string{iamUserCred, federationTokenCred}, ","), 869 "default_sts_ttl": int64(0), 870 "max_sts_ttl": int64(0), 871 "user_path": "", 872 "permissions_boundary_arn": "", 873 "iam_groups": []string(nil), 874 } 875 if !reflect.DeepEqual(resp.Data, expected) { 876 return fmt.Errorf("bad: got: %#v\nexpected: %#v", resp.Data, expected) 877 } 878 return nil 879 }, 880 } 881} 882 883const testDynamoPolicy = `{ 884 "Version": "2012-10-17", 885 "Statement": [ 886 { 887 "Sid": "Stmt1426528957000", 888 "Effect": "Allow", 889 "Action": [ 890 "dynamodb:List*" 891 ], 892 "Resource": [ 893 "*" 894 ] 895 } 896 ] 897} 898` 899 900const testS3Policy = `{ 901 "Version": "2012-10-17", 902 "Statement": [ 903 { 904 "Effect": "Allow", 905 "Action": [ 906 "s3:Get*", 907 "s3:List*" 908 ], 909 "Resource": "*" 910 } 911 ] 912}` 913 914const ( 915 adminAccessPolicyArn = "arn:aws:iam::aws:policy/AdministratorAccess" 916 ec2PolicyArn = "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess" 917 iamPolicyArn = "arn:aws:iam::aws:policy/IAMReadOnlyAccess" 918 dynamoPolicyArn = "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess" 919) 920 921func testAccStepWriteRole(t *testing.T, name string, data map[string]interface{}) logicaltest.TestStep { 922 return logicaltest.TestStep{ 923 Operation: logical.UpdateOperation, 924 Path: "roles/" + name, 925 Data: data, 926 } 927} 928 929func testAccStepReadRole(t *testing.T, name string, expected map[string]interface{}) logicaltest.TestStep { 930 return logicaltest.TestStep{ 931 Operation: logical.ReadOperation, 932 Path: "roles/" + name, 933 Check: func(resp *logical.Response) error { 934 if resp == nil { 935 if expected == nil { 936 return nil 937 } 938 return fmt.Errorf("bad: nil response") 939 } 940 if !reflect.DeepEqual(resp.Data, expected) { 941 return fmt.Errorf("bad: got %#v\nexpected: %#v", resp.Data, expected) 942 } 943 return nil 944 }, 945 } 946} 947 948func testAccStepWriteArnPolicyRef(t *testing.T, name string, arn string) logicaltest.TestStep { 949 return logicaltest.TestStep{ 950 Operation: logical.UpdateOperation, 951 Path: "roles/" + name, 952 Data: map[string]interface{}{ 953 "arn": ec2PolicyArn, 954 }, 955 } 956} 957 958func TestBackend_basicPolicyArnRef(t *testing.T) { 959 t.Parallel() 960 logicaltest.Test(t, logicaltest.TestCase{ 961 AcceptanceTest: true, 962 PreCheck: func() { testAccPreCheck(t) }, 963 LogicalBackend: getBackend(t), 964 Steps: []logicaltest.TestStep{ 965 testAccStepConfig(t), 966 testAccStepWriteArnPolicyRef(t, "test", ec2PolicyArn), 967 testAccStepRead(t, "creds", "test", []credentialTestFunc{describeInstancesTest}), 968 }, 969 }) 970} 971 972func TestBackend_iamUserManagedInlinePoliciesGroups(t *testing.T) { 973 t.Parallel() 974 compacted, err := compactJSON(testDynamoPolicy) 975 if err != nil { 976 t.Fatalf("bad: %#v", err) 977 } 978 groupName := generateUniqueName(t.Name()) 979 roleData := map[string]interface{}{ 980 "policy_document": testDynamoPolicy, 981 "policy_arns": []string{ec2PolicyArn, iamPolicyArn}, 982 "iam_groups": []string{groupName}, 983 "credential_type": iamUserCred, 984 "user_path": "/path/", 985 } 986 expectedRoleData := map[string]interface{}{ 987 "policy_document": compacted, 988 "policy_arns": []string{ec2PolicyArn, iamPolicyArn}, 989 "credential_type": iamUserCred, 990 "role_arns": []string(nil), 991 "default_sts_ttl": int64(0), 992 "max_sts_ttl": int64(0), 993 "user_path": "/path/", 994 "permissions_boundary_arn": "", 995 "iam_groups": []string{groupName}, 996 } 997 998 logicaltest.Test(t, logicaltest.TestCase{ 999 AcceptanceTest: true, 1000 PreCheck: func() { 1001 testAccPreCheck(t) 1002 createGroup(t, groupName, testS3Policy, []string{}) 1003 }, 1004 LogicalBackend: getBackend(t), 1005 Steps: []logicaltest.TestStep{ 1006 testAccStepConfig(t), 1007 testAccStepWriteRole(t, "test", roleData), 1008 testAccStepReadRole(t, "test", expectedRoleData), 1009 testAccStepRead(t, "creds", "test", []credentialTestFunc{describeInstancesTest, listIamUsersTest, listDynamoTablesTest, assertCreatedIAMUser, listS3BucketsTest}), 1010 testAccStepRead(t, "sts", "test", []credentialTestFunc{describeInstancesTest, listIamUsersTest, listDynamoTablesTest, listS3BucketsTest}), 1011 }, 1012 Teardown: func() error { 1013 return deleteTestGroup(groupName) 1014 }, 1015 }) 1016} 1017 1018// Similar to TestBackend_iamUserManagedInlinePoliciesGroups() but managing 1019// policies only with groups 1020func TestBackend_iamUserGroups(t *testing.T) { 1021 t.Parallel() 1022 group1Name := generateUniqueName(t.Name()) 1023 group2Name := generateUniqueName(t.Name()) 1024 roleData := map[string]interface{}{ 1025 "iam_groups": []string{group1Name, group2Name}, 1026 "credential_type": iamUserCred, 1027 "user_path": "/path/", 1028 } 1029 expectedRoleData := map[string]interface{}{ 1030 "policy_document": "", 1031 "policy_arns": []string(nil), 1032 "credential_type": iamUserCred, 1033 "role_arns": []string(nil), 1034 "default_sts_ttl": int64(0), 1035 "max_sts_ttl": int64(0), 1036 "user_path": "/path/", 1037 "permissions_boundary_arn": "", 1038 "iam_groups": []string{group1Name, group2Name}, 1039 } 1040 1041 logicaltest.Test(t, logicaltest.TestCase{ 1042 AcceptanceTest: true, 1043 PreCheck: func() { 1044 testAccPreCheck(t) 1045 createGroup(t, group1Name, testS3Policy, []string{ec2PolicyArn, iamPolicyArn}) 1046 createGroup(t, group2Name, testDynamoPolicy, []string{}) 1047 }, 1048 LogicalBackend: getBackend(t), 1049 Steps: []logicaltest.TestStep{ 1050 testAccStepConfig(t), 1051 testAccStepWriteRole(t, "test", roleData), 1052 testAccStepReadRole(t, "test", expectedRoleData), 1053 testAccStepRead(t, "creds", "test", []credentialTestFunc{describeInstancesTest, listIamUsersTest, listDynamoTablesTest, assertCreatedIAMUser, listS3BucketsTest}), 1054 testAccStepRead(t, "sts", "test", []credentialTestFunc{describeInstancesTest, listIamUsersTest, listDynamoTablesTest, listS3BucketsTest}), 1055 }, 1056 Teardown: func() error { 1057 if err := deleteTestGroup(group1Name); err != nil { 1058 return err 1059 } 1060 return deleteTestGroup(group2Name) 1061 }, 1062 }) 1063} 1064 1065func TestBackend_AssumedRoleWithPolicyDoc(t *testing.T) { 1066 t.Parallel() 1067 roleName := generateUniqueName(t.Name()) 1068 // This looks a bit curious. The policy document and the role document act 1069 // as a logical intersection of policies. The role allows ec2:Describe* 1070 // (among other permissions). This policy allows everything BUT 1071 // ec2:DescribeAvailabilityZones. Thus, the logical intersection of the two 1072 // is all ec2:Describe* EXCEPT ec2:DescribeAvailabilityZones, and so the 1073 // describeAZs call should fail 1074 allowAllButDescribeAzs := ` 1075{ 1076 "Version": "2012-10-17", 1077 "Statement": [{ 1078 "Effect": "Allow", 1079 "NotAction": "ec2:DescribeAvailabilityZones", 1080 "Resource": "*" 1081 }] 1082} 1083` 1084 awsAccountID, err := getAccountID() 1085 if err != nil { 1086 t.Logf("Unable to retrive user via sts:GetCallerIdentity: %#v", err) 1087 t.Skip("Could not determine AWS account ID from sts:GetCallerIdentity for acceptance tests, skipping") 1088 } 1089 roleData := map[string]interface{}{ 1090 "policy_document": allowAllButDescribeAzs, 1091 "role_arns": []string{fmt.Sprintf("arn:aws:iam::%s:role/%s", awsAccountID, roleName)}, 1092 "credential_type": assumedRoleCred, 1093 } 1094 logicaltest.Test(t, logicaltest.TestCase{ 1095 AcceptanceTest: true, 1096 PreCheck: func() { 1097 testAccPreCheck(t) 1098 createRole(t, roleName, awsAccountID, []string{ec2PolicyArn}) 1099 // Sleep sometime because AWS is eventually consistent 1100 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 1101 time.Sleep(10 * time.Second) 1102 }, 1103 LogicalBackend: getBackend(t), 1104 Steps: []logicaltest.TestStep{ 1105 testAccStepConfig(t), 1106 testAccStepWriteRole(t, "test", roleData), 1107 testAccStepRead(t, "sts", "test", []credentialTestFunc{describeInstancesTest, describeAzsTestUnauthorized}), 1108 testAccStepRead(t, "creds", "test", []credentialTestFunc{describeInstancesTest, describeAzsTestUnauthorized}), 1109 }, 1110 Teardown: func() error { 1111 return deleteTestRole(roleName) 1112 }, 1113 }) 1114} 1115 1116func TestBackend_AssumedRoleWithPolicyARN(t *testing.T) { 1117 t.Parallel() 1118 roleName := generateUniqueName(t.Name()) 1119 1120 awsAccountID, err := getAccountID() 1121 if err != nil { 1122 t.Logf("Unable to retrive user via sts:GetCallerIdentity: %#v", err) 1123 t.Skip("Could not determine AWS account ID from sts:GetCallerIdentity for acceptance tests, skipping") 1124 } 1125 roleData := map[string]interface{}{ 1126 "policy_arns": iamPolicyArn, 1127 "role_arns": []string{fmt.Sprintf("arn:aws:iam::%s:role/%s", awsAccountID, roleName)}, 1128 "credential_type": assumedRoleCred, 1129 } 1130 logicaltest.Test(t, logicaltest.TestCase{ 1131 AcceptanceTest: true, 1132 PreCheck: func() { 1133 testAccPreCheck(t) 1134 createRole(t, roleName, awsAccountID, []string{ec2PolicyArn, iamPolicyArn}) 1135 log.Printf("[WARN] Sleeping for 10 seconds waiting for AWS...") 1136 time.Sleep(10 * time.Second) 1137 }, 1138 LogicalBackend: getBackend(t), 1139 Steps: []logicaltest.TestStep{ 1140 testAccStepConfig(t), 1141 testAccStepWriteRole(t, "test", roleData), 1142 testAccStepRead(t, "sts", "test", []credentialTestFunc{listIamUsersTest, describeAzsTestUnauthorized}), 1143 testAccStepRead(t, "creds", "test", []credentialTestFunc{listIamUsersTest, describeAzsTestUnauthorized}), 1144 }, 1145 Teardown: func() error { 1146 return deleteTestRole(roleName) 1147 }, 1148 }) 1149} 1150 1151func TestBackend_AssumedRoleWithGroups(t *testing.T) { 1152 t.Parallel() 1153 roleName := generateUniqueName(t.Name()) 1154 groupName := generateUniqueName(t.Name()) 1155 // This looks a bit curious. The policy document and the role document act 1156 // as a logical intersection of policies. The role allows ec2:Describe* 1157 // (among other permissions). This policy allows everything BUT 1158 // ec2:DescribeAvailabilityZones. Thus, the logical intersection of the two 1159 // is all ec2:Describe* EXCEPT ec2:DescribeAvailabilityZones, and so the 1160 // describeAZs call should fail 1161 allowAllButDescribeAzs := `{ 1162 "Version": "2012-10-17", 1163 "Statement": [ 1164 { 1165 "Effect": "Allow", 1166 "NotAction": "ec2:DescribeAvailabilityZones", 1167 "Resource": "*" 1168 } 1169 ] 1170}` 1171 awsAccountID, err := getAccountID() 1172 if err != nil { 1173 t.Logf("Unable to retrive user via sts:GetCallerIdentity: %#v", err) 1174 t.Skip("Could not determine AWS account ID from sts:GetCallerIdentity for acceptance tests, skipping") 1175 } 1176 1177 roleData := map[string]interface{}{ 1178 "iam_groups": []string{groupName}, 1179 "role_arns": []string{fmt.Sprintf("arn:aws:iam::%s:role/%s", awsAccountID, roleName)}, 1180 "credential_type": assumedRoleCred, 1181 } 1182 logicaltest.Test(t, logicaltest.TestCase{ 1183 AcceptanceTest: true, 1184 PreCheck: func() { 1185 testAccPreCheck(t) 1186 createRole(t, roleName, awsAccountID, []string{ec2PolicyArn}) 1187 createGroup(t, groupName, allowAllButDescribeAzs, []string{}) 1188 // Sleep sometime because AWS is eventually consistent 1189 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 1190 time.Sleep(10 * time.Second) 1191 }, 1192 LogicalBackend: getBackend(t), 1193 Steps: []logicaltest.TestStep{ 1194 testAccStepConfig(t), 1195 testAccStepWriteRole(t, "test", roleData), 1196 testAccStepRead(t, "sts", "test", []credentialTestFunc{describeInstancesTest, describeAzsTestUnauthorized}), 1197 testAccStepRead(t, "creds", "test", []credentialTestFunc{describeInstancesTest, describeAzsTestUnauthorized}), 1198 }, 1199 Teardown: func() error { 1200 if err := deleteTestGroup(groupName); err != nil { 1201 return err 1202 } 1203 return deleteTestRole(roleName) 1204 }, 1205 }) 1206} 1207 1208func TestBackend_FederationTokenWithPolicyARN(t *testing.T) { 1209 t.Parallel() 1210 userName := generateUniqueName(t.Name()) 1211 accessKey := &awsAccessKey{} 1212 1213 roleData := map[string]interface{}{ 1214 "policy_arns": dynamoPolicyArn, 1215 "credential_type": federationTokenCred, 1216 } 1217 logicaltest.Test(t, logicaltest.TestCase{ 1218 AcceptanceTest: true, 1219 PreCheck: func() { 1220 testAccPreCheck(t) 1221 createUser(t, userName, accessKey) 1222 // Sleep sometime because AWS is eventually consistent 1223 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 1224 time.Sleep(10 * time.Second) 1225 }, 1226 LogicalBackend: getBackend(t), 1227 Steps: []logicaltest.TestStep{ 1228 testAccStepConfigWithCreds(t, accessKey), 1229 testAccStepWriteRole(t, "test", roleData), 1230 testAccStepRead(t, "sts", "test", []credentialTestFunc{listDynamoTablesTest, describeAzsTestUnauthorized}), 1231 testAccStepRead(t, "creds", "test", []credentialTestFunc{listDynamoTablesTest, describeAzsTestUnauthorized}), 1232 }, 1233 Teardown: func() error { 1234 return deleteTestUser(accessKey, userName) 1235 }, 1236 }) 1237} 1238 1239func TestBackend_FederationTokenWithGroups(t *testing.T) { 1240 t.Parallel() 1241 userName := generateUniqueName(t.Name()) 1242 groupName := generateUniqueName(t.Name()) 1243 accessKey := &awsAccessKey{} 1244 1245 // IAM policy where Statement is a single element, not a list 1246 iamSingleStatementPolicy := `{ 1247 "Version": "2012-10-17", 1248 "Statement": { 1249 "Effect": "Allow", 1250 "Action": [ 1251 "s3:Get*", 1252 "s3:List*" 1253 ], 1254 "Resource": "*" 1255 } 1256 }` 1257 1258 roleData := map[string]interface{}{ 1259 "iam_groups": []string{groupName}, 1260 "policy_document": iamSingleStatementPolicy, 1261 "credential_type": federationTokenCred, 1262 } 1263 logicaltest.Test(t, logicaltest.TestCase{ 1264 AcceptanceTest: true, 1265 PreCheck: func() { 1266 testAccPreCheck(t) 1267 createUser(t, userName, accessKey) 1268 createGroup(t, groupName, "", []string{dynamoPolicyArn}) 1269 // Sleep sometime because AWS is eventually consistent 1270 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 1271 time.Sleep(10 * time.Second) 1272 }, 1273 LogicalBackend: getBackend(t), 1274 Steps: []logicaltest.TestStep{ 1275 testAccStepConfigWithCreds(t, accessKey), 1276 testAccStepWriteRole(t, "test", roleData), 1277 testAccStepRead(t, "sts", "test", []credentialTestFunc{listDynamoTablesTest, describeAzsTestUnauthorized, listS3BucketsTest}), 1278 testAccStepRead(t, "creds", "test", []credentialTestFunc{listDynamoTablesTest, describeAzsTestUnauthorized, listS3BucketsTest}), 1279 }, 1280 Teardown: func() error { 1281 if err := deleteTestGroup(groupName); err != nil { 1282 return err 1283 } 1284 return deleteTestUser(accessKey, userName) 1285 }, 1286 }) 1287} 1288 1289func TestBackend_RoleDefaultSTSTTL(t *testing.T) { 1290 t.Parallel() 1291 roleName := generateUniqueName(t.Name()) 1292 minAwsAssumeRoleDuration := 900 1293 awsAccountID, err := getAccountID() 1294 if err != nil { 1295 t.Logf("Unable to retrive user via sts:GetCallerIdentity: %#v", err) 1296 t.Skip("Could not determine AWS account ID from sts:GetCallerIdentity for acceptance tests, skipping") 1297 } 1298 roleData := map[string]interface{}{ 1299 "role_arns": []string{fmt.Sprintf("arn:aws:iam::%s:role/%s", awsAccountID, roleName)}, 1300 "credential_type": assumedRoleCred, 1301 "default_sts_ttl": minAwsAssumeRoleDuration, 1302 "max_sts_ttl": minAwsAssumeRoleDuration, 1303 } 1304 logicaltest.Test(t, logicaltest.TestCase{ 1305 AcceptanceTest: true, 1306 PreCheck: func() { 1307 testAccPreCheck(t) 1308 createRole(t, roleName, awsAccountID, []string{ec2PolicyArn}) 1309 log.Println("[WARN] Sleeping for 10 seconds waiting for AWS...") 1310 time.Sleep(10 * time.Second) 1311 }, 1312 LogicalBackend: getBackend(t), 1313 Steps: []logicaltest.TestStep{ 1314 testAccStepConfig(t), 1315 testAccStepWriteRole(t, "test", roleData), 1316 testAccStepReadTTL("test", time.Duration(minAwsAssumeRoleDuration)*time.Second), // allow a little slack 1317 }, 1318 Teardown: func() error { 1319 return deleteTestRole(roleName) 1320 }, 1321 }) 1322} 1323 1324func TestBackend_policyArnCrud(t *testing.T) { 1325 t.Parallel() 1326 logicaltest.Test(t, logicaltest.TestCase{ 1327 AcceptanceTest: true, 1328 LogicalBackend: getBackend(t), 1329 Steps: []logicaltest.TestStep{ 1330 testAccStepConfig(t), 1331 testAccStepWriteArnPolicyRef(t, "test", ec2PolicyArn), 1332 testAccStepReadArnPolicy(t, "test", ec2PolicyArn), 1333 testAccStepDeletePolicy(t, "test"), 1334 testAccStepReadArnPolicy(t, "test", ""), 1335 }, 1336 }) 1337} 1338 1339func testAccStepReadArnPolicy(t *testing.T, name string, value string) logicaltest.TestStep { 1340 return logicaltest.TestStep{ 1341 Operation: logical.ReadOperation, 1342 Path: "roles/" + name, 1343 Check: func(resp *logical.Response) error { 1344 if resp == nil { 1345 if value == "" { 1346 return nil 1347 } 1348 1349 return fmt.Errorf("bad: %#v", resp) 1350 } 1351 1352 expected := map[string]interface{}{ 1353 "policy_arns": []string{value}, 1354 "role_arns": []string(nil), 1355 "policy_document": "", 1356 "credential_type": iamUserCred, 1357 "default_sts_ttl": int64(0), 1358 "max_sts_ttl": int64(0), 1359 "user_path": "", 1360 "permissions_boundary_arn": "", 1361 "iam_groups": []string(nil), 1362 } 1363 if !reflect.DeepEqual(resp.Data, expected) { 1364 return fmt.Errorf("bad: got: %#v\nexpected: %#v", resp.Data, expected) 1365 } 1366 1367 return nil 1368 }, 1369 } 1370} 1371 1372func testAccStepWriteArnRoleRef(t *testing.T, vaultRoleName, awsRoleName, awsAccountID string) logicaltest.TestStep { 1373 return logicaltest.TestStep{ 1374 Operation: logical.UpdateOperation, 1375 Path: "roles/" + vaultRoleName, 1376 Data: map[string]interface{}{ 1377 "arn": fmt.Sprintf("arn:aws:iam::%s:role/%s", awsAccountID, awsRoleName), 1378 }, 1379 } 1380} 1381 1382func TestBackend_iamGroupsCrud(t *testing.T) { 1383 t.Parallel() 1384 logicaltest.Test(t, logicaltest.TestCase{ 1385 AcceptanceTest: true, 1386 LogicalBackend: getBackend(t), 1387 Steps: []logicaltest.TestStep{ 1388 testAccStepConfig(t), 1389 testAccStepWriteIamGroups(t, "test", []string{"group1", "group2"}), 1390 testAccStepReadIamGroups(t, "test", []string{"group1", "group2"}), 1391 testAccStepDeletePolicy(t, "test"), 1392 testAccStepReadIamGroups(t, "test", []string{}), 1393 }, 1394 }) 1395} 1396 1397func testAccStepWriteIamGroups(t *testing.T, name string, groups []string) logicaltest.TestStep { 1398 return logicaltest.TestStep{ 1399 Operation: logical.UpdateOperation, 1400 Path: "roles/" + name, 1401 Data: map[string]interface{}{ 1402 "credential_type": iamUserCred, 1403 "iam_groups": groups, 1404 }, 1405 } 1406} 1407 1408func testAccStepReadIamGroups(t *testing.T, name string, groups []string) logicaltest.TestStep { 1409 return logicaltest.TestStep{ 1410 Operation: logical.ReadOperation, 1411 Path: "roles/" + name, 1412 Check: func(resp *logical.Response) error { 1413 if resp == nil { 1414 if len(groups) == 0 { 1415 return nil 1416 } 1417 1418 return fmt.Errorf("bad: %#v", resp) 1419 } 1420 1421 expected := map[string]interface{}{ 1422 "policy_arns": []string(nil), 1423 "role_arns": []string(nil), 1424 "policy_document": "", 1425 "credential_type": iamUserCred, 1426 "default_sts_ttl": int64(0), 1427 "max_sts_ttl": int64(0), 1428 "user_path": "", 1429 "permissions_boundary_arn": "", 1430 "iam_groups": groups, 1431 } 1432 if !reflect.DeepEqual(resp.Data, expected) { 1433 return fmt.Errorf("bad: got: %#v\nexpected: %#v", resp.Data, expected) 1434 } 1435 1436 return nil 1437 }, 1438 } 1439} 1440 1441func TestBackend_iamTagsCrud(t *testing.T) { 1442 logicaltest.Test(t, logicaltest.TestCase{ 1443 AcceptanceTest: true, 1444 LogicalBackend: getBackend(t), 1445 Steps: []logicaltest.TestStep{ 1446 testAccStepConfig(t), 1447 testAccStepWriteIamTags(t, "test", map[string]string{"key1": "value1", "key2": "value2"}), 1448 testAccStepReadIamTags(t, "test", map[string]string{"key1": "value1", "key2": "value2"}), 1449 testAccStepDeletePolicy(t, "test"), 1450 testAccStepReadIamTags(t, "test", map[string]string{}), 1451 }, 1452 }) 1453} 1454 1455func testAccStepWriteIamTags(t *testing.T, name string, tags map[string]string) logicaltest.TestStep { 1456 return logicaltest.TestStep{ 1457 Operation: logical.UpdateOperation, 1458 Path: "roles/" + name, 1459 Data: map[string]interface{}{ 1460 "credential_type": iamUserCred, 1461 "iam_tags": tags, 1462 }, 1463 } 1464} 1465 1466func testAccStepReadIamTags(t *testing.T, name string, tags map[string]string) logicaltest.TestStep { 1467 return logicaltest.TestStep{ 1468 Operation: logical.ReadOperation, 1469 Path: "roles/" + name, 1470 Check: func(resp *logical.Response) error { 1471 if resp == nil { 1472 if len(tags) == 0 { 1473 return nil 1474 } 1475 1476 return fmt.Errorf("vault response not received") 1477 } 1478 1479 expected := map[string]interface{}{ 1480 "policy_arns": []string(nil), 1481 "role_arns": []string(nil), 1482 "policy_document": "", 1483 "credential_type": iamUserCred, 1484 "default_sts_ttl": int64(0), 1485 "max_sts_ttl": int64(0), 1486 "user_path": "", 1487 "permissions_boundary_arn": "", 1488 "iam_groups": []string(nil), 1489 "iam_tags": tags, 1490 } 1491 if !reflect.DeepEqual(resp.Data, expected) { 1492 return fmt.Errorf("bad: got: %#v\nexpected: %#v", resp.Data, expected) 1493 } 1494 1495 return nil 1496 }, 1497 } 1498} 1499 1500func generateUniqueName(prefix string) string { 1501 return testhelpers.RandomWithPrefix(prefix) 1502} 1503 1504type awsAccessKey struct { 1505 AccessKeyID string 1506 SecretAccessKey string 1507} 1508 1509type credentialTestFunc func(string, string, string) error 1510