Skip to content

Commit 4618d37

Browse files
committed
Add README for STS; cleanup
Added the README.md file for the STS examples. Also, added and updated comments and snippet tags.
1 parent a012b1b commit 4618d37

File tree

2 files changed

+192
-70
lines changed

2 files changed

+192
-70
lines changed

swift/example_code/sts/AssumeRole/Sources/entry.swift

Lines changed: 103 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,69 @@
22
// SPDX-License-Identifier: Apache-2.0
33
//
44
/// A simple example that shows how to use the AWS SDK for Swift to
5-
/// authenticate using an AWS IAM role ARN.
5+
/// authenticate using optional static credentials and an AWS IAM role ARN.
66

7-
// snippet-start:[swift.static-resolver.imports]
7+
// snippet-start:[swift.AssumeRole.imports]
88
import ArgumentParser
99
import AWSClientRuntime
1010
import AWSS3
1111
import AWSSDKIdentity
1212
import AWSSTS
1313
import Foundation
1414
import SmithyIdentity
15-
// snippet-end:[swift.static-resolver.imports]
15+
// snippet-end:[swift.AssumeRole.imports]
1616

1717
struct ExampleCommand: ParsableCommand {
1818
@Option(help: "AWS access key ID")
19-
var accessKey: String
19+
var accessKey: String? = nil
2020
@Option(help: "AWS secret access key")
21-
var secretKey: String
21+
var secretKey: String? = nil
2222
@Option(help: "Session token")
2323
var sessionToken: String? = nil
2424
@Argument(help: "ARN of the role to assume")
2525
var roleArn: String
2626

2727
static var configuration = CommandConfiguration(
28-
commandName: "static-resolver",
28+
commandName: "AssumeRole",
2929
abstract: """
30-
Authenticate using the access key, secret access key, and role provided.
31-
Then list the available buckets.
30+
Authenticate using the specified role, optionally using specified
31+
access key, secret access key, and session token first.
3232
""",
3333
discussion: """
34-
This program uses the specified credentials when assuming the specified
35-
role, then uses the credentials returned by the role to list the user's
36-
buckets. This shows a couple of ways to use a
34+
This program uses the specified access key, secret access key, and
35+
optional session token, to request temporary credentials for the
36+
specified role Then it uses the credentials to list the user's
37+
Amazon S3 buckets. This shows a couple of ways to use a
3738
StaticAWSCredentialIdentityResolver object.
3839
"""
3940
)
4041

4142
/// Called by ``main()`` to do the actual running of the AWS
4243
/// example.
43-
// snippet-start:[swift.static-resolver.command.runasync]
44+
// snippet-start:[swift.AssumeRole.command.runasync]
4445
func runAsync() async throws {
45-
// Authenticate using the command line inputs.
46+
// If credentials are specified, create a credential identity
47+
// resolver that uses them to authenticate. This identity will be used
48+
// to ask for permission to use the specified role.
49+
4650
var identityResolver: StaticAWSCredentialIdentityResolver? = nil
47-
/*
48-
do {
49-
identityResolver = try getIdentityResolver(accessKey: accessKey,
50-
secretKey: secretKey, sessionToken: sessionToken)
51-
} catch {
52-
print("ERROR: Unable to get identity resolver in runAsync:",
53-
dump(error))
54-
throw error
51+
52+
if accessKey != nil && secretKey != nil {
53+
do {
54+
identityResolver = try getIdentityResolver(accessKey: accessKey,
55+
secretKey: secretKey, sessionToken: sessionToken)
56+
} catch {
57+
print("ERROR: Unable to get identity resolver in runAsync:",
58+
dump(error))
59+
throw error
60+
}
5561
}
56-
*/
5762

58-
// Assume the role.
63+
// Assume the role using the credentials provided on the command line,
64+
// or using the default credentials if none were specified.
5965

6066
do {
61-
// snippet-start: [swift.static-resolver.use-role-credentials]
67+
// snippet-start: [swift.AssumeRole.use-role-credentials]
6268
let credentials = try await assumeRole(identityResolver: identityResolver,
6369
roleArn: roleArn)
6470
do {
@@ -72,7 +78,7 @@ struct ExampleCommand: ParsableCommand {
7278
dump(error))
7379
throw error
7480
}
75-
// snippet-end: [swift.static-resolver.use-role-credentials]
81+
// snippet-end: [swift.AssumeRole.use-role-credentials]
7682
} catch {
7783
print("ERROR: Error assuming role in runAsync:", dump(error))
7884
throw AssumeRoleExampleError.assumeRoleFailed
@@ -92,14 +98,21 @@ struct ExampleCommand: ParsableCommand {
9298
throw error
9399
}
94100
}
95-
// snippet-end:[swift.static-resolver.command.runasync]
101+
// snippet-end:[swift.AssumeRole.command.runasync]
96102
}
97103

104+
/// An `Error` type used to return errors from the
105+
/// `assumeRole(identityResolver: roleArn:)` function.
98106
enum AssumeRoleExampleError: Error {
107+
/// An error indicating that the STS `AssumeRole` request failed.
99108
case assumeRoleFailed
109+
/// An error indicating that the returned credentials were missing
110+
/// required information.
100111
case incompleteCredentials
112+
/// An error indicating that no credentials were returned by `AssumeRole`.
101113
case missingCredentials
102114

115+
/// Return a human-readable explanation of the error.
103116
var errorDescription: String? {
104117
switch self {
105118
case .assumeRoleFailed:
@@ -112,78 +125,94 @@ enum AssumeRoleExampleError: Error {
112125
}
113126
}
114127

115-
// snippet-start:[swift.static-resolver.assumeRole-function]
128+
// snippet-start:[swift.AssumeRole.assumeRole-function]
129+
/// Assume the specified role. If any kind of credential identity resolver is
130+
/// specified, that identity is adopted before assuming the role.
131+
///
132+
/// - Parameters:
133+
/// - identityResolver: Any kind of `AWSCredentialIdentityResolver`. If
134+
/// provided, this identity is adopted before attempting to assume the
135+
/// specified role.
136+
/// - roleArn: The ARN of the AWS role to assume.
137+
///
138+
/// - Throws: Re-throws STS errors. Also can throw any
139+
/// `AssumeRoleExampleError`.
140+
/// - Returns: An `AWSCredentialIdentity` containing the temporary credentials
141+
/// assigned.
116142
func assumeRole(identityResolver: (any AWSCredentialIdentityResolver)?,
117143
roleArn: String) async throws -> AWSCredentialIdentity {
118144
let stsConfiguration = try await STSClient.STSClientConfiguration(
119145
awsCredentialIdentityResolver: identityResolver
120146
)
121147
let stsClient = STSClient(config: stsConfiguration)
122148

149+
// Assume the role and return the assigned credentials.
150+
151+
// snippet-start: [swift.sts.AssumeRole]
123152
let input = AssumeRoleInput(
124153
roleArn: roleArn,
125-
roleSessionName: "Static-Resolver-Example"
154+
roleSessionName: "AssumeRole-Example"
126155
)
127156

128-
// Assume the role and return the assigned credentials.
157+
let output = try await stsClient.assumeRole(input: input)
129158

130-
do {
131-
let output = try await stsClient.assumeRole(input: input)
132-
133-
guard let credentials = output.credentials else {
134-
throw AssumeRoleExampleError.missingCredentials
135-
}
159+
guard let credentials = output.credentials else {
160+
throw AssumeRoleExampleError.missingCredentials
161+
}
136162

137-
guard let accessKey = credentials.accessKeyId,
138-
let secretKey = credentials.secretAccessKey,
139-
let sessionToken = credentials.sessionToken else {
140-
throw AssumeRoleExampleError.incompleteCredentials
141-
}
163+
guard let accessKey = credentials.accessKeyId,
164+
let secretKey = credentials.secretAccessKey,
165+
let sessionToken = credentials.sessionToken else {
166+
throw AssumeRoleExampleError.incompleteCredentials
167+
}
168+
// snippet-end: [swift.sts.AssumeRole]
142169

143-
// Return an `AWSCredentialIdentity` object with the temporary
144-
// credentials.
170+
// Return an `AWSCredentialIdentity` object with the temporary
171+
// credentials.
145172

146-
let awsCredentials = AWSCredentialIdentity(
147-
accessKey: accessKey,
148-
secret: secretKey,
149-
sessionToken: sessionToken
150-
)
151-
return awsCredentials
152-
}
173+
let awsCredentials = AWSCredentialIdentity(
174+
accessKey: accessKey,
175+
secret: secretKey,
176+
sessionToken: sessionToken
177+
)
178+
return awsCredentials
153179
}
154-
// snippet-end:[swift.static-resolver.assumeRole-function]
180+
// snippet-end:[swift.AssumeRole.assumeRole-function]
155181

156-
// snippet-start:[s3.swift.intro.getbucketnames]
157-
// Return an array containing the names of all available buckets.
158-
//
159-
// - Returns: An array of strings listing the buckets.
182+
/// Return an array containing the names of all available buckets using
183+
/// the specified credential identity resolver to authenticate.
184+
///
185+
/// - Parameter identityResolver: Any type of `AWSCredentialIdentityResolver`,
186+
/// used to authenticate and authorize the user for access to the bucket
187+
/// names.
188+
///
189+
/// - Throws: Re-throws errors from `ListBucketsPaginated`.
190+
///
191+
/// - Returns: An array of strings listing the buckets.
160192
func getBucketNames(identityResolver: (any AWSCredentialIdentityResolver)?)
161193
async throws -> [String] {
162194
do {
163195
// Get an S3Client with which to access Amazon S3.
164-
// snippet-start:[s3.swift.intro.client-init]
196+
// snippet-start:[swift.AssumeRole.use-resolver]
165197
let configuration = try await S3Client.S3ClientConfiguration(
166198
awsCredentialIdentityResolver: identityResolver
167199
)
168-
// configuration.region = "us-east-2" // Uncomment this to set the region programmatically.
169200
let client = S3Client(config: configuration)
170-
// snippet-end:[s3.swift.intro.client-init]
171201

172-
// snippet-start:[s3.swift.intro.listbuckets]
173-
// Use "Paginated" to get all the buckets.
174-
// This lets the SDK handle the 'continuationToken' in "ListBucketsOutput".
202+
// Use "Paginated" to get all the buckets. This lets the SDK handle
203+
// the 'continuationToken' in "ListBucketsOutput".
175204
let pages = client.listBucketsPaginated(
176205
input: ListBucketsInput( maxBuckets: 10)
177206
)
178-
// snippet-end:[s3.swift.intro.listbuckets]
207+
// snippet-end:[swift.AssumeRole.use-resolver]
179208

180209
// Get the bucket names.
181210
var bucketNames: [String] = []
182211

183212
do {
184213
for try await page in pages {
185214
guard let buckets = page.buckets else {
186-
print("Error: no buckets returned.")
215+
print("Error: page is empty.")
187216
continue
188217
}
189218

@@ -210,22 +239,28 @@ func getBucketNames(identityResolver: (any AWSCredentialIdentityResolver)?)
210239
/// - Throws: Re-throws errors from AWSSDKIdentity.
211240
/// - Returns: A `StaticAWSCredentialIdentityResolver` that can be used when
212241
/// configuring service clients.
213-
func getIdentityResolver(accessKey: String, secretKey: String,
242+
func getIdentityResolver(accessKey: String?, secretKey: String?,
214243
sessionToken: String?)
215-
throws -> StaticAWSCredentialIdentityResolver {
244+
throws -> StaticAWSCredentialIdentityResolver? {
245+
246+
if accessKey == nil || secretKey == nil {
247+
return nil
248+
}
249+
250+
guard let accessKey = accessKey,
251+
let secretKey = secretKey else {
252+
return nil
253+
}
254+
216255
let credentials = AWSCredentialIdentity(
217256
accessKey: accessKey,
218257
secret: secretKey,
219-
//expiration: cognitoCredentials.expiration,
220258
sessionToken: sessionToken
221259
)
222260

223261
return try StaticAWSCredentialIdentityResolver(credentials)
224262
}
225263

226-
// snippet-end:[s3.swift.intro.getbucketnames]
227-
228-
// snippet-start:[s3.swift.intro.main]
229264
/// The program's asynchronous entry point.
230265
@main
231266
struct Main {
@@ -240,5 +275,3 @@ struct Main {
240275
}
241276
}
242277
}
243-
244-
// snippet-end:[s3.swift.intro.main]

swift/example_code/sts/README.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# AWS STS code examples for the SDK for Swift
2+
3+
## Overview
4+
5+
Shows how to use the AWS SDK for Swift to work with AWS Security Token Service (AWS STS).
6+
7+
<!--custom.overview.start-->
8+
<!--custom.overview.end-->
9+
10+
_AWS STS creates and provides trusted users with temporary security credentials that can control access to your AWS resources._
11+
12+
## ⚠ Important
13+
14+
* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/).
15+
* Running the tests might result in charges to your AWS account.
16+
* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege).
17+
* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services).
18+
19+
<!--custom.important.start-->
20+
<!--custom.important.end-->
21+
22+
## Code examples
23+
24+
### Prerequisites
25+
26+
For prerequisites, see the [README](../../README.md#Prerequisites) in the `swift` folder.
27+
28+
29+
<!--custom.prerequisites.start-->
30+
<!--custom.prerequisites.end-->
31+
32+
### Single actions
33+
34+
Code excerpts that show you how to call individual service functions.
35+
36+
- [AssumeRole](../iam/basics/Sources/ServiceHandler/ServiceHandlerSTS.swift#L160)
37+
38+
39+
<!--custom.examples.start-->
40+
<!--custom.examples.end-->
41+
42+
## Run the examples
43+
44+
### Instructions
45+
46+
To build any of these examples from a terminal window, navigate into its
47+
directory, then use the following command:
48+
49+
```
50+
$ swift build
51+
```
52+
53+
To build one of these examples in Xcode, navigate to the example's directory
54+
(such as the `ListUsers` directory, to build that example). Then type `xed.`
55+
to open the example directory in Xcode. You can then use standard Xcode build
56+
and run commands.
57+
58+
<!--custom.instructions.start-->
59+
<!--custom.instructions.end-->
60+
61+
62+
63+
### Tests
64+
65+
⚠ Running tests might result in charges to your AWS account.
66+
67+
68+
To find instructions for running these tests, see the [README](../../README.md#Tests)
69+
in the `swift` folder.
70+
71+
72+
73+
<!--custom.tests.start-->
74+
<!--custom.tests.end-->
75+
76+
## Additional resources
77+
78+
- [AWS STS User Guide](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_temp.html)
79+
- [AWS STS API Reference](https://docs.aws.amazon.com/STS/latest/APIReference/welcome.html)
80+
- [SDK for Swift AWS STS reference](https://sdk.amazonaws.com/swift/api/awssts/latest/documentation/awssts)
81+
82+
<!--custom.resources.start-->
83+
<!--custom.resources.end-->
84+
85+
---
86+
87+
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
88+
89+
SPDX-License-Identifier: Apache-2.0

0 commit comments

Comments
 (0)