boto3-assist 0.11.0__py3-none-any.whl → 0.13.0__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.
@@ -4,21 +4,14 @@ Maintainers: Eric Wilson
4
4
  MIT License. See Project Root for the license information.
5
5
  """
6
6
 
7
- from typing import Any, Optional
8
-
7
+ from typing import Optional, List, Any
9
8
  import boto3
10
- from aws_lambda_powertools import Logger
11
9
  from botocore.config import Config
12
- from botocore.exceptions import ProfileNotFound
13
- from boto3_assist.environment_services.environment_variables import EnvironmentVariables
14
-
15
-
16
- logger = Logger(__name__)
10
+ from .session_setup_mixin import SessionSetupMixin
11
+ from .role_assumption_mixin import RoleAssumptionMixin
17
12
 
18
13
 
19
- class Boto3SessionManager:
20
- """Manages Boto3 Sessions"""
21
-
14
+ class Boto3SessionManager(SessionSetupMixin, RoleAssumptionMixin):
22
15
  def __init__(
23
16
  self,
24
17
  service_name: str,
@@ -26,8 +19,9 @@ class Boto3SessionManager:
26
19
  aws_profile: Optional[str] = None,
27
20
  aws_region: Optional[str] = None,
28
21
  assume_role_arn: Optional[str] = None,
22
+ assume_role_chain: Optional[List[str]] = None,
29
23
  assume_role_session_name: Optional[str] = None,
30
- cross_account_role_arn: Optional[str] = None,
24
+ assume_role_duration_seconds: Optional[int] = 3600,
31
25
  config: Optional[Config] = None,
32
26
  aws_endpoint_url: Optional[str] = None,
33
27
  aws_access_key_id: Optional[str] = None,
@@ -37,144 +31,57 @@ class Boto3SessionManager:
37
31
  self.service_name = service_name
38
32
  self.aws_profile = aws_profile
39
33
  self.aws_region = aws_region
40
- self.assume_role_arn = assume_role_arn
41
- self.assume_role_session_name = assume_role_session_name
42
34
  self.config = config
43
- self.cross_account_role_arn = cross_account_role_arn
44
35
  self.endpoint_url = aws_endpoint_url
36
+ self.assume_role_chain = assume_role_chain or (
37
+ [assume_role_arn] if assume_role_arn else []
38
+ )
39
+ self.assume_role_session_name = (
40
+ assume_role_session_name or f"AssumeRoleSessionFor{service_name}"
41
+ )
42
+ self.assume_role_duration_seconds = assume_role_duration_seconds
45
43
  self.aws_access_key_id = aws_access_key_id
46
44
  self.aws_secret_access_key = aws_secret_access_key
47
45
  self.aws_session_token = aws_session_token
48
46
 
49
- self.__session: Any = None
47
+ self.__session: Optional[boto3.Session] = None
50
48
  self.__client: Any = None
51
49
  self.__resource: Any = None
52
50
 
53
- self.__setup()
54
-
55
- def __setup(self):
56
- """Setup AWS session, client, and resource."""
57
-
58
- profile = self.aws_profile or EnvironmentVariables.AWS.profile()
59
- region = self.aws_region or EnvironmentVariables.AWS.region()
60
- if self.assume_role_arn:
61
- self.__assume_role()
62
- else:
63
- logger.debug("Connecting without assuming a role.")
64
- self.__session = self.__get_aws_session(profile, region)
65
-
66
- if profile:
67
- print(f"Connecting with a profile: {profile}")
68
-
69
- def __assume_role(self):
70
- """Assume an AWS IAM role."""
71
- try:
72
- logger.debug(f"Assuming role {self.assume_role_arn}")
73
- sts_client = boto3.client("sts")
74
- session_name = (
75
- self.assume_role_session_name
76
- or f"AssumeRoleSessionFor{self.service_name}"
77
- )
78
- if not self.assume_role_arn:
79
- raise ValueError("assume_role_arn is required")
80
- assumed_role_response = sts_client.assume_role(
81
- RoleArn=self.assume_role_arn,
82
- RoleSessionName=session_name,
83
- )
84
- credentials = assumed_role_response["Credentials"]
85
- self.__session = boto3.Session(
86
- aws_access_key_id=credentials["AccessKeyId"],
87
- aws_secret_access_key=credentials["SecretAccessKey"],
88
- aws_session_token=credentials["SessionToken"],
89
- )
90
-
91
- except Exception as e:
92
- logger.error(f"Error assuming role: {e}")
93
- raise RuntimeError(f"Failed to assume role {self.assume_role_arn}") from e
94
-
95
- def __get_aws_session(
96
- self, aws_profile: Optional[str] = None, aws_region: Optional[str] = None
97
- ) -> boto3.Session | None:
98
- """Get a boto3 session for AWS."""
99
- logger.debug({"profile": aws_profile, "region": aws_region})
100
- try:
101
- self.aws_profile = aws_profile or EnvironmentVariables.AWS.profile()
102
- self.aws_region = aws_region or EnvironmentVariables.AWS.region()
103
- tmp_access_key_id = self.aws_access_key_id
104
- tmp_secret_access_key = self.aws_secret_access_key
105
- if not EnvironmentVariables.AWS.display_aws_access_key_id():
106
- tmp_access_key_id = (
107
- "None" if tmp_access_key_id is None else "***************"
108
- )
109
- if not EnvironmentVariables.AWS.display_aws_secret_access_key():
110
- tmp_secret_access_key = (
111
- "None" if tmp_secret_access_key is None else "***************"
112
- )
113
-
114
- logger.debug(
115
- {
116
- "profile": self.aws_profile,
117
- "region": self.aws_region,
118
- "aws_access_key_id": tmp_access_key_id,
119
- "aws_secret_access_key": tmp_secret_access_key,
120
- "aws_session_token": "*******"
121
- if self.aws_session_token is not None
122
- else "",
123
- }
51
+ self.__initialize()
52
+
53
+ def __initialize(self):
54
+ base_session = self._create_base_session(
55
+ self.aws_profile,
56
+ self.aws_region,
57
+ self.aws_access_key_id,
58
+ self.aws_secret_access_key,
59
+ self.aws_session_token,
60
+ )
61
+
62
+ if self.assume_role_chain:
63
+ self.__session = self._assume_roles_in_chain(
64
+ base_session,
65
+ self.assume_role_chain,
66
+ self.assume_role_session_name,
67
+ self.assume_role_duration_seconds,
68
+ self.aws_region,
124
69
  )
125
- logger.debug("Creating boto3 session")
126
- session = self.__create_boto3_session()
127
- # if self.aws_profile or self.aws_region
128
- # else boto3.Session()
129
-
130
- except Exception as e:
131
- logger.error(e)
132
- raise RuntimeError("Failed to create a boto3 session.") from e
133
-
134
- logger.debug({"session": session})
135
- return session
70
+ else:
71
+ self.__session = base_session
136
72
 
137
73
  @property
138
74
  def client(self) -> Any:
139
- """Return the boto3 client connection."""
140
75
  if not self.__client:
141
- logger.debug(f"Creating {self.service_name} client")
142
76
  self.__client = self.__session.client(
143
- self.service_name,
144
- config=self.config,
145
- endpoint_url=self.endpoint_url,
77
+ self.service_name, config=self.config, endpoint_url=self.endpoint_url
146
78
  )
147
-
148
79
  return self.__client
149
80
 
150
81
  @property
151
82
  def resource(self) -> Any:
152
- """Return the boto3 resource connection."""
153
83
  if not self.__resource:
154
- logger.debug(f"Creating {self.service_name} resource")
155
84
  self.__resource = self.__session.resource(
156
- self.service_name,
157
- config=self.config,
158
- endpoint_url=self.endpoint_url,
85
+ self.service_name, config=self.config, endpoint_url=self.endpoint_url
159
86
  )
160
87
  return self.__resource
161
-
162
- def __create_boto3_session(self) -> boto3.Session | None:
163
- try:
164
- logger.debug(f"Creating session for {self.service_name}")
165
- session = boto3.Session(
166
- profile_name=self.aws_profile,
167
- region_name=self.aws_region,
168
- aws_access_key_id=self.aws_access_key_id,
169
- aws_secret_access_key=self.aws_secret_access_key,
170
- aws_session_token=self.aws_session_token,
171
- )
172
- return session
173
- except ProfileNotFound as e:
174
- print(
175
- f"An error occurred setting up the boto3 sessions. Profile not found: {e}"
176
- )
177
- raise e
178
- except Exception as e:
179
- print(f"An error occurred setting up the boto3 sessions: {e}")
180
- raise e
@@ -30,6 +30,7 @@ class Connection:
30
30
  aws_access_key_id: Optional[str] = None,
31
31
  aws_secret_access_key: Optional[str] = None,
32
32
  aws_end_point_url: Optional[str] = None,
33
+ assume_role_arn: Optional[str] = None,
33
34
  ) -> None:
34
35
  self.__aws_profile = aws_profile
35
36
  self.__aws_region = aws_region
@@ -37,7 +38,7 @@ class Connection:
37
38
  self.__aws_secret_access_key = aws_secret_access_key
38
39
  self.end_point_url = aws_end_point_url
39
40
  self.__session: Boto3SessionManager | None = None
40
-
41
+ self.__assume_role_arn: Optional[str] = assume_role_arn
41
42
  self.__service_name: str | None = service_name
42
43
 
43
44
  if self.__service_name is None:
@@ -73,6 +74,7 @@ class Connection:
73
74
  aws_access_key_id=self.aws_access_key_id,
74
75
  aws_secret_access_key=self.aws_secret_access_key,
75
76
  aws_endpoint_url=self.end_point_url,
77
+ assume_role_arn=self.__assume_role_arn,
76
78
  )
77
79
 
78
80
  tracker.add(service_name=self.service_name)
@@ -24,7 +24,6 @@ from boto3_assist.utilities.string_utility import StringUtility
24
24
  logger = Logger()
25
25
 
26
26
 
27
-
28
27
  class DynamoDB(DynamoDBConnection):
29
28
  """
30
29
  DynamoDB. Wrapper for basic DynamoDB Connection and Actions
@@ -41,6 +40,7 @@ class DynamoDB(DynamoDBConnection):
41
40
  aws_end_point_url: Optional[str] = None,
42
41
  aws_access_key_id: Optional[str] = None,
43
42
  aws_secret_access_key: Optional[str] = None,
43
+ assume_role_arn: Optional[str] = None,
44
44
  ) -> None:
45
45
  super().__init__(
46
46
  aws_profile=aws_profile,
@@ -48,6 +48,7 @@ class DynamoDB(DynamoDBConnection):
48
48
  aws_end_point_url=aws_end_point_url,
49
49
  aws_access_key_id=aws_access_key_id,
50
50
  aws_secret_access_key=aws_secret_access_key,
51
+ assume_role_arn=assume_role_arn,
51
52
  )
52
53
  self.helpers: DynamoDBHelpers = DynamoDBHelpers()
53
54
  self.log_dynamodb_item_size = (
@@ -55,7 +56,6 @@ class DynamoDB(DynamoDBConnection):
55
56
  )
56
57
  logger.setLevel(os.getenv("LOG_LEVEL", "INFO"))
57
58
 
58
-
59
59
  def save(
60
60
  self,
61
61
  item: dict | DynamoDBModelBase,
@@ -169,7 +169,6 @@ class DynamoDB(DynamoDBConnection):
169
169
  call_type: str = "resource",
170
170
  ) -> Dict[str, Any]: ...
