diff --git a/docs/api/sagemaker_mlops.rst b/docs/api/sagemaker_mlops.rst index f67879111d..d9f911068e 100644 --- a/docs/api/sagemaker_mlops.rst +++ b/docs/api/sagemaker_mlops.rst @@ -21,6 +21,14 @@ Workflow Management :undoc-members: :show-inheritance: +Feature Store +------------- + +.. automodule:: sagemaker.mlops.feature_store + :members: + :undoc-members: + :show-inheritance: + Local Development ----------------- diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py index f15d6d3845..1b635df2a7 100644 --- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py +++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/__init__.py @@ -2,8 +2,11 @@ # Licensed under the Apache License, Version 2.0 """SageMaker FeatureStore V3 - powered by sagemaker-core.""" +# FeatureGroup with Lake Formation support (local subclass) +from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig + # Resources from core -from sagemaker.core.resources import FeatureGroup, FeatureMetadata +from sagemaker.core.resources import FeatureMetadata # Shapes from core (Pydantic - no to_dict() needed) from sagemaker.core.shapes import ( @@ -79,6 +82,7 @@ "FeatureParameter", "FeatureValue", "Filter", + "LakeFormationConfig", "OfflineStoreConfig", "OnlineStoreConfig", "OnlineStoreSecurityConfig", diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py new file mode 100644 index 0000000000..97863c3f04 --- /dev/null +++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_group.py @@ -0,0 +1,746 @@ +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +# Licensed under the Apache License, Version 2.0 +"""FeatureGroup with Lake Formation support.""" + +import json +import logging +from typing import List, Optional + +import botocore.exceptions + +from sagemaker.core.resources import FeatureGroup as CoreFeatureGroup +from sagemaker.core.resources import Base +from sagemaker.core.shapes import ( + FeatureDefinition, + OfflineStoreConfig, + OnlineStoreConfig, + Tag, + ThroughputConfig, +) +from sagemaker.core.shapes import Unassigned +from sagemaker.core.helper.pipeline_variable import StrPipeVar +from sagemaker.core.s3.utils import parse_s3_url +from sagemaker.core.common_utils import aws_partition +from boto3 import Session + + +logger = logging.getLogger(__name__) + + +class LakeFormationConfig(Base): + """Configuration for Lake Formation governance on Feature Group offline stores. + + Attributes: + enabled: If True, enables Lake Formation governance for the offline store. + Requires offline_store_config and role_arn to be set on the Feature Group. + use_service_linked_role: Whether to use the Lake Formation service-linked role + for S3 registration. If True, Lake Formation uses its service-linked role. + If False, registration_role_arn must be provided. Default is True. + registration_role_arn: IAM role ARN to use for S3 registration with Lake Formation. + Required when use_service_linked_role is False. This can be different from the + Feature Group's execution role. + show_s3_policy: If True, prints the S3 deny policy to the console after successful + Lake Formation setup. This policy should be added to your S3 bucket to restrict + access to only the allowed principals. Default is False. + disable_hybrid_access_mode: If True, revokes IAMAllowedPrincipal permissions from + the Glue table, moving it to Lake Formation-only access mode. If False, keeps + hybrid access mode where both IAM and Lake Formation control access. + Default is True (LF-only mode). + """ + + enabled: bool = False + use_service_linked_role: bool = True + registration_role_arn: Optional[str] = None + show_s3_policy: bool = False + disable_hybrid_access_mode: bool = True + + +class FeatureGroup(CoreFeatureGroup): + + # Inherit parent docstring and append our additions + if CoreFeatureGroup.__doc__ and __doc__: + __doc__ = CoreFeatureGroup.__doc__ + + @staticmethod + def _s3_uri_to_arn(s3_uri: str, region: Optional[str] = None) -> str: + """ + Convert S3 URI to S3 ARN format for Lake Formation. + + Args: + s3_uri: S3 URI in format s3://bucket/path or already an ARN + region: AWS region name (e.g., 'us-west-2'). Used to determine the correct + partition for the ARN. If not provided, defaults to 'aws' partition. + + Returns: + S3 ARN in format arn:{partition}:s3:::bucket/path + + Note: + This format is specifically used for Lake Formation resource registration. + The triple colon (:::) after 's3' is correct - S3 ARNs don't include + region or account ID fields. + """ + if s3_uri.startswith("arn:"): + return s3_uri + + # Determine partition based on region + partition = aws_partition(region) if region else "aws" + + bucket, key = parse_s3_url(s3_uri) + # Reconstruct as ARN - key may be empty string + s3_path = f"{bucket}/{key}" if key else bucket + return f"arn:{partition}:s3:::{s3_path}" + + @staticmethod + def _extract_account_id_from_arn(arn: str) -> str: + """ + Extract AWS account ID from an ARN. + + Args: + arn: AWS ARN in format arn:aws:service:region:account:resource + + Returns: + AWS account ID (the 5th colon-separated field) + + Raises: + ValueError: If ARN format is invalid (fewer than 5 colon-separated parts) + """ + parts = arn.split(":") + if len(parts) < 5: + raise ValueError(f"Invalid ARN format: {arn}") + return parts[4] + + @staticmethod + def _get_lake_formation_service_linked_role_arn( + account_id: str, region: Optional[str] = None + ) -> str: + """ + Generate the Lake Formation service-linked role ARN for an account. + + Args: + account_id: AWS account ID + region: AWS region name (e.g., 'us-west-2'). Used to determine the correct + partition for the ARN. If not provided, defaults to 'aws' partition. + + Returns: + Lake Formation service-linked role ARN in format: + arn:{partition}:iam::{account}:role/aws-service-role/lakeformation.amazonaws.com/ + AWSServiceRoleForLakeFormationDataAccess + """ + partition = aws_partition(region) if region else "aws" + return ( + f"arn:{partition}:iam::{account_id}:role/aws-service-role/" + f"lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" + ) + + def _generate_s3_deny_policy( + self, + bucket_name: str, + s3_prefix: str, + lake_formation_role_arn: str, + feature_store_role_arn: str, + region: Optional[str] = None, + ) -> dict: + """ + Generate an S3 deny policy for Lake Formation governance. + + This policy denies S3 access to the offline store data prefix except for + the Lake Formation role and Feature Store execution role. + + Args: + bucket_name: S3 bucket name. + s3_prefix: S3 prefix path (without bucket name). + lake_formation_role_arn: Lake Formation registration role ARN. + feature_store_role_arn: Feature Store execution role ARN. + region: AWS region name (e.g., 'us-west-2'). Used to determine the correct + partition for S3 ARNs. If not provided, defaults to 'aws' partition. + + Returns: + S3 bucket policy as a dict with valid JSON structure containing: + - Version: "2012-10-17" + - Statement: List with two deny statements: + 1. Deny GetObject, PutObject, DeleteObject on data prefix except allowed principals + 2. Deny ListBucket on bucket with prefix condition except allowed principals + """ + partition = aws_partition(region) if region else "aws" + + policy = { + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "DenyAllAccessToFeatureStorePrefixExceptAllowedPrincipals", + "Effect": "Deny", + "Principal": "*", + "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"], + "Resource": f"arn:{partition}:s3:::{bucket_name}/{s3_prefix}/*", + "Condition": { + "StringNotEquals": { + "aws:PrincipalArn": [ + lake_formation_role_arn, + feature_store_role_arn, + ] + } + }, + }, + { + "Sid": "DenyListOnPrefixExceptAllowedPrincipals", + "Effect": "Deny", + "Principal": "*", + "Action": "s3:ListBucket", + "Resource": f"arn:{partition}:s3:::{bucket_name}", + "Condition": { + "StringLike": {"s3:prefix": f"{s3_prefix}/*"}, + "StringNotEquals": { + "aws:PrincipalArn": [ + lake_formation_role_arn, + feature_store_role_arn, + ] + }, + }, + }, + ], + } + return policy + + def _get_lake_formation_client( + self, + session: Optional[Session] = None, + region: Optional[str] = None, + ): + """ + Get a Lake Formation client, reusing a cached client when possible. + + The client is cached on the instance keyed by (session, region). Subsequent + calls with the same arguments return the existing client instead of creating + a new one. + + Args: + session: Boto3 session. If not provided, a new session will be created. + region: AWS region name. + + Returns: + A boto3 Lake Formation client. + """ + cache_key = (id(session), region) + if not hasattr(self, "_lf_client_cache"): + self._lf_client_cache: dict = {} + + if cache_key not in self._lf_client_cache: + boto_session = session or Session() + self._lf_client_cache[cache_key] = boto_session.client( + "lakeformation", region_name=region + ) + + return self._lf_client_cache[cache_key] + + def _register_s3_with_lake_formation( + self, + s3_location: str, + session: Optional[Session] = None, + region: Optional[str] = None, + use_service_linked_role: bool = True, + role_arn: Optional[str] = None, + ) -> bool: + """ + Register an S3 location with Lake Formation. + + Args: + s3_location: S3 URI or ARN to register. + session: Boto3 session. + region: AWS region. If not provided, will be inferred from the session. + use_service_linked_role: Whether to use the Lake Formation service-linked role. + If True, Lake Formation uses its service-linked role for registration. + If False, role_arn must be provided. + role_arn: IAM role ARN to use for registration. Required when + use_service_linked_role is False. + + Returns: + True if registration succeeded or location already registered. + + Raises: + ValueError: If use_service_linked_role is False but role_arn is not provided. + ClientError: If registration fails for unexpected reasons. + """ + if not use_service_linked_role and not role_arn: + raise ValueError("role_arn must be provided when use_service_linked_role is False") + + # Get region from session if not provided + if region is None and session is not None: + region = session.region_name + + client = self._get_lake_formation_client(session, region) + resource_arn = self._s3_uri_to_arn(s3_location, region) + + try: + register_params = {"ResourceArn": resource_arn} + + if use_service_linked_role: + register_params["UseServiceLinkedRole"] = True + else: + register_params["RoleArn"] = role_arn + + client.register_resource(**register_params) + logger.info(f"Successfully registered S3 location: {resource_arn}") + return True + except botocore.exceptions.ClientError as e: + if e.response["Error"]["Code"] == "AlreadyExistsException": + logger.info(f"S3 location already registered: {resource_arn}") + return True + raise + + def _revoke_iam_allowed_principal( + self, + database_name: str, + table_name: str, + session: Optional[Session] = None, + region: Optional[str] = None, + ) -> bool: + """ + Revoke IAMAllowedPrincipal permissions from a Glue table. + + Args: + database_name: Glue database name. + table_name: Glue table name. + session: Boto3 session. + region: AWS region. If not provided, will be inferred from the session. + + Returns: + True if revocation succeeded or permissions didn't exist. + + Raises: + ClientError: If revocation fails for unexpected reasons. + """ + # Get region from session if not provided + if region is None and session is not None: + region = session.region_name + + client = self._get_lake_formation_client(session, region) + + try: + client.revoke_permissions( + Principal={"DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS"}, + Resource={ + "Table": { + "DatabaseName": database_name, + "Name": table_name, + } + }, + Permissions=["ALL"], + ) + logger.info(f"Revoked IAMAllowedPrincipal from table: {database_name}.{table_name}") + return True + except botocore.exceptions.ClientError as e: + # if the Table doesn't have that permission because the user already revoked it + # then just return True + if e.response["Error"]["Code"] == "InvalidInputException": + logger.info( + f"IAMAllowedPrincipal permissions may not exist on: {database_name}.{table_name}" + ) + return True + raise + + def _grant_lake_formation_permissions( + self, + role_arn: str, + database_name: str, + table_name: str, + session: Optional[Session] = None, + region: Optional[str] = None, + ) -> bool: + """ + Grant permissions to a role on a Glue table via Lake Formation. + + Args: + role_arn: IAM role ARN to grant permissions to. + database_name: Glue database name. + table_name: Glue table name. + session: Boto3 session. + region: AWS region. If not provided, will be inferred from the session. + + Returns: + True if grant succeeded or permissions already exist. + + Raises: + ClientError: If grant fails for unexpected reasons. + """ + # Get region from session if not provided + if region is None and session is not None: + region = session.region_name + + client = self._get_lake_formation_client(session, region) + permissions = ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"] + + try: + client.grant_permissions( + Principal={"DataLakePrincipalIdentifier": role_arn}, + Resource={ + "Table": { + "DatabaseName": database_name, + "Name": table_name, + } + }, + Permissions=permissions, + PermissionsWithGrantOption=[], + ) + logger.info(f"Granted permissions to {role_arn} on table: {database_name}.{table_name}") + return True + except botocore.exceptions.ClientError as e: + if e.response["Error"]["Code"] == "InvalidInputException": + logger.info( + f"Permissions may already exist for {role_arn} on: {database_name}.{table_name}" + ) + return True + raise + + @Base.add_validate_call + def enable_lake_formation( + self, + session: Optional[Session] = None, + region: Optional[str] = None, + use_service_linked_role: bool = True, + registration_role_arn: Optional[str] = None, + wait_for_active: bool = False, + show_s3_policy: bool = False, + disable_hybrid_access_mode: bool = True, + ) -> dict: + """ + Enable Lake Formation governance for this Feature Group's offline store. + + This method: + 1. Optionally waits for Feature Group to reach 'Created' status + 2. Validates Feature Group status is 'Created' + 3. Registers the offline store S3 location as data lake location + 4. Grants the execution role permissions on the Glue table + 5. Optionally revokes IAMAllowedPrincipal permissions from the Glue table + (controlled by disable_hybrid_access_mode) + + The role ARN is automatically extracted from the Feature Group's configuration. + Each phase depends on the success of the previous phase - if any phase fails, + subsequent phases are not executed. + + Parameters: + session: Boto3 session. + region: Region name. + use_service_linked_role: Whether to use the Lake Formation service-linked role + for S3 registration. If True, Lake Formation uses its service-linked role. + If False, registration_role_arn must be provided. Default is True. + registration_role_arn: IAM role ARN to use for S3 registration with Lake Formation. + Required when use_service_linked_role is False. This can be different from the + Feature Group's execution role (role_arn) + wait_for_active: If True, waits for the Feature Group to reach 'Created' status + before enabling Lake Formation. Default is False. + show_s3_policy: If True, prints the S3 deny policy to the console after successful + Lake Formation setup. This policy should be added to your S3 bucket to restrict + access to only the allowed principals. Default is False. + disable_hybrid_access_mode: If True, revokes IAMAllowedPrincipal permissions from + the Glue table, moving it to Lake Formation-only access mode. If False, keeps + hybrid access mode where both IAM and Lake Formation control access. + Default is True. + + Returns: + Dict with status of each Lake Formation operation: + - s3_registration: bool + - iam_principal_revoked: bool or None (None when disable_hybrid_access_mode=False) + - permissions_granted: bool + + Raises: + ValueError: If the Feature Group has no offline store configured, + if role_arn is not set on the Feature Group, if use_service_linked_role + is False but registration_role_arn is not provided, or if the Feature Group + is not in 'Created' status. + ClientError: If Lake Formation operations fail. + RuntimeError: If a phase fails and subsequent phases cannot proceed. + """ + # Get region from session if not provided + if region is None and session is not None: + region = session.region_name + + # Wait for Created status if requested + if wait_for_active: + self.wait_for_status(target_status="Created") + + # Refresh to get latest state + self.refresh() + + # Validate Feature Group status + if self.feature_group_status not in ["Created"]: + raise ValueError( + f"Feature Group '{self.feature_group_name}' must be in 'Created' status " + f"to enable Lake Formation. Current status: '{self.feature_group_status}'. " + f"Use wait_for_active=True to automatically wait for the Feature Group to be ready." + ) + + # Validate offline store exists + if self.offline_store_config is None or self.offline_store_config == Unassigned(): + raise ValueError( + f"Feature Group '{self.feature_group_name}' does not have an offline store configured. " + "Lake Formation can only be enabled for Feature Groups with offline stores." + ) + + # Get role ARN from Feature Group config + if self.role_arn is None or self.role_arn == Unassigned(): + raise ValueError( + f"Feature Group '{self.feature_group_name}' does not have a role_arn configured. " + "Lake Formation requires a role ARN to grant permissions." + ) + if not use_service_linked_role and registration_role_arn is None: + raise ValueError( + "Either 'use_service_linked_role' must be True or 'registration_role_arn' must be provided." + ) + + # Extract required configuration + s3_config = self.offline_store_config.s3_storage_config + if s3_config is None: + raise ValueError("Offline store S3 configuration is missing") + + resolved_s3_uri = s3_config.resolved_output_s3_uri + if resolved_s3_uri is None or resolved_s3_uri == Unassigned(): + raise ValueError( + "Resolved S3 URI not available. Ensure the Feature Group is in 'Created' status." + ) + + data_catalog_config = self.offline_store_config.data_catalog_config + if data_catalog_config is None: + raise ValueError("Data catalog configuration is missing from offline store config") + + database_name = data_catalog_config.database + table_name = data_catalog_config.table_name + + if not database_name or not table_name: + raise ValueError("Database name and table name are required from data catalog config") + + # Convert to str to handle PipelineVariable types + resolved_s3_uri_str = str(resolved_s3_uri) + database_name_str = str(database_name) + table_name_str = str(table_name) + role_arn_str = str(self.role_arn) + + # Execute Lake Formation setup with fail-fast behavior + results = { + "s3_registration": False, + "iam_principal_revoked": False, + "permissions_granted": False, + } + + # Phase 1: Register S3 with Lake Formation + try: + results["s3_registration"] = self._register_s3_with_lake_formation( + resolved_s3_uri_str, + session, + region, + use_service_linked_role=use_service_linked_role, + role_arn=registration_role_arn, + ) + except Exception as e: + raise RuntimeError( + f"Failed to register S3 location with Lake Formation. " + f"Subsequent phases skipped. Results: {results}. Error: {e}" + ) from e + + if not results["s3_registration"]: + raise RuntimeError( + f"Failed to register S3 location with Lake Formation. " + f"Subsequent phases skipped. Results: {results}" + ) + + # Phase 2: Grant Lake Formation permissions to the role + try: + results["permissions_granted"] = self._grant_lake_formation_permissions( + role_arn_str, database_name_str, table_name_str, session, region + ) + except Exception as e: + raise RuntimeError( + f"Failed to grant Lake Formation permissions. " + f"Subsequent phases skipped. Results: {results}. Error: {e}" + ) from e + + if not results["permissions_granted"]: + raise RuntimeError( + f"Failed to grant Lake Formation permissions. " + f"Subsequent phases skipped. Results: {results}" + ) + + # Phase 3: Revoke IAMAllowedPrincipal permissions (if disabling hybrid access mode) + if disable_hybrid_access_mode: + try: + results["iam_principal_revoked"] = self._revoke_iam_allowed_principal( + database_name_str, table_name_str, session, region + ) + except Exception as e: + raise RuntimeError( + f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}. Error: {e}" + ) from e + + if not results["iam_principal_revoked"]: + raise RuntimeError( + f"Failed to revoke IAMAllowedPrincipal permissions. Results: {results}" + ) + else: + results["iam_principal_revoked"] = None + logger.info( + "Skipping IAMAllowedPrincipal revocation - hybrid access mode preserved." + ) + + logger.info(f"Lake Formation setup complete for {self.feature_group_name}: {results}") + + # Generate and optionally print S3 deny policy + if show_s3_policy: + # Extract bucket name and prefix from resolved S3 URI using core utility + bucket_name, s3_prefix = parse_s3_url(resolved_s3_uri_str) + + # Extract account ID from Feature Group ARN + feature_group_arn_str = str(self.feature_group_arn) if self.feature_group_arn else "" + account_id = self._extract_account_id_from_arn(feature_group_arn_str) + + # Determine Lake Formation role ARN based on use_service_linked_role flag + if use_service_linked_role: + lf_role_arn = self._get_lake_formation_service_linked_role_arn(account_id, region) + else: + # registration_role_arn is validated earlier when use_service_linked_role is False + lf_role_arn = str(registration_role_arn) + + # Generate the S3 deny policy + policy = self._generate_s3_deny_policy( + bucket_name=bucket_name, + s3_prefix=s3_prefix, + lake_formation_role_arn=lf_role_arn, + feature_store_role_arn=role_arn_str, + region=region, + ) + + # Print policy with clear instructions + print("\n" + "=" * 80) + print("S3 Bucket Policy Update recommended") + print("=" * 80) + print( + "\nTo complete Lake Formation setup, add the following deny policy to your S3 bucket." + ) + print( + "This policy restricts access to the offline store data to only the allowed principals." + ) + print("\nBucket:", bucket_name) + print("\nPolicy to add:") + print("-" * 40) + print(json.dumps(policy, indent=2)) + print("-" * 40) + print("\nNote: Merge this with your existing bucket policy if one exists.") + print("=" * 80 + "\n") + + return results + + @classmethod + @Base.add_validate_call + def create( + cls, + feature_group_name: StrPipeVar, + record_identifier_feature_name: StrPipeVar, + event_time_feature_name: StrPipeVar, + feature_definitions: List[FeatureDefinition], + online_store_config: Optional[OnlineStoreConfig] = None, + offline_store_config: Optional[OfflineStoreConfig] = None, + throughput_config: Optional[ThroughputConfig] = None, + role_arn: Optional[StrPipeVar] = None, + description: Optional[StrPipeVar] = None, + tags: Optional[List[Tag]] = None, + use_pre_prod_offline_store_replicator_lambda: Optional[bool] = None, + lake_formation_config: Optional[LakeFormationConfig] = None, + session: Optional[Session] = None, + region: Optional[StrPipeVar] = None, + ) -> Optional["FeatureGroup"]: + """ + Create a FeatureGroup resource with optional Lake Formation governance. + + Parameters: + feature_group_name: The name of the FeatureGroup. + record_identifier_feature_name: The name of the Feature whose value uniquely + identifies a Record. + event_time_feature_name: The name of the feature that stores the EventTime. + feature_definitions: A list of Feature names and types. + online_store_config: Configuration for the OnlineStore. + offline_store_config: Configuration for the OfflineStore. + throughput_config: Throughput configuration. + role_arn: IAM execution role ARN for the OfflineStore. + description: A free-form description of the FeatureGroup. + tags: Tags used to identify Features in each FeatureGroup. + use_pre_prod_offline_store_replicator_lambda: Pre-prod replicator flag. + lake_formation_config: Optional LakeFormationConfig to configure Lake Formation + governance. When enabled=True, requires offline_store_config and role_arn. + session: Boto3 session. + region: Region name. + + Returns: + The FeatureGroup resource. + + Raises: + botocore.exceptions.ClientError: This exception is raised for AWS service related errors. + The error message and error code can be parsed from the exception as follows: + ``` + try: + # AWS service call here + except botocore.exceptions.ClientError as e: + error_message = e.response['Error']['Message'] + error_code = e.response['Error']['Code'] + ``` + ResourceInUse: Resource being accessed is in use. + ResourceLimitExceeded: You have exceeded an SageMaker resource limit. + For example, you might have too many training jobs created. + ConfigSchemaValidationError: Raised when a configuration file does not adhere to the schema + LocalConfigNotFoundError: Raised when a configuration file is not found in local file system + S3ConfigNotFoundError: Raised when a configuration file is not found in S3 + """ + # Validation for Lake Formation + if lake_formation_config is not None and lake_formation_config.enabled: + if offline_store_config is None: + raise ValueError( + "lake_formation_config with enabled=True requires offline_store_config to be configured" + ) + if role_arn is None: + raise ValueError( + "lake_formation_config with enabled=True requires role_arn to be specified" + ) + if ( + not lake_formation_config.use_service_linked_role + and not lake_formation_config.registration_role_arn + ): + raise ValueError( + "registration_role_arn must be provided in lake_formation_config " + "when use_service_linked_role is False" + ) + + # Build kwargs, only including non-None values so parent uses its defaults + create_kwargs = { + "feature_group_name": feature_group_name, + "record_identifier_feature_name": record_identifier_feature_name, + "event_time_feature_name": event_time_feature_name, + "feature_definitions": feature_definitions, + "session": session, + "region": region, + } + if online_store_config is not None: + create_kwargs["online_store_config"] = online_store_config + if offline_store_config is not None: + create_kwargs["offline_store_config"] = offline_store_config + if throughput_config is not None: + create_kwargs["throughput_config"] = throughput_config + if role_arn is not None: + create_kwargs["role_arn"] = role_arn + if description is not None: + create_kwargs["description"] = description + if tags is not None: + create_kwargs["tags"] = tags + if use_pre_prod_offline_store_replicator_lambda is not None: + create_kwargs["use_pre_prod_offline_store_replicator_lambda"] = use_pre_prod_offline_store_replicator_lambda + + feature_group = super().create(**create_kwargs) + + # Enable Lake Formation if requested + if lake_formation_config is not None and lake_formation_config.enabled: + feature_group.wait_for_status(target_status="Created") + feature_group.enable_lake_formation( + session=session, + region=region, + use_service_linked_role=lake_formation_config.use_service_linked_role, + registration_role_arn=lake_formation_config.registration_role_arn, + show_s3_policy=lake_formation_config.show_s3_policy, + disable_hybrid_access_mode=lake_formation_config.disable_hybrid_access_mode, + ) + return feature_group diff --git a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py index 3e3e7813df..5ee04780be 100644 --- a/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py +++ b/sagemaker-mlops/src/sagemaker/mlops/feature_store/feature_utils.py @@ -731,4 +731,4 @@ def _cast_object_to_string(data_frame: pandas.DataFrame) -> pandas.DataFrame: """ for label in data_frame.select_dtypes(["object", "O"]).columns.tolist(): data_frame[label] = data_frame[label].astype("str").astype("string") - return data_frame \ No newline at end of file + return data_frame diff --git a/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py new file mode 100644 index 0000000000..dc6f12181a --- /dev/null +++ b/sagemaker-mlops/tests/integ/test_featureStore_lakeformation.py @@ -0,0 +1,660 @@ +""" +Integration tests for Lake Formation with FeatureGroup. + +These tests require: +- AWS credentials with Lake Formation and SageMaker permissions +- An S3 bucket for offline store (uses default SageMaker bucket) +- An IAM role for Feature Store (uses execution role) + +Run with: pytest tests/integ/test_featureStore_lakeformation.py -v -m integ +""" + +import uuid + +import boto3 +import pytest +from botocore.exceptions import ClientError + +from sagemaker.core.helper.session_helper import Session, get_execution_role +from sagemaker.mlops.feature_store import ( + FeatureGroup, + LakeFormationConfig, + OfflineStoreConfig, + OnlineStoreConfig, + S3StorageConfig, + StringFeatureDefinition, + FractionalFeatureDefinition, +) + +feature_definitions = [ + StringFeatureDefinition(feature_name="record_id"), + StringFeatureDefinition(feature_name="event_time"), + FractionalFeatureDefinition(feature_name="feature_value"), +] + + +@pytest.fixture(scope="module") +def sagemaker_session(): + return Session() + + +@pytest.fixture(scope="module") +def role(sagemaker_session): + return get_execution_role(sagemaker_session) + + +@pytest.fixture(scope="module") +def s3_uri(sagemaker_session): + bucket = sagemaker_session.default_bucket() + return f"s3://{bucket}/feature-store-test" + + +@pytest.fixture(scope="module") +def region(): + return "us-west-2" + + +@pytest.fixture(scope="module") +def shared_feature_group_for_negative_tests(s3_uri, role, region): + """ + Create a single FeatureGroup for negative tests that only need to verify + error conditions without modifying the resource. + + This fixture is module-scoped to be created once and shared across tests, + reducing test execution time. + """ + fg_name = f"test-lf-negative-{uuid.uuid4().hex[:8]}" + fg = None + + try: + fg = create_test_feature_group(fg_name, s3_uri, role, region) + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + yield fg + finally: + if fg: + cleanup_feature_group(fg) + + +def generate_feature_group_name(): + """Generate a unique feature group name for testing.""" + return f"test-lf-fg-{uuid.uuid4().hex[:8]}" + + +def create_test_feature_group(name: str, s3_uri: str, role_arn: str, region: str) -> FeatureGroup: + """Create a FeatureGroup with offline store for testing.""" + + offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri)) + + fg = FeatureGroup.create( + feature_group_name=name, + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + role_arn=role_arn, + region=region, + ) + + return fg + + +def cleanup_feature_group(fg: FeatureGroup): + """ + Delete a FeatureGroup and its associated Glue table. + + Args: + fg: The FeatureGroup to delete. + """ + try: + # Delete the Glue table if it exists + if fg.offline_store_config is not None: + try: + fg.refresh() # Ensure we have latest config + data_catalog_config = fg.offline_store_config.data_catalog_config + if data_catalog_config is not None: + database_name = data_catalog_config.database + table_name = data_catalog_config.table_name + + if database_name and table_name: + glue_client = boto3.client("glue") + try: + glue_client.delete_table(DatabaseName=database_name, Name=table_name) + except ClientError as e: + # Ignore if table doesn't exist + if e.response["Error"]["Code"] != "EntityNotFoundException": + raise + except Exception: + # Don't fail cleanup if Glue table deletion fails + pass + + # Delete the FeatureGroup + fg.delete() + except ClientError: + # Don't fail cleanup if Glue table deletion fails + pass + + +@pytest.mark.serial +@pytest.mark.slow_test +def test_create_feature_group_and_enable_lake_formation(s3_uri, role, region): + """ + Test creating a FeatureGroup and enabling Lake Formation governance. + + This test: + 1. Creates a new FeatureGroup with offline store + 2. Waits for it to reach Created status + 3. Enables Lake Formation governance (registers S3, grants permissions, revokes IAM principals) + 4. Cleans up the FeatureGroup + """ + + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup + fg = create_test_feature_group(fg_name, s3_uri, role, region) + assert fg is not None + + # Wait for Created status + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + assert fg.feature_group_status == "Created" + + # Enable Lake Formation governance + result = fg.enable_lake_formation() + + # Verify all phases completed successfully + assert result["s3_registration"] is True + assert result["permissions_granted"] is True + assert result["iam_principal_revoked"] is True + + finally: + print('done') + # Cleanup + if fg: + cleanup_feature_group(fg) + + +@pytest.mark.serial +@pytest.mark.slow_test +def test_create_feature_group_with_lake_formation_enabled(s3_uri, role, region): + """ + Test creating a FeatureGroup with lake_formation_config.enabled=True. + + This test verifies the integrated workflow where Lake Formation is enabled + automatically during FeatureGroup creation: + 1. Creates a new FeatureGroup with lake_formation_config.enabled=True + 2. Verifies the FeatureGroup is created and Lake Formation is configured + 3. Cleans up the FeatureGroup + """ + + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup with Lake Formation enabled + + offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri)) + lake_formation_config = LakeFormationConfig() + lake_formation_config.enabled = True + + fg = FeatureGroup.create( + feature_group_name=fg_name, + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + role_arn=role, + lake_formation_config=lake_formation_config, + ) + + # Verify the FeatureGroup was created + assert fg is not None + assert fg.feature_group_name == fg_name + assert fg.feature_group_status == "Created" + + # Verify Lake Formation is configured by checking we can refresh without errors + fg.refresh() + assert fg.offline_store_config is not None + + finally: + # Cleanup + if fg: + cleanup_feature_group(fg) + + +@pytest.mark.serial +def test_create_feature_group_without_lake_formation(s3_uri, role, region): + """ + Test creating a FeatureGroup without Lake Formation enabled. + + This test verifies that when lake_formation_config is not provided or enabled=False, + the FeatureGroup is created successfully without any Lake Formation operations: + 1. Creates a new FeatureGroup without lake_formation_config + 2. Verifies the FeatureGroup is created successfully + 3. Verifies no Lake Formation operations were performed + 4. Cleans up the FeatureGroup + """ + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup without Lake Formation + offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri)) + + # Create without lake_formation_config (default behavior) + fg = FeatureGroup.create( + feature_group_name=fg_name, + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + role_arn=role, + ) + + # Verify the FeatureGroup was created + assert fg is not None + assert fg.feature_group_name == fg_name + + # Wait for Created status to ensure it's fully provisioned + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + assert fg.feature_group_status == "Created" + + # Verify offline store is configured + fg.refresh() + assert fg.offline_store_config is not None + assert fg.offline_store_config.s3_storage_config is not None + + finally: + # Cleanup + if fg: + cleanup_feature_group(fg) + + +# ============================================================================ +# Negative Integration Tests +# ============================================================================ + + +def test_create_feature_group_with_lake_formation_fails_without_offline_store(role, region): + """ + Test that creating a FeatureGroup with enable_lake_formation=True fails + when no offline store is configured. + + Expected behavior: ValueError should be raised indicating offline store is required. + """ + fg_name = generate_feature_group_name() + + lake_formation_config = LakeFormationConfig() + lake_formation_config.enabled = True + + # Attempt to create without offline store but with Lake Formation enabled + with pytest.raises(ValueError) as exc_info: + FeatureGroup.create( + feature_group_name=fg_name, + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + role_arn=role, + lake_formation_config=lake_formation_config, + ) + + # Verify error message mentions offline_store_config requirement + assert "lake_formation_config with enabled=True requires offline_store_config to be configured" in str( + exc_info.value + ) + + +def test_create_feature_group_with_lake_formation_fails_without_role(s3_uri, region): + """ + Test that creating a FeatureGroup with lake_formation_config.enabled=True fails + when no role_arn is provided. + + Expected behavior: ValueError should be raised indicating role_arn is required. + """ + fg_name = generate_feature_group_name() + + offline_store_config = OfflineStoreConfig(s3_storage_config=S3StorageConfig(s3_uri=s3_uri)) + lake_formation_config = LakeFormationConfig() + lake_formation_config.enabled = True + + # Attempt to create without role_arn but with Lake Formation enabled + with pytest.raises(ValueError) as exc_info: + FeatureGroup.create( + feature_group_name=fg_name, + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + lake_formation_config=lake_formation_config, + ) + + # Verify error message mentions role_arn requirement + assert "lake_formation_config with enabled=True requires role_arn to be specified" in str(exc_info.value) + + +def test_enable_lake_formation_fails_for_non_created_status(s3_uri, role, region): + """ + Test that enable_lake_formation() fails when called on a FeatureGroup + that is not in 'Created' status. + + Expected behavior: ValueError should be raised indicating the Feature Group + must be in 'Created' status. + + Note: This test creates its own FeatureGroup because it needs to test + behavior during the 'Creating' status, which requires a fresh resource. + """ + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup + fg = create_test_feature_group(fg_name, s3_uri, role, region) + assert fg is not None + + # Immediately try to enable Lake Formation without waiting for Created status + # The Feature Group will be in 'Creating' status + with pytest.raises(ValueError) as exc_info: + fg.enable_lake_formation(wait_for_active=False) + + # Verify error message mentions status requirement + error_msg = str(exc_info.value) + assert "must be in 'Created' status to enable Lake Formation" in error_msg + + finally: + # Cleanup + if fg: + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + cleanup_feature_group(fg) + + +def test_enable_lake_formation_without_offline_store(role, region): + """ + Test that enable_lake_formation() fails when called on a FeatureGroup + without an offline store configured. + + Expected behavior: ValueError should be raised indicating offline store is required. + + Note: This test creates a FeatureGroup with only online store, which is a valid + configuration, but Lake Formation cannot be enabled for it. + """ + fg_name = generate_feature_group_name() + fg = None + + try: + # Create a FeatureGroup with only online store (no offline store) + online_store_config = OnlineStoreConfig(enable_online_store=True) + + fg = FeatureGroup.create( + feature_group_name=fg_name, + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + online_store_config=online_store_config, + role_arn=role, + ) + + # Wait for Created status + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + + # Attempt to enable Lake Formation + with pytest.raises(ValueError) as exc_info: + fg.enable_lake_formation() + # Verify error message mentions offline store requirement + assert "does not have an offline store configured" in str(exc_info.value) + + finally: + # Cleanup + if fg: + cleanup_feature_group(fg) + + +def test_enable_lake_formation_fails_with_invalid_registration_role( + shared_feature_group_for_negative_tests, +): + """ + Test that enable_lake_formation() fails when use_service_linked_role=False + but no registration_role_arn is provided. + + Expected behavior: ValueError should be raised indicating registration_role_arn + is required when not using service-linked role. + """ + fg = shared_feature_group_for_negative_tests + + # Attempt to enable Lake Formation without service-linked role and without registration_role_arn + with pytest.raises(ValueError) as exc_info: + fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=None, + ) + + # Verify error message mentions role requirement + error_msg = str(exc_info.value) + assert "registration_role_arn" in error_msg + + +def test_enable_lake_formation_fails_with_nonexistent_role( + shared_feature_group_for_negative_tests, role +): + """ + Test that enable_lake_formation() properly bubbles errors when using + a nonexistent role ARN for Lake Formation registration. + + Expected behavior: RuntimeError or ClientError should be raised with details + about the registration failure. + + Note: This test uses a nonexistent role ARN (current role with random suffix) + to trigger an error during S3 registration with Lake Formation. + """ + fg = shared_feature_group_for_negative_tests + + # Generate a nonexistent role ARN by appending a random string to the current role + nonexistent_role = f"{role}-nonexistent-{uuid.uuid4().hex[:8]}" + + with pytest.raises(RuntimeError) as exc_info: + fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=nonexistent_role, + ) + + # Verify we got an appropriate error + error_msg = str(exc_info.value) + print(exc_info) + # Should mention role-related issues (not found, invalid, access denied, etc.) + assert "EntityNotFoundException" in error_msg + + +# ============================================================================ +# Full Flow Integration Tests with Policy Output +# ============================================================================ + + +@pytest.mark.serial +@pytest.mark.slow_test +def test_enable_lake_formation_full_flow_with_policy_output(s3_uri, role, region, capsys): + """ + Test the full Lake Formation flow with S3 deny policy output. + + This test verifies: + 1. Creates a FeatureGroup with offline store + 2. Enables Lake Formation with show_s3_policy=True + 3. Verifies all Lake Formation phases complete successfully + 4. Verifies the S3 deny policy is printed to the console + 5. Verifies the policy structure contains expected elements + + This validates Requirements 6.1-6.9 from the design document. + """ + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup + fg = create_test_feature_group(fg_name, s3_uri, role, region) + assert fg is not None + + # Wait for Created status + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + assert fg.feature_group_status == "Created" + + # Enable Lake Formation governance with policy output + result = fg.enable_lake_formation(show_s3_policy=True) + + # Verify all phases completed successfully + assert result["s3_registration"] is True + assert result["permissions_granted"] is True + assert result["iam_principal_revoked"] is True + + # Capture the printed output + captured = capsys.readouterr() + output = captured.out + + # Re-print the output so it's visible in terminal with -s flag + print(output) + + # Verify the policy header is printed + assert "S3 Bucket Policy Update recommended" in output + assert "=" * 80 in output + + # Verify bucket information is printed + # Extract bucket name from s3_uri (s3://bucket/path -> bucket) + expected_bucket = s3_uri.replace("s3://", "").split("/")[0] + assert f"Bucket: {expected_bucket}" in output + + # Verify policy structure elements are present + assert '"Version": "2012-10-17"' in output + assert '"Statement"' in output + assert '"Effect": "Deny"' in output + assert '"Principal": "*"' in output + + # Verify the deny actions are present + assert "s3:GetObject" in output + assert "s3:PutObject" in output + assert "s3:DeleteObject" in output + assert "s3:ListBucket" in output + + # Verify the condition structure is present + assert "StringNotEquals" in output + assert "aws:PrincipalArn" in output + + # Verify the role ARN is in the allowed principals + assert role in output + + # Verify the service-linked role pattern is present (default use_service_linked_role=True) + assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" in output + + # Verify instructions are printed + assert "Merge this with your existing bucket policy" in output + + finally: + # Cleanup + if fg: + cleanup_feature_group(fg) + + +@pytest.mark.serial +@pytest.mark.slow_test +def test_enable_lake_formation_no_policy_output_by_default(s3_uri, role, region, capsys): + """ + Test that S3 deny policy is NOT printed when show_s3_policy=False (default). + + This test verifies: + 1. Creates a FeatureGroup with offline store + 2. Enables Lake Formation without show_s3_policy (defaults to False) + 3. Verifies all Lake Formation phases complete successfully + 4. Verifies the S3 deny policy is NOT printed to the console + + This validates Requirement 6.2 from the design document. + """ + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup + fg = create_test_feature_group(fg_name, s3_uri, role, region) + assert fg is not None + + # Wait for Created status + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + assert fg.feature_group_status == "Created" + + # Enable Lake Formation governance WITHOUT policy output (default) + result = fg.enable_lake_formation() + + # Verify all phases completed successfully + assert result["s3_registration"] is True + assert result["permissions_granted"] is True + assert result["iam_principal_revoked"] is True + + # Capture the printed output + captured = capsys.readouterr() + output = captured.out + + # Verify the policy is NOT printed + assert "S3 Bucket Policy Update recommended" not in output + assert '"Version": "2012-10-17"' not in output + assert "s3:GetObject" not in output + + finally: + # Cleanup + if fg: + cleanup_feature_group(fg) + + +@pytest.mark.serial +@pytest.mark.slow_test +def test_enable_lake_formation_with_custom_role_policy_output(s3_uri, role, region, capsys): + """ + Test the full Lake Formation flow with custom registration role and policy output. + + This test verifies: + 1. Creates a FeatureGroup with offline store + 2. Enables Lake Formation with use_service_linked_role=False and a custom registration_role_arn + 3. Verifies the S3 deny policy uses the custom role ARN instead of service-linked role + + This validates Requirements 6.4, 6.5 from the design document. + + Note: This test uses the same execution role as the registration role for simplicity. + In production, these would typically be different roles. + """ + fg_name = generate_feature_group_name() + fg = None + + try: + # Create the FeatureGroup + fg = create_test_feature_group(fg_name, s3_uri, role, region) + assert fg is not None + + # Wait for Created status + fg.wait_for_status(target_status="Created", poll=30, timeout=300) + assert fg.feature_group_status == "Created" + + # Enable Lake Formation with custom registration role and policy output + # Using the same role for both execution and registration for test simplicity + result = fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=role, + show_s3_policy=True, + ) + + # Verify all phases completed successfully + assert result["s3_registration"] is True + assert result["permissions_granted"] is True + assert result["iam_principal_revoked"] is True + + # Capture the printed output + captured = capsys.readouterr() + output = captured.out + + # Verify the policy header is printed + assert "S3 Bucket Policy Update recommended" in output + + # Verify the custom role ARN is used in the policy (appears twice - once for each principal) + # The role should appear as both the Lake Formation role and the Feature Store role + assert output.count(role) >= 2 + + # Verify the service-linked role is NOT used + assert "aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" not in output + + finally: + # Cleanup + if fg: + cleanup_feature_group(fg) diff --git a/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py new file mode 100644 index 0000000000..534d4a6406 --- /dev/null +++ b/sagemaker-mlops/tests/unit/sagemaker/mlops/feature_store/test_lakeformation.py @@ -0,0 +1,2319 @@ +"""Unit tests for Lake Formation integration with FeatureGroup.""" +from unittest.mock import MagicMock, patch + +import botocore.exceptions +import pytest + +from sagemaker.mlops.feature_store import FeatureGroup, LakeFormationConfig + + +class TestS3UriToArn: + """Tests for _s3_uri_to_arn static method.""" + + def test_converts_s3_uri_to_arn(self): + """Test S3 URI is converted to ARN format.""" + uri = "s3://my-bucket/my-prefix/data" + result = FeatureGroup._s3_uri_to_arn(uri) + assert result == "arn:aws:s3:::my-bucket/my-prefix/data" + + def test_handles_bucket_only_uri(self): + """Test S3 URI with bucket only.""" + uri = "s3://my-bucket" + result = FeatureGroup._s3_uri_to_arn(uri) + assert result == "arn:aws:s3:::my-bucket" + + def test_returns_arn_unchanged(self): + """Test ARN input is returned unchanged (idempotent).""" + arn = "arn:aws:s3:::my-bucket/path" + result = FeatureGroup._s3_uri_to_arn(arn) + assert result == arn + + def test_uses_region_for_partition(self): + """Test that region is used to determine partition.""" + uri = "s3://my-bucket/path" + result = FeatureGroup._s3_uri_to_arn(uri, region="cn-north-1") + assert result.startswith("arn:aws-cn:s3:::") + + + +class TestGetLakeFormationClient: + """Tests for _get_lake_formation_client method.""" + + @patch("sagemaker.mlops.feature_store.feature_group.Session") + def test_creates_client_with_default_session(self, mock_session_class): + """Test client creation with default session.""" + mock_session = MagicMock() + mock_client = MagicMock() + mock_session.client.return_value = mock_client + mock_session_class.return_value = mock_session + + fg = MagicMock(spec=FeatureGroup) + fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg) + + client = fg._get_lake_formation_client(region="us-west-2") + + mock_session.client.assert_called_with("lakeformation", region_name="us-west-2") + assert client == mock_client + + def test_creates_client_with_provided_session(self): + """Test client creation with provided session.""" + mock_session = MagicMock() + mock_client = MagicMock() + mock_session.client.return_value = mock_client + + fg = MagicMock(spec=FeatureGroup) + fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg) + + client = fg._get_lake_formation_client(session=mock_session, region="us-west-2") + + mock_session.client.assert_called_with("lakeformation", region_name="us-west-2") + assert client == mock_client + + def test_caches_client_for_same_session_and_region(self): + """Test that repeated calls with the same session and region reuse the cached client.""" + mock_session = MagicMock() + mock_client = MagicMock() + mock_session.client.return_value = mock_client + + fg = MagicMock(spec=FeatureGroup) + fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg) + + client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2") + client2 = fg._get_lake_formation_client(session=mock_session, region="us-west-2") + + assert client1 is client2 + mock_session.client.assert_called_once() + + def test_creates_new_client_for_different_region(self): + """Test that a different region produces a new client.""" + mock_session = MagicMock() + mock_client_west = MagicMock() + mock_client_east = MagicMock() + mock_session.client.side_effect = [mock_client_west, mock_client_east] + + fg = MagicMock(spec=FeatureGroup) + fg._get_lake_formation_client = FeatureGroup._get_lake_formation_client.__get__(fg) + + client1 = fg._get_lake_formation_client(session=mock_session, region="us-west-2") + client2 = fg._get_lake_formation_client(session=mock_session, region="us-east-1") + + assert client1 is not client2 + assert mock_session.client.call_count == 2 + + +class TestRegisterS3WithLakeFormation: + """Tests for _register_s3_with_lake_formation method.""" + + def setup_method(self): + """Set up test fixtures.""" + self.fg = MagicMock(spec=FeatureGroup) + self.fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn + self.fg._register_s3_with_lake_formation = ( + FeatureGroup._register_s3_with_lake_formation.__get__(self.fg) + ) + self.mock_client = MagicMock() + self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client) + + def test_successful_registration_returns_true(self): + """Test successful S3 registration returns True.""" + self.mock_client.register_resource.return_value = {} + + result = self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix") + + assert result is True + self.mock_client.register_resource.assert_called_with( + ResourceArn="arn:aws:s3:::test-bucket/prefix", + UseServiceLinkedRole=True, + ) + + def test_already_exists_exception_returns_true(self): + """Test AlreadyExistsException is handled gracefully.""" + self.mock_client.register_resource.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "AlreadyExistsException", "Message": "Already exists"}}, + "RegisterResource", + ) + + result = self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix") + + assert result is True + + def test_other_exceptions_are_propagated(self): + """Test non-AlreadyExistsException errors are propagated.""" + self.mock_client.register_resource.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}}, + "RegisterResource", + ) + + with pytest.raises(botocore.exceptions.ClientError) as exc_info: + self.fg._register_s3_with_lake_formation("s3://test-bucket/prefix") + + assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException" + + def test_uses_service_linked_role(self): + """Test UseServiceLinkedRole is set to True.""" + self.mock_client.register_resource.return_value = {} + + self.fg._register_s3_with_lake_formation("s3://bucket/path") + + call_args = self.mock_client.register_resource.call_args + assert call_args[1]["UseServiceLinkedRole"] is True + + def test_uses_custom_role_arn_when_service_linked_role_disabled(self): + """Test custom role ARN is used when use_service_linked_role is False.""" + self.mock_client.register_resource.return_value = {} + custom_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole" + + self.fg._register_s3_with_lake_formation( + "s3://bucket/path", + use_service_linked_role=False, + role_arn=custom_role, + ) + + call_args = self.mock_client.register_resource.call_args + assert call_args[1]["RoleArn"] == custom_role + assert "UseServiceLinkedRole" not in call_args[1] + + def test_raises_error_when_role_arn_missing_and_service_linked_role_disabled(self): + """Test ValueError when use_service_linked_role is False but role_arn not provided.""" + with pytest.raises(ValueError) as exc_info: + self.fg._register_s3_with_lake_formation( + "s3://bucket/path", use_service_linked_role=False + ) + + assert "role_arn must be provided when use_service_linked_role is False" in str( + exc_info.value + ) + + + +class TestRevokeIamAllowedPrincipal: + """Tests for _revoke_iam_allowed_principal method.""" + + def setup_method(self): + """Set up test fixtures.""" + self.fg = MagicMock(spec=FeatureGroup) + self.fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__( + self.fg + ) + self.mock_client = MagicMock() + self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client) + + def test_successful_revocation_returns_true(self): + """Test successful revocation returns True.""" + self.mock_client.revoke_permissions.return_value = {} + + result = self.fg._revoke_iam_allowed_principal("test_database", "test_table") + + assert result is True + self.mock_client.revoke_permissions.assert_called_once() + + def test_revoke_permissions_call_structure(self): + """Test that revoke_permissions is called with correct parameters.""" + self.mock_client.revoke_permissions.return_value = {} + database_name = "my_database" + table_name = "my_table" + + self.fg._revoke_iam_allowed_principal(database_name, table_name) + + call_args = self.mock_client.revoke_permissions.call_args + assert call_args[1]["Principal"] == { + "DataLakePrincipalIdentifier": "IAM_ALLOWED_PRINCIPALS" + } + assert call_args[1]["Permissions"] == ["ALL"] + assert call_args[1]["Resource"] == { + "Table": { + "DatabaseName": database_name, + "Name": table_name, + } + } + + def test_invalid_input_exception_returns_true(self): + """Test InvalidInputException is handled gracefully (permissions may not exist).""" + self.mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "InvalidInputException", "Message": "Permissions not found"}}, + "RevokePermissions", + ) + + result = self.fg._revoke_iam_allowed_principal("test_database", "test_table") + + assert result is True + + def test_other_exceptions_are_propagated(self): + """Test non-InvalidInputException errors are propagated.""" + self.mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}}, + "RevokePermissions", + ) + + with pytest.raises(botocore.exceptions.ClientError) as exc_info: + self.fg._revoke_iam_allowed_principal("test_database", "test_table") + + assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException" + + def test_passes_session_and_region_to_client(self): + """Test session and region are passed to get_lake_formation_client.""" + self.mock_client.revoke_permissions.return_value = {} + mock_session = MagicMock() + + self.fg._revoke_iam_allowed_principal( + "test_database", "test_table", session=mock_session, region="us-west-2" + ) + + self.fg._get_lake_formation_client.assert_called_with(mock_session, "us-west-2") + + + +class TestGrantLakeFormationPermissions: + """Tests for _grant_lake_formation_permissions method.""" + + def setup_method(self): + """Set up test fixtures.""" + self.fg = MagicMock(spec=FeatureGroup) + self.fg._grant_lake_formation_permissions = ( + FeatureGroup._grant_lake_formation_permissions.__get__(self.fg) + ) + self.mock_client = MagicMock() + self.fg._get_lake_formation_client = MagicMock(return_value=self.mock_client) + + def test_successful_grant_returns_true(self): + """Test successful permission grant returns True.""" + self.mock_client.grant_permissions.return_value = {} + + result = self.fg._grant_lake_formation_permissions( + "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table" + ) + + assert result is True + self.mock_client.grant_permissions.assert_called_once() + + def test_grant_permissions_call_structure(self): + """Test that grant_permissions is called with correct parameters.""" + self.mock_client.grant_permissions.return_value = {} + role_arn = "arn:aws:iam::123456789012:role/MyExecutionRole" + + self.fg._grant_lake_formation_permissions(role_arn, "my_database", "my_table") + + call_args = self.mock_client.grant_permissions.call_args + assert call_args[1]["Principal"] == {"DataLakePrincipalIdentifier": role_arn} + assert call_args[1]["Resource"] == { + "Table": { + "DatabaseName": "my_database", + "Name": "my_table", + } + } + assert call_args[1]["Permissions"] == ["SELECT", "INSERT", "DELETE", "DESCRIBE", "ALTER"] + assert call_args[1]["PermissionsWithGrantOption"] == [] + + def test_invalid_input_exception_returns_true(self): + """Test InvalidInputException is handled gracefully (permissions may exist).""" + self.mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "InvalidInputException", "Message": "Permissions already exist"}}, + "GrantPermissions", + ) + + result = self.fg._grant_lake_formation_permissions( + "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table" + ) + + assert result is True + + def test_other_exceptions_are_propagated(self): + """Test non-InvalidInputException errors are propagated.""" + self.mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "AccessDeniedException", "Message": "Access denied"}}, + "GrantPermissions", + ) + + with pytest.raises(botocore.exceptions.ClientError) as exc_info: + self.fg._grant_lake_formation_permissions( + "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table" + ) + + assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException" + + def test_passes_session_and_region_to_client(self): + """Test session and region are passed to get_lake_formation_client.""" + self.mock_client.grant_permissions.return_value = {} + mock_session = MagicMock() + + self.fg._grant_lake_formation_permissions( + "arn:aws:iam::123456789012:role/TestRole", + "test_database", + "test_table", + session=mock_session, + region="us-west-2", + ) + + self.fg._get_lake_formation_client.assert_called_with(mock_session, "us-west-2") + + + +class TestEnableLakeFormationValidation: + """Tests for enable_lake_formation validation logic.""" + + @patch.object(FeatureGroup, "refresh") + def test_raises_error_when_no_offline_store(self, mock_refresh): + """Test that enable_lake_formation raises ValueError when no offline store is configured.""" + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = None + fg.feature_group_status = "Created" + + with pytest.raises(ValueError, match="does not have an offline store configured"): + fg.enable_lake_formation() + + # Verify refresh was called + mock_refresh.assert_called_once() + + @patch.object(FeatureGroup, "refresh") + def test_raises_error_when_no_role_arn(self, mock_refresh): + """Test that enable_lake_formation raises ValueError when no role_arn is configured.""" + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = None + fg.feature_group_status = "Created" + + with pytest.raises(ValueError, match="does not have a role_arn configured"): + fg.enable_lake_formation() + + # Verify refresh was called + mock_refresh.assert_called_once() + + @patch.object(FeatureGroup, "refresh") + def test_raises_error_when_invalid_status(self, mock_refresh): + """Test enable_lake_formation raises ValueError when Feature Group not in Created status.""" + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/TestRole" + fg.feature_group_status = "Creating" + + with pytest.raises(ValueError, match="must be in 'Created' status"): + fg.enable_lake_formation() + + # Verify refresh was called + mock_refresh.assert_called_once() + + @patch.object(FeatureGroup, "wait_for_status") + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + def test_wait_for_active_calls_wait_for_status( + self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait + ): + """Test that wait_for_active=True calls wait_for_status with 'Created' target.""" + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/TestRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call with wait_for_active=True + fg.enable_lake_formation(wait_for_active=True) + + # Verify wait_for_status was called with "Created" + mock_wait.assert_called_once_with(target_status="Created") + # Verify refresh was called after wait + mock_refresh.assert_called_once() + + @patch.object(FeatureGroup, "wait_for_status") + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + def test_wait_for_active_false_does_not_call_wait( + self, mock_revoke, mock_grant, mock_register, mock_refresh, mock_wait + ): + """Test that wait_for_active=False does not call wait_for_status.""" + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/TestRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call with wait_for_active=False (default) + fg.enable_lake_formation(wait_for_active=False) + + # Verify wait_for_status was NOT called + mock_wait.assert_not_called() + # Verify refresh was still called + mock_refresh.assert_called_once() + + + @pytest.mark.parametrize( + "feature_group_name,role_arn,s3_uri,database_name,table_name", + [ + ("test-fg", "TestRole", "path1", "db1", "table1"), + ("my_feature_group", "ExecutionRole", "data/features", "feature_db", "feature_table"), + ("fg123", "MyRole123", "ml/features/v1", "analytics", "features_v1"), + ("simple", "SimpleRole", "simple-path", "simple_db", "simple_table"), + ( + "complex-name", + "ComplexExecutionRole", + "complex/path/structure", + "complex_database", + "complex_table_name", + ), + ( + "underscore_name", + "Underscore_Role", + "underscore_path", + "underscore_db", + "underscore_table", + ), + ("mixed-123", "Mixed123Role", "mixed/path/123", "mixed_db_123", "mixed_table_123"), + ("x", "XRole", "x", "x", "x"), + ( + "very-long-name", + "VeryLongRoleName", + "very/long/path/structure", + "very_long_database_name", + "very_long_table_name", + ), + ], + ) + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + def test_fail_fast_phase_execution( + self, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + feature_group_name, + role_arn, + s3_uri, + database_name, + table_name, + ): + """ + Test fail-fast behavior for Lake Formation phases. + + If Phase 1 (S3 registration) fails, Phase 2 and 3 should not execute. + If Phase 2 fails, Phase 3 should not execute. + RuntimeError should indicate which phase failed. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name=feature_group_name) + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri=f"s3://test-bucket/{s3_uri}", + resolved_output_s3_uri=f"s3://test-bucket/resolved-{s3_uri}", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database=database_name, table_name=table_name + ), + ) + fg.role_arn = f"arn:aws:iam::123456789012:role/{role_arn}" + fg.feature_group_status = "Created" + + # Test Phase 1 failure - subsequent phases should not be called + mock_register.side_effect = Exception("Phase 1 failed") + mock_grant.return_value = True + mock_revoke.return_value = True + + with pytest.raises( + RuntimeError, match="Failed to register S3 location with Lake Formation" + ): + fg.enable_lake_formation() + + # Verify Phase 1 was called but Phase 2 and 3 were not + mock_register.assert_called_once() + mock_grant.assert_not_called() + mock_revoke.assert_not_called() + + # Reset mocks for Phase 2 failure test + mock_register.reset_mock() + mock_grant.reset_mock() + mock_revoke.reset_mock() + + # Test Phase 2 failure - Phase 3 should not be called + mock_register.side_effect = None + mock_register.return_value = True + mock_grant.side_effect = Exception("Phase 2 failed") + mock_revoke.return_value = True + + with pytest.raises(RuntimeError, match="Failed to grant Lake Formation permissions"): + fg.enable_lake_formation() + + # Verify Phase 1 and 2 were called but Phase 3 was not + mock_register.assert_called_once() + mock_grant.assert_called_once() + mock_revoke.assert_not_called() + + # Reset mocks for Phase 3 failure test + mock_register.reset_mock() + mock_grant.reset_mock() + mock_revoke.reset_mock() + + # Test Phase 3 failure - all phases should be called + mock_register.side_effect = None + mock_register.return_value = True + mock_grant.side_effect = None + mock_grant.return_value = True + mock_revoke.side_effect = Exception("Phase 3 failed") + + with pytest.raises(RuntimeError, match="Failed to revoke IAMAllowedPrincipal permissions"): + fg.enable_lake_formation() + + # Verify all phases were called + mock_register.assert_called_once() + mock_grant.assert_called_once() + mock_revoke.assert_called_once() + + + +class TestUnhandledExceptionPropagation: + """Tests for proper propagation of unhandled boto3 exceptions.""" + + def test_register_s3_propagates_unhandled_exceptions(self): + """ + Non-AlreadyExists Errors Propagate from S3 Registration + + For any error from Lake Formation's register_resource API that is not + AlreadyExistsException, the error should be propagated to the caller unchanged. + + """ + fg = MagicMock(spec=FeatureGroup) + fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn + fg._register_s3_with_lake_formation = FeatureGroup._register_s3_with_lake_formation.__get__( + fg + ) + mock_client = MagicMock() + fg._get_lake_formation_client = MagicMock(return_value=mock_client) + + # Configure mock to raise an unhandled error + mock_client.register_resource.side_effect = botocore.exceptions.ClientError( + { + "Error": { + "Code": "AccessDeniedException", + "Message": "User does not have permission", + } + }, + "RegisterResource", + ) + + # Verify the exception is propagated unchanged + with pytest.raises(botocore.exceptions.ClientError) as exc_info: + fg._register_s3_with_lake_formation("s3://test-bucket/path") + + # Verify error details are preserved + assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException" + assert exc_info.value.response["Error"]["Message"] == "User does not have permission" + assert exc_info.value.operation_name == "RegisterResource" + + def test_revoke_iam_principal_propagates_unhandled_exceptions(self): + """ + Non-InvalidInput Errors Propagate from IAM Principal Revocation + + For any error from Lake Formation's revoke_permissions API that is not + InvalidInputException, the error should be propagated to the caller unchanged. + + """ + fg = MagicMock(spec=FeatureGroup) + fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(fg) + mock_client = MagicMock() + fg._get_lake_formation_client = MagicMock(return_value=mock_client) + + # Configure mock to raise an unhandled error + mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError( + { + "Error": { + "Code": "AccessDeniedException", + "Message": "User does not have permission", + } + }, + "RevokePermissions", + ) + + # Verify the exception is propagated unchanged + with pytest.raises(botocore.exceptions.ClientError) as exc_info: + fg._revoke_iam_allowed_principal("test_database", "test_table") + + # Verify error details are preserved + assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException" + assert exc_info.value.response["Error"]["Message"] == "User does not have permission" + assert exc_info.value.operation_name == "RevokePermissions" + + def test_grant_permissions_propagates_unhandled_exceptions(self): + """ + Non-InvalidInput Errors Propagate from Permission Grant + + For any error from Lake Formation's grant_permissions API that is not + InvalidInputException, the error should be propagated to the caller unchanged. + + """ + fg = MagicMock(spec=FeatureGroup) + fg._grant_lake_formation_permissions = ( + FeatureGroup._grant_lake_formation_permissions.__get__(fg) + ) + mock_client = MagicMock() + fg._get_lake_formation_client = MagicMock(return_value=mock_client) + + # Configure mock to raise an unhandled error + mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError( + { + "Error": { + "Code": "AccessDeniedException", + "Message": "User does not have permission", + } + }, + "GrantPermissions", + ) + + # Verify the exception is propagated unchanged + with pytest.raises(botocore.exceptions.ClientError) as exc_info: + fg._grant_lake_formation_permissions( + "arn:aws:iam::123456789012:role/TestRole", "test_database", "test_table" + ) + + # Verify error details are preserved + assert exc_info.value.response["Error"]["Code"] == "AccessDeniedException" + assert exc_info.value.response["Error"]["Message"] == "User does not have permission" + assert exc_info.value.operation_name == "GrantPermissions" + + def test_handled_exceptions_do_not_propagate(self): + """ + Verify that specifically handled exceptions (AlreadyExistsException, InvalidInputException) + do NOT propagate but return True instead, while all other exceptions are propagated. + """ + fg = MagicMock(spec=FeatureGroup) + fg._s3_uri_to_arn = FeatureGroup._s3_uri_to_arn + fg._register_s3_with_lake_formation = FeatureGroup._register_s3_with_lake_formation.__get__( + fg + ) + fg._revoke_iam_allowed_principal = FeatureGroup._revoke_iam_allowed_principal.__get__(fg) + fg._grant_lake_formation_permissions = ( + FeatureGroup._grant_lake_formation_permissions.__get__(fg) + ) + mock_client = MagicMock() + fg._get_lake_formation_client = MagicMock(return_value=mock_client) + + # Test AlreadyExistsException is handled (not propagated) + mock_client.register_resource.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "AlreadyExistsException", "Message": "Already exists"}}, + "RegisterResource", + ) + result = fg._register_s3_with_lake_formation("s3://test-bucket/path") + assert result is True # Should return True, not raise + + # Test InvalidInputException is handled for revoke (not propagated) + mock_client.revoke_permissions.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "InvalidInputException", "Message": "Invalid input"}}, + "RevokePermissions", + ) + result = fg._revoke_iam_allowed_principal("db", "table") + assert result is True # Should return True, not raise + + # Test InvalidInputException is handled for grant (not propagated) + mock_client.grant_permissions.side_effect = botocore.exceptions.ClientError( + {"Error": {"Code": "InvalidInputException", "Message": "Invalid input"}}, + "GrantPermissions", + ) + result = fg._grant_lake_formation_permissions( + "arn:aws:iam::123456789012:role/TestRole", "db", "table" + ) + assert result is True # Should return True, not raise + + + +class TestCreateWithLakeFormation: + """Tests for create() method with Lake Formation integration.""" + + @pytest.mark.parametrize( + "feature_group_name,record_id_feature,event_time_feature", + [ + ("test-fg", "record_id", "event_time"), + ("my_feature_group", "id", "timestamp"), + ("fg123", "identifier", "time"), + ("simple", "rec_id", "evt_time"), + ("complex-name", "record_identifier", "event_timestamp"), + ("underscore_name", "record_id_field", "event_time_field"), + ("mixed-123", "id_123", "time_123"), + ("x", "x_id", "x_time"), + ("very-long-name", "very_long_record_id", "very_long_event_time"), + ], + ) + @patch("sagemaker.core.resources.Base.get_sagemaker_client") + @patch.object(FeatureGroup, "get") + @patch.object(FeatureGroup, "wait_for_status") + @patch.object(FeatureGroup, "enable_lake_formation") + def test_no_lake_formation_operations_when_disabled( + self, + mock_enable_lf, + mock_wait, + mock_get, + mock_get_client, + feature_group_name, + record_id_feature, + event_time_feature, + ): + """ + No Lake Formation Operations When Disabled + + For any call to FeatureGroup.create() where lake_formation_config is None or has enabled=False, + no Lake Formation client methods should be invoked. + + """ + from sagemaker.core.shapes import FeatureDefinition + + # Mock the SageMaker client + mock_client = MagicMock() + mock_client.create_feature_group.return_value = { + "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test" + } + mock_get_client.return_value = mock_client + + # Mock the get method to return a feature group + mock_fg = MagicMock(spec=FeatureGroup) + mock_fg.feature_group_name = feature_group_name + mock_get.return_value = mock_fg + + # Create feature definitions + feature_definitions = [ + FeatureDefinition(feature_name=record_id_feature, feature_type="String"), + FeatureDefinition(feature_name=event_time_feature, feature_type="String"), + ] + + # Test 1: lake_formation_config with enabled=False (explicit) + lf_config = LakeFormationConfig() + lf_config.enabled = False + result = FeatureGroup.create( + feature_group_name=feature_group_name, + record_identifier_feature_name=record_id_feature, + event_time_feature_name=event_time_feature, + feature_definitions=feature_definitions, + lake_formation_config=lf_config, + ) + + # Verify enable_lake_formation was NOT called + mock_enable_lf.assert_not_called() + # Verify wait_for_status was NOT called + mock_wait.assert_not_called() + # Verify the feature group was returned + assert result == mock_fg + + # Reset mocks for next test + mock_enable_lf.reset_mock() + mock_wait.reset_mock() + mock_get.reset_mock() + mock_get.return_value = mock_fg + + # Test 2: lake_formation_config not specified (defaults to None) + result = FeatureGroup.create( + feature_group_name=feature_group_name, + record_identifier_feature_name=record_id_feature, + event_time_feature_name=event_time_feature, + feature_definitions=feature_definitions, + # lake_formation_config not specified, should default to None + ) + + # Verify enable_lake_formation was NOT called + mock_enable_lf.assert_not_called() + # Verify wait_for_status was NOT called + mock_wait.assert_not_called() + # Verify the feature group was returned + assert result == mock_fg + + @pytest.mark.parametrize( + "feature_group_name,record_id_feature,event_time_feature,role_arn,s3_uri,database,table", + [ + ("test-fg", "record_id", "event_time", "TestRole", "path1", "db1", "table1"), + ( + "my_feature_group", + "id", + "timestamp", + "ExecutionRole", + "data/features", + "feature_db", + "feature_table", + ), + ( + "fg123", + "identifier", + "time", + "MyRole123", + "ml/features/v1", + "analytics", + "features_v1", + ), + ], + ) + @patch("sagemaker.core.resources.Base.get_sagemaker_client") + @patch.object(FeatureGroup, "get") + @patch.object(FeatureGroup, "wait_for_status") + @patch.object(FeatureGroup, "enable_lake_formation") + def test_enable_lake_formation_called_when_enabled( + self, + mock_enable_lf, + mock_wait, + mock_get, + mock_get_client, + feature_group_name, + record_id_feature, + event_time_feature, + role_arn, + s3_uri, + database, + table, + ): + """ + Test that enable_lake_formation is called when lake_formation_config has enabled=True. + + This verifies the integration between create() and enable_lake_formation(). + """ + from sagemaker.core.shapes import ( + FeatureDefinition, + OfflineStoreConfig, + S3StorageConfig, + DataCatalogConfig, + ) + + # Mock the SageMaker client + mock_client = MagicMock() + mock_client.create_feature_group.return_value = { + "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test" + } + mock_get_client.return_value = mock_client + + # Mock the get method to return a feature group + mock_fg = MagicMock(spec=FeatureGroup) + mock_fg.feature_group_name = feature_group_name + mock_fg.wait_for_status = mock_wait + mock_fg.enable_lake_formation = mock_enable_lf + mock_get.return_value = mock_fg + + # Create feature definitions + feature_definitions = [ + FeatureDefinition(feature_name=record_id_feature, feature_type="String"), + FeatureDefinition(feature_name=event_time_feature, feature_type="String"), + ] + + # Create offline store config + offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database=database, table_name=table + ), + ) + + # Create LakeFormationConfig with enabled=True + lf_config = LakeFormationConfig() + lf_config.enabled = True + + # Create with lake_formation_config enabled=True + result = FeatureGroup.create( + feature_group_name=feature_group_name, + record_identifier_feature_name=record_id_feature, + event_time_feature_name=event_time_feature, + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + role_arn=f"arn:aws:iam::123456789012:role/{role_arn}", + lake_formation_config=lf_config, + ) + + # Verify wait_for_status was called with "Created" + mock_wait.assert_called_once_with(target_status="Created") + # Verify enable_lake_formation was called with default use_service_linked_role=True + mock_enable_lf.assert_called_once_with( + session=None, + region=None, + use_service_linked_role=True, + registration_role_arn=None, + show_s3_policy=False, + disable_hybrid_access_mode=True, + ) + # Verify the feature group was returned + assert result == mock_fg + + @pytest.mark.parametrize( + "feature_group_name,record_id_feature,event_time_feature", + [ + ("test-fg", "record_id", "event_time"), + ("my_feature_group", "id", "timestamp"), + ("fg123", "identifier", "time"), + ], + ) + @patch("sagemaker.core.resources.Base.get_sagemaker_client") + def test_validation_error_when_lake_formation_enabled_without_offline_store( + self, mock_get_client, feature_group_name, record_id_feature, event_time_feature + ): + """Test create() raises ValueError when lake_formation_config enabled=True without offline_store.""" + from sagemaker.core.shapes import FeatureDefinition + + # Mock the SageMaker client + mock_client = MagicMock() + mock_get_client.return_value = mock_client + + # Create feature definitions + feature_definitions = [ + FeatureDefinition(feature_name=record_id_feature, feature_type="String"), + FeatureDefinition(feature_name=event_time_feature, feature_type="String"), + ] + + # Create LakeFormationConfig with enabled=True + lf_config = LakeFormationConfig() + lf_config.enabled = True + + # Test with lake_formation_config enabled=True but no offline_store_config + with pytest.raises( + ValueError, + match="lake_formation_config with enabled=True requires offline_store_config to be configured", + ): + FeatureGroup.create( + feature_group_name=feature_group_name, + record_identifier_feature_name=record_id_feature, + event_time_feature_name=event_time_feature, + feature_definitions=feature_definitions, + lake_formation_config=lf_config, + # offline_store_config not provided + ) + + @pytest.mark.parametrize( + "feature_group_name,record_id_feature,event_time_feature,s3_uri,database,table", + [ + ("test-fg", "record_id", "event_time", "path1", "db1", "table1"), + ("my_feature_group", "id", "timestamp", "data/features", "feature_db", "feature_table"), + ("fg123", "identifier", "time", "ml/features/v1", "analytics", "features_v1"), + ], + ) + @patch("sagemaker.core.resources.Base.get_sagemaker_client") + def test_validation_error_when_lake_formation_enabled_without_role_arn( + self, + mock_get_client, + feature_group_name, + record_id_feature, + event_time_feature, + s3_uri, + database, + table, + ): + """Test create() raises ValueError when lake_formation_config enabled=True without role_arn.""" + from sagemaker.core.shapes import ( + FeatureDefinition, + OfflineStoreConfig, + S3StorageConfig, + DataCatalogConfig, + ) + + # Mock the SageMaker client + mock_client = MagicMock() + mock_get_client.return_value = mock_client + + # Create feature definitions + feature_definitions = [ + FeatureDefinition(feature_name=record_id_feature, feature_type="String"), + FeatureDefinition(feature_name=event_time_feature, feature_type="String"), + ] + + # Create offline store config + offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database=database, table_name=table + ), + ) + + # Create LakeFormationConfig with enabled=True + lf_config = LakeFormationConfig() + lf_config.enabled = True + + # Test with lake_formation_config enabled=True but no role_arn + with pytest.raises( + ValueError, match="lake_formation_config with enabled=True requires role_arn to be specified" + ): + FeatureGroup.create( + feature_group_name=feature_group_name, + record_identifier_feature_name=record_id_feature, + event_time_feature_name=event_time_feature, + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + lake_formation_config=lf_config, + # role_arn not provided + ) + + + @pytest.mark.parametrize( + "feature_group_name,record_id_feature,event_time_feature,role_arn,s3_uri,database,table,use_slr", + [ + ("test-fg", "record_id", "event_time", "TestRole", "path1", "db1", "table1", True), + ("my_feature_group", "id", "timestamp", "ExecutionRole", "data/features", "feature_db", "feature_table", False), + ("fg123", "identifier", "time", "MyRole123", "ml/features/v1", "analytics", "features_v1", True), + ], + ) + @patch("sagemaker.core.resources.Base.get_sagemaker_client") + @patch.object(FeatureGroup, "get") + @patch.object(FeatureGroup, "wait_for_status") + @patch.object(FeatureGroup, "enable_lake_formation") + def test_use_service_linked_role_extraction_from_config( + self, + mock_enable_lf, + mock_wait, + mock_get, + mock_get_client, + feature_group_name, + record_id_feature, + event_time_feature, + role_arn, + s3_uri, + database, + table, + use_slr, + ): + """ + Test that use_service_linked_role is correctly extracted from lake_formation_config. + + Verifies: + - use_service_linked_role defaults to True when not specified + - use_service_linked_role is passed correctly to enable_lake_formation() + """ + from sagemaker.core.shapes import ( + FeatureDefinition, + OfflineStoreConfig, + S3StorageConfig, + DataCatalogConfig, + ) + + # Mock the SageMaker client + mock_client = MagicMock() + mock_client.create_feature_group.return_value = { + "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test" + } + mock_get_client.return_value = mock_client + + # Mock the get method to return a feature group + mock_fg = MagicMock(spec=FeatureGroup) + mock_fg.feature_group_name = feature_group_name + mock_fg.wait_for_status = mock_wait + mock_fg.enable_lake_formation = mock_enable_lf + mock_get.return_value = mock_fg + + # Create feature definitions + feature_definitions = [ + FeatureDefinition(feature_name=record_id_feature, feature_type="String"), + FeatureDefinition(feature_name=event_time_feature, feature_type="String"), + ] + + # Create offline store config + offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig(s3_uri=f"s3://test-bucket/{s3_uri}"), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database=database, table_name=table + ), + ) + + # Build LakeFormationConfig with use_service_linked_role + lf_config = LakeFormationConfig() + lf_config.enabled = True + lf_config.use_service_linked_role = use_slr + # When use_service_linked_role is False, registration_role_arn is required + expected_registration_role = None + if not use_slr: + lf_config.registration_role_arn = "arn:aws:iam::123456789012:role/LFRegistrationRole" + expected_registration_role = "arn:aws:iam::123456789012:role/LFRegistrationRole" + + # Create with lake_formation_config + result = FeatureGroup.create( + feature_group_name=feature_group_name, + record_identifier_feature_name=record_id_feature, + event_time_feature_name=event_time_feature, + feature_definitions=feature_definitions, + offline_store_config=offline_store_config, + role_arn=f"arn:aws:iam::123456789012:role/{role_arn}", + lake_formation_config=lf_config, + ) + + # Verify enable_lake_formation was called with correct use_service_linked_role value + mock_enable_lf.assert_called_once_with( + session=None, + region=None, + use_service_linked_role=use_slr, + registration_role_arn=expected_registration_role, + show_s3_policy=False, + disable_hybrid_access_mode=True, + ) + # Verify the feature group was returned + assert result == mock_fg + + +class TestDisableHybridAccessMode: + """Tests for disable_hybrid_access_mode parameter in enable_lake_formation.""" + + def setup_method(self): + """Set up test fixtures.""" + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + self.fg = FeatureGroup(feature_group_name="test-fg") + self.fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + self.fg.role_arn = "arn:aws:iam::123456789012:role/TestRole" + self.fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + self.fg.feature_group_status = "Created" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + def test_revoke_called_when_disable_hybrid_access_mode_true( + self, mock_revoke, mock_grant, mock_register, mock_refresh + ): + """Test that IAMAllowedPrincipal is revoked when disable_hybrid_access_mode=True (default).""" + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + result = self.fg.enable_lake_formation(disable_hybrid_access_mode=True) + + mock_revoke.assert_called_once() + assert result["iam_principal_revoked"] is True + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + def test_revoke_skipped_when_disable_hybrid_access_mode_false( + self, mock_revoke, mock_grant, mock_register, mock_refresh + ): + """Test that IAMAllowedPrincipal revocation is skipped when disable_hybrid_access_mode=False.""" + mock_register.return_value = True + mock_grant.return_value = True + + result = self.fg.enable_lake_formation(disable_hybrid_access_mode=False) + + mock_revoke.assert_not_called() + assert result["iam_principal_revoked"] is None + assert result["s3_registration"] is True + assert result["permissions_granted"] is True + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + def test_default_disable_hybrid_access_mode_is_true( + self, mock_revoke, mock_grant, mock_register, mock_refresh + ): + """Test that disable_hybrid_access_mode defaults to True (revoke is called by default).""" + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call without specifying disable_hybrid_access_mode + result = self.fg.enable_lake_formation() + + mock_revoke.assert_called_once() + assert result["iam_principal_revoked"] is True + + +class TestCreateWithLakeFormationDisableHybridAccessMode: + """Tests for disable_hybrid_access_mode passed through create() via LakeFormationConfig.""" + + @patch("sagemaker.core.resources.Base.get_sagemaker_client") + @patch.object(FeatureGroup, "get") + @patch.object(FeatureGroup, "wait_for_status") + @patch.object(FeatureGroup, "enable_lake_formation") + def test_disable_hybrid_access_mode_false_passed_through_create( + self, mock_enable_lf, mock_wait, mock_get, mock_get_client + ): + """Test that disable_hybrid_access_mode=False is passed through create() to enable_lake_formation.""" + from sagemaker.core.shapes import FeatureDefinition, OfflineStoreConfig, S3StorageConfig + + mock_client = MagicMock() + mock_client.create_feature_group.return_value = { + "FeatureGroupArn": "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test" + } + mock_get_client.return_value = mock_client + + mock_fg = MagicMock(spec=FeatureGroup) + mock_fg.wait_for_status = mock_wait + mock_fg.enable_lake_formation = mock_enable_lf + mock_get.return_value = mock_fg + + feature_definitions = [ + FeatureDefinition(feature_name="record_id", feature_type="String"), + FeatureDefinition(feature_name="event_time", feature_type="String"), + ] + + lf_config = LakeFormationConfig() + lf_config.enabled = True + lf_config.disable_hybrid_access_mode = False + + FeatureGroup.create( + feature_group_name="test-fg", + record_identifier_feature_name="record_id", + event_time_feature_name="event_time", + feature_definitions=feature_definitions, + offline_store_config=OfflineStoreConfig( + s3_storage_config=S3StorageConfig(s3_uri="s3://bucket/path") + ), + role_arn="arn:aws:iam::123456789012:role/TestRole", + lake_formation_config=lf_config, + ) + + mock_enable_lf.assert_called_once_with( + session=None, + region=None, + use_service_linked_role=True, + registration_role_arn=None, + show_s3_policy=False, + disable_hybrid_access_mode=False, + ) + + +class TestLakeFormationConfigDefaults: + """Tests for LakeFormationConfig default values.""" + + def test_disable_hybrid_access_mode_defaults_to_true(self): + """Test that LakeFormationConfig.disable_hybrid_access_mode defaults to True.""" + config = LakeFormationConfig() + assert config.disable_hybrid_access_mode is True + + def test_disable_hybrid_access_mode_can_be_set_to_false(self): + """Test that LakeFormationConfig.disable_hybrid_access_mode can be set to False.""" + config = LakeFormationConfig() + config.disable_hybrid_access_mode = False + assert config.disable_hybrid_access_mode is False + + +class TestExtractAccountIdFromArn: + """Tests for _extract_account_id_from_arn static method.""" + + def test_extracts_account_id_from_sagemaker_arn(self): + """Test extracting account ID from a SageMaker Feature Group ARN.""" + arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-feature-group" + result = FeatureGroup._extract_account_id_from_arn(arn) + assert result == "123456789012" + + def test_raises_value_error_for_invalid_arn_too_few_parts(self): + """Test that ValueError is raised for ARN with fewer than 5 colon-separated parts.""" + invalid_arn = "arn:aws:sagemaker:us-west-2" # Only 4 parts + with pytest.raises(ValueError, match="Invalid ARN format"): + FeatureGroup._extract_account_id_from_arn(invalid_arn) + + def test_raises_value_error_for_empty_string(self): + """Test that ValueError is raised for empty string.""" + with pytest.raises(ValueError, match="Invalid ARN format"): + FeatureGroup._extract_account_id_from_arn("") + + def test_raises_value_error_for_non_arn_string(self): + """Test that ValueError is raised for non-ARN string.""" + with pytest.raises(ValueError, match="Invalid ARN format"): + FeatureGroup._extract_account_id_from_arn("not-an-arn") + + def test_raises_value_error_for_s3_uri(self): + """Test that ValueError is raised for S3 URI (not ARN).""" + with pytest.raises(ValueError, match="Invalid ARN format"): + FeatureGroup._extract_account_id_from_arn("s3://my-bucket/my-prefix") + + def test_handles_arn_with_resource_path(self): + """Test extracting account ID from ARN with complex resource path.""" + arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/my-fg/version/1" + result = FeatureGroup._extract_account_id_from_arn(arn) + assert result == "123456789012" + + +class TestGetLakeFormationServiceLinkedRoleArn: + """Tests for _get_lake_formation_service_linked_role_arn static method.""" + + def test_generates_correct_service_linked_role_arn(self): + """Test that the method generates the correct service-linked role ARN format.""" + account_id = "123456789012" + result = FeatureGroup._get_lake_formation_service_linked_role_arn(account_id) + expected = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" + assert result == expected + + def test_uses_region_for_partition(self): + """Test that region is used to determine partition.""" + account_id = "123456789012" + result = FeatureGroup._get_lake_formation_service_linked_role_arn(account_id, region="cn-north-1") + assert result.startswith("arn:aws-cn:iam::") + + + +class TestGenerateS3DenyPolicy: + """Tests for _generate_s3_deny_policy method.""" + + def setup_method(self): + """Set up test fixtures.""" + self.fg = MagicMock(spec=FeatureGroup) + self.fg._generate_s3_deny_policy = FeatureGroup._generate_s3_deny_policy.__get__(self.fg) + + def test_policy_includes_correct_bucket_arn_in_object_statement(self): + """Test that the policy includes correct bucket ARN and prefix in object actions statement.""" + bucket_name = "my-feature-store-bucket" + s3_prefix = "feature-store/data/my-feature-group" + lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole" + fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + + policy = self.fg._generate_s3_deny_policy( + bucket_name=bucket_name, + s3_prefix=s3_prefix, + lake_formation_role_arn=lf_role_arn, + feature_store_role_arn=fs_role_arn, + ) + + # Verify the object actions statement has correct Resource ARN + object_statement = policy["Statement"][0] + expected_resource = f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*" + assert object_statement["Resource"] == expected_resource + + def test_policy_includes_correct_bucket_arn_in_list_statement(self): + """Test that the policy includes correct bucket ARN in ListBucket statement.""" + bucket_name = "my-feature-store-bucket" + s3_prefix = "feature-store/data/my-feature-group" + lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole" + fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + + policy = self.fg._generate_s3_deny_policy( + bucket_name=bucket_name, + s3_prefix=s3_prefix, + lake_formation_role_arn=lf_role_arn, + feature_store_role_arn=fs_role_arn, + ) + + # Verify the ListBucket statement has correct Resource ARN (bucket only) + list_statement = policy["Statement"][1] + expected_resource = f"arn:aws:s3:::{bucket_name}" + assert list_statement["Resource"] == expected_resource + + def test_policy_includes_correct_prefix_condition_in_list_statement(self): + """Test that the policy includes correct prefix condition in ListBucket statement.""" + bucket_name = "my-feature-store-bucket" + s3_prefix = "feature-store/data/my-feature-group" + lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole" + fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + + policy = self.fg._generate_s3_deny_policy( + bucket_name=bucket_name, + s3_prefix=s3_prefix, + lake_formation_role_arn=lf_role_arn, + feature_store_role_arn=fs_role_arn, + ) + + # Verify the ListBucket statement has correct prefix condition + list_statement = policy["Statement"][1] + expected_prefix = f"{s3_prefix}/*" + assert list_statement["Condition"]["StringLike"]["s3:prefix"] == expected_prefix + + def test_policy_preserves_bucket_name_exactly(self): + """Test that bucket name is preserved exactly without modification.""" + # Test with various bucket name formats + test_cases = [ + "simple-bucket", + "bucket.with.dots", + "bucket-with-dashes-123", + "mybucket", + "a" * 63, # Max bucket name length + ] + + for bucket_name in test_cases: + policy = self.fg._generate_s3_deny_policy( + bucket_name=bucket_name, + s3_prefix="prefix", + lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole", + feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole", + ) + + # Verify bucket name is preserved in both statements + assert bucket_name in policy["Statement"][0]["Resource"] + assert bucket_name in policy["Statement"][1]["Resource"] + + def test_policy_preserves_prefix_exactly(self): + """Test that S3 prefix is preserved exactly without modification.""" + # Test with various prefix formats + test_cases = [ + "simple-prefix", + "path/to/data", + "feature-store/account-id/region/feature-group-name", + "deep/nested/path/structure/data", + "prefix_with_underscores", + "prefix-with-dashes", + ] + + for s3_prefix in test_cases: + policy = self.fg._generate_s3_deny_policy( + bucket_name="test-bucket", + s3_prefix=s3_prefix, + lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole", + feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole", + ) + + # Verify prefix is preserved in object statement Resource + assert f"{s3_prefix}/*" in policy["Statement"][0]["Resource"] + # Verify prefix is preserved in list statement Condition + assert policy["Statement"][1]["Condition"]["StringLike"]["s3:prefix"] == f"{s3_prefix}/*" + + def test_policy_has_correct_s3_arn_format(self): + """Test that the policy uses correct S3 ARN format (arn:aws:s3:::bucket/path).""" + bucket_name = "test-bucket" + s3_prefix = "test/prefix" + + policy = self.fg._generate_s3_deny_policy( + bucket_name=bucket_name, + s3_prefix=s3_prefix, + lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole", + feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole", + ) + + # Verify object statement Resource starts with correct ARN prefix + object_resource = policy["Statement"][0]["Resource"] + assert object_resource.startswith("arn:aws:s3:::") + assert object_resource == f"arn:aws:s3:::{bucket_name}/{s3_prefix}/*" + + # Verify list statement Resource is bucket-only ARN + list_resource = policy["Statement"][1]["Resource"] + assert list_resource.startswith("arn:aws:s3:::") + assert list_resource == f"arn:aws:s3:::{bucket_name}" + + def test_policy_structure_validation(self): + """Test that the policy has correct overall structure.""" + policy = self.fg._generate_s3_deny_policy( + bucket_name="test-bucket", + s3_prefix="test/prefix", + lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole", + feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole", + ) + + # Verify policy version + assert policy["Version"] == "2012-10-17" + + # Verify exactly two statements + assert len(policy["Statement"]) == 2 + + # Verify first statement structure (object actions) + object_statement = policy["Statement"][0] + assert object_statement["Sid"] == "DenyAllAccessToFeatureStorePrefixExceptAllowedPrincipals" + assert object_statement["Effect"] == "Deny" + assert object_statement["Principal"] == "*" + assert "Condition" in object_statement + assert "StringNotEquals" in object_statement["Condition"] + + # Verify second statement structure (list bucket) + list_statement = policy["Statement"][1] + assert list_statement["Sid"] == "DenyListOnPrefixExceptAllowedPrincipals" + assert list_statement["Effect"] == "Deny" + assert list_statement["Principal"] == "*" + assert "Condition" in list_statement + assert "StringLike" in list_statement["Condition"] + assert "StringNotEquals" in list_statement["Condition"] + + def test_policy_includes_both_principals_in_allowed_list(self): + """Test that both Lake Formation role and Feature Store role are in allowed principals.""" + lf_role_arn = "arn:aws:iam::123456789012:role/LakeFormationRole" + fs_role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + + policy = self.fg._generate_s3_deny_policy( + bucket_name="test-bucket", + s3_prefix="test/prefix", + lake_formation_role_arn=lf_role_arn, + feature_store_role_arn=fs_role_arn, + ) + + # Verify both principals in object statement + object_principals = policy["Statement"][0]["Condition"]["StringNotEquals"]["aws:PrincipalArn"] + assert lf_role_arn in object_principals + assert fs_role_arn in object_principals + assert len(object_principals) == 2 + + # Verify both principals in list statement + list_principals = policy["Statement"][1]["Condition"]["StringNotEquals"]["aws:PrincipalArn"] + assert lf_role_arn in list_principals + assert fs_role_arn in list_principals + assert len(list_principals) == 2 + + def test_policy_has_correct_actions_in_each_statement(self): + """Test that each statement has the correct S3 actions.""" + policy = self.fg._generate_s3_deny_policy( + bucket_name="test-bucket", + s3_prefix="test/prefix", + lake_formation_role_arn="arn:aws:iam::123456789012:role/LFRole", + feature_store_role_arn="arn:aws:iam::123456789012:role/FSRole", + ) + + # Verify object statement has correct actions + object_actions = policy["Statement"][0]["Action"] + assert "s3:GetObject" in object_actions + assert "s3:PutObject" in object_actions + assert "s3:DeleteObject" in object_actions + assert len(object_actions) == 3 + + # Verify list statement has correct action + list_action = policy["Statement"][1]["Action"] + assert list_action == "s3:ListBucket" + + + +class TestEnableLakeFormationServiceLinkedRoleInPolicy: + """Tests for service-linked role ARN usage in S3 deny policy generation.""" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch.object(FeatureGroup, "_generate_s3_deny_policy") + @patch("builtins.print") + def test_uses_service_linked_role_arn_when_use_service_linked_role_true( + self, + mock_print, + mock_generate_policy, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that enable_lake_formation uses the auto-generated service-linked role ARN + when use_service_linked_role=True. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []} + + # Call with use_service_linked_role=True (default) + fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True) + + # Verify _generate_s3_deny_policy was called with the service-linked role ARN + expected_slr_arn = "arn:aws:iam::123456789012:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" + mock_generate_policy.assert_called_once() + call_kwargs = mock_generate_policy.call_args[1] + assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn + assert call_kwargs["feature_store_role_arn"] == fg.role_arn + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch.object(FeatureGroup, "_generate_s3_deny_policy") + @patch("builtins.print") + def test_uses_service_linked_role_arn_by_default( + self, + mock_print, + mock_generate_policy, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that enable_lake_formation uses the service-linked role ARN by default + (when use_service_linked_role is not explicitly specified). + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::987654321098:role/MyFeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-east-1:987654321098:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []} + + # Call without specifying use_service_linked_role (should default to True) + fg.enable_lake_formation(show_s3_policy=True) + + # Verify _generate_s3_deny_policy was called with the service-linked role ARN + expected_slr_arn = "arn:aws:iam::987654321098:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" + mock_generate_policy.assert_called_once() + call_kwargs = mock_generate_policy.call_args[1] + assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch.object(FeatureGroup, "_generate_s3_deny_policy") + @patch("builtins.print") + def test_service_linked_role_arn_uses_correct_account_id( + self, + mock_print, + mock_generate_policy, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that the service-linked role ARN is generated with the correct account ID + extracted from the Feature Group ARN. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Use a specific account ID to verify it's extracted correctly + account_id = "111222333444" + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = f"arn:aws:iam::{account_id}:role/FeatureStoreRole" + fg.feature_group_arn = f"arn:aws:sagemaker:us-west-2:{account_id}:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []} + + # Call with use_service_linked_role=True + fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True) + + # Verify the service-linked role ARN contains the correct account ID + expected_slr_arn = f"arn:aws:iam::{account_id}:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess" + mock_generate_policy.assert_called_once() + call_kwargs = mock_generate_policy.call_args[1] + assert call_kwargs["lake_formation_role_arn"] == expected_slr_arn + assert account_id in call_kwargs["lake_formation_role_arn"] + + + +class TestRegistrationRoleArnUsedWhenServiceLinkedRoleFalse: + """Tests for verifying registration_role_arn is used when use_service_linked_role=False.""" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch.object(FeatureGroup, "_generate_s3_deny_policy") + @patch("builtins.print") + def test_uses_registration_role_arn_when_use_service_linked_role_false( + self, + mock_print, + mock_generate_policy, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that when use_service_linked_role=False, the registration_role_arn is used + in the S3 deny policy instead of the auto-generated service-linked role ARN. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []} + + # Custom registration role ARN + custom_registration_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole" + + # Call with use_service_linked_role=False and registration_role_arn + fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=custom_registration_role, + show_s3_policy=True, + ) + + # Verify _generate_s3_deny_policy was called with the custom registration role ARN + mock_generate_policy.assert_called_once() + call_kwargs = mock_generate_policy.call_args[1] + assert call_kwargs["lake_formation_role_arn"] == custom_registration_role + + # Verify it's NOT the service-linked role ARN + service_linked_role_pattern = "aws-service-role/lakeformation.amazonaws.com" + assert service_linked_role_pattern not in call_kwargs["lake_formation_role_arn"] + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch.object(FeatureGroup, "_generate_s3_deny_policy") + @patch("builtins.print") + def test_registration_role_arn_passed_to_s3_registration( + self, + mock_print, + mock_generate_policy, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that when use_service_linked_role=False, the registration_role_arn is also + passed to _register_s3_with_lake_formation. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []} + + # Custom registration role ARN + custom_registration_role = "arn:aws:iam::123456789012:role/CustomLakeFormationRole" + + # Call with use_service_linked_role=False and registration_role_arn + fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=custom_registration_role, + show_s3_policy=True, + ) + + # Verify _register_s3_with_lake_formation was called with the correct parameters + mock_register.assert_called_once() + call_args = mock_register.call_args + assert call_args[1]["use_service_linked_role"] == False + assert call_args[1]["role_arn"] == custom_registration_role + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch.object(FeatureGroup, "_generate_s3_deny_policy") + @patch("builtins.print") + def test_different_registration_role_arns_produce_different_policies( + self, + mock_print, + mock_generate_policy, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that different registration_role_arn values result in different + lake_formation_role_arn values in the generated policy. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + mock_generate_policy.return_value = {"Version": "2012-10-17", "Statement": []} + + # First call with one registration role + first_role = "arn:aws:iam::123456789012:role/FirstLakeFormationRole" + fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=first_role, + show_s3_policy=True, + ) + + first_call_kwargs = mock_generate_policy.call_args[1] + first_lf_role = first_call_kwargs["lake_formation_role_arn"] + + # Reset mocks + mock_generate_policy.reset_mock() + mock_register.reset_mock() + mock_grant.reset_mock() + mock_revoke.reset_mock() + + # Second call with different registration role + second_role = "arn:aws:iam::123456789012:role/SecondLakeFormationRole" + fg.enable_lake_formation( + use_service_linked_role=False, + registration_role_arn=second_role, + show_s3_policy=True, + ) + + second_call_kwargs = mock_generate_policy.call_args[1] + second_lf_role = second_call_kwargs["lake_formation_role_arn"] + + # Verify different roles were used + assert first_lf_role == first_role + assert second_lf_role == second_role + assert first_lf_role != second_lf_role + + + +class TestPolicyPrintedWithClearInstructions: + """Tests for verifying the S3 deny policy is printed with clear instructions.""" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch("builtins.print") + def test_policy_printed_with_header_and_instructions( + self, + mock_print, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that enable_lake_formation prints the S3 deny policy with clear + header and instructions for the user. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call enable_lake_formation with show_s3_policy=True + fg.enable_lake_formation(show_s3_policy=True) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify header is printed + assert "S3 Bucket Policy" in all_printed_text, "Header should mention 'S3 Bucket Policy'" + + # Verify instructions are printed + assert ( + "Lake Formation" in all_printed_text + or "deny policy" in all_printed_text + ), "Instructions should mention Lake Formation or deny policy" + + # Verify bucket name is printed + assert "test-bucket" in all_printed_text, "Bucket name should be printed" + + # Verify note about merging with existing policy is printed + assert ( + "Merge" in all_printed_text or "existing" in all_printed_text + ), "Note about merging with existing policy should be printed" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch("builtins.print") + def test_policy_json_is_printed( + self, + mock_print, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that the S3 deny policy JSON is printed to the console when show_s3_policy=True. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call enable_lake_formation with show_s3_policy=True + fg.enable_lake_formation(show_s3_policy=True) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify policy JSON structure elements are printed + assert "Version" in all_printed_text, "Policy JSON should contain 'Version'" + assert "Statement" in all_printed_text, "Policy JSON should contain 'Statement'" + assert "Effect" in all_printed_text, "Policy JSON should contain 'Effect'" + assert "Deny" in all_printed_text, "Policy JSON should contain 'Deny' effect" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch("builtins.print") + def test_policy_printed_only_after_successful_setup( + self, + mock_print, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that the S3 deny policy is only printed after all Lake Formation + phases complete successfully. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock Phase 1 failure + mock_register.side_effect = Exception("Phase 1 failed") + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call enable_lake_formation with show_s3_policy=True - should fail + with pytest.raises(RuntimeError): + fg.enable_lake_formation(show_s3_policy=True) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify policy was NOT printed when setup failed + assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when setup fails" + + # Reset mocks + mock_print.reset_mock() + mock_register.reset_mock() + mock_register.side_effect = None + mock_register.return_value = True + + # Mock Phase 2 failure + mock_grant.side_effect = Exception("Phase 2 failed") + + # Call enable_lake_formation with show_s3_policy=True - should fail + with pytest.raises(RuntimeError): + fg.enable_lake_formation(show_s3_policy=True) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify policy was NOT printed when setup fails at Phase 2 + assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when Phase 2 fails" + + # Reset mocks + mock_print.reset_mock() + mock_grant.reset_mock() + mock_grant.side_effect = None + mock_grant.return_value = True + + # Mock Phase 3 failure + mock_revoke.side_effect = Exception("Phase 3 failed") + + # Call enable_lake_formation with show_s3_policy=True - should fail + with pytest.raises(RuntimeError): + fg.enable_lake_formation(show_s3_policy=True) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify policy was NOT printed when setup fails at Phase 3 + assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when Phase 3 fails" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch("builtins.print") + def test_policy_includes_both_allowed_principals( + self, + mock_print, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that the printed policy includes both the Lake Formation role + and the Feature Store execution role as allowed principals. + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + feature_store_role = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.role_arn = feature_store_role + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call enable_lake_formation with service-linked role and show_s3_policy=True + fg.enable_lake_formation(use_service_linked_role=True, show_s3_policy=True) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify Feature Store role is in the printed output + assert feature_store_role in all_printed_text, "Feature Store role should be in printed policy" + + # Verify Lake Formation service-linked role pattern is in the printed output + assert "AWSServiceRoleForLakeFormationDataAccess" in all_printed_text, \ + "Lake Formation service-linked role should be in printed policy" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch("builtins.print") + def test_policy_not_printed_when_show_s3_policy_false( + self, + mock_print, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that the S3 deny policy is NOT printed when show_s3_policy=False (default). + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call enable_lake_formation with show_s3_policy=False (default) + fg.enable_lake_formation(show_s3_policy=False) + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify policy was NOT printed + assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed when show_s3_policy=False" + assert "Version" not in all_printed_text, "Policy JSON should not be printed when show_s3_policy=False" + + @patch.object(FeatureGroup, "refresh") + @patch.object(FeatureGroup, "_register_s3_with_lake_formation") + @patch.object(FeatureGroup, "_grant_lake_formation_permissions") + @patch.object(FeatureGroup, "_revoke_iam_allowed_principal") + @patch("builtins.print") + def test_policy_not_printed_by_default( + self, + mock_print, + mock_revoke, + mock_grant, + mock_register, + mock_refresh, + ): + """ + Test that the S3 deny policy is NOT printed by default (when show_s3_policy is not specified). + """ + from sagemaker.core.shapes import OfflineStoreConfig, S3StorageConfig, DataCatalogConfig + + # Set up Feature Group with required configuration + fg = FeatureGroup(feature_group_name="test-fg") + fg.offline_store_config = OfflineStoreConfig( + s3_storage_config=S3StorageConfig( + s3_uri="s3://test-bucket/path", + resolved_output_s3_uri="s3://test-bucket/resolved-path/data", + ), + data_catalog_config=DataCatalogConfig( + catalog="AwsDataCatalog", database="test_db", table_name="test_table" + ), + ) + fg.role_arn = "arn:aws:iam::123456789012:role/FeatureStoreRole" + fg.feature_group_arn = "arn:aws:sagemaker:us-west-2:123456789012:feature-group/test-fg" + fg.feature_group_status = "Created" + + # Mock successful Lake Formation operations + mock_register.return_value = True + mock_grant.return_value = True + mock_revoke.return_value = True + + # Call enable_lake_formation without specifying show_s3_policy (should default to False) + fg.enable_lake_formation() + + # Collect all print calls + print_calls = [str(call) for call in mock_print.call_args_list] + all_printed_text = " ".join(print_calls) + + # Verify policy was NOT printed + assert "S3 Bucket Policy" not in all_printed_text, "Policy should not be printed by default" + assert "Version" not in all_printed_text, "Policy JSON should not be printed by default" diff --git a/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb b/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb new file mode 100644 index 0000000000..59f7920998 --- /dev/null +++ b/v3-examples/ml-ops-examples/FS-lakeformation-cross-account.ipynb @@ -0,0 +1,580 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "4e7cc789-55ea-4460-a07e-a57ffe6ee4e6", + "metadata": {}, + "source": [ + "1. Create Feature Group in central account with Lakeformation enabled" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "id": "d8f0e80d-bc9b-4c5e-b545-32fff784b8b5", + "metadata": {}, + "source": [ + "# Cross Account Lakeformation governed Feature Group Demo\n", + "\n", + "This is a demo to showcase how cross account access would work with lakeformation(LF) governed Feature Group(FG)\n", + "\n", + "[simpler single account demo](./v3-feature-store-lake-formation.ipynb) \n", + "\n", + "The following scenario will be setup where you have a central account that owns the FG and then you have a producer account to ingest into the FG and another one reading from the FG\n", + "\n", + "![image.png](./imgs/fs-lf-cross-account1.png)" + ] + }, + { + "cell_type": "markdown", + "id": "f0c347d3-2736-4acf-8aff-bc6c9cc7a990", + "metadata": {}, + "source": [ + "## Helper Methods" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d30e0db4-122c-4da4-b33d-6ed3c3a40a3c", + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "import os\n", + "\n", + "boto3.DEFAULT_SESSION = None\n", + "def assume_role(role_arn, session_name=\"AssumedRoleSession\"):\n", + " \"\"\"\n", + " Assume an AWS IAM role and return temporary credentials.\n", + " \n", + " Args:\n", + " role_arn: The ARN of the role to assume\n", + " session_name: A name for the assumed role session\n", + " \n", + " Returns:\n", + " A boto3 session with the assumed role credentials\n", + " \"\"\"\n", + " sts_client = boto3.client('sts')\n", + " \n", + " response = sts_client.assume_role(\n", + " RoleArn=role_arn,\n", + " RoleSessionName=session_name\n", + " )\n", + " \n", + " credentials = response['Credentials']\n", + " \n", + " # Create a new session with the temporary credentials\n", + " session = boto3.Session(\n", + " aws_access_key_id=credentials['AccessKeyId'],\n", + " aws_secret_access_key=credentials['SecretAccessKey'],\n", + " aws_session_token=credentials['SessionToken']\n", + " )\n", + " \n", + " return session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "bf42a253-bf5e-49f3-96cc-744606cda4f4", + "metadata": {}, + "outputs": [], + "source": [ + "from sagemaker.core.helper.session_helper import Session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "afc7f261-e7fe-4abc-88c3-cd3b1aa61dd2", + "metadata": {}, + "outputs": [], + "source": [ + "central_account = \"account-1\"\n", + "producer_account = \"account-2\"\n", + "consumer_account = \"account-3\"\n", + "\n", + "acc_to_role_arn = {\n", + " central_account: f\"arn:aws:iam::{central_account}:role/admin\",\n", + " producer_account: f\"arn:aws:iam::{producer_account}:role/Admin\",\n", + " consumer_account: f\"arn:aws:iam::{consumer_account}:role/Admin\"\n", + "}\n", + "\n", + "central_acc_boto_session = assume_role(acc_to_role_arn[central_account])\n", + "central_acc_sagemaker_session = Session(boto_session=central_acc_boto_session)\n", + "\n", + "producer_acc_boto_session = assume_role(acc_to_role_arn[producer_account])\n", + "producer_acc_sagemaker_session = Session(boto_session=producer_acc_boto_session)\n", + "\n", + "consumer_acc_boto_session = assume_role(acc_to_role_arn[consumer_account])\n", + "consumer_acc_sagemaker_session = Session(boto_session=consumer_acc_boto_session)\n" + ] + }, + { + "cell_type": "markdown", + "id": "28a96af6-409a-4756-8cb7-60850342c955", + "metadata": {}, + "source": [ + "## 1. Create Feature Group in central account and enable Lakeformation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4f6a2639-2640-4a51-8fad-886b4d7226da", + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import boto3\n", + "from botocore.exceptions import ClientError\n", + "# Import the FeatureGroup with Lake Formation support\n", + "from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig\n", + "from sagemaker.core.shapes import (\n", + " FeatureDefinition,\n", + " FeatureValue,\n", + " OfflineStoreConfig,\n", + " OnlineStoreConfig,\n", + " S3StorageConfig,\n", + ")\n", + "from sagemaker.core.helper.session_helper import Session as SageMakerSession, get_execution_role\n", + "\n", + "feature_definitions = [\n", + " FeatureDefinition(feature_name=\"customer_id\", feature_type=\"String\"),\n", + " FeatureDefinition(feature_name=\"event_time\", feature_type=\"String\"),\n", + " FeatureDefinition(feature_name=\"age\", feature_type=\"Integral\"),\n", + " FeatureDefinition(feature_name=\"total_purchases\", feature_type=\"Integral\"),\n", + " FeatureDefinition(feature_name=\"avg_order_value\", feature_type=\"Fractional\"),\n", + "]\n", + "\n", + "# Offline store role (dedicated role for Feature Store S3 access)\n", + "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n", + "OFFLINE_STORE_ROLE_ARN = \"your-offline-store-role-arn\"\n", + "\n", + "S3_BUCKET = central_acc_sagemaker_session.default_bucket()\n", + "REGION = central_acc_boto_session.region_name\n", + "\n", + "\n", + "# Configure online and offline stores\n", + "FEATURE_GROUP_NAME='lakeformation-managed-fg-2'\n", + "\n", + "online_store_config = OnlineStoreConfig(enable_online_store=True)\n", + "\n", + "offline_store_config = OfflineStoreConfig(\n", + " s3_storage_config=S3StorageConfig(\n", + " s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n", + " )\n", + ")\n", + "\n", + "# Configure Lake Formation - enabled at creation\n", + "lake_formation_config = LakeFormationConfig(\n", + " enabled=True\n", + ")\n", + "\n", + "# create FG in central account and enable LF\n", + "feature_group = FeatureGroup.create(\n", + " feature_group_name=FEATURE_GROUP_NAME,\n", + " record_identifier_feature_name=\"customer_id\",\n", + " event_time_feature_name=\"event_time\",\n", + " feature_definitions=feature_definitions,\n", + " online_store_config=online_store_config,\n", + " offline_store_config=offline_store_config,\n", + " role_arn=OFFLINE_STORE_ROLE_ARN,\n", + " description=\"Feature Group with lakeformation enabled\",\n", + " lake_formation_config=lake_formation_config, # new parameter\n", + " session=central_acc_boto_session \n", + ")\n", + "\n", + "print(f\"\\nFeature Group created: {feature_group.feature_group_name}\")\n", + "# feature_group = FeatureGroup.get(FEATURE_GROUP_NAME)\n", + "central_acc_sagemaker_session.describe_feature_group(FEATURE_GROUP_NAME)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "956b3ed3-7ede-4486-af44-46845b683a09", + "metadata": {}, + "outputs": [], + "source": [ + "feature_group.refresh()\n", + "feature_group_arn = feature_group.feature_group_arn\n", + "data_catalog_config = feature_group.offline_store_config.data_catalog_config\n", + "database_name = str(data_catalog_config.database)\n", + "table_name = str(data_catalog_config.table_name)\n", + "catalog_id = str(data_catalog_config.catalog)\n", + "print(f\"Feature Group ARN: {feature_group_arn}\")\n", + "print(f\"Database: {database_name}\")\n", + "print(f\"Table: {table_name}\")\n", + "print(f\"Catalog: {catalog_id}\")" + ] + }, + { + "cell_type": "markdown", + "id": "4708e998-6ac4-454c-a3ab-3a1f4fd71bc4", + "metadata": {}, + "source": [ + "## 2. Share Feature Group with producer account" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ea63cc0-7418-440f-8784-9108ca244e6c", + "metadata": {}, + "outputs": [], + "source": [ + "ram_client = central_acc_boto_session.client(\"ram\")\n", + "response = ram_client.create_resource_share(\n", + " name='producer-account-fg-share',\n", + " resourceArns=[\n", + " feature_group_arn\n", + " ],\n", + " principals=[\n", + " str(producer_account)\n", + " ],\n", + " permissionArns=[\n", + " \"arn:aws:ram::aws:permission/AWSRAMPermissionSageMakerFeatureGroupReadWrite\"\n", + " ]\n", + ")\n", + "response" + ] + }, + { + "cell_type": "markdown", + "id": "18df5f35-8efe-4b02-bfbf-d4bcbb6cb9cd", + "metadata": {}, + "source": [ + "### Producer Accepts the RAM share" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2360602b-fdc4-45ea-958e-9dbec0efdd52", + "metadata": {}, + "outputs": [], + "source": [ + "# Producer account accepts the RAM invitation\n", + "ram_client_producer = producer_acc_boto_session.client('ram')\n", + "\n", + "response = ram_client_producer.get_resource_share_invitations()\n", + "pending = [\n", + " inv for inv in response['resourceShareInvitations']\n", + " if inv['status'] == 'PENDING' and inv['senderAccountId'] == str(central_account)\n", + "]\n", + "\n", + "for inv in pending:\n", + " ram_client_producer.accept_resource_share_invitation(\n", + " resourceShareInvitationArn=inv['resourceShareInvitationArn']\n", + " )\n", + " print(f\"Accepted: {inv['resourceShareInvitationArn']}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2b59161c-5016-41ac-b70f-b0375067cdbc", + "metadata": {}, + "outputs": [], + "source": [ + "# Test ingest from producer\n", + "\n", + "from datetime import datetime\n", + "\n", + "# Use the producer session to call PutRecord on the shared Feature Group\n", + "sm_runtime = producer_acc_boto_session.client('sagemaker-featurestore-runtime')\n", + "\n", + "sm_runtime.put_record(\n", + " FeatureGroupName=feature_group_arn,\n", + " Record=[\n", + " {'FeatureName': 'customer_id', 'ValueAsString': 'CUST-001'},\n", + " {'FeatureName': 'event_time', 'ValueAsString': datetime.utcnow().isoformat() + 'Z'},\n", + " {'FeatureName': 'age', 'ValueAsString': '35'},\n", + " {'FeatureName': 'total_purchases', 'ValueAsString': '12'},\n", + " {'FeatureName': 'avg_order_value', 'ValueAsString': '49.99'},\n", + " ]\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "486142f8-de45-4029-a08c-e0e1457cb3ea", + "metadata": {}, + "outputs": [], + "source": [ + "# Test getRecord\n", + "sm_runtime.get_record(\n", + " FeatureGroupName=feature_group_arn,\n", + " RecordIdentifierValueAsString='CUST-001'\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "5f531d4a-b668-42a8-a725-94a165ba76f8", + "metadata": {}, + "source": [ + "## 3. Share Glue Table with consumer account using LF" + ] + }, + { + "attachments": { + "d1f0c7d4-d102-42f3-a1fc-b26eeb94a2bf.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAABqAAAALOCAYAAADGG9JtAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAGoKADAAQAAAABAAACzgAAAADCWs0rAABAAElEQVR4AezdB5gUVdaA4TN5BoaccxIQSaKoGDCvAdOimNNizrprWuE3ryzmsIY1Z1xFUNewpnUVA4oIkkRAcs4ypIk9/znVU93VzfTEnp7ume8+T9s1XVW3br1VjV116p6b1HPA0GKhIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIBAlgeQo1UM1CCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCDgCBKA4ERBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIIIEAAinMAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAgqgIEoKLKSWUIIIAAAggggAACCCCAAAIIIIAAAggggAACCCCAAAIEoDgHEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEoipAACqqnFSGAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACCCBAAIpzAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBBBAIKoCBKCiykllCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAggggAACBKA4BxBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQAABBKIqQAAqqpxUhgACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgggQACKcwABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQQQQCCqAgSgospJZQgggAACCCCAAAIIIIAAAggggAACCCCAAAIIIIAAAgSgOAcQQAABBBBAAAEEEEAAAQQQQAABBBBAAAEEEEAAAQSiKkAAKqqcVIYA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br7+slhz9ZWzO2eed1m88NJrM3mq7l9af9014vhjDs868ubbA2P33/257neqlnqQhk/bbbt57N53h1h5pRVmqDWdXfPQI09ls6Leeuf9Ge4X7UIaBF1+4enJDLHuFV177Y134tCjTqix5QnTZfTuufXaaNNm2vKIaX37HnBkTJky679NtNKKyyV7Vl1Tsb/XAYceE88+/3JFu30gQIAAAQKlKmAGVKmOjHYRIECAAAECBAgQIFBdAQFUdeWUq7MCdyd/qN19hWXrbPur0/B0r6s+u+1XnaLzfZl09lM6a65Xzy2iZYsWM3h88umguLXffckMncdi9JixM9wvyoV0qcLTTzom+vTauqJL6fJ2Bx12bHz6+eCKa/PywwbrrhnXXXl+1K9fL3vtTbfeHf88++LZVnHaiX+N3ZLwMD2+/GpIbLfzvpEu5ecgQIAAAQKlLCCAKuXR0TYCBAgQIECAAAECBKojYAm+6qgpU6cFdt25V7ZEV53uRBUb/92w4XHHXQ9UsZTHU4ERI36KZ54bEDfcclcM+fa75NfOgtFxwQ4VOB06tItNNlw3frdX30hn7Xz/w4j4fvgPFfeL8iFdqvDxp56PdPbXOmutns0wat26VfTZfutIQ7gvvvx6nnf1q2++zepbf501snf3WGn5+HrIt/HRJ5/Psq63330/0n/P05lsbZMZVJMmTY50BpWDAAECBAiUsoAl+Ep5dLSNAAECBAgQIECAAIHqCJgBVR01Zeq0wKYbrRcn/P3waNGieZ3ux5w2fkwyK+eMcy+Lp597aU6LeG42Aisu3y2bFbXdNptH8+YzbhSezji75Y57s/2Hfvll2obis3llnbqd/jt04dknVfw7VFY2Nc696Mq4/obba6Qfl5x3amy71abZu9MAbI/fHRIDP/h4lnXtsUvvOPWEo7Nnxo8fH9v02Se+HTpslmXcJECAAAECeQqYAZWnvroJECBAgAABAgQIEKgJAQFUTah6JwEC84VAGmKmM4B269srluu29Ax9Hjv2l7j/ocfjtmSJvg8//myG+3X5Qrell4yrLz0rm/VV3o977n8kTjztvHm+3F2zZk2j303XRLelu2ZVpUHSTnscED/+9HN51TP8rF+/fqTLba6w3DLZvcefei4O+csJMzznAgECBAgQKBUBAVSpjIR2ECBAgAABAgQIECAwrwQswTevJL2H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6gsBAgQIECBAgAABAgQIVCYwduSgePORPSu7Xen1ssm/ZPd+GvJivDm86uUrfXEt3Zg04cdaqkk1BEpfQABV+mOkhQQIECBQIAHLDhRoMHWFAAECBAgQIECAAAECBCoXmDo5Jo3/ofL7s7lTVjYhysZPmM1TbhMgUMoCluAr5dHRNgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAHRQwA6oODpomEyBAgEDdErDsQN0aL60lQIAAAQIECBAgQIAAAQIECBCYewEB1NwbegMBAgQIEJi1gGUHZu3jLgECBAgQIECAAAECBAgQIECAQOEELMFXuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV0AAla+/2gkQIECAAAECBAgQIECAAAECBAgQIECAAAEChRMQQBVuSHWIAAECBAgQIECAAAECBAgQIECAAAECBAgQIJCvgAAqX3+1EyBAgAABAgQIECBAgAABAgQIECBAgAABAgQKJyCAKtyQ6hABAgQIECBAgAABAgQIECBAgAABAgQIECBAIF8BAVS+/monQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBROQABVuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV0AAla+/2gkQIECAAAECBAgQIECAAAECBAgQIECAAAEChRMQQBVuSHWIAAECBAgQIECAAAECBAgQIECAAAECBAgQIJCvgAAqX3+1EyBAgAABAgQIECBAgAABAgQIECBAgAABAgQKJyCAKtyQ6hABAgQIECBAgAABAgQIECBAgAABAgQIECBAIF8BAVS+/monQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBROQABVuCHVIQIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBAvgICqHz91U6AAAECBAgQIECAAAECBAgQIECAAAECBAgQKJyAAKpwQ6pDBAgQIECAAAECBAgQIECAAAECBAgQIECAAIF8BQRQ+fqrnQABAgQIECBAgAABAgQIECBAgAABAgQIECBQOAEBVOGGVIcIECBAgAABAgQIECBAgAABAgQIECBAgAABAvkKCKDy9Vc7AQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBwAgKowg2pDhEgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIE8hUQQOXrr3YCBAgQIECAAAECBAgQIECAAAECBAgQIECAQOEEBFCFG1IdIkCAAAECBAgQIECAAAECBAgQIECAAAECBAjkKyCAytdf7QQIECBAgAABAgQIECBAgAABAgQIECBAgACBwgkIoAo3pDpEgAABAgQIECBAgAABAgQIECBAgAABAgQIEMhXQACVr7/aCRAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQKFExBAFW5IdYgAAQIECBAgQIAAAQIECBAgQIAAAQIECBAgkK+AACpff7UTIECAAAECBAgQIECAAAECBAgQIECAAAECBAonIIAq3JDqEAECBAgQIECAAAECBAgQIECAAAECBAgQIEAgXwEBVL7+aidAgAABAgQIECBAgAABAgQIECBAgAABAgQIFE5AAFW4IdUhAgQIECBAgAABAgQIECBAgAABAgQIECBAgEC+AgKofP3VToAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAonIAAqnBDqkMECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgXwFBFD5+qudAAECBAgQIECAAAECBAgQIECAAAECBAgQIFA4AQFU4YZUhwgQIECAAAECBAgQIECAAAECBAgQIECAAAEC+QoIoPL1VzsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoHACAqjCDakOESBAgAABAgQIECBAgAABAgQIECBAgAABAgTyFRBA5euvdgIECBAgQIAAAQIECBAgQIAAAQIECBAgQIBA4QQEUIUbUh0iQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECOQrIIDK11/tBAgQIECAAAECBAgQIECAAAECBAgQIECAAIHCCQigCjekOkSAAAECBAgQIECAAAECBAgQIECAAAECBAgQyFdAAJWvv9oJECBAgAABAgQIECBAgAABAgQIECBAgAABAoUTEEAVbkh1iAABAgQIECBAgAABAgQIECBAgAABAgQIECCQr4AAKl9/tRMgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECicggCrckOoQAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQCBfAQFUvv5qJ0CAAAECBAgQIECAAAECBAgQIECAAAECBAgUTkAAVbgh1SECBAgQIECAAAECBAgQIECAAAECBAgQIECAQL4CAqh8/dVOgAABAgQIECBAgAABAgQIECBAgAABAgQIECicgACqcEOqQwQIECBAgAABAgQIECBAgAABAgQIECBAgACBfAUEUPn6q50AAQIECBAgQIAAAQIECBAgQIAAAQIECBAgUDgBAVThhlSHCBAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQL5Cgig8vVXOwECBAgQIECAAAECBAgQIECAAAECBAgQIECgcAICqMINqQ4RIECAAAECBAgQIECAAAECBAgQIECAAAECBPIVEEDl6692AgQIECBAgAABAgQIECBAgAABAgQIECBAgEDhBARQhRtSHSJAgAABAgQIECBAgAABAgQIECBAgAABAgQI5CsggMrXX+0ECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgcIJCKAKN6Q6RIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBDIV6DeMj02nJpvE9ROgAABAgQIECBAgAABAgQIECBAgAABAgQIECBQJAEzoIo0mvpCgAABAgQIECBAgAABAgQIECBAgAABAgQIECgBAQFUCQyCJhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIEiiQggCrSaOoLAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKAEBARQJTAImkCAAAECBAgQIECAAAECBAgQIECAAAECBAgQKJKAAKpIo6kvBAgQIECAAAECBAgQIECAAAECBAgQIECAAIESEBBAlcAgaAIBAgQIECBAgAABAgQIECBAgAABAgQIECBAoEgCAqgijaa+ECBAgAABAgQIECBAgAABAgQIECBAgAABAgRKQEAAVQKDoAkECBAgQIAAAQIECBAgQIAAAQIECBAgQIAAgSIJCKCKNJr6QoAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoAQEBVAkMgiYQIECAAAECBAgQIECAAAECBAgQIECAAAECBIokIIAq0mjqCwECBAgQIECAAAECBAgQIECAAAECBAgQIECgBAQEUCUwCJpAgAABAgQIECBAgAABAgQIECBAgAABAgQIECiSgACqSKOpLwQIECBAgAABAgQIECBAgAABAgQIECBAgACBEhAQQJXAIGgCAQIECBAgQIAAAQIECBAgQIAAAQIECBAgQKBIAgKoIo2mvhAgQIAAAQIECBAgQIAAAQIECBAgQIAAAQIESkBAAFUCg6AJBAgQIECAAAECBAgQIECAAAECBAgQIECAAIEiCQigijSa+kKAAAECBAgQIECAAAECBAgQIECAAAECBAgQKAEBAVQJDIImECBAgAABAgQIECBAgAABAgQIECBAgAABAgSKJCCAKtJo6gsBAgQIECBAgAABAgQIECBAgAABAgQIECBAoAQEBFAlMAiaQIAAAQIECBAgQIAAAQIECBAgQIAAAQIECBAoksD/AxNWEy9iPvIAAAAAAElFTkSuQmCC" + } + }, + "cell_type": "markdown", + "id": "ad9e20ae-934a-4b98-b6ab-091c77572c61", + "metadata": {}, + "source": [ + "The central account has an LF tag `data_classification:dev` which we will first add to glue table and grant consumer role permissions to that tag\n", + "\n", + "![image.png](attachment:d1f0c7d4-d102-42f3-a1fc-b26eeb94a2bf.png)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5506c39d-5b59-436f-82ca-ba1934e60c4d", + "metadata": {}, + "outputs": [], + "source": [ + "lf_client_central = central_acc_boto_session.client('lakeformation')\n", + "lf_client_central.get_data_lake_settings()\n", + "\n", + "lf_client_central.add_lf_tags_to_resource(\n", + " Resource={\n", + " 'Table': {\n", + " 'CatalogId': str(central_account),\n", + " 'DatabaseName': database_name,\n", + " 'Name': table_name\n", + " }\n", + " },\n", + " LFTags=[\n", + " {\n", + " 'CatalogId': str(central_account),\n", + " 'TagKey': 'data_classification',\n", + " 'TagValues': ['dev']\n", + " }\n", + " ]\n", + ")\n", + "print(f\"Tagged table {database_name}.{table_name} with SharedAccess=consumer\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "c0bfc0ff-95be-47a5-b49a-028adc23a8c9", + "metadata": {}, + "source": [ + "Now we need to grant the role in consumer account permissions to the LF tag" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c069580b-6254-4173-a618-2bdf2fbd2889", + "metadata": {}, + "outputs": [], + "source": [ + "lf_client_central.grant_permissions(\n", + " Principal={\n", + " 'DataLakePrincipalIdentifier': acc_to_role_arn[consumer_account]\n", + " },\n", + " Resource={\n", + " 'LFTagPolicy': {\n", + " 'CatalogId': str(central_account),\n", + " 'ResourceType': 'TABLE',\n", + " 'Expression': [\n", + " {\n", + " 'TagKey': 'data_classification',\n", + " 'TagValues': ['dev']\n", + " }\n", + " ]\n", + " }\n", + " },\n", + " Permissions=['SELECT', 'DESCRIBE'],\n", + " PermissionsWithGrantOption=[]\n", + ")\n", + "\n", + "\n", + "print(f\"Granted LF-tag based SELECT/DESCRIBE to consumer account {consumer_account}\")\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "8508880e-a856-4574-8c8a-edbc972c9326", + "metadata": {}, + "source": [ + "Cross account lakeformation grant permissions automatically creates a RAM share so we need to accept that in consumer account" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "df5665a2-1817-4366-97a6-7370bb3ebf44", + "metadata": {}, + "outputs": [], + "source": [ + "# Producer account accepts the RAM invitation\n", + "ram_client_consumer = consumer_acc_boto_session.client('ram')\n", + "\n", + "response = ram_client_consumer.get_resource_share_invitations()\n", + "pending = [\n", + " inv for inv in response['resourceShareInvitations']\n", + " if inv['status'] == 'PENDING' and inv['senderAccountId'] == str(central_account)\n", + "]\n", + "for inv in pending:\n", + " ram_client_consumer.accept_resource_share_invitation(\n", + " resourceShareInvitationArn=inv['resourceShareInvitationArn']\n", + " )\n", + " print(f\"Accepted: {inv['resourceShareInvitationArn']}\")" + ] + }, + { + "cell_type": "markdown", + "id": "305acbb5-80b4-4890-adb0-954beba91995", + "metadata": {}, + "source": [ + "## 4. Consumer reads data from the glue table using Athena" + ] + }, + { + "cell_type": "markdown", + "id": "3fa4fe66-4e03-4197-80b5-116f1c591183", + "metadata": {}, + "source": [ + "create a link between glue table in central and the consumer account" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b089a0cf-e69d-461a-91ab-39d3fc17dc7e", + "metadata": {}, + "outputs": [], + "source": [ + "glue_client_consumer = consumer_acc_boto_session.client('glue')\n", + "\n", + "CONSUMER_DB_NAME = 'shared_feature_store_db'\n", + "try:\n", + " glue_client_consumer.create_database(\n", + " DatabaseInput={'Name': CONSUMER_DB_NAME}\n", + " )\n", + " print(f\"Created database: {CONSUMER_DB_NAME}\")\n", + "except glue_client_consumer.exceptions.AlreadyExistsException:\n", + " print(f\"Database {CONSUMER_DB_NAME} already exists\")\n", + "\n", + "try:\n", + " glue_client_consumer.create_table(\n", + " DatabaseName=CONSUMER_DB_NAME,\n", + " TableInput={\n", + " 'Name': f'{table_name}_link',\n", + " 'TargetTable': {\n", + " 'CatalogId': str(central_account),\n", + " 'DatabaseName': database_name,\n", + " 'Name': table_name\n", + " }\n", + " }\n", + " )\n", + " print(f\"Created resource link: {CONSUMER_DB_NAME}.{table_name}_link\")\n", + "except glue_client_consumer.exceptions.AlreadyExistsException:\n", + " print(\"Resource link already exists\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4be3b18e-9682-4edd-bfd1-603932622b0b", + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "\n", + "athena_client = consumer_acc_boto_session.client('athena')\n", + "CONSUMER_S3_BUCKET = consumer_acc_sagemaker_session.default_bucket()\n", + "\n", + "query = f'SELECT * FROM {CONSUMER_DB_NAME}.{table_name}_link LIMIT 10'\n", + "\n", + "response = athena_client.start_query_execution(\n", + " QueryString=query,\n", + " ResultConfiguration={\n", + " 'OutputLocation': f's3://{CONSUMER_S3_BUCKET}/athena-results/'\n", + " }\n", + ")\n", + "\n", + "query_id = response['QueryExecutionId']\n", + "print(f\"Query started: {query_id}\")\n", + "\n", + "while True:\n", + " status = athena_client.get_query_execution(QueryExecutionId=query_id)\n", + " state = status['QueryExecution']['Status']['State']\n", + " if state in ['SUCCEEDED', 'FAILED', 'CANCELLED']:\n", + " break\n", + " print(f\"Status: {state}...\")\n", + " time.sleep(2)\n", + "\n", + "if state == 'SUCCEEDED':\n", + " results = athena_client.get_query_results(QueryExecutionId=query_id)\n", + " for row in results['ResultSet']['Rows']:\n", + " print([col.get('VarCharValue', '') for col in row['Data']])\n", + "else:\n", + " reason = status['QueryExecution']['Status'].get('StateChangeReason', 'unknown')\n", + " print(f\"Query {state}: {reason}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b54072b5-eed0-41de-b238-a79f8884d1e6", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "py3.10.14", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": { + "15d7159da97842f289a6eae80d88f367": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + }, + "16cf8427b8774feabe06a535381438ef": { + "model_module": "@jupyter-widgets/base", + "model_module_version": "2.0.0", + "model_name": "LayoutModel", + "state": {} + } + }, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png b/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png new file mode 100644 index 0000000000..a126d2e207 Binary files /dev/null and b/v3-examples/ml-ops-examples/imgs/fs-lf-cross-account1.png differ diff --git a/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb new file mode 100644 index 0000000000..5f689a3c0d --- /dev/null +++ b/v3-examples/ml-ops-examples/v3-feature-store-lake-formation.ipynb @@ -0,0 +1,851 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Feature Group Lake Formation Governance " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This Demo builds on sagemaker v3 features which is not out yet so we need to tell pip to use local version \n", + "\n", + "1. install `pyenv` following the instructions here https://github.com/pyenv/pyenv?tab=readme-ov-file#a-getting-pyenv\n", + "2. setup your shell env for pyenv https://github.com/pyenv/pyenv?tab=readme-ov-file#b-set-up-your-shell-environment-for-pyenv\n", + "3. install and activate python for example (this code was tested on python 3.10.14)\n", + "```\n", + "pyenv install 3.10.14\n", + "pyenv virtualenv 3.10.14 py3.10.14\n", + "pyenv activate py3.10.14\n", + "```\n", + "3. You will then need to run `pip install -e ./sagemaker-mlops` before starting the jupyter notebook to use the local packages\n", + "4. `pip install jupyter notebook`\n", + "5. `jupyter notebook`" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## New SDK API Changes\n", + "\n", + "This release introduces Lake Formation integration through the following additions:\n", + "\n", + "### New Class: `LakeFormationConfig`\n", + "\n", + "A configuration class for Lake Formation governance settings:\n", + "\n", + "```python\n", + "from sagemaker.mlops.feature_store.feature_group import LakeFormationConfig\n", + "\n", + "lake_formation_config = LakeFormationConfig()\n", + "lake_formation_config.enabled = True # Enable Lake Formation governance\n", + "lake_formation_config.use_service_linked_role = True # Use LF service-linked role (default)\n", + "lake_formation_config.registration_role_arn = None # This is the role used by LF to access your Resources\n", + "lake_formation_config.show_s3_policy = True # Print recommended S3 deny policy\n", + "```\n", + "\n", + "### New Parameter in FeatureGroup.create(): lake_formation_config\n", + "Pass a LakeFormationConfig object to enable Lake Formation at creation time:\n", + "```python\n", + "fg = FeatureGroup.create(\n", + " feature_group_name=\"my-feature-group\",\n", + " # ... other parameters ...\n", + " lake_formation_config=lake_formation_config, # OPTIONAL NEW PARAMETER\n", + ")\n", + "```\n", + "\n", + "### New Method: FeatureGroup.enable_lake_formation()\n", + "Enable Lake Formation on an existing Feature Group:\n", + "```python\n", + "fg.enable_lake_formation(\n", + " use_service_linked_role=True, # Use LF service-linked role (default)\n", + " registration_role_arn=None, # Custom role ARN (if not using SLR)\n", + " wait_for_active=False, # Wait for Feature Group to be Created\n", + " show_s3_policy=False, # Print recommended S3 deny policy\n", + ")\n", + "```\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Lake Formation Setup Process\n", + "\n", + "When you enable Lake Formation governance (either at creation time or via `enable_lake_formation()`), the SDK performs the following steps automatically:\n", + "\n", + "### Step 1: Register S3 Location with Lake Formation\n", + "\n", + "The offline store's S3 location is registered as a Lake Formation data lake location. This allows Lake Formation to manage access to the underlying data files.\n", + "\n", + "- Uses either the Lake Formation service-linked role (default) or a custom registration role\n", + "- If the location is already registered, this step is skipped\n", + "\n", + "### Step 2: Grant Lake Formation Permissions\n", + "\n", + "The Feature Group's `role_arn` (offline store role) is granted the following permissions on the Glue table via Lake Formation:\n", + "\n", + "- `SELECT` - Read data from the table\n", + "- `INSERT` - Write new records\n", + "- `DELETE` - Remove records\n", + "- `DESCRIBE` - View table metadata\n", + "- `ALTER` - Modify table schema\n", + "\n", + "### Step 3: Revoke IAMAllowedPrincipal Permissions\n", + "\n", + "By default, Glue tables allow access to any IAM principal with appropriate IAM permissions (`IAMAllowedPrincipal`). This step revokes that default permission, ensuring that:\n", + "\n", + "- Access is now controlled exclusively through Lake Formation\n", + "- Only principals explicitly granted permissions via Lake Formation can access the data\n", + "\n", + "### Optional: S3 Deny Policy\n", + "\n", + "When `show_s3_policy=True`, the SDK prints a recommended S3 bucket policy. This policy adds an additional layer of protection by denying direct S3 access to all principals except:\n", + "\n", + "- The Lake Formation service-linked role\n", + "- The Feature Store offline store role\n", + "\n", + "**Note:** The S3 policy is not applied automatically—you must manually add it to your bucket policy if desired.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \n", + "This notebook demonstrates two workflows for using SageMaker Feature Store with Lake Formation governance:\n", + "\n", + "1. **Example 1**: Create Feature Group with Lake Formation enabled at creation time\n", + "2. **Example 2**: Create Feature Group first, then enable Lake Formation separately\n", + "\n", + "Both workflows include record ingestion to verify everything works end-to-end.\n", + "\n", + "## Prerequisites\n", + "\n", + "- AWS credentials configured with permissions for SageMaker, S3, Glue, and Lake Formation\n", + "- An S3 bucket for the offline store\n", + "- An IAM role with Feature Store permissions\n", + "\n", + "## Required IAM Permissions\n", + "\n", + "This notebook uses two separate IAM roles:\n", + "1. **Execution Role**: The SageMaker execution role running this notebook. It requires having Lakeformation Data lake admin permissions and Feature store permissions\n", + "2. **Offline Store Role**: A dedicated role for Feature Store S3 access\n", + "\n", + "## Lake Formation Admin Requirements\n", + "\n", + "The person enabling Lake Formation governance must be a **Data Lake Administrator** in Lake Formation. There are two options for enabling lakeformation governance depending on your organization's setup:\n", + "\n", + "### Option 1: Single Role (Data Lake Admin + Feature Store Admin)\n", + "\n", + "If the caller has both:\n", + "- Data Lake Administrator privileges in Lake Formation\n", + "- Permissions to create Feature Groups in SageMaker\n", + "\n", + "Then they can use `FeatureGroup.create()` with `lake_formation_config` to enable governance at creation time (Example 1).\n", + "\n", + "### Option 2: Separate Roles (ML Engineer + Data Lake Admin)\n", + "\n", + "If the person creating the Feature Group is different from the Data Lake Administrator:\n", + "\n", + "1. **ML Engineer** creates the Feature Group without Lake Formation using `FeatureGroup.create()`\n", + "2. **Data Lake Admin** later enables governance by calling `enable_lake_formation()` on the existing Feature Group (Example 2)\n", + "\n", + "\n", + "### Execution Role Policy\n", + "\n", + "You can assume a role with the following policy to run this notebook\n", + "Make sure to update the policy to use the offline store role\n", + "\n", + "```json\n", + "{\n", + " \"Version\": \"2012-10-17\",\n", + " \"Statement\": [\n", + " {\n", + " \"Sid\": \"FeatureGroupManagement\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"sagemaker:*\"\n", + " ],\n", + " \"Resource\": \"arn:aws:sagemaker:*:*:feature-group/*\"\n", + " },\n", + " {\n", + " \"Sid\": \"LakeFormation\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"lakeformation:RegisterResource\",\n", + " \"lakeformation:DeregisterResource\",\n", + " \"lakeformation:GrantPermissions\",\n", + " \"lakeformation:RevokePermissions\"\n", + " ],\n", + " \"Resource\": \"*\"\n", + " },\n", + " {\n", + " \"Sid\": \"GlueCatalogRead\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"glue:GetTable\",\n", + " \"glue:GetDatabase\",\n", + " \"glue:DeleteTable\"\n", + " ],\n", + " \"Resource\": [\n", + " \"arn:aws:glue:*:*:catalog\",\n", + " \"arn:aws:glue:*:*:database/sagemaker_featurestore\",\n", + " \"arn:aws:glue:*:*:table/sagemaker_featurestore/*\"\n", + " ]\n", + " },\n", + " {\n", + " \"Sid\": \"PassOfflineStoreRole\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": \"iam:PassRole\",\n", + " \"Resource\": \"arn:aws:iam::*:role/\"\n", + " },\n", + " {\n", + " \"Sid\": \"LakeFormationServiceLinkedRole\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"iam:GetRole\",\n", + " \"iam:PutRolePolicy\",\n", + " \"iam:GetRolePolicy\"\n", + " ],\n", + " \"Resource\": \"arn:aws:iam::*:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess\"\n", + " },\n", + " {\n", + " \"Sid\": \"S3SagemakerDefaultBucket\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"s3:CreateBucket\",\n", + " \"s3:GetBucketAcl\",\n", + " \"s3:ListBucket\"\n", + " ],\n", + " \"Resource\": [\n", + " \"arn:aws:s3:::sagemaker-*\"\n", + " ]\n", + " },\n", + " {\n", + " \"Sid\": \"CreateGlueTable\",\n", + " \"Effect\": \"Allow\",\n", + " \"Action\": [\n", + " \"glue:CreateTable\"\n", + " ],\n", + " \"Resource\": [\n", + " \"*\"\n", + " ]\n", + " }\n", + " ]\n", + "}\n", + "```" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import boto3\n", + "import os\n", + "\n", + "boto3.DEFAULT_SESSION = None\n", + "def assume_role(role_arn, session_name=\"AssumedRoleSession\"):\n", + " \"\"\"\n", + " Assume an AWS IAM role and return temporary credentials.\n", + " \n", + " Args:\n", + " role_arn: The ARN of the role to assume\n", + " session_name: A name for the assumed role session\n", + " \n", + " Returns:\n", + " A boto3 session with the assumed role credentials\n", + " \"\"\"\n", + " sts_client = boto3.client('sts')\n", + " \n", + " response = sts_client.assume_role(\n", + " RoleArn=role_arn,\n", + " RoleSessionName=session_name\n", + " )\n", + " \n", + " credentials = response['Credentials']\n", + " \n", + " # Create a new session with the temporary credentials\n", + " session = boto3.Session(\n", + " aws_access_key_id=credentials['AccessKeyId'],\n", + " aws_secret_access_key=credentials['SecretAccessKey'],\n", + " aws_session_token=credentials['SessionToken']\n", + " )\n", + " \n", + " return session" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "from datetime import datetime\n", + "from datetime import timezone\n", + "\n", + "import boto3\n", + "from botocore.exceptions import ClientError\n", + "\n", + "# Import the FeatureGroup with Lake Formation support\n", + "from sagemaker.mlops.feature_store.feature_group import FeatureGroup, LakeFormationConfig\n", + "from sagemaker.core.shapes import (\n", + " FeatureDefinition,\n", + " FeatureValue,\n", + " OfflineStoreConfig,\n", + " OnlineStoreConfig,\n", + " S3StorageConfig,\n", + ")\n", + "from sagemaker.core.helper.session_helper import Session as SageMakerSession, get_execution_role" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Use SageMaker session to get default bucket and execution role\n", + "\n", + "# Execution role (for running this notebook)\n", + "EXECUTION_ROLE_ARN = 'arn:aws:iam:::role/'\n", + "\n", + "\n", + "# Offline store role (dedicated role for Feature Store S3 access)\n", + "# Replace with your dedicated offline store role ARN\n", + "# https://docs.aws.amazon.com/sagemaker/latest/dg/feature-store-adding-policies.html\n", + "OFFLINE_STORE_ROLE_ARN = \"arn:aws:iam:::role/\"\n", + "\n", + "\n", + "boto_session = assume_role(EXECUTION_ROLE_ARN)\n", + "sagemaker_session = SageMakerSession(boto_session=boto_session)\n", + "sts = boto_session.client('sts')\n", + "\n", + "S3_BUCKET = sagemaker_session.default_bucket()\n", + "REGION = sagemaker_session.boto_session.region_name\n", + "\n", + "\n", + "print(f\"S3 Bucket: {S3_BUCKET}\")\n", + "print(f\"Execution Role ARN:{sts.get_caller_identity()['Arn']}\")\n", + "print(f\"Offline Store Role ARN: {OFFLINE_STORE_ROLE_ARN}\")\n", + "print(f\"Region: {REGION}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Common Feature Definitions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "feature_definitions = [\n", + " FeatureDefinition(feature_name=\"customer_id\", feature_type=\"String\"),\n", + " FeatureDefinition(feature_name=\"event_time\", feature_type=\"String\"),\n", + " FeatureDefinition(feature_name=\"age\", feature_type=\"Integral\"),\n", + " FeatureDefinition(feature_name=\"total_purchases\", feature_type=\"Integral\"),\n", + " FeatureDefinition(feature_name=\"avg_order_value\", feature_type=\"Fractional\"),\n", + "]\n", + "\n", + "print(\"Feature Definitions:\")\n", + "for fd in feature_definitions:\n", + " print(f\" - {fd.feature_name}: {fd.feature_type}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helper Function: Ingest Records" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def ingest_sample_records(feature_group, num_records=3):\n", + " \"\"\"\n", + " Ingest sample records into the Feature Group.\n", + " \n", + " Args:\n", + " feature_group: The FeatureGroup to ingest records into\n", + " num_records: Number of sample records to ingest\n", + " \"\"\"\n", + " print(f\"\\nIngesting {num_records} sample records...\")\n", + " \n", + " for i in range(num_records):\n", + " event_time = datetime.now(timezone.utc).isoformat()\n", + " record = [\n", + " FeatureValue(feature_name=\"customer_id\", value_as_string=f\"cust_{i+1}\"),\n", + " FeatureValue(feature_name=\"event_time\", value_as_string=event_time),\n", + " FeatureValue(feature_name=\"age\", value_as_string=str(25 + i * 5)),\n", + " FeatureValue(feature_name=\"total_purchases\", value_as_string=str(10 + i * 3)),\n", + " FeatureValue(feature_name=\"avg_order_value\", value_as_string=str(50.0 + i * 10.5)),\n", + " ]\n", + " \n", + " feature_group.put_record(record=record)\n", + " print(f\" Ingested record for customer: cust_{i+1}\")\n", + " \n", + " print(f\"Successfully ingested {num_records} records!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# Example 1: Create Feature Group with Lake Formation Enabled\n", + "\n", + "This example creates a Feature Group with Lake Formation governance enabled at creation time using `LakeFormationConfig`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate unique name for example 1\n", + "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n", + "FG_NAME_WORKFLOW1 = f\"lf-demo-workflow1-{timestamp}\"\n", + "\n", + "print(f\"Example 1 Feature Group: {FG_NAME_WORKFLOW1}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Configure online and offline stores\n", + "online_store_config = OnlineStoreConfig(enable_online_store=True)\n", + "\n", + "offline_store_config_1 = OfflineStoreConfig(\n", + " s3_storage_config=S3StorageConfig(\n", + " s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n", + " )\n", + ")\n", + "\n", + "# Configure Lake Formation - enabled at creation\n", + "lake_formation_config = LakeFormationConfig()\n", + "lake_formation_config.enabled = True\n", + "lake_formation_config.use_service_linked_role = True\n", + "lake_formation_config.show_s3_policy = True\n", + "\n", + "print(\"Store Config:\")\n", + "print(f\" Online Store: enabled\")\n", + "print(f\" Offline Store S3: s3://{S3_BUCKET}/feature-store-demo/\")\n", + "print(\"\\nLake Formation Config:\")\n", + "print(f\" enabled: {lake_formation_config.enabled}\")\n", + "print(f\" use_service_linked_role: {lake_formation_config.use_service_linked_role}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Create Feature Group with Lake Formation enabled\n", + "print(\"Creating Feature Group with Lake Formation enabled...\")\n", + "print(\"This will:\")\n", + "print(\" 1. Create the Feature Group with online + offline stores\")\n", + "print(\" 2. Wait for 'Created' status\")\n", + "print(\" 3. Register S3 with Lake Formation\")\n", + "print(\" 4. Grant permissions to execution role\")\n", + "print(\" 5. Revoke IAMAllowedPrincipal permissions\")\n", + "print()\n", + "\n", + "fg_workflow1 = FeatureGroup.create(\n", + " feature_group_name=FG_NAME_WORKFLOW1,\n", + " record_identifier_feature_name=\"customer_id\",\n", + " event_time_feature_name=\"event_time\",\n", + " feature_definitions=feature_definitions,\n", + " online_store_config=online_store_config,\n", + " offline_store_config=offline_store_config_1,\n", + " role_arn=OFFLINE_STORE_ROLE_ARN,\n", + " description=\"Workflow 1: Lake Formation enabled at creation\",\n", + " lake_formation_config=lake_formation_config, # new parameter\n", + " region=REGION,\n", + " session=boto_session\n", + ")\n", + "\n", + "print(f\"\\nFeature Group created: {fg_workflow1.feature_group_name}\")\n", + "print(f\"Status: {fg_workflow1.feature_group_status}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Verify Feature Group status\n", + "fg_workflow1.refresh()\n", + "print(f\"Feature Group: {fg_workflow1.feature_group_name}\")\n", + "print(f\"Status: {fg_workflow1.feature_group_status}\")\n", + "print(f\"ARN: {fg_workflow1.feature_group_arn}\")\n", + "\n", + "DataCatalogConfig = fg_workflow1.offline_store_config.data_catalog_config\n", + "print(f'Table Name: {DataCatalogConfig.table_name}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Ingest sample records to verify everything works\n", + "ingest_sample_records(fg_workflow1, num_records=10)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Retrieve a sample record from the online store\n", + "print(\"Retrieving record for customer 'cust_1' from online store...\")\n", + "response = fg_workflow1.get_record(record_identifier_value_as_string=\"cust_3\")\n", + "\n", + "print(f\"\\nRecord retrieved successfully!\")\n", + "print(f\"Features:\")\n", + "for feature in response.record:\n", + " print(f\" {feature.feature_name}: {feature.value_as_string}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# Example 2: Create Feature Group, Then Enable Lake Formation\n", + "\n", + "This example creates a Feature Group first without Lake Formation, then enables it separately using `enable_lake_formation()`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Generate unique name for example 2\n", + "timestamp = datetime.now().strftime(\"%Y%m%d%H%M%S\")\n", + "FG_NAME_WORKFLOW2 = f\"lf-demo-workflow2-{timestamp}\"\n", + "\n", + "print(f\"Example 2 Feature Group: {FG_NAME_WORKFLOW2}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Configure online and offline stores\n", + "online_store_config_2 = OnlineStoreConfig(enable_online_store=True)\n", + "\n", + "offline_store_config_2 = OfflineStoreConfig(\n", + " s3_storage_config=S3StorageConfig(\n", + " s3_uri=f\"s3://{S3_BUCKET}/feature-store-demo/\"\n", + " ),\n", + " table_format=\"Iceberg\"\n", + ")\n", + "\n", + "# Step 1: Create Feature Group WITHOUT Lake Formation\n", + "print(\"Step 1: Creating Feature Group without Lake Formation...\")\n", + "\n", + "fg_workflow2 = FeatureGroup.create(\n", + " feature_group_name=FG_NAME_WORKFLOW2,\n", + " record_identifier_feature_name=\"customer_id\",\n", + " event_time_feature_name=\"event_time\",\n", + " feature_definitions=feature_definitions,\n", + " online_store_config=online_store_config_2,\n", + " offline_store_config=offline_store_config_2,\n", + " role_arn=OFFLINE_STORE_ROLE_ARN,\n", + " description=\"Workflow 2: Lake Formation enabled after creation\",\n", + " region=REGION,\n", + " session=boto_session\n", + ")\n", + "\n", + "print(f\"Feature Group created: {fg_workflow2.feature_group_name}\")\n", + "print(f\"Status: {fg_workflow2.feature_group_status}\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 2: Wait for Feature Group to be ready\n", + "print(\"Step 2: Waiting for Feature Group to reach 'Created' status...\")\n", + "fg_workflow2.wait_for_status(target_status=\"Created\", poll=10, timeout=300)\n", + "print(f\"Status: {fg_workflow2.feature_group_status}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here you can optionally assume a different role with just datalake permissions and describe Feature Group permission" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 3: Enable Lake Formation governance\n", + "print(\"Step 3: Enabling Lake Formation governance...\")\n", + "print(\"This will:\")\n", + "print(\" 1. Register S3 with Lake Formation\")\n", + "print(\" 2. Grant permissions to execution role\")\n", + "print(\" 3. Revoke IAMAllowedPrincipal permissions\")\n", + "print()\n", + "fg_workflow2 = FeatureGroup.get(FG_NAME_WORKFLOW2)\n", + "result = fg_workflow2.enable_lake_formation( # new method\n", + " use_service_linked_role=True,\n", + ")\n", + "\n", + "print(f\"\\nLake Formation setup results:\")\n", + "print(f\" s3_registration: {result['s3_registration']}\")\n", + "print(f\" permissions_granted: {result['permissions_granted']}\")\n", + "print(f\" iam_principal_revoked: {result['iam_principal_revoked']}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 4: Ingest sample records to verify everything works\n", + "# This is still using the first role\n", + "print(\"Step 4: Ingesting records to verify Lake Formation setup...\")\n", + "ingest_sample_records(fg_workflow2, num_records=4)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Step 5: Retrieve a sample record from the online store\n", + "print(\"Step 5: Retrieving record for customer 'cust_1' from online store...\")\n", + "response = fg_workflow2.get_record(record_identifier_value_as_string=\"cust_1\")\n", + "\n", + "print(f\"\\nRecord retrieved successfully!\")\n", + "print(f\"Features:\")\n", + "for feature in response.record:\n", + " print(f\" {feature.feature_name}: {feature.value_as_string}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Verify Feature Group status\n", + "fg_workflow2.refresh()\n", + "print(f\"Feature Group: {fg_workflow2.feature_group_name}\")\n", + "print(f\"Status: {fg_workflow2.feature_group_status}\")\n", + "print(f\"ARN: {fg_workflow2.feature_group_arn}\")\n", + "DataCatalogTable = fg_workflow2.offline_store_config.data_catalog_config.table_name\n", + "print(f\"Table Name: {DataCatalogTable}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# Cleanup\n", + "\n", + "Delete the Feature Groups and **associated Glue tables** created in this demo." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Helper Function: Cleanup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def cleanup_feature_group(fg):\n", + " \"\"\"\n", + " Delete a FeatureGroup and its associated Glue table.\n", + " \n", + " Args:\n", + " fg: The FeatureGroup to delete.\n", + " \"\"\"\n", + " try:\n", + " # Delete the Glue table if it exists\n", + " if fg.offline_store_config is not None:\n", + " try:\n", + " fg.refresh() # Ensure we have latest config\n", + " data_catalog_config = fg.offline_store_config.data_catalog_config\n", + " if data_catalog_config is not None:\n", + " database_name = data_catalog_config.database\n", + " table_name = data_catalog_config.table_name\n", + "\n", + " if database_name and table_name:\n", + " glue_client = boto3.client(\"glue\")\n", + " try:\n", + " glue_client.delete_table(DatabaseName=database_name, Name=table_name)\n", + " print(f\"Deleted Glue table: {database_name}.{table_name}\")\n", + " except ClientError as e:\n", + " # Ignore if table doesn't exist\n", + " if e.response[\"Error\"][\"Code\"] != \"EntityNotFoundException\":\n", + " raise\n", + " except Exception as e:\n", + " # Don't fail cleanup if Glue table deletion fails\n", + " print(f\"Warning: Could not delete Glue table: {e}\")\n", + "\n", + " # Delete the FeatureGroup\n", + " fg.delete()\n", + " print(f\"Deleted Feature Group: {fg.feature_group_name}\")\n", + " except ClientError as e:\n", + " print(f\"Error during cleanup: {e}\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Uncomment to delete the Feature Groups\n", + "cleanup_feature_group(fg_workflow1)\n", + "cleanup_feature_group(fg_workflow2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# Summary\n", + "\n", + "This notebook demonstrated two workflows:\n", + "\n", + "**Example 1: Enable Lake Formation Governance at Creation**\n", + "- Use `LakeFormationConfig` with `enabled=True` in `FeatureGroup.create()`\n", + "- Lake Formation is automatically configured after Feature Group creation\n", + "- Both online and offline stores enabled\n", + "\n", + "**Example 2: Enable Lake Formation Later**\n", + "- Create Feature Group normally without Lake Formation\n", + "- Call `enable_lake_formation()` method after creation\n", + "- More control over when Lake Formation is enabled\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "# FAQ:\n", + "\n", + "## What is the S3 deny policy for?\n", + "\n", + "When you enable Lake Formation governance, you control access to data through Lake Formation permissions. However, **IAM roles that already have direct S3 access will continue to have access** to the underlying data files, bypassing Lake Formation entirely.\n", + "\n", + "The S3 deny policy closes this access path by explicitly denying S3 access to all principals except:\n", + "- The Lake Formation service-linked role (for data access)\n", + "- The Feature Store offline store role provided during Feature Group creation\n", + "\n", + "## Why don't we apply the S3 deny policy automatically?\n", + "\n", + "We provide the policy as a **recommendation** rather than applying it automatically for several important reasons:\n", + "\n", + "### 1. Protect existing SageMaker workflows from breaking\n", + "\n", + "Many customers already have SageMaker training and processing jobs wired directly to S3 URIs. An automatic S3 deny could cause those jobs to fail the moment governance is enabled on a table.\n", + "\n", + "### 2. Support different personas and trust levels\n", + "\n", + "Different users have different access needs:\n", + "- **Analysts / BI users** - should only see data through governed surfaces (Lake Formation tables, Athena, Redshift, etc.)\n", + "- **ML / Data engineers** - often need raw S3 access for training, feature engineering, and debugging\n", + "\n", + "### 3. Enable gradual migration to stronger governance\n", + "\n", + "Many customers want to phase in Lake Formation governance:\n", + "1. Start by governing table access only\n", + "2. Later tighten S3 access once they've refactored jobs and validated behavior\n", + "\n", + "### 4. Avoid breaking existing bucket policies\n", + "\n", + "Automatically modifying bucket policies could:\n", + "- Conflict with existing policy statements\n", + "- Lock out users or services unexpectedly\n", + "- Cause cascading failures across multiple applications sharing the bucket\n", + "\n", + "Therefore, the S3 policy is provided as a starting point that should be validated by the user. \n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.14" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +}