@@ -130,6 +130,8 @@ def __init__(
130
130
bq_connection_id ,
131
131
cloud_resource_manager_client ,
132
132
cloud_function_service_account ,
133
+ cloud_function_kms_key_name ,
134
+ cloud_function_docker_repository ,
133
135
):
134
136
self ._gcp_project_id = gcp_project_id
135
137
self ._cloud_function_region = cloud_function_region
@@ -142,6 +144,8 @@ def __init__(
142
144
bq_connection_client , cloud_resource_manager_client
143
145
)
144
146
self ._cloud_function_service_account = cloud_function_service_account
147
+ self ._cloud_function_kms_key_name = cloud_function_kms_key_name
148
+ self ._cloud_function_docker_repository = cloud_function_docker_repository
145
149
146
150
def create_bq_remote_function (
147
151
self , input_args , input_types , output_type , endpoint , bq_function_name
@@ -344,7 +348,9 @@ def create_cloud_function(self, def_, cf_name, package_requirements=None):
344
348
)
345
349
346
350
# Determine an upload URL for user code
347
- upload_url_request = functions_v2 .GenerateUploadUrlRequest ()
351
+ upload_url_request = functions_v2 .GenerateUploadUrlRequest (
352
+ kms_key_name = self ._cloud_function_kms_key_name
353
+ )
348
354
upload_url_request .parent = self .get_cloud_function_fully_qualified_parent ()
349
355
upload_url_response = self ._cloud_functions_client .generate_upload_url (
350
356
request = upload_url_request
@@ -383,12 +389,16 @@ def create_cloud_function(self, def_, cf_name, package_requirements=None):
383
389
function .build_config .source .storage_source .object_ = (
384
390
upload_url_response .storage_source .object_
385
391
)
392
+ function .build_config .docker_repository = (
393
+ self ._cloud_function_docker_repository
394
+ )
386
395
function .service_config = functions_v2 .ServiceConfig ()
387
396
function .service_config .available_memory = "1024M"
388
397
function .service_config .timeout_seconds = 600
389
398
function .service_config .service_account_email = (
390
399
self ._cloud_function_service_account
391
400
)
401
+ function .kms_key_name = self ._cloud_function_kms_key_name
392
402
create_function_request .function = function
393
403
394
404
# Create the cloud function and wait for it to be ready to use
@@ -597,6 +607,8 @@ def remote_function(
597
607
name : Optional [str ] = None ,
598
608
packages : Optional [Sequence [str ]] = None ,
599
609
cloud_function_service_account : Optional [str ] = None ,
610
+ cloud_function_kms_key_name : Optional [str ] = None ,
611
+ cloud_function_docker_repository : Optional [str ] = None ,
600
612
):
601
613
"""Decorator to turn a user defined function into a BigQuery remote function.
602
614
@@ -699,6 +711,20 @@ def remote_function(
699
711
for more details. Please make sure the service account has the
700
712
necessary IAM permissions configured as described in
701
713
https://cloud.google.com/functions/docs/reference/iam/roles#additional-configuration.
714
+ cloud_function_kms_key_name (str, Optional):
715
+ Customer managed encryption key to protect cloud functions and
716
+ related data at rest. This is of the format
717
+ projects/PROJECT_ID/locations/LOCATION/keyRings/KEYRING/cryptoKeys/KEY.
718
+ Read https://cloud.google.com/functions/docs/securing/cmek for
719
+ more details including granting necessary service accounts
720
+ access to the key.
721
+ cloud_function_docker_repository (str, Optional):
722
+ Docker repository created with the same encryption key as
723
+ `cloud_function_kms_key_name` to store encrypted artifacts
724
+ created to support the cloud function. This is of the format
725
+ projects/PROJECT_ID/locations/LOCATION/repositories/REPOSITORY_NAME.
726
+ For more details see
727
+ https://cloud.google.com/functions/docs/securing/cmek#before_you_begin.
702
728
"""
703
729
import bigframes .pandas as bpd
704
730
@@ -780,6 +806,16 @@ def remote_function(
780
806
f"{ bq_location } ."
781
807
)
782
808
809
+ # If any CMEK is intended then check that a docker repository is also specified
810
+ if (
811
+ cloud_function_kms_key_name is not None
812
+ and cloud_function_docker_repository is None
813
+ ):
814
+ raise ValueError (
815
+ "cloud_function_docker_repository must be specified with cloud_function_kms_key_name."
816
+ " For more details see https://cloud.google.com/functions/docs/securing/cmek#before_you_begin"
817
+ )
818
+
783
819
def wrapper (f ):
784
820
if not callable (f ):
785
821
raise TypeError ("f must be callable, got {}" .format (f ))
@@ -800,6 +836,8 @@ def wrapper(f):
800
836
bq_connection_id ,
801
837
resource_manager_client ,
802
838
cloud_function_service_account ,
839
+ cloud_function_kms_key_name ,
840
+ cloud_function_docker_repository ,
803
841
)
804
842
805
843
rf_name , cf_name = remote_function_client .provision_bq_remote_function (
0 commit comments