171
171
 
172
-
173
172
  def get(
174
173
  self,
175
174
  key: Optional[dict] = None,
@@ -344,7 +343,6 @@ class DynamoDB(DynamoDBConnection):
344
343
  ) -> dict:
345
344
  pass
346
345
 
347
-
348
346
  def delete(
349
347
  self,
350
348
  *,
@@ -32,6 +32,7 @@ class DynamoDBConnection(Connection):
32
32
  aws_end_point_url: Optional[str] = None,
33
33
  aws_access_key_id: Optional[str] = None,
34
34
  aws_secret_access_key: Optional[str] = None,
35
+ assume_role_arn: Optional[str] = None,
35
36
  ) -> None:
36
37
  super().__init__(
37
38
  service_name="dynamodb",
@@ -40,6 +41,7 @@ class DynamoDBConnection(Connection):
40
41
  aws_access_key_id=aws_access_key_id,
41
42
  aws_secret_access_key=aws_secret_access_key,
42
43
  aws_end_point_url=aws_end_point_url,
44
+ assume_role_arn=assume_role_arn,
43
45
  )
44
46
 
45
47
  self.__dynamodb_client: DynamoDBClient | None = None
@@ -0,0 +1,38 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import boto3
8
+ from typing import List
9
+
10
+
11
+ class RoleAssumptionMixin:
12
+ def _assume_roles_in_chain(
13
+ self,
14
+ base_session: boto3.Session,
15
+ role_chain: List[str],
16
+ session_name: str,
17
+ duration_seconds: int,
18
+ region: str,
19
+ ) -> boto3.Session:
20
+ session = base_session
21
+
22
+ for role_arn in role_chain:
23
+ sts_client = session.client("sts")
24
+ response = sts_client.assume_role(
25
+ RoleArn=role_arn,
26
+ RoleSessionName=session_name,
27
+ DurationSeconds=duration_seconds,
28
+ )
29
+ creds = response["Credentials"]
30
+
31
+ session = boto3.Session(
32
+ aws_access_key_id=creds["AccessKeyId"],
33
+ aws_secret_access_key=creds["SecretAccessKey"],
34
+ aws_session_token=creds["SessionToken"],
35
+ region_name=region,
36
+ )
37
+
38
+ return session
@@ -0,0 +1,29 @@
1
+ """
2
+ Geek Cafe, LLC
3
+ Maintainers: Eric Wilson
4
+ MIT License. See Project Root for the license information.
5
+ """
6
+
7
+ import boto3
8
+ from typing import Optional
9
+
10
+
11
+ class SessionSetupMixin:
12
+ def _create_base_session(
13
+ self,
14
+ aws_profile: Optional[str],
15
+ aws_region: Optional[str],
16
+ aws_access_key_id: Optional[str],
17
+ aws_secret_access_key: Optional[str],
18
+ aws_session_token: Optional[str],
19
+ ) -> boto3.Session:
20
+ try:
21
+ return boto3.Session(
22
+ profile_name=aws_profile,
23
+ region_name=aws_region,
24
+ aws_access_key_id=aws_access_key_id,
25
+ aws_secret_access_key=aws_secret_access_key,
26
+ aws_session_token=aws_session_token,
27
+ )
28
+ except Exception as e:
29
+ raise RuntimeError(f"Failed to create boto3 session: {e}") from e
boto3_assist/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.11.0'
1
+ __version__ = '0.13.0'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boto3_assist
3
- Version: 0.11.0
3
+ Version: 0.13.0
4
4
  Summary: Additional boto3 wrappers to make your life a little easier
