diff --git a/blueprints/fedramp-high/gemini-enterprise/README.md b/blueprints/fedramp-high/gemini-enterprise/README.md index 0d1575032..2b4fc0682 100644 --- a/blueprints/fedramp-high/gemini-enterprise/README.md +++ b/blueprints/fedramp-high/gemini-enterprise/README.md @@ -904,6 +904,7 @@ The blueprint sets up the following key components: - `access_end_hour`: End hour (0-23 ET, default: 17) - `access_start_day`: Start day (1=Mon, 7=Sun, default: 1) - `access_end_day`: End day (1=Mon, 7=Sun, default: 5) + - **Model Armor:** Template defined in `model_armor.tf` and optionally configured for the FedRAMP High compliance regime to provide an extra layer of security by filtering user prompts and model responses to conform to responsible AI practices. 4. **Data Stores:** CMEK-encrypted GCS buckets and BigQuery datasets for Vertex AI Search, managed by the `discovery-engine` module. diff --git a/blueprints/fedramp-high/gemini-enterprise/deploy.sh b/blueprints/fedramp-high/gemini-enterprise/deploy.sh index bcc785a68..b53a67d65 100755 --- a/blueprints/fedramp-high/gemini-enterprise/deploy.sh +++ b/blueprints/fedramp-high/gemini-enterprise/deploy.sh @@ -1350,6 +1350,28 @@ prompt_gemini_apps() { ENABLE_AGENT_SHARING_NO_APPROVAL_FLAG="false" fi + if [[ "$COMPLIANCE_REGIME" == "FEDRAMP_HIGH" || "$COMPLIANCE_REGIME" == "NONE" ]]; then + echo "" + echo -e "${YELLOW}Model Armor Feature:${NC}" + echo -e "${YELLOW}When enabled, Model Armor enhances the security and safety of your AI applications by proactively screening the prompts and responses given by the Gemini Enterprise assistant.${NC}" + read -p "Would you like to enable 'Model Armor'? [y/N]: " ENABLE_MODEL_ARMOR + if [[ "$ENABLE_MODEL_ARMOR" =~ ^[Yy]$ ]]; then + ENABLE_MODEL_ARMOR_FLAG="true" + echo -e "${BLUE}Enabling Model Armor API...${NC}" + gcloud services enable modelarmor.googleapis.com + echo "" + echo -e "${BLUE}--- Model Armor ---${NC}" + echo -e "${YELLOW}Model Armor enhances the security and safety of your AI applications by proactively screening the prompts and responses given by the Gemini Enterprise assistant.${NC}" + echo "" + echo -e "Please review the configuration in: ${BLUE}blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/model_armor.tf${NC}" + echo -e "For more information on configuring Model Armor templatees, visit: ${BLUE}https://docs.cloud.google.com/model-armor/manage-templates#create-ma-template${NC}" + echo "" + read -p "Press Enter to acknowledge and continue..." + else + ENABLE_MODEL_ARMOR_FLAG="false" + fi + fi + GCS_KEYS_STR="[$(IFS=,; echo "${SELECTED_GCS_KEYS[*]}")]" BQ_KEYS_STR="[$(IFS=,; echo "${SELECTED_BQ_KEYS[*]}")]" @@ -1361,7 +1383,8 @@ prompt_gemini_apps() { --argjson agent_sharing "$ENABLE_AGENT_SHARING_FLAG" \ --argjson agent_sharing_no_approval "$ENABLE_AGENT_SHARING_NO_APPROVAL_FLAG" \ --argjson audit_logs "$ENABLE_AUDIT_LOGS_FLAG" \ - '{display_name: $display, company_name: $company, gcs_data_store_keys: $gcs_keys, bq_data_store_keys: $bq_keys, enable_agent_sharing: $agent_sharing, enable_agent_sharing_without_approval: $agent_sharing_no_approval, enable_audit_logs: $audit_logs}') + --argjson model_armor "$ENABLE_MODEL_ARMOR_FLAG" \ + '{display_name: $display, company_name: $company, gcs_data_store_keys: $gcs_keys, bq_data_store_keys: $bq_keys, enable_agent_sharing: $agent_sharing, enable_agent_sharing_without_approval: $agent_sharing_no_approval, enable_audit_logs: $audit_logs, enable_model_armor: $model_armor}') # Add to the apps map APPS_OBJ=$(echo "$APPS_OBJ" | jq --arg key "$ENG_ID" --argjson val "$APP_JSON" '. + {($key): $val}') @@ -2490,10 +2513,12 @@ deploy_stage_0() { echo "" echo "Configuring logging and assistant compliance settings for Gemini applications..." AUDIT_LOGS_MAP=$(terraform output -json gemini_apps_audit_logs 2>/dev/null || echo "{}") + MODEL_ARMOR_MAP=$(terraform output -json gemini_apps_model_armor 2>/dev/null || echo "{}") + MODEL_ARMOR_TEMPLATE_NAME=$(terraform output -raw model_armor_template_name 2>/dev/null || echo "") if [[ -n "$AUDIT_LOGS_MAP" && "$AUDIT_LOGS_MAP" != "{}" ]]; then ACCESS_TOKEN=$(gcloud auth print-access-token) - while IFS=$'\t' read -r ENG_ID ENABLE_AUDIT ; do + while IFS=$'\t' read -r ENG_ID ENABLE_AUDIT ENABLE_MA ; do if [[ -n "$ENG_ID" ]]; then # A. Configure Observability Config (Audit Logs) if [[ "$ENABLE_AUDIT" == "true" ]]; then @@ -2537,6 +2562,14 @@ deploy_stage_0() { MASK="displayName,webGroundingType,defaultWebGroundingToggleOff,disableLocationContext" fi + if [[ "$ENABLE_MA" == "true" && -n "$MODEL_ARMOR_TEMPLATE_NAME" && "$MODEL_ARMOR_TEMPLATE_NAME" != "null" ]]; then + echo "Enabling Model Armor template for Engine: ${ENG_ID}..." + ASSISTANT_BODY=$(echo "$BASE_JSON" | jq --arg template "$MODEL_ARMOR_TEMPLATE_NAME" '. + {customerPolicy: {modelArmorConfig: {userPromptTemplate: $template, responseTemplate: $template, failureMode: "FAIL_OPEN"}}}') + MASK="${MASK},customerPolicy" + else + ASSISTANT_BODY="$BASE_JSON" + fi + curl -s -o /dev/null -X PATCH \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ diff --git a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/model_armor.tf b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/model_armor.tf new file mode 100644 index 000000000..bb212b5ea --- /dev/null +++ b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/model_armor.tf @@ -0,0 +1,106 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +locals { + # Create Model Armor if any app has it enabled, + # and the compliance regime supports it. + create_model_armor = anytrue([for k, v in var.gemini_apps : coalesce(v.enable_model_armor, false)]) && (var.compliance_regime == "FEDRAMP_HIGH" || var.compliance_regime == "NONE") +} + +# Model Armor Template Configuration +# Complete Reference: https://docs.cloud.google.com/model-armor/reference/rest/v1/projects.locations.templates +# and https://cloud.google.com/python/docs/reference/modelarmor/latest/google.cloud.modelarmor_v1.types.Template + +resource "google_model_armor_template" "model_armor_template" { + count = local.create_model_armor ? 1 : 0 + project = var.main_project_id + location = var.geolocation + template_id = "${var.prefix}-model-armor-template" + + # Required. Filter configuration for this template. + filter_config { + # Prompt Injection and Jailbreak Filter Settings + pi_and_jailbreak_filter_settings { + filter_enforcement = "ENABLED" # Options: ENABLED, DISABLED, PI_AND_JAILBREAK_FILTER_ENFORCEMENT_UNSPECIFIED + confidence_level = "MEDIUM_AND_ABOVE" # Options: LOW_AND_ABOVE, MEDIUM_AND_ABOVE, HIGH, DETECTION_CONFIDENCE_LEVEL_UNSPECIFIED + } + + # Malicious URI Filter Settings + malicious_uri_filter_settings { + filter_enforcement = "ENABLED" # Options: ENABLED, DISABLED, MALICIOUS_URI_FILTER_ENFORCEMENT_UNSPECIFIED + } + + # Responsible AI (RAI) Filter Settings + rai_settings { + rai_filters { + filter_type = "HATE_SPEECH" # Options: SEXUALLY_EXPLICIT, HATE_SPEECH, HARASSMENT, DANGEROUS, RAI_FILTER_TYPE_UNSPECIFIED + confidence_level = "MEDIUM_AND_ABOVE" + } + rai_filters { + filter_type = "HARASSMENT" + confidence_level = "MEDIUM_AND_ABOVE" + } + rai_filters { + filter_type = "SEXUALLY_EXPLICIT" + confidence_level = "MEDIUM_AND_ABOVE" + } + rai_filters { + filter_type = "DANGEROUS" + confidence_level = "MEDIUM_AND_ABOVE" + } + } + + # Sensitive Data Protection (SDP) Settings + # Note: You can use either basic_config or advanced_config (mutually exclusive). + sdp_settings { + # Basic inspection using a fixed set of six info-types. + basic_config { + filter_enforcement = "ENABLED" # Options: ENABLED, DISABLED, SDP_BASIC_CONFIG_ENFORCEMENT_UNSPECIFIED + } + + # To use advanced SDP templates (supporting inspection and de-identification) instead of basic_config, + # comment out basic_config above and uncomment advanced_config below: + # advanced_config { + # inspect_template = "projects/YOUR_PROJECT_ID/locations/YOUR_LOCATION/inspectTemplates/YOUR_INSPECT_TEMPLATE_ID" + # deidentify_template = "projects/YOUR_PROJECT_ID/locations/YOUR_LOCATION/deidentifyTemplates/YOUR_DEIDENTIFY_TEMPLATE_ID" + # } + } + } + + # Optional. Metadata and operational settings for this template. + template_metadata { + # If true, partial detector failures should be ignored. + ignore_partial_invocation_failures = false + + # Enforcement type for Model Armor filters. + enforcement_type = "INSPECT_AND_BLOCK" # Options: ENFORCEMENT_TYPE_UNSPECIFIED (default, same as INSPECT_AND_BLOCK), INSPECT_ONLY, INSPECT_AND_BLOCK + + # Custom error code and message returned to the end user by service extensions if the user prompt trips filters. + custom_prompt_safety_error_code = 403 + custom_prompt_safety_error_message = "Your prompt was blocked by security policies." + + # Custom error code and message returned to the end user if the LLM response trips filters. + custom_llm_response_safety_error_code = 403 + custom_llm_response_safety_error_message = "The generated response was blocked by security policies." + + # Logging configuration for template CRUD operations and sanitization requests. + log_template_operations = true + log_sanitize_operations = true + + # Multi-language detection settings. + multi_language_detection { + enable_multi_language_detection = true + } + } +} diff --git a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/outputs.tf b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/outputs.tf index f408d2bb1..e26543093 100644 --- a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/outputs.tf +++ b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/outputs.tf @@ -155,3 +155,14 @@ output "gemini_apps_audit_logs" { value = { for k, v in var.gemini_apps : google_discovery_engine_search_engine.gemini_enterprise_search_engine[k].engine_id => coalesce(v.enable_audit_logs, false) } description = "A map of Engine IDs to their enable_audit_logs configuration." } + +output "gemini_apps_model_armor" { + value = { for k, v in var.gemini_apps : google_discovery_engine_search_engine.gemini_enterprise_search_engine[k].engine_id => coalesce(v.enable_model_armor, false) } + description = "A map of Engine IDs to their enable_model_armor configuration." +} + +output "model_armor_template_name" { + value = local.create_model_armor ? google_model_armor_template.model_armor_template[0].name : null + description = "The name of the Model Armor template resource." +} + diff --git a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/terraform.tfvars.sample b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/terraform.tfvars.sample index 877b9adfb..c28a8520d 100644 --- a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/terraform.tfvars.sample +++ b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/terraform.tfvars.sample @@ -105,6 +105,7 @@ gemini_apps = { "bq_data_store_keys": ["bigquery-data-store-name"], "enable_agent_sharing": false, "enable_agent_sharing_without_approval": false, - "enable_audit_logs": false + "enable_audit_logs": false, + "enable_model_armor": false } } diff --git a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/variables.tf b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/variables.tf index 7fc46936b..d9380cfb0 100644 --- a/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/variables.tf +++ b/blueprints/fedramp-high/gemini-enterprise/gemini-stage-0/variables.tf @@ -343,6 +343,7 @@ variable "gemini_apps" { enable_agent_sharing = optional(bool, false) enable_agent_sharing_without_approval = optional(bool, true) enable_audit_logs = optional(bool, false) + enable_model_armor = optional(bool, false) })) default = {} }