boto3-refresh-session 1.0.4__py3-none-any.whl → 6.2.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- boto3_refresh_session/__init__.py +14 -4
- boto3_refresh_session/exceptions.py +51 -0
- boto3_refresh_session/methods/__init__.py +10 -0
- boto3_refresh_session/methods/custom.py +141 -0
- boto3_refresh_session/methods/iot/__init__.py +7 -0
- boto3_refresh_session/methods/iot/core.py +40 -0
- boto3_refresh_session/methods/iot/x509.py +570 -0
- boto3_refresh_session/methods/sts.py +230 -0
- boto3_refresh_session/session.py +67 -123
- boto3_refresh_session/utils/__init__.py +10 -0
- boto3_refresh_session/utils/cache.py +94 -0
- boto3_refresh_session/utils/internal.py +437 -0
- boto3_refresh_session/utils/typing.py +133 -0
- boto3_refresh_session-6.2.5.dist-info/METADATA +564 -0
- boto3_refresh_session-6.2.5.dist-info/RECORD +18 -0
- {boto3_refresh_session-1.0.4.dist-info → boto3_refresh_session-6.2.5.dist-info}/WHEEL +1 -1
- boto3_refresh_session-6.2.5.dist-info/licenses/NOTICE +12 -0
- boto3_refresh_session-1.0.4.dist-info/METADATA +0 -102
- boto3_refresh_session-1.0.4.dist-info/RECORD +0 -6
- {boto3_refresh_session-1.0.4.dist-info → boto3_refresh_session-6.2.5.dist-info/licenses}/LICENSE +0 -0
|
@@ -0,0 +1,564 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: boto3-refresh-session
|
|
3
|
+
Version: 6.2.5
|
|
4
|
+
Summary: A simple Python package for refreshing the temporary security credentials in a boto3.session.Session object automatically.
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
License-File: NOTICE
|
|
8
|
+
Keywords: boto3,botocore,aws,sts,credentials,token,refresh,iot,x509,mqtt
|
|
9
|
+
Author: Mike Letts
|
|
10
|
+
Author-email: lettsmt@gmail.com
|
|
11
|
+
Maintainer: Michael Letts
|
|
12
|
+
Maintainer-email: lettsmt@gmail.com
|
|
13
|
+
Requires-Python: >=3.10
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
|
+
Requires-Dist: awscrt
|
|
22
|
+
Requires-Dist: awsiotsdk
|
|
23
|
+
Requires-Dist: boto3
|
|
24
|
+
Requires-Dist: botocore
|
|
25
|
+
Requires-Dist: requests
|
|
26
|
+
Requires-Dist: typing-extensions
|
|
27
|
+
Project-URL: Documentation, https://michaelthomasletts.github.io/boto3-refresh-session/index.html
|
|
28
|
+
Project-URL: Repository, https://github.com/michaelthomasletts/boto3-refresh-session
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
<div align="center">
|
|
32
|
+
<img src="https://raw.githubusercontent.com/michaelthomasletts/boto3-refresh-session/refs/heads/main/doc/brs.png" />
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
</br>
|
|
36
|
+
|
|
37
|
+
<div align="center"><em>
|
|
38
|
+
A simple Python package for refreshing the temporary security credentials in a <code>boto3.session.Session</code> object automatically.
|
|
39
|
+
</em></div>
|
|
40
|
+
|
|
41
|
+
</br>
|
|
42
|
+
|
|
43
|
+
<div align="center">
|
|
44
|
+
|
|
45
|
+
<a href="https://pypi.org/project/boto3-refresh-session/">
|
|
46
|
+
<img
|
|
47
|
+
src="https://img.shields.io/pypi/v/boto3-refresh-session?color=%23FF0000FF&logo=python&label=Latest%20Version"
|
|
48
|
+
alt="pypi_version"
|
|
49
|
+
/>
|
|
50
|
+
</a>
|
|
51
|
+
|
|
52
|
+
<a href="https://pypi.org/project/boto3-refresh-session/">
|
|
53
|
+
<img
|
|
54
|
+
src="https://img.shields.io/pypi/pyversions/boto3-refresh-session?style=pypi&color=%23FF0000FF&logo=python&label=Compatible%20Python%20Versions"
|
|
55
|
+
alt="py_version"
|
|
56
|
+
/>
|
|
57
|
+
</a>
|
|
58
|
+
|
|
59
|
+
<a href="https://github.com/michaelthomasletts/boto3-refresh-session/actions/workflows/push.yml">
|
|
60
|
+
<img
|
|
61
|
+
src="https://img.shields.io/github/actions/workflow/status/michaelthomasletts/boto3-refresh-session/push.yml?logo=github&color=%23FF0000FF&label=Build"
|
|
62
|
+
alt="workflow"
|
|
63
|
+
/>
|
|
64
|
+
</a>
|
|
65
|
+
|
|
66
|
+
<a href="https://github.com/michaelthomasletts/boto3-refresh-session/commits/main">
|
|
67
|
+
<img
|
|
68
|
+
src="https://img.shields.io/github/last-commit/michaelthomasletts/boto3-refresh-session?logo=github&color=%23FF0000FF&label=Last%20Commit"
|
|
69
|
+
alt="last_commit"
|
|
70
|
+
/>
|
|
71
|
+
</a>
|
|
72
|
+
|
|
73
|
+
<a href="https://github.com/michaelthomasletts/boto3-refresh-session/stargazers">
|
|
74
|
+
<img
|
|
75
|
+
src="https://img.shields.io/github/stars/michaelthomasletts/boto3-refresh-session?style=flat&logo=github&labelColor=555&color=FF0000&label=Stars"
|
|
76
|
+
alt="stars"
|
|
77
|
+
/>
|
|
78
|
+
</a>
|
|
79
|
+
|
|
80
|
+
<a href="https://pepy.tech/projects/boto3-refresh-session">
|
|
81
|
+
<img
|
|
82
|
+
src="https://img.shields.io/endpoint?url=https%3A%2F%2Fmichaelthomasletts.github.io%2Fpepy-stats%2Fboto3-refresh-session.json&style=flat&logo=python&labelColor=555&color=FF0000"
|
|
83
|
+
alt="downloads"
|
|
84
|
+
/>
|
|
85
|
+
</a>
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
<a href="https://michaelthomasletts.github.io/boto3-refresh-session/index.html">
|
|
89
|
+
<img
|
|
90
|
+
src="https://img.shields.io/badge/Official%20Documentation-📘-FF0000?style=flat&labelColor=555&logo=readthedocs"
|
|
91
|
+
alt="documentation"
|
|
92
|
+
/>
|
|
93
|
+
</a>
|
|
94
|
+
|
|
95
|
+
<a href="https://github.com/michaelthomasletts/boto3-refresh-session">
|
|
96
|
+
<img
|
|
97
|
+
src="https://img.shields.io/badge/Source%20Code-💻-FF0000?style=flat&labelColor=555&logo=github"
|
|
98
|
+
alt="github"
|
|
99
|
+
/>
|
|
100
|
+
</a>
|
|
101
|
+
|
|
102
|
+
<a href="https://michaelthomasletts.github.io/boto3-refresh-session/qanda.html">
|
|
103
|
+
<img
|
|
104
|
+
src="https://img.shields.io/badge/Q%26A-❔-FF0000?style=flat&labelColor=555&logo=vercel&label=Q%26A"
|
|
105
|
+
alt="qanda"
|
|
106
|
+
/>
|
|
107
|
+
</a>
|
|
108
|
+
|
|
109
|
+
<a href="https://michaelthomasletts.github.io/blog/brs-rationale/">
|
|
110
|
+
<img
|
|
111
|
+
src="https://img.shields.io/badge/Blog%20Post-📘-FF0000?style=flat&labelColor=555&logo=readthedocs"
|
|
112
|
+
alt="blog"
|
|
113
|
+
/>
|
|
114
|
+
</a>
|
|
115
|
+
|
|
116
|
+
<a href="https://github.com/sponsors/michaelthomasletts">
|
|
117
|
+
<img
|
|
118
|
+
src="https://img.shields.io/badge/Sponsor%20this%20Project-💙-FF0000?style=flat&labelColor=555&logo=githubsponsors"
|
|
119
|
+
alt="sponsorship"
|
|
120
|
+
/>
|
|
121
|
+
</a>
|
|
122
|
+
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
## 😛 Features
|
|
126
|
+
|
|
127
|
+
- Drop-in replacement for `boto3.session.Session`
|
|
128
|
+
- MFA support included for STS
|
|
129
|
+
- SSO support via AWS profiles
|
|
130
|
+
- Optionally caches boto3 clients
|
|
131
|
+
- Supports automatic temporary credential refresh for:
|
|
132
|
+
- **STS**
|
|
133
|
+
- **IoT Core**
|
|
134
|
+
- X.509 certificates w/ role aliases over mTLS (PEM files and PKCS#11)
|
|
135
|
+
- MQTT actions are available!
|
|
136
|
+
- [Tested](https://github.com/michaelthomasletts/boto3-refresh-session/tree/main/tests), [documented](https://michaelthomasletts.github.io/boto3-refresh-session/index.html), and [published to PyPI](https://pypi.org/project/boto3-refresh-session/)
|
|
137
|
+
|
|
138
|
+
## 😌 Recognition and Testimonials
|
|
139
|
+
|
|
140
|
+
[Featured in TL;DR Sec.](https://tldrsec.com/p/tldr-sec-282)
|
|
141
|
+
|
|
142
|
+
[Featured in CloudSecList.](https://cloudseclist.com/issues/issue-290)
|
|
143
|
+
|
|
144
|
+
Recognized during AWS Community Day Midwest on June 5th, 2025 (the founder's birthday!).
|
|
145
|
+
|
|
146
|
+
A testimonial from a Cyber Security Engineer at a FAANG company:
|
|
147
|
+
|
|
148
|
+
> _Most of my work is on tooling related to AWS security, so I'm pretty choosy about boto3 credentials-adjacent code. I often opt to just write this sort of thing myself so I at least know that I can reason about it. But I found boto3-refresh-session to be very clean and intuitive [...] We're using the RefreshableSession class as part of a client cache construct [...] We're using AWS Lambda to perform lots of operations across several regions in hundreds of accounts, over and over again, all day every day. And it turns out that there's a surprising amount of overhead to creating boto3 clients (mostly deserializing service definition json), so we can run MUCH more efficiently if we keep a cache of clients, all equipped with automatically refreshing sessions._
|
|
149
|
+
|
|
150
|
+
## 💻 Installation
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install boto3-refresh-session
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## 🏃 Quick Start Guide
|
|
157
|
+
|
|
158
|
+
The following example shows how to initialize `RefreshableSession` using an AWS profile, enable MFA support, initialize an S3 client with some configurations, and list some buckets in S3.
|
|
159
|
+
|
|
160
|
+
```python
|
|
161
|
+
from boto3_refresh_session import RefreshableSession
|
|
162
|
+
from botocore.config import Config
|
|
163
|
+
import subprocess
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def mfa_token_provider(cmd: list[str], timeout: float = 10.0):
|
|
167
|
+
"""Returns an MFA code. This is completely optional, unless you want MFA enabled."""
|
|
168
|
+
|
|
169
|
+
p = subprocess.run(
|
|
170
|
+
cmd,
|
|
171
|
+
check=False,
|
|
172
|
+
capture_output=True,
|
|
173
|
+
text=True,
|
|
174
|
+
timeout=timeout,
|
|
175
|
+
)
|
|
176
|
+
return (p.stdout or "").strip()
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
session = RefreshableSession(
|
|
180
|
+
assume_role_kwargs={
|
|
181
|
+
"RoleArn": "arn:aws:iam::123456789012:role/CoolGuy", # required
|
|
182
|
+
"RoleSessionName": "just-goofin-around", # defaults to 'boto3-refresh-session'
|
|
183
|
+
"SerialNumber": "arn:aws:iam::123456789012:mfa/test-user", # required if using MFA
|
|
184
|
+
},
|
|
185
|
+
mfa_token_provider=mfa_token_provider, # required if using MFA
|
|
186
|
+
mfa_token_provider_kwargs={ # depends on if mfa_token_provider needs args
|
|
187
|
+
"cmd": ["ykman", "oath", "code", "--single", "AWS-prod"],
|
|
188
|
+
"timeout": 3.0
|
|
189
|
+
},
|
|
190
|
+
profile_name="test-aws-profile",
|
|
191
|
+
)
|
|
192
|
+
s3 = session.client("s3", config=Config(retries={"max_attempts": 2}))
|
|
193
|
+
s3.list_buckets()
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
## 📝 Usage
|
|
197
|
+
|
|
198
|
+
<details>
|
|
199
|
+
<summary><strong>Core Concepts (click to expand)</strong></summary>
|
|
200
|
+
|
|
201
|
+
### Core Concepts
|
|
202
|
+
|
|
203
|
+
1. `RefreshableSession` is the intended interface for using `boto3-refresh-session`. Whether you're using this package to refresh temporary credentials returned by STS, the IoT credential provider (which is really just STS, but I digress), or some custom authentication or credential provider, `RefreshableSession` is where you *ought to* be working when using `boto3-refresh-session`.
|
|
204
|
+
|
|
205
|
+
2. *You can use all of the same keyword parameters normally associated with `boto3.session.Session`!* For instance, suppose you want to pass `region_name` to `RefreshableSession` as a parameter, whereby it's passed to `boto3.session.Session`. That's perfectly fine! Just pass it like you normally would when initializing `boto3.session.Session`. These keyword parameters are *completely optional*, though. If you're confused, the main idea to remember is this: if initializing `boto3.session.Session` *requires* a particular keyword parameter then pass it to `RefreshableSession`; if not, don't worry about it.
|
|
206
|
+
|
|
207
|
+
3. To tell `RefreshableSession` which AWS service you're working with for authentication and credential retrieval purposes (STS vs. IoT vs. some custom credential provider), you'll need to pass a `method` parameter to `RefreshableSession`. Since the `service_name` namespace is already occupied by `boto3.sesssion.Session`, [`boto3-refresh-session` uses `method` instead of "service" so as to avoid confusion](https://github.com/michaelthomasletts/boto3-refresh-session/blob/04acb2adb34e505c4dc95711f6b2f97748a2a489/boto3_refresh_session/utils/typing.py#L40). If you're using `RefreshableSession` for STS, however, then `method` is set to `"sts"` by default. You don't need to pass the `method` keyword argument in that case.
|
|
208
|
+
|
|
209
|
+
4. Using `RefreshableSession` for STS, IoT, or custom flows requires different keyword parameters that are unique to those particular methods. For instance, `STSRefreshableSession`, which is the engine for STS in `boto3-refresh-session`, requires `assume_role_kwargs` and optionally allows `sts_client_kwargs` whereas `CustomRefreshableSession` and `IoTX509RefreshableSession` do not. To familiarize yourself with the keyword parameters for each method, check the documentation for each of those engines [in the Refresh Strategies section here](https://michaelthomasletts.com/boto3-refresh-session/modules/index.html).
|
|
210
|
+
|
|
211
|
+
5. Irrespective of whatever `method` you pass as a keyword parameter, `RefreshableSession` accepts a keyword parameter named `defer_refresh`. Basically, this boolean tells `boto3-refresh-session` either to refresh credentials *the moment they expire* or to *wait until credentials are explicitly needed*. If you are working in a low-latency environment then `defer_refresh = False` might be helpful. For most users, however, `defer_refresh = True` is most desirable. For that reason, `defer_refresh = True` is the default value. Most users, therefore, should not concern themselves too much with this feature.
|
|
212
|
+
|
|
213
|
+
6. Some developers struggle to imagine where `boto3-refresh-session` might be helpful. To figure out if `boto3-refresh-session` is for your use case, or whether `credential_process` satisfies your needs, check out [this blog post](https://michaelthomasletts.com/blog/brs-rationale/). `boto3-refresh-session` is not for every developer or use-case; it is a niche tool.
|
|
214
|
+
|
|
215
|
+
7. `boto3-refresh-session` supports client caching in order to minimize the massive memory footprint associated with duplicative clients. By default, `RefreshableSession` caches clients. To deactivate this feature, set `cache_clients=False`.
|
|
216
|
+
|
|
217
|
+
8. `boto3-refresh-session` supports MFA. Refer to the MFA section further below for more details.
|
|
218
|
+
|
|
219
|
+
9. `boto3-refresh-session` supports SSO; however, it _does not_ and _will never_ automatically handle `sso login` for you -- that is, not unless you write your own hacky custom credential getter and pass that to `RefreshableSession(method="custom", ...)`, which I do not recommend (but cannot prevent you from doing).
|
|
220
|
+
|
|
221
|
+
</details>
|
|
222
|
+
|
|
223
|
+
<details>
|
|
224
|
+
<summary><strong>Clients (click to expand)</strong></summary>
|
|
225
|
+
|
|
226
|
+
### Clients
|
|
227
|
+
|
|
228
|
+
Most developers who use `boto3` interact primarily with `boto3.client` instead of `boto3.session.Session`. But many developers may not realize that `boto3.session.Session` belies `boto3.client`! In fact, that's precisely what makes `boto3-refresh-session` possible!
|
|
229
|
+
|
|
230
|
+
Before we get to initializing clients via `RefreshableSession`, however, let's briefly talk about `boto3` clients and memory . . .
|
|
231
|
+
|
|
232
|
+
Clients consume a shocking amount of memory. So much so that many developers create their own bespoke client cache. To minimize the memory footprint associated with duplicative clients, as well as make the lives of developers a little easier, `boto3-refresh-session` includes a `cache_clients` parameter which, by default, caches clients according to the parameters passed to the `client` method!
|
|
233
|
+
|
|
234
|
+
With client caching out of the way, in order to use the `boto3.client` interface, but with the benefits of `boto3-refresh-session`, you have a few options! In the following examples, let's assume you want to use STS for retrieving temporary credentials for the sake of simplicity. Let's also focus specifically on `client`. Switching to `resource` follows the same exact idioms as below, except that `client` must be switched to `resource` in the pseudo-code, obviously. If you are not sure how to use `RefreshableSession` for STS (or custom auth flows) then check the usage instructions in the following sections!
|
|
235
|
+
|
|
236
|
+
##### `RefreshableSession.client` (Recommended)
|
|
237
|
+
|
|
238
|
+
So long as you reuse the same `session` object when creating `client` objects, this approach can be used everywhere in your code.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
from boto3_refresh_session import RefreshableSession
|
|
242
|
+
|
|
243
|
+
assume_role_kwargs = {
|
|
244
|
+
"RoleArn": "<your-role-arn>",
|
|
245
|
+
"RoleSessionName": "<your-role-session-name>",
|
|
246
|
+
"DurationSeconds": "<your-selection>",
|
|
247
|
+
...
|
|
248
|
+
}
|
|
249
|
+
session = RefreshableSession(assume_role_kwargs=assume_role_kwargs)
|
|
250
|
+
s3 = session.client("s3")
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
##### `DEFAULT_SESSION`
|
|
254
|
+
|
|
255
|
+
This technique can be helpful if you want to use the same instance of `RefreshableSession` everywhere in your code without reference to `boto3_refresh_session`!
|
|
256
|
+
|
|
257
|
+
```python
|
|
258
|
+
from boto3 import DEFAULT_SESSION, client
|
|
259
|
+
from boto3_refresh_session import RefreshableSession
|
|
260
|
+
|
|
261
|
+
assume_role_kwargs = {
|
|
262
|
+
"RoleArn": "<your-role-arn>",
|
|
263
|
+
"RoleSessionName": "<your-role-session-name>",
|
|
264
|
+
"DurationSeconds": "<your-selection>",
|
|
265
|
+
...
|
|
266
|
+
}
|
|
267
|
+
DEFAULT_SESSION = RefreshableSession(assume_role_kwargs=assume_role_kwargs)
|
|
268
|
+
s3 = client("s3")
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
##### `botocore_session`
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
from boto3 import client
|
|
275
|
+
from boto3_refresh_session import RefreshableSession
|
|
276
|
+
|
|
277
|
+
assume_role_kwargs = {
|
|
278
|
+
"RoleArn": "<your-role-arn>",
|
|
279
|
+
"RoleSessionName": "<your-role-session-name>",
|
|
280
|
+
"DurationSeconds": "<your-selection>",
|
|
281
|
+
...
|
|
282
|
+
}
|
|
283
|
+
s3 = client(
|
|
284
|
+
service_name="s3",
|
|
285
|
+
botocore_session=RefreshableSession(assume_role_kwargs=assume_role_kwargs)
|
|
286
|
+
)
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
</details>
|
|
290
|
+
|
|
291
|
+
<details>
|
|
292
|
+
<summary><strong>STS (click to expand)</strong></summary>
|
|
293
|
+
|
|
294
|
+
### STS
|
|
295
|
+
|
|
296
|
+
Most developers use AWS STS to assume an IAM role and return a set of temporary security credentials. boto3-refresh-session can be used to ensure those temporary credentials refresh automatically. For additional information on the exact parameters that `RefreshableSession` takes for STS, [check this documentation](https://michaelthomasletts.com/boto3-refresh-session/modules/generated/boto3_refresh_session.methods.sts.STSRefreshableSession.html).
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
import boto3_refresh_session as brs
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
assume_role_kwargs = {
|
|
303
|
+
"RoleArn": "<your IAM role arn>", # required
|
|
304
|
+
"RoleSessionName": "<your role session name>", # required
|
|
305
|
+
...
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
session = brs.RefreshableSession(
|
|
309
|
+
assume_role_kwargs=assume_role_kwargs, # required
|
|
310
|
+
sts_client_kwargs={...}, # optional
|
|
311
|
+
... # misc. params for boto3.session.Session
|
|
312
|
+
)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
</details>
|
|
316
|
+
|
|
317
|
+
<details>
|
|
318
|
+
<summary><strong>MFA (click to expand)</strong></summary>
|
|
319
|
+
|
|
320
|
+
### MFA Support
|
|
321
|
+
|
|
322
|
+
When assuming a role that requires MFA, `boto3-refresh-session` supports automatic token provisioning through the `mfa_token_provider` parameter. This parameter accepts a callable that returns a fresh MFA token code (string) whenever credentials need to be refreshed.
|
|
323
|
+
|
|
324
|
+
The `mfa_token_provider` approach is **strongly recommended** over manually providing `TokenCode` in `assume_role_kwargs`, as MFA tokens expire after 30 seconds while AWS temporary credentials can last for hours. By using a callable, your application can automatically fetch fresh tokens on each refresh without manual intervention. There is nothing preventing you from manually providing `TokenCode` *without* `mfa_token_provider`; however, *you* will be responsible for updating `TokenCode` *before* automatic temporary credential refresh occurs, which is likely to be a fragile and complicated approach.
|
|
325
|
+
|
|
326
|
+
When using `mfa_token_provider`, you must also provide `SerialNumber` (your MFA device ARN) in `assume_role_kwargs`. For additional information on the exact parameters that `RefreshableSession` takes for MFA, [check this documentation](https://michaelthomasletts.com/boto3-refresh-session/modules/generated/boto3_refresh_session.methods.sts.STSRefreshableSession.html).
|
|
327
|
+
|
|
328
|
+
⚠️ Most developers will probably find example number four most helpful.
|
|
329
|
+
|
|
330
|
+
#### Examples
|
|
331
|
+
|
|
332
|
+
```python
|
|
333
|
+
import boto3_refresh_session as brs
|
|
334
|
+
|
|
335
|
+
# Example 1: Interactive prompt for MFA token
|
|
336
|
+
def get_mfa_token():
|
|
337
|
+
return input("Enter MFA token: ")
|
|
338
|
+
|
|
339
|
+
# we'll reuse this object in each example for simplicity :)
|
|
340
|
+
assume_role_kwargs = {
|
|
341
|
+
"RoleArn": "<your-role-arn>",
|
|
342
|
+
"RoleSessionName": "<your-role-session-name>",
|
|
343
|
+
"SerialNumber": "arn:aws:iam::123456789012:mfa/your-user", # required with mfa_token_provider
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
session = brs.RefreshableSession(
|
|
347
|
+
assume_role_kwargs=assume_role_kwargs,
|
|
348
|
+
mfa_token_provider=get_mfa_token, # callable that returns MFA token
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
# Example 2: Using pyotp for TOTP-based MFA
|
|
352
|
+
import pyotp
|
|
353
|
+
|
|
354
|
+
def get_totp_token():
|
|
355
|
+
totp = pyotp.TOTP("<your-secret-key>")
|
|
356
|
+
return totp.now()
|
|
357
|
+
|
|
358
|
+
session = brs.RefreshableSession(
|
|
359
|
+
assume_role_kwargs=assume_role_kwargs,
|
|
360
|
+
mfa_token_provider=get_totp_token,
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
# Example 3: Retrieving token from environment variable or external service
|
|
364
|
+
import os
|
|
365
|
+
|
|
366
|
+
def get_env_token():
|
|
367
|
+
return os.environ.get("AWS_MFA_TOKEN", "")
|
|
368
|
+
|
|
369
|
+
session = brs.RefreshableSession(
|
|
370
|
+
assume_role_kwargs=assume_role_kwargs,
|
|
371
|
+
mfa_token_provider=get_env_token,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
# Example 4: Using Yubikey (or any token provider CLI)
|
|
375
|
+
from typing import Sequence
|
|
376
|
+
import subprocess
|
|
377
|
+
|
|
378
|
+
def mfa_token_provider(cmd: Sequence[str], timeout: float):
|
|
379
|
+
p = subprocess.run(
|
|
380
|
+
list(cmd),
|
|
381
|
+
check=False,
|
|
382
|
+
capture_output=True,
|
|
383
|
+
text=True,
|
|
384
|
+
timeout=timeout,
|
|
385
|
+
)
|
|
386
|
+
return (p.stdout or "").strip()
|
|
387
|
+
|
|
388
|
+
mfa_token_provider_args = {
|
|
389
|
+
"cmd": ["ykman", "oath", "code", "--single", "AWS-prod"], # example token source
|
|
390
|
+
"timeout": 3.0,
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
session = RefreshableSession(
|
|
394
|
+
assume_role_kwargs=assume_role_kwargs,
|
|
395
|
+
mfa_token_provider=mfa_token_provider,
|
|
396
|
+
mfa_token_provider_args=mfa_token_provider_args,
|
|
397
|
+
)
|
|
398
|
+
```
|
|
399
|
+
</details>
|
|
400
|
+
|
|
401
|
+
<details>
|
|
402
|
+
<summary><strong>SSO (click to expand)</strong></summary>
|
|
403
|
+
|
|
404
|
+
### SSO
|
|
405
|
+
|
|
406
|
+
`boto3-refresh-session` supports SSO by virtue of AWS profiles.
|
|
407
|
+
|
|
408
|
+
The below pseudo-code illustrates how to assume an IAM role using an AWS profile with SSO. Not shown, however, is running `sso login` manually, which `boto3-refresh-session` does not perform automatically for you. Therefore, you must manually run `sso login` as necessary.
|
|
409
|
+
|
|
410
|
+
If you wish to automate `sso login` (not recommended) then you will need to write your own custom callable function and pass it to `RefreshableSession(method="custom", ...)`. In that event, please refer to the `Custom` documentation found in a separate section below.
|
|
411
|
+
|
|
412
|
+
```python
|
|
413
|
+
from boto3_refresh_session import RefreshableSession
|
|
414
|
+
|
|
415
|
+
session = RefreshableSession(
|
|
416
|
+
assume_role_kwargs={
|
|
417
|
+
"RoleArn": "<your IAM role arn>",
|
|
418
|
+
"RoleSessionName": "<your role session name>",
|
|
419
|
+
},
|
|
420
|
+
profile_name="<your AWS profile name>",
|
|
421
|
+
...
|
|
422
|
+
)
|
|
423
|
+
s3 = session.client("s3")
|
|
424
|
+
```
|
|
425
|
+
</details>
|
|
426
|
+
|
|
427
|
+
<details>
|
|
428
|
+
<summary><strong>Custom (click to expand)</strong></summary>
|
|
429
|
+
|
|
430
|
+
### Custom
|
|
431
|
+
|
|
432
|
+
If you have a highly sophisticated, novel, or idiosyncratic authentication flow not included in boto3-refresh-session then you will need to provide your own custom temporary credentials callable object. `RefreshableSession` accepts custom credentials callable objects, as shown below. For additional information on the exact parameters that `RefreshableSession` takes for custom authentication flows, [check this documentation](https://michaelthomasletts.com/boto3-refresh-session/modules/generated/boto3_refresh_session.methods.custom.CustomRefreshableSession.html#boto3_refresh_session.methods.custom.CustomRefreshableSession).
|
|
433
|
+
|
|
434
|
+
```python
|
|
435
|
+
# create (or import) your custom credential method
|
|
436
|
+
def your_custom_credential_getter(...):
|
|
437
|
+
...
|
|
438
|
+
return {
|
|
439
|
+
"access_key": ...,
|
|
440
|
+
"secret_key": ...,
|
|
441
|
+
"token": ...,
|
|
442
|
+
"expiry_time": ...,
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
# and pass it to RefreshableSession
|
|
446
|
+
session = RefreshableSession(
|
|
447
|
+
method="custom", # required
|
|
448
|
+
custom_credentials_method=your_custom_credential_getter, # required
|
|
449
|
+
custom_credentials_method_args=..., # optional
|
|
450
|
+
region_name=region_name, # optional
|
|
451
|
+
profile_name=profile_name, # optional
|
|
452
|
+
... # misc. boto3.session.Session params
|
|
453
|
+
)
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
</details>
|
|
457
|
+
|
|
458
|
+
<details>
|
|
459
|
+
<summary><strong>IoT Core X.509 (click to expand)</strong></summary>
|
|
460
|
+
|
|
461
|
+
### IoT Core X.509
|
|
462
|
+
|
|
463
|
+
AWS IoT Core can vend temporary AWS credentials through the **credentials provider** when you connect with an X.509 certificate and a **role alias**. `boto3-refresh-session` makes this flow seamless by automatically refreshing credentials over **mTLS**.
|
|
464
|
+
|
|
465
|
+
For additional information on the exact parameters that `IOTX509RefreshableSession` takes, [check this documentation](https://michaelthomasletts.com/boto3-refresh-session/modules/generated/boto3_refresh_session.methods.iot.x509.IOTX509RefreshableSession.html).
|
|
466
|
+
|
|
467
|
+
### PEM file
|
|
468
|
+
|
|
469
|
+
```python
|
|
470
|
+
import boto3_refresh_session as brs
|
|
471
|
+
|
|
472
|
+
# PEM certificate + private key example
|
|
473
|
+
session = brs.RefreshableSession(
|
|
474
|
+
method="iot",
|
|
475
|
+
endpoint="<your-credentials-endpoint>.credentials.iot.<region>.amazonaws.com",
|
|
476
|
+
role_alias="<your-role-alias>",
|
|
477
|
+
certificate="/path/to/certificate.pem",
|
|
478
|
+
private_key="/path/to/private-key.pem",
|
|
479
|
+
thing_name="<your-thing-name>", # optional, if used in policies
|
|
480
|
+
duration_seconds=3600, # optional, capped by role alias
|
|
481
|
+
region_name="us-east-1",
|
|
482
|
+
)
|
|
483
|
+
|
|
484
|
+
# Now you can use the session like any boto3 session
|
|
485
|
+
s3 = session.client("s3")
|
|
486
|
+
print(s3.list_buckets())
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### PKCS#11
|
|
490
|
+
|
|
491
|
+
```python
|
|
492
|
+
session = brs.RefreshableSession(
|
|
493
|
+
method="iot",
|
|
494
|
+
endpoint="<your-credentials-endpoint>.credentials.iot.<region>.amazonaws.com",
|
|
495
|
+
role_alias="<your-role-alias>",
|
|
496
|
+
certificate="/path/to/certificate.pem",
|
|
497
|
+
pkcs11={
|
|
498
|
+
"pkcs11_lib": "/usr/local/lib/softhsm/libsofthsm2.so",
|
|
499
|
+
"user_pin": "1234",
|
|
500
|
+
"slot_id": 0,
|
|
501
|
+
"token_label": "MyToken",
|
|
502
|
+
"private_key_label": "MyKey",
|
|
503
|
+
},
|
|
504
|
+
thing_name="<your-thing-name>",
|
|
505
|
+
region_name="us-east-1",
|
|
506
|
+
)
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### MQTT
|
|
510
|
+
|
|
511
|
+
After initializing a session object, you can can begin making actions with MQTT using the [mqtt method](https://github.com/michaelthomasletts/boto3-refresh-session/blob/deb68222925bf648f26e878ed4bc24b45317c7db/boto3_refresh_session/methods/iot/x509.py#L367)! You can reuse the same certificate, private key, et al as that used to initialize `RefreshableSession`. Or, alternatively, you can provide separate PKCS#11 or certificate information, whether those be file paths or bytes values. Either way, at a minimum, you will need to provide the endpoint and client identifier (i.e. thing name).
|
|
512
|
+
|
|
513
|
+
```python
|
|
514
|
+
from awscrt.mqtt.QoS import AT_LEAST_ONCE
|
|
515
|
+
conn = session.mqtt(
|
|
516
|
+
endpoint="<your endpoint>-ats.iot.<region>.amazonaws.com",
|
|
517
|
+
client_id="<your thing name or client ID>",
|
|
518
|
+
)
|
|
519
|
+
conn.connect()
|
|
520
|
+
conn.connect().result()
|
|
521
|
+
conn.publish(topic="foo/bar", payload=b"hi", qos=AT_LEAST_ONCE)
|
|
522
|
+
conn.disconnect().result()
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
</details>
|
|
526
|
+
|
|
527
|
+
## ⚠️ Changes
|
|
528
|
+
|
|
529
|
+
Browse through the various changes to `boto3-refresh-session` over time.
|
|
530
|
+
|
|
531
|
+
#### 😥 v3.0.0
|
|
532
|
+
|
|
533
|
+
**The changes introduced by v3.0.0 will not impact ~99% of users** who generally interact with `boto3-refresh-session` by only `RefreshableSession`, *which is the intended usage for this package after all.*
|
|
534
|
+
|
|
535
|
+
Advanced users, however, particularly those using low-level objects such as `BaseRefreshableSession | refreshable_session | BRSSession | utils.py`, may experience breaking changes.
|
|
536
|
+
|
|
537
|
+
Please review [this PR](https://github.com/michaelthomasletts/boto3-refresh-session/pull/75) for additional details.
|
|
538
|
+
|
|
539
|
+
#### ✂️ v4.0.0
|
|
540
|
+
|
|
541
|
+
The `ecs` module has been dropped. For additional details and rationale, please review [this PR](https://github.com/michaelthomasletts/boto3-refresh-session/pull/78).
|
|
542
|
+
|
|
543
|
+
#### 😛 v5.0.0
|
|
544
|
+
|
|
545
|
+
Support for IoT Core via X.509 certificate-based authentication (over HTTPS) is now available!
|
|
546
|
+
|
|
547
|
+
#### ➕ v5.1.0
|
|
548
|
+
|
|
549
|
+
MQTT support added for IoT Core via X.509 certificate-based authentication.
|
|
550
|
+
|
|
551
|
+
#### ➕ v6.0.0
|
|
552
|
+
|
|
553
|
+
MFA support for STS added!
|
|
554
|
+
|
|
555
|
+
#### 🔒😥 v6.2.0
|
|
556
|
+
|
|
557
|
+
- Client caching introduced to `RefreshableSession` in order to minimize memory footprint! Available via `cache_clients` parameter.
|
|
558
|
+
- Testing suite expanded to include IOT, MFA, caching, and much more!
|
|
559
|
+
- A subtle bug was uncovered where `RefreshableSession` created refreshable credentials but boto3's underlying session continued to resolve credentials via the default provider chain (i.e. env vars, shared config, etc) unless explicitly wired. `get_credentials()` and clients could, in certain setups, use base session credentials instead of the refreshable STS/IoT/custom credentials via assumed role. To fix this, I updated the implementation in `BRSSession.__post_init__` to set `self._session._credentials = self._credentials`, ensuring all boto3 clients created from `RefreshableSession` use the refreshable credentials source of truth provided to `RefreshableCredentials | DeferredRefreshableCredentials`. After this change, refreshable credentials are used consistently everywhere, irrespective of setup.
|
|
560
|
+
|
|
561
|
+
#### ✂️ v6.2.3
|
|
562
|
+
|
|
563
|
+
- The `RefreshableTemporaryCredentials` type hint was deprecated in favor of `TemporaryCredentials`.
|
|
564
|
+
- `expiry_time` was added as a parameter returned by the `refreshable_credentials` method and `credentials` attribute.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
boto3_refresh_session/__init__.py,sha256=TZOTX4oLP6KUcWm2lCwdm11KgKL49whkLBl32yOv7EU,415
|
|
2
|
+
boto3_refresh_session/exceptions.py,sha256=uS0tcAl9UZoCvktOz08GC59JDNV4ml-su8CVUs0qzNw,1287
|
|
3
|
+
boto3_refresh_session/methods/__init__.py,sha256=FpwWixSVpy_6pUe1u4fXmjO-_fDH--qTk_xrMnBCHxU,193
|
|
4
|
+
boto3_refresh_session/methods/custom.py,sha256=i07paDNtzi_92Bqc7Pk4cEVfKPV5okEOGHyXipp6HWQ,5136
|
|
5
|
+
boto3_refresh_session/methods/iot/__init__.py,sha256=wIYp7HFZ_Q8XEHwWmpKjDNXxBm29C0RisP_9GSVwzZI,147
|
|
6
|
+
boto3_refresh_session/methods/iot/core.py,sha256=K9Zcwpu4yPD51Pz9ImXFDc9XswPQhTlHU-DxwbPU5Bo,1218
|
|
7
|
+
boto3_refresh_session/methods/iot/x509.py,sha256=3dk0616bQI47pVyPV05vrdtNcTS-SEHablrehy2XPAM,21332
|
|
8
|
+
boto3_refresh_session/methods/sts.py,sha256=ZX5yM0n5pMmmieNmOYDR1bGdZ4Y0m7PHIylabI5Q9rg,9124
|
|
9
|
+
boto3_refresh_session/session.py,sha256=EMydUVFLdghH3La0nGCnZeZJHt4xWqumgJEMf3iCTBo,3359
|
|
10
|
+
boto3_refresh_session/utils/__init__.py,sha256=wll77Z3SIQCfJqOKjSZC1EjXUT-7KOB31u6Fl4FLjkY,214
|
|
11
|
+
boto3_refresh_session/utils/cache.py,sha256=NEDu8bS_wj3O0KQpHnhqZAYsUE4-Xs0Ec5YqzWsK2tI,2836
|
|
12
|
+
boto3_refresh_session/utils/internal.py,sha256=VBKgPTdqyT6slOGu6XrdDE4CCwtj4dK15LpNuR0Ssr8,14546
|
|
13
|
+
boto3_refresh_session/utils/typing.py,sha256=DW5sm-KPi5wetadJXwkkTpwEGx5KiriBkXIAGcWVYSI,3171
|
|
14
|
+
boto3_refresh_session-6.2.5.dist-info/METADATA,sha256=nytkgxWL2e6ECb1ZVfvSU4H7KpTUu6jJaYR62-cRahM,26565
|
|
15
|
+
boto3_refresh_session-6.2.5.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
16
|
+
boto3_refresh_session-6.2.5.dist-info/licenses/LICENSE,sha256=I3ZYTXAjbIly6bm6J-TvFTuuHwTKws4h89QaY5c5HiY,1067
|
|
17
|
+
boto3_refresh_session-6.2.5.dist-info/licenses/NOTICE,sha256=1s8r33qbl1z0YvPB942iWgvbkP94P_e8AnROr1qXXuw,939
|
|
18
|
+
boto3_refresh_session-6.2.5.dist-info/RECORD,,
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
boto3-refresh-session
|
|
2
|
+
Copyright 2024 Michael Letts
|
|
3
|
+
|
|
4
|
+
boto3-refresh-session (BRS) includes software designed and developed by Michael Letts (the author).
|
|
5
|
+
|
|
6
|
+
Although the author was formerly employed by Amazon, this project was conceived, designed, developed, and released independently after that period of employment. It is not affiliated with or endorsed by Amazon Web Services (AWS), Amazon, or any contributors to boto3 or botocore, regardless of their employment status.
|
|
7
|
+
|
|
8
|
+
Developers are welcome and encouraged to modify and adapt this software to suit their needs — this is in fact already common practice among some of the largest users of BRS.
|
|
9
|
+
|
|
10
|
+
If you find boto3-refresh-session (BRS) helpful in your work, a note of thanks or a mention in your project’s documentation or acknowledgments is appreciated — though not required under the terms of the MIT License.
|
|
11
|
+
|
|
12
|
+
Licensed under the MIT License. See the LICENSE file for details.
|