5
5
  Author-email: Eric Wilson <boto3-assist@geekcafe.com>
6
6
  License-File: LICENSE-EXPLAINED.txt
@@ -1,9 +1,11 @@
1
1
  boto3_assist/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- boto3_assist/boto3session.py,sha256=JnZIRbut5R_C_r50bY2xiF6CjR93jQSOeVmhdK97mDg,6712
3
- boto3_assist/connection.py,sha256=-z_OZtZmSVjSSECpoqx1FnqW7B9A_LovfN_cJ_nhHgg,4361
2
+ boto3_assist/boto3session.py,sha256=p4FKVSX5A-xNHdpRan8pgMoY4iIywNfwriyTfjQ-zTQ,2967
3
+ boto3_assist/connection.py,sha256=UJg6YHxVpz3F51Lih5cjfPhbkheRvXoJTpCilErNzkc,4523
4
4
  boto3_assist/connection_tracker.py,sha256=UgfR9RlvXf3A4ssMr3gDMpw89ka8mSRvJn4M34SzhbU,4378
5
5
  boto3_assist/http_status_codes.py,sha256=G0zRSWenwavYKETvDF9tNVUXQz3Ae2gXdBETYbjvJe8,3284
6
- boto3_assist/version.py,sha256=UHGsGhGjMtfvoaFMaJdv4diSXG2uXo8Y2yCo7kiUOdk,23
6
+ boto3_assist/role_assumption_mixin.py,sha256=PMUU5yC2FUBjFD1UokVkRY3CPB5zTw85AhIB5BMtbc8,1031
7
+ boto3_assist/session_setup_mixin.py,sha256=KgHOf560f2W_Qj04mnu4CiGHXAI_irjmQeEfhAJN3kA,865
8
+ boto3_assist/version.py,sha256=8jbyfDafOI8eZRtXgKR6mD8oxCBRAURo9UJ6grdsnZU,23
7
9
  boto3_assist/aws_lambda/event_info.py,sha256=OkZ4WzuGaHEu_T8sB188KBgShAJhZpWASALKRGBOhMg,14648
