@@ -123,12 +123,17 @@ def create(self):
123123 bucket , key_prefix = s3 .determine_bucket_and_prefix (
124124 bucket = self .s3_bucket , key_prefix = None , sagemaker_session = self .session
125125 )
126+ # Spot check: if the resolved bucket is the session's default bucket,
127+ # enforce ownership on the upload so an attacker cannot squat on the
128+ # predictable default name.
129+ expected_owner = self .session ._get_account_id_if_default_bucket (bucket )
126130 key = _upload_to_s3 (
127131 s3_client = _get_s3_client (self .session ),
128132 function_name = self .function_name ,
129133 zipped_code_dir = self .zipped_code_dir ,
130134 s3_bucket = bucket ,
131135 s3_key_prefix = key_prefix ,
136+ expected_bucket_owner = expected_owner ,
132137 )
133138 code = {"S3Bucket" : bucket , "S3Key" : key }
134139
@@ -179,6 +184,13 @@ def update(self):
179184 else :
180185 function_name_for_s3 = self .function_name
181186
187+ # Spot check: enforce ownership only when the resolved bucket is
188+ # the session's default bucket (defends against squatting on the
189+ # predictable default name). Other buckets are left untouched.
190+ expected_owner = self .session ._get_account_id_if_default_bucket (
191+ bucket
192+ )
193+
182194 response = lambda_client .update_function_code (
183195 FunctionName = (self .function_name or self .function_arn ),
184196 S3Bucket = bucket ,
@@ -188,6 +200,7 @@ def update(self):
188200 zipped_code_dir = self .zipped_code_dir ,
189201 s3_bucket = bucket ,
190202 s3_key_prefix = key_prefix ,
203+ expected_bucket_owner = expected_owner ,
191204 ),
192205 )
193206 return response
@@ -276,13 +289,29 @@ def _get_lambda_client(session):
276289 return lambda_client
277290
278291
279- def _upload_to_s3 (s3_client , function_name , zipped_code_dir , s3_bucket , s3_key_prefix = None ):
292+ def _upload_to_s3 (
293+ s3_client ,
294+ function_name ,
295+ zipped_code_dir ,
296+ s3_bucket ,
297+ s3_key_prefix = None ,
298+ expected_bucket_owner = None ,
299+ ):
280300 """Upload the zipped code to S3 bucket provided in the Lambda instance.
281301
282302 Lambda instance must have a path to the zipped code folder and a S3 bucket to upload
283303 the code. The key will lambda/function_name/code and the S3 URI where the code is
284304 uploaded is in this format: s3://bucket_name/lambda/function_name/code.
285305
306+ Args:
307+ s3_client: boto3 S3 client used for the upload.
308+ function_name (str): Lambda function name used to build the S3 key.
309+ zipped_code_dir (str): Local path to the zipped Lambda code.
310+ s3_bucket (str): Destination S3 bucket.
311+ s3_key_prefix (str): Optional S3 key prefix.
312+ expected_bucket_owner (str): Optional account id passed as ``ExpectedBucketOwner``
313+ on the upload when the destination bucket should belong to that account.
314+
286315 Returns: the S3 key where the code is uploaded.
287316 """
288317
@@ -292,7 +321,10 @@ def _upload_to_s3(s3_client, function_name, zipped_code_dir, s3_bucket, s3_key_p
292321 function_name ,
293322 "code" ,
294323 )
295- s3_client .upload_file (zipped_code_dir , s3_bucket , key )
324+ extra_args = None
325+ if expected_bucket_owner :
326+ extra_args = {"ExpectedBucketOwner" : expected_bucket_owner }
327+ s3_client .upload_file (zipped_code_dir , s3_bucket , key , ExtraArgs = extra_args )
296328 return key
297329
298330
0 commit comments