-
Notifications
You must be signed in to change notification settings - Fork 81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add integration test for STS assume role credentials provider. #1839
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,130 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation | ||
import XCTest | ||
import AWSSTS | ||
import AWSIAM | ||
import AWSSDKIdentity | ||
import ClientRuntime | ||
|
||
class STSAssumeRoleAWSCredentialIdentityResolverTests: XCTestCase { | ||
private let region = "us-east-1" | ||
|
||
// MARK: - Clients, policies, and variables | ||
|
||
// STS client with only the STSAssumeRoleAWSCredentialIdentityResolver configured. | ||
private var assumeRoleStsClient: STSClient! | ||
private var assumeRoleStsConfig: STSClient.STSClientConfiguration! | ||
|
||
// Used to create temporary role assumed by STS assume role credentials provider. | ||
private var iamClient: IAMClient! | ||
private let roleName = "aws-sts-integration-test-\(UUID().uuidString.split(separator: "-").first!.lowercased())" | ||
private let roleSessionName = "aws-sts-integration-test-\(UUID().uuidString.split(separator: "-").first!.lowercased())" | ||
private var roleArn: String! | ||
|
||
// JSON assume role policy | ||
private func assumeRolePolicy(acctID: String) -> String { | ||
return """ | ||
{ | ||
"Version": "2012-10-17", | ||
"Statement": [ | ||
{ | ||
"Effect": "Allow", | ||
"Principal": { | ||
"AWS": "arn:aws:iam::\(acctID):root" | ||
}, | ||
"Action": "sts:AssumeRole" | ||
} | ||
] | ||
} | ||
""" | ||
} | ||
|
||
private let identityPolicyName = "temp-allow-STS-getCallerIdentity" | ||
// JSON identity policy | ||
private let roleIdentityPolicy = """ | ||
{"Version": "2012-10-17","Statement": [{"Sid": "","Effect": "Allow", | ||
"Action": "sts:GetCallerIdentity","Resource": "*"}]} | ||
Comment on lines
+48
to
+52
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: consider creating a constant and moving these to another file There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For now this identity policy is only used by this test, so it makes sense to have it in same file as the tests for cohesion. When new integration tests down the line use identical policies, then we can consider refactoring it. |
||
""" | ||
|
||
// MARK: - Test case | ||
|
||
// Confirm STS assume role credentials provider works by validating response. | ||
func testGetCallerIdentity() async throws { | ||
let response = try await assumeRoleStsClient.getCallerIdentity( | ||
input: GetCallerIdentityInput() | ||
) | ||
|
||
// Ensure returned caller info aren't nil | ||
let account = try XCTUnwrap(response.account) | ||
let userId = try XCTUnwrap(response.userId) | ||
let arn = try XCTUnwrap(response.arn) | ||
|
||
// Ensure returned caller info aren't empty strings | ||
XCTAssertNotEqual(account, "") | ||
XCTAssertNotEqual(userId, "") | ||
XCTAssertNotEqual(arn, "") | ||
} | ||
|
||
// MARK: - Setup & teardown | ||
|
||
override func setUp() async throws { | ||
guard let acctID = try await STSClient(region: region).getCallerIdentity(input: GetCallerIdentityInput()).account else { | ||
throw AssumeRoleTestError.failedToGetAccountID("Failed to retrieve account ID for the test.") | ||
} | ||
|
||
// Create role with trust policy (assume role policy). | ||
iamClient = try IAMClient(region: region) | ||
roleArn = try await iamClient.createRole(input: CreateRoleInput( | ||
assumeRolePolicyDocument: assumeRolePolicy(acctID: acctID), | ||
roleName: roleName | ||
)).role?.arn | ||
// This wait is necessary for role creation to propagate everywhere | ||
let seconds = 10 | ||
let NSEC_PER_SEC = 1_000_000_000 | ||
try await Task.sleep(nanoseconds: UInt64(seconds * NSEC_PER_SEC)) | ||
|
||
// Attach identity policy to role. | ||
_ = try await iamClient.putRolePolicy(input: PutRolePolicyInput( | ||
policyDocument: roleIdentityPolicy, | ||
policyName: identityPolicyName, | ||
roleName: roleName | ||
)) | ||
|
||
// Construct STS client wih assume-role credentials provider. | ||
let underlyingResolver = try DefaultAWSCredentialIdentityResolverChain() | ||
let assumeRoleAWSCredentialIdentityResolver = try STSAssumeRoleAWSCredentialIdentityResolver( | ||
awsCredentialIdentityResolver: underlyingResolver, | ||
roleArn: roleArn, | ||
sessionName: roleSessionName | ||
) | ||
assumeRoleStsConfig = try await STSClient.STSClientConfiguration( | ||
awsCredentialIdentityResolver: assumeRoleAWSCredentialIdentityResolver, | ||
region: region | ||
) | ||
assumeRoleStsClient = STSClient(config: assumeRoleStsConfig) | ||
} | ||
|
||
override func tearDown() async throws { | ||
// Delete identity policy attached to role (inline policy). | ||
let policyName = try await iamClient.listRolePolicies(input: ListRolePoliciesInput(roleName: roleName)).policyNames | ||
_ = try await iamClient.deleteRolePolicy(input: DeleteRolePolicyInput( | ||
policyName: policyName?[0], roleName: roleName | ||
)) | ||
|
||
// Delete role | ||
_ = try? await iamClient.deleteRole(input: DeleteRoleInput(roleName: roleName)) | ||
} | ||
|
||
// MARK: - ERROR USED IN SETUP | ||
enum AssumeRoleTestError: Error { | ||
case failedToGetAccountID(String) | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: consider extract this out to a helper function since assume role is also used in IMDS integration test
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One in IMDS integ test is slightly different bc that one allows EC2 principal rather than account principal. I think it probably will require a function that needs multiple arguments with messy string concat logic just to handle the two cases.
But if more and more integration tests have this sort of duplicates, we can then consider refactoring integration test suite a bit and adding some utility class that can be used by any test for common uses like these.