8
10
  boto3_assist/aws_lambda/mock_context.py,sha256=LPjHP-3YSoY6iPl1kPqJDwSVf1zLNTcukUunDtYcbK0,116
9
11
  boto3_assist/cloudwatch/cloudwatch_connection.py,sha256=mnGWaLSQpHh5EeY7Ek_2o9JKHJxOELIYtQVMX1IaHn4,2480
@@ -16,8 +18,8 @@ boto3_assist/cognito/cognito_connection.py,sha256=deuXR3cNHz0mCYff2k0LfAvK--9Okq
16
18
  boto3_assist/cognito/cognito_utility.py,sha256=IVZAg58nHG1U7uxe7FsTYpqwwZiwwdIBGiVTZuLCFqg,18417
17
19
  boto3_assist/cognito/jwks_cache.py,sha256=1Y9r-YfQ8qrgZN5xYPvjUEEV0vthbdcPdAIaPbZP7kU,373
18
20
  boto3_assist/cognito/user.py,sha256=qc44qLx3gwq6q2zMxcPQze1EjeZwy5Kuav93vbe-4WU,820
19
- boto3_assist/dynamodb/dynamodb.py,sha256=ARbxuAQitqDBdEb_vHiRaC7x9nDMr71SgRA7tD6NVKk,15681
20
- boto3_assist/dynamodb/dynamodb_connection.py,sha256=x6Ylb_uVAY5TS0AIBUNOSyywKIqros3xX8diLTjZUsc,3275
21
+ boto3_assist/dynamodb/dynamodb.py,sha256=8uzKaw9knqPvlkroQK5aMR-ASRxFwCCcMacm6wWpp8g,15757
22
+ boto3_assist/dynamodb/dynamodb_connection.py,sha256=kOFB07ulFM3ohtqr_Ytk4OaCfPL_DdCQ-GXGq6Gi-Ag,3367
21
23
  boto3_assist/dynamodb/dynamodb_helpers.py,sha256=RoRRqKjdwfC-2-gvlkLvCoNWhIoMrHm-68dkyhXI_Xk,12080
22
24
  boto3_assist/dynamodb/dynamodb_importer.py,sha256=nCKsyRQeMqDSf0Q5mQ_X_oVIg4PRnu0hcUzZnBli610,3471
23
25
  boto3_assist/dynamodb/dynamodb_index.py,sha256=D0Lq121qk1cXeMetPeqnzvv6CXd0XfEygfdUXaljLG8,8551
@@ -53,8 +55,8 @@ boto3_assist/utilities/logging_utility.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5N
53
55
  boto3_assist/utilities/numbers_utility.py,sha256=wzv9d0uXT_2_ZHHio7LBzibwxPqhGpvbq9HinrVn_4A,10160
54
56
  boto3_assist/utilities/serialization_utility.py,sha256=nieqW9b71Dr0X2HPsNmCei6zoIbsPRl9fDAigBQkaUg,21730
55
57
  boto3_assist/utilities/string_utility.py,sha256=0ChxbuT37xdG4y3cKzbNTHk4T3fl8lNMdOT7L5aJBQk,10382
56
- boto3_assist-0.11.0.dist-info/METADATA,sha256=bXUuUsYCrxXCm125R0K6pI13n3oh8rfRdJPj9mNrCdA,2875
57
- boto3_assist-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
58
- boto3_assist-0.11.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
59
- boto3_assist-0.11.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
60
- boto3_assist-0.11.0.dist-info/RECORD,,
58
+ boto3_assist-0.13.0.dist-info/METADATA,sha256=gLgFlW_mfJdcOGYgYtXdSFA7CgxdVRNg-kO-kwU2isA,2875
59
+ boto3_assist-0.13.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
60
+ boto3_assist-0.13.0.dist-info/licenses/LICENSE-EXPLAINED.txt,sha256=WFREvTpfTjPjDHpOLADxJpCKpIla3Ht87RUUGii4ODU,606
61
+ boto3_assist-0.13.0.dist-info/licenses/LICENSE.txt,sha256=PXDhFWS5L5aOTkVhNvoitHKbAkgxqMI2uUPQyrnXGiI,1105
62
+ boto3_assist-0.13.0.dist-info/RECORD,,