Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions blueprints/fedramp-high/gemini-enterprise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
37 changes: 35 additions & 2 deletions blueprints/fedramp-high/gemini-enterprise/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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[*]}")]"

Expand All @@ -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}')
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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" \
Expand Down
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}

Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
}