├── gcp-terraform ├── gcp-configuration │ ├── terraform.tfvars.example │ ├── terraform.tfvars.json │ ├── variables.tf │ └── main.tf ├── storages │ ├── outputs.tf │ ├── main.tf │ ├── terraform.tfvars.example │ ├── terraform.tfvars.json │ └── variables.tf ├── modules │ ├── management-roles │ │ ├── variables.tf │ │ └── main.tf │ ├── storage-stacks │ │ ├── pubsub-topics.tf │ │ ├── outputs.tf │ │ ├── service-accounts.tf │ │ ├── variables.tf │ │ ├── secret-manager.tf │ │ ├── main.tf │ │ ├── cloud-functions.tf │ │ └── iam-bindings.tf │ ├── scanner-stacks │ │ ├── service-accounts.tf │ │ ├── variables.tf │ │ ├── outputs.tf │ │ ├── main.tf │ │ ├── pubsub-topics.tf │ │ ├── secret-manager.tf │ │ ├── cloud-functions.tf │ │ └── iam-bindings.tf │ ├── function-auto-update-settings │ │ ├── variables.tf │ │ └── main.tf │ └── google-api │ │ ├── variables.tf │ │ └── main.tf ├── scanners │ ├── outputs.tf │ ├── terraform.tfvars.example │ ├── terraform.tfvars.json │ ├── main.tf │ └── variables.tf ├── all-in-one │ ├── outputs.tf │ ├── terraform.tfvars.example │ ├── terraform.tfvars.json │ ├── main.tf │ └── variables.tf └── docs │ ├── deployment_tutorial_scanner.md │ ├── deployment_tutorial_storage.md │ └── deployment_tutorial_all_in_one.md ├── gcp ├── common.py ├── scanner │ ├── scanner-stack-service-accounts.yaml │ ├── scanner_stack_roles.py │ ├── scanner.yaml │ ├── scanner_stack_service_accounts.py │ └── scanner.py ├── storage │ ├── storage_stack_roles.py │ ├── storage.yaml │ ├── storage_stack_service_accounts.py │ └── storage.py ├── fss-roles.yaml ├── deployment-script.sh ├── role.py ├── management_roles.py ├── docs │ ├── deployment_tutorial_scanner.md │ ├── deployment_tutorial_storage.md │ └── deployment_tutorial_all_in_one.md ├── deployment-script-storage.sh └── deployment-script-scanner.sh ├── README.md ├── .vscode └── settings.json ├── azure └── FSS-All-In-One-Template.parameters.json ├── aws ├── deployment-role-policy-for-account-scanner.json ├── deployment-role-policy.json └── FSS-All-In-One.template └── LICENSE /gcp-terraform/gcp-configuration/terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | projectID = "gcp-project-id" 2 | -------------------------------------------------------------------------------- /gcp-terraform/gcp-configuration/terraform.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectID": "" 3 | } 4 | -------------------------------------------------------------------------------- /gcp-terraform/storages/outputs.tf: -------------------------------------------------------------------------------- 1 | output "storage_stacks_outputs" { 2 | value = module.storage_stacks.storage_stacks_outputs 3 | } 4 | -------------------------------------------------------------------------------- /gcp-terraform/gcp-configuration/variables.tf: -------------------------------------------------------------------------------- 1 | variable "projectID" { 2 | type = string 3 | } 4 | 5 | variable "customRolePrefix" { 6 | type = string 7 | default = "" 8 | } 9 | -------------------------------------------------------------------------------- /gcp-terraform/modules/management-roles/variables.tf: -------------------------------------------------------------------------------- 1 | variable "projectID" { 2 | type = string 3 | } 4 | 5 | variable "customRolePrefix" { 6 | type = string 7 | default = "" 8 | } 9 | -------------------------------------------------------------------------------- /gcp/common.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | 3 | def get_prefix(context, stack): 4 | prefix = context.env['deployment'].split(f'-{stack}')[0] 5 | return prefix[:22] 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cloudone-filestorage-deployment-templates 2 | 3 | The deployment templates for Cloud One File Storage Security customers to review. 4 | 5 | > Please still use the templates hosted on S3 to deploy. 6 | -------------------------------------------------------------------------------- /gcp-terraform/scanners/outputs.tf: -------------------------------------------------------------------------------- 1 | output "scanner_stacks_outputs" { 2 | value = module.scanner_stacks.scanner_stacks_outputs 3 | } 4 | 5 | output "scanner_informations" { 6 | value = module.scanner_stacks.scanner_informations 7 | } 8 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/pubsub-topics.tf: -------------------------------------------------------------------------------- 1 | resource "google_pubsub_topic" "scan_result_topic" { 2 | for_each = local.storage_stacks 3 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scan-result-topic" 4 | } 5 | -------------------------------------------------------------------------------- /gcp-terraform/scanners/terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | projectID = "gcp-project-id" 2 | scannerStacks = { 3 | fss-scanner = { 4 | region = "gcp-region" 5 | managementServiceAccountProjectID = "gcp-project-id" 6 | managementServiceAccountID = "fss-gcp-service-account" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/outputs.tf: -------------------------------------------------------------------------------- 1 | output "storage_stacks_outputs" { 2 | value = <<-EOT 3 | ${jsonencode({ 4 | "storageStacks": [for k, v in local.storage_stacks : {"deploymentName": "${k}", "projectID": "${var.projectID}"}], 5 | })} 6 | EOT 7 | } 8 | 9 | output "management_service_accounts" { 10 | value = local.management_service_accounts 11 | } 12 | -------------------------------------------------------------------------------- /gcp-terraform/all-in-one/outputs.tf: -------------------------------------------------------------------------------- 1 | output "all_in_one_outputs" { 2 | value = <<-EOT 3 | [%{ for scanner, v in var.scannerStacks ~}{"deploymentName":"${scanner}", "projectID": "${var.projectID}", "storageStacks": [%{ for storage, v in var.storageStacks ~}%{ if v.scanner == scanner ~}{"deploymentName":"${storage}", "projectID":"${var.projectID}"},%{ endif ~}%{ endfor ~}]},%{ endfor ~}] 4 | EOT 5 | } 6 | -------------------------------------------------------------------------------- /gcp-terraform/scanners/terraform.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectID": "", 3 | "functionAutoUpdate": true, 4 | "scannerStacks": { 5 | "": { 6 | "region": "", 7 | "managementServiceAccountProjectID": "", 8 | "managementServiceAccountID": "" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | "*.template": "yaml" 4 | }, 5 | "yaml.customTags": [ 6 | "!And", 7 | "!If", 8 | "!Not", 9 | "!Equals", 10 | "!Or", 11 | "!FindInMap sequence", 12 | "!Base64", 13 | "!Cidr", 14 | "!Ref", 15 | "!Sub", 16 | "!GetAtt", 17 | "!GetAZs", 18 | "!ImportValue", 19 | "!Select", 20 | "!Select sequence", 21 | "!Split", 22 | "!Join sequence" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/service-accounts.tf: -------------------------------------------------------------------------------- 1 | resource "google_service_account" "scanner_service_account" { 2 | for_each = local.scanner_stacks 3 | account_id = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scan-sa" 4 | display_name = "Service Account for Scanner Cloud Function" 5 | } 6 | 7 | resource "google_service_account" "pattern_updater_service_account" { 8 | for_each = local.scanner_stacks 9 | account_id = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-upd-sa" 10 | display_name = "Service Account for Pattern Updater Function" 11 | } 12 | -------------------------------------------------------------------------------- /gcp-terraform/gcp-configuration/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | google = { 4 | source = "hashicorp/google" 5 | version = "~> 5.38.0" 6 | } 7 | } 8 | 9 | required_version = ">= 1.2.0" 10 | } 11 | 12 | provider "google" { 13 | project = var.projectID 14 | } 15 | 16 | module "google_api"{ 17 | source = "../modules/google-api" 18 | projectID = var.projectID 19 | customRolePrefix = var.customRolePrefix 20 | } 21 | 22 | module "management_roles"{ 23 | source = "../modules/management-roles" 24 | projectID = var.projectID 25 | customRolePrefix = var.customRolePrefix 26 | } 27 | -------------------------------------------------------------------------------- /gcp-terraform/modules/function-auto-update-settings/variables.tf: -------------------------------------------------------------------------------- 1 | variable "projectID" { 2 | type = string 3 | description = "The GCP project ID you want to apply the deployment to." 4 | default = "" 5 | } 6 | 7 | variable "customRolePrefix" { 8 | type = string 9 | default = "" 10 | } 11 | 12 | variable "managementServiceAccounts" { 13 | description = "The list of management service accounts" 14 | type = list(string) 15 | default = [] 16 | } 17 | 18 | variable "functionAutoUpdate" { 19 | type = bool 20 | description = "Enable or disable automatic remote code update." 21 | default = true 22 | } 23 | -------------------------------------------------------------------------------- /gcp-terraform/scanners/main.tf: -------------------------------------------------------------------------------- 1 | module "scanner_stacks" { 2 | source = "../modules/scanner-stacks" 3 | customRolePrefix = var.customRolePrefix 4 | functionAutoUpdate = var.functionAutoUpdate 5 | projectID = var.projectID 6 | packageURL = var.packageURL 7 | scannerStacks = var.scannerStacks 8 | } 9 | 10 | module "function-auto-update-settings" { 11 | source = "../modules/function-auto-update-settings" 12 | functionAutoUpdate = var.functionAutoUpdate 13 | projectID = var.projectID 14 | customRolePrefix = var.customRolePrefix 15 | managementServiceAccounts = toset(module.scanner_stacks.management_service_accounts) 16 | } 17 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/variables.tf: -------------------------------------------------------------------------------- 1 | variable "scannerStacks" { 2 | type = map(object({ 3 | region = string 4 | managementServiceAccountProjectID = string 5 | managementServiceAccountID = string 6 | })) 7 | } 8 | 9 | variable "projectID" { 10 | type = string 11 | default = "" 12 | } 13 | 14 | variable "customRolePrefix" { 15 | type = string 16 | default = "" 17 | } 18 | 19 | variable "packageURL" { 20 | type = string 21 | default = "https://file-storage-security.s3.amazonaws.com/latest/cloud-functions/" 22 | } 23 | 24 | variable "functionAutoUpdate" { 25 | type = bool 26 | default = true 27 | } 28 | -------------------------------------------------------------------------------- /gcp-terraform/modules/google-api/variables.tf: -------------------------------------------------------------------------------- 1 | variable "projectID" { 2 | type = string 3 | } 4 | 5 | variable "customRolePrefix" { 6 | type = string 7 | default = "" 8 | } 9 | 10 | variable "gcpServicesList" { 11 | description = "Google APIs need to be enabled" 12 | type = set(string) 13 | default = [ 14 | "cloudbuild.googleapis.com", 15 | "deploymentmanager.googleapis.com", 16 | "cloudfunctions.googleapis.com", 17 | "pubsub.googleapis.com", 18 | "cloudresourcemanager.googleapis.com", 19 | "cloudscheduler.googleapis.com", 20 | "iamcredentials.googleapis.com", 21 | "iam.googleapis.com", 22 | "secretmanager.googleapis.com" 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /gcp-terraform/storages/main.tf: -------------------------------------------------------------------------------- 1 | module "storage_stacks" { 2 | source = "../modules/storage-stacks" 3 | customRolePrefix = var.customRolePrefix 4 | functionAutoUpdate = var.functionAutoUpdate 5 | projectID = var.projectID 6 | packageURL = var.packageURL 7 | storageStacks = var.storageStacks 8 | scanner_service_accounts = null 9 | scanner_pubsub_topics = null 10 | } 11 | 12 | module "function-auto-update-settings" { 13 | source = "../modules/function-auto-update-settings" 14 | functionAutoUpdate = var.functionAutoUpdate 15 | projectID = var.projectID 16 | customRolePrefix = var.customRolePrefix 17 | managementServiceAccounts = toset(module.storage_stacks.management_service_accounts) 18 | } 19 | -------------------------------------------------------------------------------- /gcp-terraform/storages/terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | projectID = "gcp-project-id" 2 | storageStacks = { 3 | fss-aio-storage = { 4 | scanner = null 5 | scanningBucketName = "scanning-cloud-storage-bucket-name", 6 | region = "gcp-region" 7 | managementServiceAccountProjectID = "cloud-one-service-account-gcp-project-id" 8 | managementServiceAccountID = "cloud-one-service-account-id" 9 | scannerProjectID = "fss-scanner-project-id" 10 | scannerTopic = "fss-scanner-topic-name" 11 | scannerServiceAccountID = "fss-scanner-service-account" 12 | reportObjectKey = false 13 | disableScanningBucketIAMBinding = false 14 | objectFilterPrefix = "" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /gcp-terraform/storages/terraform.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectID": "", 3 | "functionAutoUpdate": true, 4 | "storageStacks": { 5 | "": { 6 | "scanningBucketName": "", 7 | "region": "", 8 | "managementServiceAccountProjectID": "", 9 | "managementServiceAccountID": "", 10 | "scannerProjectID": "", 11 | "scannerTopic": "", 12 | "scannerServiceAccountID": "", 13 | "reportObjectKey": false, 14 | "disableScanningBucketIAMBinding": false, 15 | "scanner": null, 16 | "objectFilterPrefix": "" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/service-accounts.tf: -------------------------------------------------------------------------------- 1 | resource "google_service_account" "bucket_listener_service_account" { 2 | for_each = local.storage_stacks 3 | account_id = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-bl-sa" 4 | display_name = "Service Account for Bucket Listener Cloud Function" 5 | } 6 | 7 | resource "google_service_account" "post_action_tag_service_account" { 8 | for_each = local.storage_stacks 9 | account_id = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-pat-sa" 10 | display_name = "Service Account for PostAction Tag Cloud Function" 11 | } 12 | 13 | 14 | data "google_service_account" "bucket_listener_service_accounts" { 15 | for_each = local.storage_stacks 16 | account_id = google_service_account.bucket_listener_service_account[each.key].id 17 | } 18 | -------------------------------------------------------------------------------- /gcp/scanner/scanner-stack-service-accounts.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | 3 | imports: 4 | - path: ../common.py 5 | name: common.py 6 | - path: ../management_roles.py 7 | name: management_roles.py 8 | - path: ../role.py 9 | name: role.py 10 | - path: scanner_stack_service_accounts.py 11 | 12 | resources: 13 | - name: scanner-stack-service-accounts 14 | type: scanner_stack_service_accounts.py 15 | properties: 16 | managementServiceAccountID: 17 | 18 | outputs: 19 | - name: scannerServiceAccountID 20 | value: $(ref.scanner-stack-service-accounts.scannerServiceAccountID) 21 | - name: patternUpdaterServiceAccountID 22 | value: $(ref.scanner-stack-service-accounts.patternUpdaterServiceAccountID) 23 | - name: scannerProjectID 24 | value: $(ref.scanner-stack-service-accounts.scannerProjectID) 25 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/outputs.tf: -------------------------------------------------------------------------------- 1 | output "scanner_stacks_outputs" { 2 | value = <<-EOT 3 | ${jsonencode({ 4 | "scannerStacks": [for k, v in local.scanner_stacks : {"deploymentName": "${k}", "projectID": "${var.projectID}"}], 5 | })} 6 | EOT 7 | } 8 | 9 | output "scanner_informations" { 10 | value = <<-EOT 11 | [%{ for k, v in local.scanner_stacks ~}{"deploymentName":"${k}", "projectID": "${var.projectID}", "scannerServiceAccountID": "${google_service_account.scanner_service_account[k].account_id}", "scannerTopic": "${google_pubsub_topic.scanner_topic[k].name}" }",%{ endfor ~}] 12 | EOT 13 | } 14 | 15 | output "scanner_service_accounts" { 16 | value = google_service_account.scanner_service_account 17 | } 18 | 19 | output "scanner_pubsub_topics" { 20 | value = google_pubsub_topic.scanner_topic 21 | } 22 | 23 | output "management_service_accounts" { 24 | value = local.management_service_accounts 25 | } 26 | -------------------------------------------------------------------------------- /gcp-terraform/all-in-one/terraform.tfvars.example: -------------------------------------------------------------------------------- 1 | projectID = "gcp-project-id" 2 | scannerStacks = { 3 | fss-aio-scanner = { 4 | region = "gcp-region" 5 | managementServiceAccountProjectID = "cloud-one-service-account-gcp-project-id" 6 | managementServiceAccountID = "cloud-one-service-account-id" 7 | } 8 | } 9 | storageStacks = { 10 | fss-aio-storage = { 11 | scanner = "fss-aio-scanner " 12 | scanningBucketName = "scanning-cloud-storage-bucket-name", 13 | region = "gcp-region" 14 | managementServiceAccountProjectID = "cloud-one-service-account-gcp-project-id" 15 | managementServiceAccountID = "cloud-one-service-account-id" 16 | scannerProjectID = null 17 | scannerTopic = null 18 | scannerServiceAccountID = null 19 | reportObjectKey = false 20 | disableScanningBucketIAMBinding = false 21 | objectFilterPrefix = "" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /azure/FSS-All-In-One-Template.parameters.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", 3 | "contentVersion": "1.0.0.0", 4 | "parameters": { 5 | "FileStorageSecurityServicePrincipalID": { 6 | "value": "" 7 | }, 8 | "CloudOneRegion": { 9 | "value": "us-1" 10 | }, 11 | "ScannerStackResourceGroup": { 12 | "value": "Scanner-TM-FileStorageSecurity" 13 | }, 14 | "StorageStackResourceGroup": { 15 | "value": "Storage-TM-FileStorageSecurity" 16 | }, 17 | "BlobStorageAccountResourceID": { 18 | "value": "" 19 | }, 20 | "BlobSystemTopicExist": { 21 | "value": "No" 22 | }, 23 | "BlobSystemTopicName": { 24 | "value": "BlobEventTopic" 25 | }, 26 | "UpdateScanResultToBlobMetadata": { 27 | "value": "Yes" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /gcp/storage/storage_stack_roles.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import role 3 | 4 | resources = [] 5 | outputs = [] 6 | 7 | BUCKET_LISTENER_ROLE = 'trend-micro-fss-bucket-listener-role' 8 | POST_ACTION_TAG_ROLE = 'trend-micro-fss-post-action-tag-role' 9 | 10 | roles = { 11 | BUCKET_LISTENER_ROLE: { 12 | 'name': BUCKET_LISTENER_ROLE, 13 | 'key': 'fssBucketListenerRoleID', 14 | 'permissions': [ 15 | 'iam.serviceAccounts.signBlob' 16 | ] 17 | }, 18 | POST_ACTION_TAG_ROLE: { 19 | 'name': POST_ACTION_TAG_ROLE, 20 | 'key': 'fssPostActionTagRoleID', 21 | 'permissions': [ 22 | 'storage.objects.get', 23 | 'storage.objects.update' 24 | ] 25 | } 26 | } 27 | 28 | def get_role(role_name): 29 | return roles[role_name] 30 | 31 | def generate_config(context): 32 | """ Entry point for the deployment resources. """ 33 | 34 | return role.create_roles(roles.values()) 35 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/variables.tf: -------------------------------------------------------------------------------- 1 | variable "storageStacks" { 2 | type = map(object({ 3 | scanner = string 4 | scannerProjectID = string 5 | scannerTopic = string 6 | scannerServiceAccountID = string 7 | scanningBucketName = string 8 | region = string 9 | managementServiceAccountProjectID = string 10 | managementServiceAccountID = string 11 | reportObjectKey = string 12 | disableScanningBucketIAMBinding = bool 13 | objectFilterPrefix = string 14 | })) 15 | } 16 | 17 | variable "projectID" { 18 | type = string 19 | default = "" 20 | } 21 | 22 | variable "customRolePrefix" { 23 | type = string 24 | default = "" 25 | } 26 | 27 | variable "packageURL" { 28 | type = string 29 | default = "https://file-storage-security.s3.amazonaws.com/latest/cloud-functions/" 30 | } 31 | 32 | variable "functionAutoUpdate" { 33 | type = bool 34 | default = true 35 | } 36 | 37 | variable "scanner_service_accounts" {} 38 | variable "scanner_pubsub_topics" {} 39 | -------------------------------------------------------------------------------- /gcp-terraform/all-in-one/terraform.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "projectID": "", 3 | "functionAutoUpdate": true, 4 | "scannerStacks": { 5 | "": { 6 | "region": "", 7 | "managementServiceAccountProjectID": "", 8 | "managementServiceAccountID": "" 9 | } 10 | }, 11 | "storageStacks": { 12 | "": { 13 | "scanner": "", 14 | "scanningBucketName": "", 15 | "region": "", 16 | "managementServiceAccountProjectID": "", 17 | "managementServiceAccountID": "", 18 | "scannerProjectID": null, 19 | "scannerTopic": null, 20 | "scannerServiceAccountID": null, 21 | "reportObjectKey": false, 22 | "disableScanningBucketIAMBinding": false, 23 | "objectFilterPrefix": "" 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /gcp/scanner/scanner_stack_roles.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import role 3 | 4 | resources = [] 5 | outputs = [] 6 | 7 | PATTERN_UPDATE_ROLE = 'trend-micro-fss-pattern-update-role' 8 | GET_PATTERN_UPDATE_SCANNER_ROLE = 'trend-micro-fss-get-pattern-update-scanner-role' 9 | 10 | roles = { 11 | PATTERN_UPDATE_ROLE: { 12 | 'name': PATTERN_UPDATE_ROLE, 13 | 'key': 'fssPatternUpdaterRoleID', 14 | 'permissions': [ 15 | 'storage.objects.create', 16 | 'storage.objects.delete', 17 | 'storage.objects.get', 18 | 'storage.objects.list', 19 | 'storage.objects.update' 20 | ] 21 | }, 22 | GET_PATTERN_UPDATE_SCANNER_ROLE: { 23 | 'name': GET_PATTERN_UPDATE_SCANNER_ROLE, 24 | 'key': 'fssPatternUpdateScannerRoleID', 25 | 'permissions': [ 26 | 'storage.objects.get', 27 | 'storage.objects.list', 28 | ] 29 | } 30 | } 31 | 32 | def generate_config(context): 33 | """ Entry point for the deployment resources. """ 34 | 35 | return role.create_roles(roles.values()) 36 | -------------------------------------------------------------------------------- /gcp-terraform/all-in-one/main.tf: -------------------------------------------------------------------------------- 1 | provider "google" { 2 | project = var.projectID 3 | } 4 | 5 | module "scanner_stacks" { 6 | source = "../modules/scanner-stacks" 7 | customRolePrefix = var.customRolePrefix 8 | functionAutoUpdate = var.functionAutoUpdate 9 | projectID = var.projectID 10 | packageURL = var.packageURL 11 | scannerStacks = var.scannerStacks 12 | } 13 | 14 | module "storage_stacks" { 15 | source = "../modules/storage-stacks" 16 | customRolePrefix = var.customRolePrefix 17 | functionAutoUpdate = var.functionAutoUpdate 18 | projectID = var.projectID 19 | packageURL = var.packageURL 20 | storageStacks = var.storageStacks 21 | scanner_service_accounts = module.scanner_stacks.scanner_service_accounts 22 | scanner_pubsub_topics = module.scanner_stacks.scanner_pubsub_topics 23 | } 24 | 25 | module "function-auto-update-settings" { 26 | source = "../modules/function-auto-update-settings" 27 | customRolePrefix = var.customRolePrefix 28 | functionAutoUpdate = var.functionAutoUpdate 29 | projectID = var.projectID 30 | managementServiceAccounts = toset(concat(module.scanner_stacks.management_service_accounts, module.storage_stacks.management_service_accounts)) 31 | } 32 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/main.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_providers { 4 | google = { 5 | source = "hashicorp/google" 6 | version = "~> 5.38.0" 7 | } 8 | } 9 | required_version = ">= 1.2.0" 10 | } 11 | 12 | provider "google" { 13 | project = var.projectID 14 | } 15 | 16 | resource "random_id" "stack_id" { 17 | for_each = local.scanner_stacks 18 | keepers = { 19 | # Generate a new suffix each time we switch to a new deployment 20 | stack_id = each.key 21 | } 22 | 23 | byte_length = 2 24 | } 25 | 26 | locals { 27 | packageURL = var.packageURL 28 | custom_role_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${var.customRolePrefix}_" 29 | management_service_accounts = [ 30 | for v in data.google_service_account.management_service_account: "serviceAccount:${v.email}" 31 | ] 32 | scanner_stacks = { 33 | for deployment_name, v in var.scannerStacks : deployment_name => { 34 | region = v.region 35 | managementServiceAccountProjectID = v.managementServiceAccountProjectID 36 | managementServiceAccountID = v.managementServiceAccountID 37 | prefix = substr(trimsuffix(deployment_name, "-scanner"), 0, 17) 38 | } 39 | } 40 | } 41 | 42 | data "google_project" "project" {} 43 | -------------------------------------------------------------------------------- /gcp-terraform/scanners/variables.tf: -------------------------------------------------------------------------------- 1 | variable "scannerStacks" { 2 | type = map(object({ 3 | region = string 4 | managementServiceAccountProjectID = string 5 | managementServiceAccountID = string 6 | })) 7 | 8 | description = "File Storage Security Scanner Stacks" 9 | 10 | validation { 11 | condition = ( 12 | !contains([for s in var.scannerStacks : ( 13 | (length(keys(var.scannerStacks)) <= 20) && 14 | (lookup(s,"region", null) == null ? false : true) && 15 | (lookup(s,"managementServiceAccountProjectID", null) == null ? false : true) && 16 | (lookup(s,"managementServiceAccountID", null) == null ? false : true) 17 | )], false) 18 | ) 19 | error_message = "Input validation failed." 20 | } 21 | } 22 | 23 | variable "projectID" { 24 | type = string 25 | description = "The GCP project ID you want to apply the deployment to." 26 | default = "" 27 | } 28 | 29 | variable "customRolePrefix" { 30 | type = string 31 | default = "" 32 | } 33 | 34 | variable "packageURL" { 35 | type = string 36 | description = "The GCP Cloud Function package location." 37 | default = "https://file-storage-security.s3.amazonaws.com/latest/cloud-functions/" 38 | } 39 | 40 | variable "functionAutoUpdate" { 41 | type = bool 42 | description = "Enable or disable automatic remote code update." 43 | default = true 44 | } 45 | -------------------------------------------------------------------------------- /gcp-terraform/modules/function-auto-update-settings/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | custom_role_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${var.customRolePrefix}_" 3 | } 4 | 5 | resource "time_static" "function_update_iam_binding_time" {} 6 | 7 | resource "google_project_iam_binding" "function_update_iam_binding" { 8 | count = var.functionAutoUpdate ? 1 : 0 9 | project = var.projectID 10 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_source_code_set_role" 11 | 12 | members = var.managementServiceAccounts 13 | 14 | condition { 15 | title = "FSS Stack Function Update Binding ${time_static.function_update_iam_binding_time.rfc3339}" // Preventing the binding is removed by the other TF deployments in the same project 16 | expression = "" 17 | } 18 | } 19 | 20 | resource "google_service_account_iam_binding" "appspot_service_account_iam_binding" { 21 | count = var.functionAutoUpdate ? 1 : 0 22 | service_account_id = "projects/${var.projectID}/serviceAccounts/${var.projectID}@appspot.gserviceaccount.com" 23 | role = "roles/iam.serviceAccountUser" 24 | 25 | members = var.managementServiceAccounts 26 | 27 | condition { 28 | title = "FSS Stack Function Update Binding ${time_static.function_update_iam_binding_time.rfc3339}" // Preventing the binding is removed by the other TF deployments in the same project 29 | expression = "" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /gcp-terraform/modules/google-api/main.tf: -------------------------------------------------------------------------------- 1 | data "google_project" "project" {} 2 | 3 | locals { 4 | custom_role_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${var.customRolePrefix}_" 5 | custom_role_title_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${replace(var.customRolePrefix, "_", "-")}-" 6 | } 7 | 8 | resource "google_project_service" "gcp_services" { 9 | project = var.projectID 10 | for_each = var.gcpServicesList 11 | service = each.value 12 | 13 | disable_on_destroy = false 14 | } 15 | 16 | resource "google_project_iam_custom_role" "trend_micro_fss_cloudservices_api_role" { 17 | project = var.projectID 18 | 19 | role_id = "${local.custom_role_prefix}trend_micro_fss_cloudservices_api_role" 20 | description = "Trend Micro File Storage Security Google APIs Service Agent role" 21 | title = "${local.custom_role_title_prefix}trend-micro-fss-cloudservices-api-role" 22 | permissions = [ 23 | "cloudfunctions.functions.setIamPolicy", 24 | "iam.roles.create", 25 | "iam.serviceAccounts.setIamPolicy", 26 | "pubsub.topics.setIamPolicy", 27 | "resourcemanager.projects.setIamPolicy" 28 | ] 29 | } 30 | 31 | resource "google_project_iam_binding" "iam_binding_cloudservice_agent" { 32 | project = var.projectID 33 | role = "projects/${var.projectID}/roles/${google_project_iam_custom_role.trend_micro_fss_cloudservices_api_role.role_id}" 34 | 35 | members = [ 36 | "serviceAccount:${data.google_project.project.number}@cloudservices.gserviceaccount.com", 37 | ] 38 | 39 | depends_on = [ 40 | data.google_project.project, 41 | google_project_iam_custom_role.trend_micro_fss_cloudservices_api_role 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /gcp/fss-roles.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | 3 | imports: 4 | - path: management_roles.py 5 | - path: role.py 6 | - path: storage/storage_stack_roles.py 7 | name: storage_stack_roles.py 8 | - path: scanner/scanner_stack_roles.py 9 | name: scanner_stack_roles.py 10 | 11 | resources: 12 | - name: scanner-stack-roles 13 | type: scanner_stack_roles.py 14 | - name: storage-stack-roles 15 | type: storage_stack_roles.py 16 | - name: management-roles 17 | type: management_roles.py 18 | 19 | outputs: 20 | - name: bucketListenerRoleID 21 | value: $(ref.storage-stack-roles.fssBucketListenerRoleID) 22 | - name: cloudFunctionManagementRoleID 23 | value: $(ref.management-roles.fssCloudFunctionManagementRoleID) 24 | - name: deploymentManagementRoleID 25 | value: $(ref.management-roles.fssDeploymentManagementRoleID) 26 | - name: logManagementRoleID 27 | value: $(ref.management-roles.fssLogManagementRoleID) 28 | - name: postActionTagRoleID 29 | value: $(ref.storage-stack-roles.fssPostActionTagRoleID) 30 | - name: pubsubManagementRoleID 31 | value: $(ref.management-roles.fssPubsubManagementRoleID) 32 | - name: secretManagementRoleID 33 | value: $(ref.management-roles.fssSecretManagementRoleID) 34 | - name: serviceAccountManagementRoleID 35 | value: $(ref.management-roles.fssServiceAccountManagementRoleID) 36 | - name: patternUpdaterRoleID 37 | value: $(ref.scanner-stack-roles.fssPatternUpdaterRoleID) 38 | - name: patternUpdateScannerRoleID 39 | value: $(ref.scanner-stack-roles.fssPatternUpdateScannerRoleID) 40 | - name: sourceCodeSetRoleID 41 | value: $(ref.management-roles.fssSourceCodeSetRoleID) 42 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/secret-manager.tf: -------------------------------------------------------------------------------- 1 | resource "google_secret_manager_secret" "storage_outputs_secret" { 2 | for_each = local.storage_stacks 3 | secret_id = "${each.key}-storage-output-secrets" 4 | 5 | replication { 6 | user_managed { 7 | replicas { 8 | location = each.value.region 9 | } 10 | } 11 | } 12 | } 13 | 14 | resource "google_secret_manager_secret_version" "storage_outputs_secret_version" { 15 | for_each = local.storage_stacks 16 | secret = google_secret_manager_secret.storage_outputs_secret[each.key].id 17 | 18 | secret_data = jsonencode({ 19 | region = each.value.region 20 | scanningBucketName = each.value.scanningBucketName 21 | storageProjectID = var.projectID 22 | scanResultTopic = google_pubsub_topic.scan_result_topic[each.key].name 23 | bucketListenerFunctionName = "projects/${google_cloudfunctions_function.bucket_listener_function[each.key].project}/locations/${google_cloudfunctions_function.bucket_listener_function[each.key].region}/functions/${google_cloudfunctions_function.bucket_listener_function[each.key].name}" 24 | postScanActionTagFunctionName = "projects/${google_cloudfunctions_function.post_action_tag_function[each.key].project}/locations/${google_cloudfunctions_function.post_action_tag_function[each.key].region}/functions/${google_cloudfunctions_function.post_action_tag_function[each.key].name}" 25 | bucketListenerServiceAccountID = google_service_account.bucket_listener_service_account[each.key].account_id 26 | postActionTagServiceAccountID = google_service_account.post_action_tag_service_account[each.key].account_id 27 | functionAutoUpdate = var.functionAutoUpdate 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /gcp-terraform/storages/variables.tf: -------------------------------------------------------------------------------- 1 | variable "storageStacks" { 2 | type = map(object({ 3 | scanner = string 4 | scannerProjectID = string 5 | scannerTopic = string 6 | scannerServiceAccountID = string 7 | scanningBucketName = string 8 | region = string 9 | managementServiceAccountProjectID: string 10 | managementServiceAccountID = string 11 | reportObjectKey = bool 12 | disableScanningBucketIAMBinding = bool 13 | objectFilterPrefix = optional(string) 14 | })) 15 | 16 | description = "File Storage Security Storage Stacks" 17 | 18 | validation { 19 | condition = ( 20 | !contains([for s in var.storageStacks : ( 21 | (length(keys(var.storageStacks))) <= 20 && 22 | (lookup(s,"region", null) == null ? false : true) && 23 | (lookup(s,"scanningBucketName", null) == null ? false : true) && 24 | (lookup(s,"managementServiceAccountID", null) == null ? false : true) && 25 | (lookup(s,"managementServiceAccountProjectID", null) == null ? false : true) 26 | )], false) 27 | ) 28 | error_message = "Input validation failed." 29 | } 30 | } 31 | 32 | variable "projectID" { 33 | type = string 34 | description = "The GCP project ID you want to apply the deployment to." 35 | default = "" 36 | } 37 | 38 | variable "customRolePrefix" { 39 | type = string 40 | default = "" 41 | } 42 | 43 | variable "packageURL" { 44 | type = string 45 | description = "The GCP Cloud Function package location." 46 | default = "https://file-storage-security.s3.amazonaws.com/latest/cloud-functions/" 47 | } 48 | 49 | variable "functionAutoUpdate" { 50 | type = bool 51 | description = "Enable or disable automatic remote code update." 52 | default = true 53 | } 54 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/pubsub-topics.tf: -------------------------------------------------------------------------------- 1 | resource "google_pubsub_topic" "scanner_topic" { 2 | for_each = local.scanner_stacks 3 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scanner-topic" 4 | 5 | depends_on = [ 6 | google_service_account.scanner_service_account 7 | ] 8 | } 9 | 10 | resource "google_pubsub_topic" "pattern_updater_topic" { 11 | for_each = local.scanner_stacks 12 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-pattern-updater-topic" 13 | 14 | depends_on = [ 15 | google_service_account.pattern_updater_service_account 16 | ] 17 | } 18 | 19 | resource "google_pubsub_topic" "scanner_topic_dlt" { 20 | for_each = local.scanner_stacks 21 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scanner-topic-dlt" 22 | } 23 | 24 | resource "null_resource" "add_gcp_scanner_topic_dlt" { 25 | for_each = local.scanner_stacks 26 | provisioner "local-exec" { 27 | command = <<-EOT 28 | SUBSCRIPTIONS=$(gcloud pubsub topics list-subscriptions ${google_pubsub_topic.scanner_topic[each.key].name}) 29 | 30 | SCANNER_SUBSCRIPTION_ID=$${SUBSCRIPTIONS#*/*/*/} 31 | 32 | gcloud pubsub subscriptions update $SCANNER_SUBSCRIPTION_ID \ 33 | --dead-letter-topic=${google_pubsub_topic.scanner_topic_dlt[each.key].name} \ 34 | --max-delivery-attempts=5 35 | 36 | gcloud pubsub subscriptions add-iam-policy-binding $SCANNER_SUBSCRIPTION_ID \ 37 | --member="serviceAccount:service-${data.google_project.project.number}@gcp-sa-pubsub.iam.gserviceaccount.com"\ 38 | --role="roles/pubsub.subscriber" 39 | EOT 40 | } 41 | 42 | depends_on = [ 43 | google_pubsub_topic.scanner_topic, 44 | google_cloudfunctions_function.scanner_function, 45 | google_pubsub_topic.scanner_topic_dlt 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | google = { 4 | source = "hashicorp/google" 5 | version = "~> 5.38.0" 6 | } 7 | } 8 | required_version = ">= 1.2.0" 9 | } 10 | 11 | provider "google" { 12 | project = var.projectID 13 | } 14 | 15 | resource "random_id" "stack_id" { 16 | for_each = local.storage_stacks 17 | keepers = { 18 | # Generate a new suffix each time we switch to a new deployment 19 | stack_id = each.key 20 | } 21 | 22 | byte_length = 2 23 | } 24 | 25 | locals { 26 | packageURL = var.packageURL 27 | custom_role_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${var.customRolePrefix}_" 28 | management_service_accounts = [ 29 | for v in data.google_service_account.management_service_account: "serviceAccount:${v.email}" 30 | ] 31 | storage_stacks = { 32 | for deployment_name, v in var.storageStacks : deployment_name => { 33 | scanner = v.scanner == null ? null : v.scanner 34 | scannerProjectID = v.scannerProjectID == null ? null : v.scannerProjectID 35 | scannerServiceAccountID = v.scannerServiceAccountID == null ? null : v.scannerServiceAccountID 36 | scannerTopic = v.scannerTopic == null ? null : v.scannerTopic 37 | scanningBucketName = v.scanningBucketName 38 | region = v.region 39 | managementServiceAccountProjectID = v.managementServiceAccountProjectID 40 | managementServiceAccountID = v.managementServiceAccountID 41 | reportObjectKey = v.reportObjectKey ? "True" : "False" 42 | disableScanningBucketIAMBinding = v.disableScanningBucketIAMBinding 43 | prefix = substr(trimsuffix(deployment_name, "-storage"), 0, 17) 44 | objectFilterPrefix = v.objectFilterPrefix == null ? "" : v.objectFilterPrefix 45 | } 46 | } 47 | } 48 | 49 | data "google_project" "project" {} 50 | -------------------------------------------------------------------------------- /gcp/scanner/scanner.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | 3 | imports: 4 | - path: ../common.py 5 | name: common.py 6 | - path: ../management_roles.py 7 | name: management_roles.py 8 | - path: ../role.py 9 | name: role.py 10 | - path: scanner.py 11 | - path: scanner_stack_service_accounts.py 12 | - path: scanner_stack_roles.py 13 | 14 | resources: 15 | - name: scanner-stack-service-accounts 16 | type: scanner_stack_service_accounts.py 17 | properties: 18 | managementServiceAccountID: 19 | 20 | - name: scanner-stack 21 | type: scanner.py 22 | properties: 23 | deploymentName: 24 | region: 25 | artifactBucket: 26 | scannerSecretsName: 27 | managementServiceAccountID: 28 | functionAutoUpdate: 29 | 30 | outputs: 31 | - name: region 32 | value: $(ref.scanner-stack.region) 33 | - name: scannerProjectID 34 | value: $(ref.scanner-stack.scannerProjectID) 35 | - name: scannerTopic 36 | value: $(ref.scanner-stack.scannerTopic) 37 | - name: scannerTopicDLT 38 | value: $(ref.scanner-stack.scannerTopicDLT) 39 | - name: scannerFunctionName 40 | value: $(ref.scanner-stack.scannerFunctionName) 41 | - name: patternUpdaterFunctionName 42 | value: $(ref.scanner-stack.patternUpdaterFunctionName) 43 | - name: scannerDLTFunctionName 44 | value: $(ref.scanner-stack.scannerDLTFunctionName) 45 | - name: scannerServiceAccountID 46 | value: $(ref.scanner-stack-service-accounts.scannerServiceAccountID) 47 | - name: scannerSecretsName 48 | value: $(ref.scanner-stack.scannerSecretsName) 49 | - name: patternUpdateSchedulerJobName 50 | value: $(ref.scanner-stack.patternUpdateSchedulerJobName) 51 | - name: patternUpdateBucket 52 | value: $(ref.scanner-stack.patternUpdateBucket) 53 | - name: functionAutoUpdate 54 | value: $(ref.scanner-stack.functionAutoUpdate) 55 | -------------------------------------------------------------------------------- /gcp/deployment-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | while getopts s:d:r:u:k:m:c:a:f: args 5 | do 6 | case "${args}" in 7 | s) SCANNING_BUCKET_NAME=${OPTARG};; 8 | d) DEPLOYMENT_NAME_PREFIX=${OPTARG};; 9 | r) REGION=${OPTARG};; 10 | u) PACKAGE_URL=${OPTARG};; 11 | k) REPORT_OBJECT_KEY=${OPTARG};; 12 | m) MANAGEMENT_SERVICE_ACCOUNT=${OPTARG};; 13 | c) CLOUD_ONE_REGION=${OPTARG};; 14 | a) CLOUD_ONE_ACCOUNT=${OPTARG};; # deprecated 15 | f) FUNCTION_AUTO_UPDATE=${OPTARG};; 16 | esac 17 | done 18 | 19 | DEPLOYMENT_NAME_SCANNER=$DEPLOYMENT_NAME_PREFIX'-scanner' 20 | DEPLOYMENT_NAME_STORAGE=$DEPLOYMENT_NAME_PREFIX'-storage' 21 | 22 | if [ -z "$PACKAGE_URL" ]; then 23 | PACKAGE_URL='https://file-storage-security.s3.amazonaws.com/latest/' 24 | fi 25 | 26 | if [ -z "$REPORT_OBJECT_KEY" ]; then 27 | REPORT_OBJECT_KEY='False' 28 | else 29 | REPORT_OBJECT_KEY=$(echo $REPORT_OBJECT_KEY | tr '[:upper:]' '[:lower:]') 30 | REPORT_OBJECT_KEY=$(echo ${REPORT_OBJECT_KEY:0:1} | tr '[a-z]' '[A-Z]')${REPORT_OBJECT_KEY:1} 31 | fi 32 | 33 | if [ -z "$CLOUD_ONE_REGION" ]; then 34 | CLOUD_ONE_REGION='us-1' 35 | fi 36 | 37 | if [ -z "$FUNCTION_AUTO_UPDATE" ]; then 38 | FUNCTION_AUTO_UPDATE='True' 39 | fi 40 | 41 | if [ ! -z "$CLOUD_ONE_ACCOUNT" ]; then 42 | echo "Option -a has deprecated" 43 | fi 44 | 45 | bash deployment-script-scanner.sh -d $DEPLOYMENT_NAME_SCANNER -r $REGION -m $MANAGEMENT_SERVICE_ACCOUNT -u $PACKAGE_URL -c $CLOUD_ONE_REGION -f $FUNCTION_AUTO_UPDATE 46 | 47 | bash deployment-script-storage.sh -s $SCANNING_BUCKET_NAME -d $DEPLOYMENT_NAME_STORAGE -r $REGION -m $MANAGEMENT_SERVICE_ACCOUNT -i "$(cat $DEPLOYMENT_NAME_SCANNER-info.json)" -u $PACKAGE_URL -k $REPORT_OBJECT_KEY -f $FUNCTION_AUTO_UPDATE 48 | 49 | echo "The stacks have been deployed successfully. Below is the content required to configure on File Storage Security console." 50 | 51 | echo "--- Content of $DEPLOYMENT_NAME_SCANNER.json ---" 52 | cat $DEPLOYMENT_NAME_SCANNER.json 53 | echo "--- End of the content ---" 54 | echo "" 55 | echo "--- Content of $DEPLOYMENT_NAME_STORAGE.json ---" 56 | cat $DEPLOYMENT_NAME_STORAGE.json 57 | echo "--- End of the content ---" 58 | -------------------------------------------------------------------------------- /gcp/storage/storage.yaml: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | 3 | imports: 4 | - path: ../common.py 5 | name: common.py 6 | - path: ../management_roles.py 7 | name: management_roles.py 8 | - path: ../role.py 9 | name: role.py 10 | - path: storage.py 11 | - path: storage_stack_service_accounts.py 12 | - path: storage_stack_roles.py 13 | 14 | resources: 15 | - name: storage-stack-service-accounts 16 | type: storage_stack_service_accounts.py 17 | properties: 18 | managementServiceAccountID: 19 | 20 | - name: storage-stack 21 | type: storage.py 22 | properties: 23 | deploymentName: 24 | region: 25 | scanningBucket: 26 | artifactBucket: 27 | scannerTopic: 28 | scannerProjectID: 29 | scannerServiceAccountID: 30 | reportObjectKey: '' 31 | managementServiceAccountID: 32 | functionAutoUpdate: 33 | 34 | outputs: 35 | - name: region 36 | value: $(ref.storage-stack.region) 37 | - name: storageProjectID 38 | value: $(ref.storage-stack.storageProjectID) 39 | - name: bucketListenerSourceArchiveUrl 40 | value: $(ref.storage-stack.bucketListenerSourceArchiveUrl) 41 | - name: bucketListenerServiceAccountID 42 | value: $(ref.storage-stack-service-accounts.bucketListenerServiceAccountID) 43 | - name: bucketListenerRoleID 44 | value: $(ref.storage-stack.fssBucketListenerRoleID) 45 | - name: postActionTagServiceAccountID 46 | value: $(ref.storage-stack-service-accounts.postActionTagServiceAccountID) 47 | - name: postActionTagRoleID 48 | value: $(ref.storage-stack.fssPostActionTagRoleID) 49 | - name: scanResultTopic 50 | value: $(ref.storage-stack.scanResultTopic) 51 | - name: bucketListenerFunctionName 52 | value: $(ref.storage-stack.bucketListenerFunctionName) 53 | - name: postScanActionTagFunctionName 54 | value: $(ref.storage-stack.postScanActionTagFunctionName) 55 | - name: functionAutoUpdate 56 | value: $(ref.storage-stack.functionAutoUpdate) 57 | -------------------------------------------------------------------------------- /gcp-terraform/all-in-one/variables.tf: -------------------------------------------------------------------------------- 1 | variable "scannerStacks" { 2 | type = map(object({ 3 | region = string 4 | managementServiceAccountProjectID = string 5 | managementServiceAccountID = string 6 | })) 7 | 8 | description = "File Storage Security Scanner Stacks" 9 | 10 | validation { 11 | condition = ( 12 | !contains([for s in var.scannerStacks : ( 13 | (length(keys(var.scannerStacks)) <= 5) && 14 | (lookup(s,"region", null) == null ? false : true) && 15 | (lookup(s,"managementServiceAccountID", null) == null ? false : true) 16 | )], false) 17 | ) 18 | error_message = "Input validation failed." 19 | } 20 | } 21 | 22 | variable "storageStacks" { 23 | type = map(object({ 24 | scanner = string 25 | scannerProjectID = string 26 | scannerTopic = string 27 | scannerServiceAccountID = string 28 | scanningBucketName = string 29 | region = string 30 | managementServiceAccountProjectID = string 31 | managementServiceAccountID = string 32 | reportObjectKey = bool 33 | disableScanningBucketIAMBinding = bool 34 | objectFilterPrefix = string 35 | })) 36 | 37 | description = "File Storage Security Storage Stacks" 38 | 39 | validation { 40 | condition = ( 41 | !contains([for s in var.storageStacks : ( 42 | (length(keys(var.storageStacks)) <= 20) && 43 | (lookup(s,"region", null) == null ? false : true) && 44 | (lookup(s,"scanningBucketName", null) == null ? false : true) && 45 | (lookup(s,"managementServiceAccountProjectID", null) == null ? false : true) && 46 | (lookup(s,"managementServiceAccountID", null) == null ? false : true) 47 | )], false) 48 | ) 49 | error_message = "Input validation failed." 50 | } 51 | } 52 | 53 | variable "projectID" { 54 | type = string 55 | description = "The GCP project ID you want to apply the deployment to." 56 | default = "" 57 | } 58 | 59 | variable "customRolePrefix" { 60 | type = string 61 | default = "" 62 | } 63 | 64 | variable "packageURL" { 65 | type = string 66 | description = "The GCP Cloud Function package location." 67 | default = "https://file-storage-security.s3.amazonaws.com/latest/cloud-functions/" 68 | } 69 | 70 | variable "functionAutoUpdate" { 71 | type = bool 72 | description = "Enable or disable automatic remote code update." 73 | default = true 74 | } 75 | -------------------------------------------------------------------------------- /gcp/role.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | 3 | def get_role_name_ref(project_id, role_name): 4 | return f"projects/{project_id}/roles/{get_role_id(role_name)}" 5 | 6 | def get_role_id(role_name): 7 | return role_name.lower().replace('-', '_') 8 | 9 | def create_roles(roles): 10 | resources = [] 11 | outputs = [] 12 | 13 | for role_to_create in roles: 14 | created = create_role(role_to_create) 15 | resources.append(created['role']) 16 | outputs += created['outputs'] 17 | 18 | return { 19 | 'resources': resources, 20 | 'outputs': outputs 21 | } 22 | 23 | def create_role(role): 24 | role_id = get_role_id(role['name']) 25 | 26 | created = { 27 | 'name': role['name'], 28 | 'type': 'role.py', 29 | 'properties': { 30 | 'resourceName': role['name'], 31 | 'title': role['name'].lower(), 32 | 'roleID': role_id, 33 | 'permissions': role['permissions'], 34 | 'outputKey': role['key'], 35 | } 36 | } 37 | return { 38 | 'role': created, 39 | 'outputs': [{ 40 | 'name': role['key'], 41 | 'value': role_id 42 | }] 43 | } 44 | 45 | def create_role_resource(context): 46 | """ Creates the role resource. """ 47 | 48 | project_id = context.env['project'] 49 | 50 | properties = context.properties 51 | resource_name = properties['resourceName'] 52 | role_id = properties['roleID'] 53 | 54 | role = { 55 | 'name': resource_name, 56 | 'type': 'gcp-types/iam-v1:projects.roles', 57 | 'properties': { 58 | 'parent': f'projects/{project_id}', 59 | 'roleId': role_id, 60 | 'role':{ 61 | 'title': properties['title'], 62 | 'description': f"Trend Micro File Storage Security {resource_name.replace('-', ' ').replace('_', ' ').replace('fss ', '')}", 63 | 'stage': 'GA', 64 | 'includedPermissions': properties['permissions'] 65 | } 66 | } 67 | } 68 | 69 | return ( 70 | [role], 71 | [{'name': properties['outputKey'], 'value': role_id}] 72 | ) 73 | 74 | def generate_config(context): 75 | """ Entry point for the deployment resources. """ 76 | 77 | resources, outputs = create_role_resource(context) 78 | 79 | return { 80 | 'resources': resources, 81 | 'outputs': outputs 82 | } 83 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/secret-manager.tf: -------------------------------------------------------------------------------- 1 | resource "google_secret_manager_secret" "scanner_secret" { 2 | for_each = local.scanner_stacks 3 | secret_id = "${each.key}-scanner-secrets" 4 | 5 | replication { 6 | user_managed { 7 | replicas { 8 | location = each.value.region 9 | } 10 | } 11 | } 12 | } 13 | 14 | resource "google_secret_manager_secret" "scanner_outputs_secret" { 15 | for_each = local.scanner_stacks 16 | secret_id = "${each.key}-scanner-output-secrets" 17 | 18 | replication { 19 | user_managed { 20 | replicas { 21 | location = each.value.region 22 | } 23 | } 24 | } 25 | } 26 | 27 | 28 | resource "google_secret_manager_secret_version" "scanner_secret_version" { 29 | for_each = local.scanner_stacks 30 | secret = google_secret_manager_secret.scanner_secret[each.key].id 31 | 32 | secret_data = jsonencode({}) 33 | } 34 | 35 | resource "google_secret_manager_secret_version" "scanner_outputs_secret_version" { 36 | for_each = local.scanner_stacks 37 | secret = google_secret_manager_secret.scanner_outputs_secret[each.key].id 38 | 39 | secret_data = jsonencode({ 40 | region = each.value.region 41 | scannerProjectID = var.projectID 42 | scannerTopic = google_pubsub_topic.scanner_topic[each.key].name 43 | scannerTopicDLT = google_pubsub_topic.scanner_topic_dlt[each.key].name 44 | scannerFunctionName = "projects/${google_cloudfunctions_function.scanner_function[each.key].project}/locations/${google_cloudfunctions_function.scanner_function[each.key].region}/functions/${google_cloudfunctions_function.scanner_function[each.key].name}" 45 | patternUpdaterFunctionName = "projects/${google_cloudfunctions_function.pattern_updater_function[each.key].project}/locations/${google_cloudfunctions_function.pattern_updater_function[each.key].region}/functions/${google_cloudfunctions_function.pattern_updater_function[each.key].name}" 46 | scannerDLTFunctionName = "projects/${google_cloudfunctions_function.scanner_dlt_function[each.key].project}/locations/${google_cloudfunctions_function.scanner_dlt_function[each.key].region}/functions/${google_cloudfunctions_function.scanner_dlt_function[each.key].name}" 47 | scannerSecretsName = google_secret_manager_secret.scanner_secret[each.key].secret_id 48 | scannerServiceAccountID = google_service_account.scanner_service_account[each.key].account_id 49 | patternUpdateSchedulerJobName = google_cloud_scheduler_job.pattern_updater_scheduler[each.key].name 50 | patternUpdateBucket = google_storage_bucket.pattern_update_bucket[each.key].name 51 | functionAutoUpdate = var.functionAutoUpdate 52 | }) 53 | } 54 | -------------------------------------------------------------------------------- /gcp/scanner/scanner_stack_service_accounts.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import common 3 | import management_roles 4 | import role 5 | 6 | def create_service_account_resources(context): 7 | prefix = common.get_prefix(context, 'scanner') 8 | project_id = context.env['project'] 9 | 10 | scanner_service_account = { 11 | 'name': f'{prefix}-scanner-service-account', 12 | 'type': 'gcp-types/iam-v1:projects.serviceAccounts', 13 | 'properties': { 14 | 'accountId': f'{prefix.lower()}-scan-sa', 15 | 'displayName': 'Service Account for Scanner Cloud Function' 16 | }, 17 | 'accessControl': { 18 | 'gcpIamPolicy': { 19 | 'bindings': [ 20 | { 21 | 'role': role.get_role_name_ref(project_id, management_roles.SERVICE_ACCOUNT_MANAGEMENT_ROLE), 22 | 'members': [ 23 | f"serviceAccount:{context.properties['managementServiceAccountID']}" 24 | ] 25 | }, 26 | ] 27 | } 28 | } 29 | 30 | } 31 | 32 | pattern_updater_service_account = { 33 | 'name': f'{prefix}-pattern-updater-service-account', 34 | 'type': 'gcp-types/iam-v1:projects.serviceAccounts', 35 | 'properties': { 36 | 'accountId': f'{prefix.lower()}-upd-sa', 37 | 'displayName': 'Service Account for Pattern Updater Function' 38 | }, 39 | 'accessControl': { 40 | 'gcpIamPolicy': { 41 | 'bindings': [ 42 | { 43 | 'role': role.get_role_name_ref(project_id, management_roles.SERVICE_ACCOUNT_MANAGEMENT_ROLE), 44 | 'members': [ 45 | f"serviceAccount:{context.properties['managementServiceAccountID']}" 46 | ] 47 | }, 48 | ] 49 | } 50 | } 51 | 52 | } 53 | 54 | resources = [ 55 | scanner_service_account, 56 | pattern_updater_service_account 57 | ] 58 | outputs = [ 59 | { 60 | 'name': 'scannerServiceAccountID', 61 | 'value': scanner_service_account['properties']['accountId'] 62 | }, 63 | { 64 | 'name': 'patternUpdaterServiceAccountID', 65 | 'value': pattern_updater_service_account['properties']['accountId'] 66 | }, 67 | { 68 | 'name': 'scannerProjectID', 69 | 'value': project_id 70 | } 71 | ] 72 | return (resources, outputs) 73 | 74 | 75 | def generate_config(context): 76 | """ Entry point for the deployment resources. """ 77 | 78 | resources, outputs = create_service_account_resources(context) 79 | 80 | return { 81 | 'resources': resources, 82 | 'outputs': outputs 83 | } 84 | -------------------------------------------------------------------------------- /gcp/storage/storage_stack_service_accounts.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import common 3 | import management_roles 4 | import role 5 | import storage_stack_roles 6 | 7 | def create_service_account_resources(context): 8 | prefix = common.get_prefix(context, 'storage') 9 | project_id = context.env['project'] 10 | 11 | bucket_listener_service_account = { 12 | 'name': f'{prefix}-bucket-listener-service-account', 13 | 'type': 'gcp-types/iam-v1:projects.serviceAccounts', 14 | 'properties': { 15 | 'accountId': f'{prefix.lower()}-bl-sa', 16 | 'displayName': 'Service Account for Bucket Listener Cloud Function', 17 | }, 18 | 'accessControl': { 19 | 'gcpIamPolicy': { 20 | 'bindings': [ 21 | { 22 | 'role': role.get_role_name_ref(project_id, management_roles.SERVICE_ACCOUNT_MANAGEMENT_ROLE), 23 | 'members': [ 24 | f"serviceAccount:{context.properties['managementServiceAccountID']}" 25 | ] 26 | }, 27 | ] 28 | } 29 | } 30 | } 31 | 32 | binding_bucket_listener_role = { 33 | 'name': 'bind-bucket-listener-iam-policy', 34 | 'type': 'gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding', 35 | 'properties': { 36 | 'resource': project_id, 37 | 'role': role.get_role_name_ref(project_id, storage_stack_roles.BUCKET_LISTENER_ROLE), 38 | 'member': f"serviceAccount:$(ref.{bucket_listener_service_account['name']}.email)" 39 | } 40 | } 41 | 42 | post_action_tag_service_account = { 43 | 'name': f'{prefix}-post-action-tag-service-account', 44 | 'type': 'gcp-types/iam-v1:projects.serviceAccounts', 45 | 'properties': { 46 | 'accountId': f'{prefix.lower()}-pat-sa', 47 | 'displayName': 'Service Account for PostAction Tag Cloud Function', 48 | }, 49 | 'accessControl': { 50 | 'gcpIamPolicy': { 51 | 'bindings': [ 52 | { 53 | 'role': role.get_role_name_ref(project_id, management_roles.SERVICE_ACCOUNT_MANAGEMENT_ROLE), 54 | 'members': [ 55 | f"serviceAccount:{context.properties['managementServiceAccountID']}" 56 | ] 57 | }, 58 | ] 59 | } 60 | } 61 | } 62 | 63 | resources = [ 64 | bucket_listener_service_account, 65 | binding_bucket_listener_role, 66 | post_action_tag_service_account 67 | ] 68 | outputs = [{ 69 | 'name': 'bucketListenerServiceAccountID', 70 | 'value': bucket_listener_service_account['properties']['accountId'] 71 | },{ 72 | 'name': 'postActionTagServiceAccountID', 73 | 'value': post_action_tag_service_account['properties']['accountId'] 74 | }] 75 | return (resources, outputs) 76 | 77 | 78 | def generate_config(context): 79 | """ Entry point for the deployment resources. """ 80 | 81 | resources, outputs = create_service_account_resources(context) 82 | 83 | return { 84 | 'resources': resources, 85 | 'outputs': outputs 86 | } 87 | -------------------------------------------------------------------------------- /gcp/management_roles.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import role 3 | 4 | CLOUD_FUNCTION_MANAGEMENT_ROLE = 'trend-micro-fss-cloud-function-management-role' 5 | DEPLOYMENT_MANAGEMENT_ROLE = 'trend-micro-fss-deployment-management-role' 6 | LOG_MANAGEMENT_ROLE = 'trend-micro-fss-log-management-role' 7 | PUBSUB_IAM_MANAGEMENT_ROLE = 'trend-micro-fss-pubsub-iam-management-role' 8 | PUBSUB_MANAGEMENT_ROLE = 'trend-micro-fss-pubsub-management-role' 9 | SECRET_MANAGEMENT_ROLE = 'trend-micro-fss-secret-management-role' 10 | SERVICE_ACCOUNT_MANAGEMENT_ROLE = 'trend-micro-fss-service-account-management-role' 11 | SOURCE_CODE_SET_ROLE = 'trend-micro-fss-source-code-set-role' 12 | 13 | roles = { 14 | CLOUD_FUNCTION_MANAGEMENT_ROLE: { 15 | 'name': CLOUD_FUNCTION_MANAGEMENT_ROLE, 16 | 'key': 'fssCloudFunctionManagementRoleID', 17 | 'permissions': [ 18 | 'cloudfunctions.functions.get', 19 | 'cloudfunctions.functions.list', 20 | 'cloudfunctions.functions.sourceCodeGet', 21 | 'cloudfunctions.functions.update', 22 | 'cloudbuild.builds.get', 23 | 'cloudbuild.builds.list' 24 | ] 25 | }, 26 | DEPLOYMENT_MANAGEMENT_ROLE: { 27 | 'name': DEPLOYMENT_MANAGEMENT_ROLE, 28 | 'key': 'fssDeploymentManagementRoleID', 29 | 'permissions': [ 30 | 'deploymentmanager.deployments.get', 31 | 'deploymentmanager.manifests.get' 32 | ] 33 | }, 34 | LOG_MANAGEMENT_ROLE: { 35 | 'name': LOG_MANAGEMENT_ROLE, 36 | 'key': 'fssLogManagementRoleID', 37 | 'permissions': [ 38 | 'logging.logs.list', 39 | 'logging.queries.create', 40 | 'logging.queries.get', 41 | 'logging.queries.list', 42 | ] 43 | }, 44 | PUBSUB_IAM_MANAGEMENT_ROLE: { 45 | 'name': PUBSUB_IAM_MANAGEMENT_ROLE, 46 | 'key': 'fssPubsubManagementRoleID', 47 | 'permissions': [ 48 | 'pubsub.topics.getIamPolicy', 49 | 'pubsub.topics.setIamPolicy', 50 | ] 51 | }, 52 | PUBSUB_MANAGEMENT_ROLE: { 53 | 'name': PUBSUB_MANAGEMENT_ROLE, 54 | 'key': 'fssPubsubManagementRoleID', 55 | 'permissions': [ 56 | 'pubsub.topics.get', 57 | 'pubsub.topics.list', 58 | 'pubsub.subscriptions.get', 59 | 'pubsub.subscriptions.list', 60 | ] 61 | }, 62 | SECRET_MANAGEMENT_ROLE: { 63 | 'name': SECRET_MANAGEMENT_ROLE, 64 | 'key': 'fssSecretManagementRoleID', 65 | 'permissions': [ 66 | 'secretmanager.secrets.get', 67 | 'secretmanager.versions.add', 68 | 'secretmanager.versions.enable', 69 | 'secretmanager.versions.destroy', 70 | 'secretmanager.versions.disable', 71 | 'secretmanager.versions.get', 72 | 'secretmanager.versions.list', 73 | 'secretmanager.versions.access', 74 | ] 75 | }, 76 | SERVICE_ACCOUNT_MANAGEMENT_ROLE: { 77 | 'name': SERVICE_ACCOUNT_MANAGEMENT_ROLE, 78 | 'key': 'fssServiceAccountManagementRoleID', 79 | 'permissions': [ 80 | 'iam.serviceAccounts.get', 81 | 'iam.serviceAccounts.getIamPolicy', 82 | 'iam.serviceAccounts.list', 83 | ] 84 | }, 85 | SOURCE_CODE_SET_ROLE: { 86 | 'name': SOURCE_CODE_SET_ROLE, 87 | 'key': 'fssSourceCodeSetRoleID', 88 | 'permissions': [ 89 | 'cloudfunctions.functions.sourceCodeSet' 90 | ] 91 | } 92 | } 93 | 94 | def generate_config(context): 95 | """ Entry point for the deployment resources. """ 96 | 97 | return role.create_roles(roles.values()) 98 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/cloud-functions.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "gcp_bucket_listener" { 2 | provisioner "local-exec" { 3 | command = "curl ${var.packageURL}gcp-listener.zip --output gcp-listener.zip" 4 | } 5 | } 6 | 7 | resource "null_resource" "gcp_post_action_tag" { 8 | provisioner "local-exec" { 9 | command = "curl ${var.packageURL}gcp-action-tag.zip --output gcp-action-tag.zip" 10 | } 11 | } 12 | 13 | resource "google_storage_bucket" "artifact_bucket" { 14 | for_each = local.storage_stacks 15 | location = each.value.region 16 | project = var.projectID 17 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-artifact" 18 | uniform_bucket_level_access = true 19 | } 20 | 21 | resource "google_storage_bucket_object" "gcp_bucket_listener_zip" { 22 | for_each = local.storage_stacks 23 | source = "gcp-listener.zip" 24 | content_type = "application/zip" 25 | 26 | name = "gcp-listener.zip" 27 | bucket = google_storage_bucket.artifact_bucket[each.key].name 28 | 29 | depends_on = [ 30 | null_resource.gcp_bucket_listener 31 | ] 32 | 33 | lifecycle { 34 | ignore_changes = all 35 | } 36 | } 37 | 38 | resource "google_storage_bucket_object" "gcp_post_action_tag_source_zip" { 39 | for_each = local.storage_stacks 40 | source = "gcp-action-tag.zip" 41 | content_type = "application/zip" 42 | 43 | name = "gcp-action-tag.zip" 44 | bucket = google_storage_bucket.artifact_bucket[each.key].name 45 | 46 | depends_on = [ 47 | null_resource.gcp_post_action_tag 48 | ] 49 | 50 | lifecycle { 51 | ignore_changes = all 52 | } 53 | } 54 | 55 | resource "google_cloudfunctions_function" "bucket_listener_function" { 56 | for_each = local.storage_stacks 57 | 58 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-bucket-listener" 59 | 60 | source_archive_bucket = google_storage_bucket.artifact_bucket[each.key].name 61 | source_archive_object = google_storage_bucket_object.gcp_bucket_listener_zip[each.key].name 62 | 63 | entry_point = "handler" 64 | runtime = "nodejs20" 65 | service_account_email = google_service_account.bucket_listener_service_account[each.key].email 66 | region = each.value.region 67 | 68 | event_trigger { 69 | event_type = "google.storage.object.finalize" 70 | resource = "projects/${var.projectID}/buckets/${each.value.scanningBucketName}" 71 | } 72 | 73 | environment_variables = { 74 | "SCANNER_PUBSUB_TOPIC": each.value.scanner != null ? var.scanner_pubsub_topics[each.value.scanner].name: each.value.scannerTopic 75 | "SCANNER_PROJECT_ID": each.value.scanner != null ? var.projectID : each.value.scannerProjectID 76 | "SCAN_RESULT_TOPIC": "projects/${var.projectID}/topics/${google_pubsub_topic.scan_result_topic[each.key].name}" 77 | "DEPLOYMENT_NAME": each.key, 78 | "REPORT_OBJECT_KEY": each.value.reportObjectKey 79 | "OBJECT_FILTER_PREFIX": each.value.objectFilterPrefix 80 | } 81 | 82 | lifecycle { 83 | ignore_changes = [ 84 | labels 85 | ] 86 | } 87 | } 88 | 89 | 90 | resource "google_cloudfunctions_function" "post_action_tag_function" { 91 | for_each = local.storage_stacks 92 | 93 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-post-action-tag" 94 | 95 | source_archive_bucket = google_storage_bucket.artifact_bucket[each.key].name 96 | source_archive_object = google_storage_bucket_object.gcp_post_action_tag_source_zip[each.key].name 97 | 98 | entry_point = "main" 99 | runtime = "python312" 100 | service_account_email = google_service_account.post_action_tag_service_account[each.key].email 101 | region = each.value.region 102 | 103 | event_trigger { 104 | event_type = "providers/cloud.pubsub/eventTypes/topic.publish" 105 | resource = google_pubsub_topic.scan_result_topic[each.key].name 106 | } 107 | 108 | lifecycle { 109 | ignore_changes = [ 110 | labels 111 | ] 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /aws/deployment-role-policy-for-account-scanner.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "SQSQueuePermissions", 6 | "Action": [ 7 | "sqs:TagQueue", 8 | "sqs:DeleteQueue", 9 | "sqs:GetQueueAttributes", 10 | "sqs:CreateQueue", 11 | "sqs:SetQueueAttributes", 12 | "sqs:UntagQueue" 13 | ], 14 | "Effect": "Allow", 15 | "Resource": "arn:aws:sqs:*:*:*" 16 | }, 17 | { 18 | "Sid": "CloudFormationStackPermissions", 19 | "Action": [ 20 | "cloudformation:CreateStack", 21 | "cloudformation:DeleteStack", 22 | "cloudformation:UpdateStack", 23 | "cloudformation:ListStacks", 24 | "cloudformation:GetTemplateSummary" 25 | ], 26 | "Effect": "Allow", 27 | "Resource": "arn:aws:cloudformation:*:*:stack/*/*" 28 | }, 29 | { 30 | "Sid": "CloudWatchLogsPermissions", 31 | "Action": [ 32 | "logs:DescribeLogGroups", 33 | "logs:DeleteLogGroup", 34 | "logs:PutRetentionPolicy", 35 | "logs:CreateLogGroup", 36 | "logs:TagResource", 37 | "logs:ListTagsForResource", 38 | "logs:UntagResource" 39 | ], 40 | "Effect": "Allow", 41 | "Resource": "arn:aws:logs:*:*:log-group:*" 42 | }, 43 | { 44 | "Sid": "IAMRolePermissions", 45 | "Action": [ 46 | "iam:GetRole", 47 | "iam:PassRole", 48 | "iam:DetachRolePolicy", 49 | "iam:DeleteRolePolicy", 50 | "iam:TagRole", 51 | "iam:CreateRole", 52 | "iam:DeleteRole", 53 | "iam:AttachRolePolicy", 54 | "iam:PutRolePolicy", 55 | "iam:GetRolePolicy", 56 | "iam:UpdateAssumeRolePolicy", 57 | "iam:UntagRole" 58 | ], 59 | "Effect": "Allow", 60 | "Resource": "arn:aws:iam::*:role/*" 61 | }, 62 | { 63 | "Sid": "LambdaFunctionPermissions", 64 | "Action": [ 65 | "lambda:CreateFunction", 66 | "lambda:UpdateFunctionCode", 67 | "lambda:InvokeFunction", 68 | "lambda:GetLayerVersion", 69 | "lambda:GetEventSourceMapping", 70 | "lambda:GetFunction", 71 | "lambda:PublishLayerVersion", 72 | "lambda:UpdateFunctionConfiguration", 73 | "lambda:CreateEventSourceMapping", 74 | "lambda:UpdateEventSourceMapping", 75 | "lambda:DeleteLayerVersion", 76 | "lambda:AddPermission", 77 | "lambda:DeleteFunction", 78 | "lambda:DeleteEventSourceMapping", 79 | "lambda:RemovePermission", 80 | "lambda:ListTags", 81 | "lambda:TagResource", 82 | "lambda:UntagResource" 83 | ], 84 | "Effect": "Allow", 85 | "Resource": "*" 86 | }, 87 | { 88 | "Sid": "S3ObjectPermissions", 89 | "Action": [ 90 | "s3:GetObject" 91 | ], 92 | "Effect": "Allow", 93 | "Resource": "arn:aws:s3:::*/*" 94 | }, 95 | { 96 | "Sid": "SNSTopicPermissions", 97 | "Action": [ 98 | "sns:TagResource", 99 | "sns:UntagResource", 100 | "sns:GetTopicAttributes", 101 | "sns:DeleteTopic", 102 | "sns:CreateTopic", 103 | "sns:SetTopicAttributes", 104 | "sns:Subscribe", 105 | "sns:Unsubscribe", 106 | "sns:ListSubscriptionsByTopic" 107 | ], 108 | "Effect": "Allow", 109 | "Resource": "arn:aws:sns:*:*:*" 110 | }, 111 | { 112 | "Sid": "EventBridgePermissions", 113 | "Action": [ 114 | "events:PutRule", 115 | "events:RemoveTargets", 116 | "events:DescribeRule", 117 | "events:DeleteRule", 118 | "events:PutTargets", 119 | "events:PutPermission", 120 | "events:RemovePermission" 121 | ], 122 | "Effect": "Allow", 123 | "Resource": "*" 124 | }, 125 | { 126 | "Sid": "SystemsMangerPermissions", 127 | "Action": [ 128 | "ssm:DeleteParameter", 129 | "ssm:PutParameter", 130 | "ssm:AddTagsToResource", 131 | "ssm:RemoveTagsFromResource", 132 | "ssm:GetParameters" 133 | ], 134 | "Effect": "Allow", 135 | "Resource": "*" 136 | } 137 | ] 138 | } 139 | -------------------------------------------------------------------------------- /gcp-terraform/docs/deployment_tutorial_scanner.md: -------------------------------------------------------------------------------- 1 | # Cloud One File Storage Security 2 | 3 | ## Deploy scanner stack 4 | 5 | ## Overview 6 | 7 | 8 | 9 | This tutorial will guide you to deploy the Trend Micro Cloud One File Storage Security scanner stack. 10 | 11 | -------------------------------- 12 | 13 | ### Permissions 14 | 15 | The permissions that File Storage Security management roles will have after it has been deployed and configured are defined in: 16 | 17 | * Management roles 18 | 19 | ### Backend updates 20 | 21 | For automatic backend updates that will be pushed, see [Update GCP components](https://cloudone.trendmicro.com/docs/file-storage-security/component-update-gcp/). 22 | 23 | After the scanner stack deployment is complete, you will need to add a storage stack to your bucket to start scanning. 24 | 25 | ## Project setup 26 | 27 | 1. Select the project from the drop-down list at the top of the GCP console. 28 | 2. Copy and execute the script below in the Cloud Shell to complete the project setup. 29 | 30 | 31 | 32 | ```sh 33 | gcloud config set project 34 | ``` 35 | 36 | ## Enable permissions for deployment 37 | 38 | You need to apply the settings and create the custom roles in the project before File Storage Security stack deployment. This only needs to be done once on a GCP project for File Storage Security stack deployment: 39 | 40 | ### Step 1: Apply the GCP configuration deployment 41 | 42 | Enable all the needed APIs and create required custom roles by Terraform. 43 | 44 | * Specify the GCP project ID in terraform.tfvars.json under `gcp-configuration` folder 45 | 46 | * Apply the Terraform template in the Cloud Shell: 47 | 48 | ```sh 49 | terraform -chdir=gcp-configuration init && \ 50 | terraform -chdir=gcp-configuration apply 51 | ``` 52 | 53 | -------------------------------- 54 | 55 | For more information, see [Permissions for deployment](https://cloudone.trendmicro.com/docs/file-storage-security/gs-before-gcp/). 56 | 57 | ## Configure and deploy the stack 58 | 59 | Specify the following fields in terraform.tfvars.json under `scanners` folder and apply the Terraform template in the Cloud Shell: 60 | 61 | 1. **projectID** Specify the project for this deployment. 62 | 2. **functionAutoUpdate:** Enable or disable automatic remote code update. The default value is `True`. Allow values: `True`, `False`. 63 | 64 | The stack in `scannerStacks` could be multiples. You can have 20 scanner stacks in a single Terraform deployment. 65 | 66 | Scanner stack: 67 | 68 | 1. **scannerStackName**: Specify the name of the scanner stack. 69 | 2. **region**: Specify the region for the scanner stack. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/). 70 | 3. **managementServiceAccountProjectID**: Copy and paste the service account information from the File Storage Security console. 71 | 4. **managementServiceAccountID**: Copy and paste the service account information from the File Storage Security console. 72 | 73 | ```sh 74 | { 75 | "projectID": "", 76 | "functionAutoUpdate": true, 77 | "scannerStacks": { 78 | "": { 79 | "region": "", 80 | "managementServiceAccountProjectID": "", 81 | "managementServiceAccountID": "" 82 | } 83 | } 84 | } 85 | ``` 86 | 87 | ### Apply the deployment 88 | 89 | ```sh 90 | terraform -chdir=scanners init && \ 91 | terraform -chdir=scanners apply 92 | ``` 93 | 94 | > Please save `terraform.tfstate` and `terraform.tfvars.json` for managing the deployment (You will need them for updating and deleting stack). We recommend you use [remote configuration](https://developer.hashicorp.com/terraform/language/settings/backends/configuration) to keep your tfstate somewhere safe. 95 | 96 | ## Configure JSON in File Storage Security console 97 | 98 | To complete the deployment process, once the stacks are deployed, follow the steps to configure management role: 99 | 100 | 1. Copy the JSON content of `scanner_stacks_outputs` from the Cloud Shell output of Terraform. 101 | 2. Paste the content back to the File Storage Security console. 102 | 103 | > **Tip**: 104 | > You can get Terraform output by the command. 105 | > ```sh 106 | > terraform -chdir=scanners output 107 | > ``` 108 | 109 | -------------------------------- 110 | 111 | ## Protect an existing bucket 112 | 113 | You have now deployed File Storage Security scanner stack successfully. 114 | 115 | To start scanning, you’ll need to add a storage stack to the scanner stack you’ve just deployed. To add a storage stack: 116 | 117 | 1. Go to the Cloud One File Storage Security console Stack Management page. 118 | 1. Select the scanner stack you deployed. 119 | 1. Click on “Add Storage” and follow the steps to complete the deployment. 120 | -------------------------------------------------------------------------------- /gcp-terraform/modules/storage-stacks/iam-bindings.tf: -------------------------------------------------------------------------------- 1 | data "google_service_account" "management_service_account" { 2 | for_each = local.storage_stacks 3 | project = each.value.managementServiceAccountProjectID 4 | account_id = each.value.managementServiceAccountID 5 | } 6 | 7 | resource "google_pubsub_topic_iam_binding" "scan_result_topic_publisher_iam_binding" { 8 | for_each = local.storage_stacks 9 | topic = google_pubsub_topic.scan_result_topic[each.key].name 10 | role = "roles/pubsub.publisher" 11 | members = [ 12 | "serviceAccount:${google_service_account.bucket_listener_service_account[each.key].email}", 13 | "serviceAccount:${google_service_account.post_action_tag_service_account[each.key].email}", 14 | "serviceAccount:${each.value.scanner != null ? var.scanner_service_accounts[each.value.scanner].account_id : each.value.scannerServiceAccountID}@${each.value.scanner != null ? var.projectID : each.value.scannerProjectID}.iam.gserviceaccount.com" 15 | ] 16 | } 17 | 18 | resource "google_pubsub_topic_iam_binding" "scan_result_topic_management_iam_binding" { 19 | for_each = local.storage_stacks 20 | topic = google_pubsub_topic.scan_result_topic[each.key].name 21 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_pubsub_management_role" 22 | members = [ 23 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 24 | ] 25 | } 26 | 27 | resource "google_cloudfunctions_function_iam_binding" "bucket_listener_iam_binding" { 28 | for_each = local.storage_stacks 29 | region = each.value.region 30 | cloud_function = google_cloudfunctions_function.bucket_listener_function[each.key].name 31 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_cloud_function_management_role" 32 | members = [ 33 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 34 | ] 35 | } 36 | 37 | resource "google_storage_bucket_iam_binding" "bucket_listener_service_account_iam_binding" { 38 | for_each = { for storage, values in local.storage_stacks: storage => values if !values.disableScanningBucketIAMBinding } 39 | bucket = each.value.scanningBucketName 40 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_bucket_listener_storage_role" 41 | members = [ 42 | "serviceAccount:${google_service_account.bucket_listener_service_account[each.key].email}" 43 | ] 44 | } 45 | 46 | resource "google_cloudfunctions_function_iam_binding" "post_action_tag_iam_binding" { 47 | for_each = local.storage_stacks 48 | region = each.value.region 49 | cloud_function = google_cloudfunctions_function.post_action_tag_function[each.key].name 50 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_cloud_function_management_role" 51 | members = [ 52 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 53 | ] 54 | } 55 | 56 | resource "google_storage_bucket_iam_binding" "post_action_tag_service_account_iam_binding" { 57 | for_each = { for storage, values in local.storage_stacks: storage => values if !values.disableScanningBucketIAMBinding } 58 | bucket = each.value.scanningBucketName 59 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_post_action_tag_role" 60 | members = [ 61 | "serviceAccount:${google_service_account.post_action_tag_service_account[each.key].email}" 62 | ] 63 | } 64 | 65 | resource "google_secret_manager_secret_iam_binding" "storage_outputs_management_service_account_iam_binding" { 66 | for_each = local.storage_stacks 67 | secret_id = google_secret_manager_secret.storage_outputs_secret[each.key].secret_id 68 | role = "roles/secretmanager.secretAccessor" 69 | members = [ 70 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 71 | ] 72 | } 73 | 74 | resource "google_project_iam_binding" "bucket_listener_sign_blob_iam_binding" { 75 | for_each = local.storage_stacks 76 | project = var.projectID 77 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_bucket_listener_role" 78 | 79 | members = ["serviceAccount:${google_service_account.bucket_listener_service_account[each.key].email}"] 80 | 81 | condition { 82 | title = "Bucket Listener Sign Blob IAM Binding" 83 | description = "Trend Micro File Storage Security Bucket Listener Sign Blob IAM Binding" 84 | expression = "(resource.type == \"storage.googleapis.com/Bucket\" && resource.name.startsWith(\"projects/_/buckets/${each.value.scanningBucketName}\")) || (resource.type != \"storage.googleapis.com/Bucket\")" 85 | } 86 | } 87 | 88 | resource "google_service_account_iam_binding" "post_action_tag_service_account_iam" { 89 | for_each = local.storage_stacks 90 | service_account_id = google_service_account.post_action_tag_service_account[each.key].name 91 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_service_account_management_role" 92 | 93 | members = [ 94 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 95 | ] 96 | } 97 | 98 | resource "google_service_account_iam_binding" "bucket_listener_service_account_iam" { 99 | for_each = local.storage_stacks 100 | service_account_id = google_service_account.bucket_listener_service_account[each.key].name 101 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_service_account_management_role" 102 | 103 | members = [ 104 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 105 | ] 106 | } 107 | -------------------------------------------------------------------------------- /aws/deployment-role-policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Sid": "SQSQueuePermissions", 6 | "Action": [ 7 | "sqs:TagQueue", 8 | "sqs:DeleteQueue", 9 | "sqs:GetQueueAttributes", 10 | "sqs:CreateQueue", 11 | "sqs:SetQueueAttributes", 12 | "sqs:UntagQueue" 13 | ], 14 | "Effect": "Allow", 15 | "Resource": "arn:aws:sqs:*:*:*" 16 | }, 17 | { 18 | "Sid": "CloudFormationStackPermissions", 19 | "Action": [ 20 | "cloudformation:CreateStack", 21 | "cloudformation:DeleteStack", 22 | "cloudformation:UpdateStack", 23 | "cloudformation:ListStacks", 24 | "cloudformation:GetTemplateSummary" 25 | ], 26 | "Effect": "Allow", 27 | "Resource": "arn:aws:cloudformation:*:*:stack/*/*" 28 | }, 29 | { 30 | "Sid": "CloudWatchLogsPermissions", 31 | "Action": [ 32 | "logs:DescribeLogGroups", 33 | "logs:DeleteLogGroup", 34 | "logs:PutRetentionPolicy", 35 | "logs:CreateLogGroup", 36 | "logs:TagResource", 37 | "logs:ListTagsForResource", 38 | "logs:UntagResource" 39 | ], 40 | "Effect": "Allow", 41 | "Resource": "arn:aws:logs:*:*:log-group:*" 42 | }, 43 | { 44 | "Sid": "IAMRolePermissions", 45 | "Action": [ 46 | "iam:GetRole", 47 | "iam:PassRole", 48 | "iam:DetachRolePolicy", 49 | "iam:DeleteRolePolicy", 50 | "iam:TagRole", 51 | "iam:CreateRole", 52 | "iam:DeleteRole", 53 | "iam:AttachRolePolicy", 54 | "iam:PutRolePolicy", 55 | "iam:GetRolePolicy", 56 | "iam:UpdateAssumeRolePolicy", 57 | "iam:UntagRole" 58 | ], 59 | "Effect": "Allow", 60 | "Resource": "arn:aws:iam::*:role/*" 61 | }, 62 | { 63 | "Sid": "LambdaFunctionPermissions", 64 | "Action": [ 65 | "lambda:CreateFunction", 66 | "lambda:UpdateFunctionCode", 67 | "lambda:CreateAlias", 68 | "lambda:InvokeFunction", 69 | "lambda:GetLayerVersion", 70 | "lambda:GetEventSourceMapping", 71 | "lambda:GetFunction", 72 | "lambda:PublishVersion", 73 | "lambda:PublishLayerVersion", 74 | "lambda:ListVersionsByFunction", 75 | "lambda:GetFunctionConfiguration", 76 | "lambda:UpdateFunctionConfiguration", 77 | "lambda:CreateEventSourceMapping", 78 | "lambda:UpdateEventSourceMapping", 79 | "lambda:AddPermission", 80 | "lambda:DeleteLayerVersion", 81 | "lambda:DeleteFunction", 82 | "lambda:DeleteAlias", 83 | "lambda:DeleteEventSourceMapping", 84 | "lambda:RemovePermission", 85 | "lambda:ListTags", 86 | "lambda:TagResource", 87 | "lambda:UntagResource" 88 | ], 89 | "Effect": "Allow", 90 | "Resource": "*" 91 | }, 92 | { 93 | "Sid": "EC2Permissions", 94 | "Action": [ 95 | "ec2:DescribeVpcs", 96 | "ec2:DescribeSubnets", 97 | "ec2:DescribeSecurityGroups" 98 | ], 99 | "Effect": "Allow", 100 | "Resource": "*" 101 | }, 102 | { 103 | "Sid": "S3BucketPermissions", 104 | "Action": [ 105 | "s3:DeleteBucket" 106 | ], 107 | "Effect": "Allow", 108 | "Resource": "arn:aws:s3:::*" 109 | }, 110 | { 111 | "Sid": "S3AccessPointPermissions", 112 | "Action": [ 113 | "s3:CreateAccessPoint", 114 | "s3:DeleteAccessPoint", 115 | "s3:GetAccessPoint", 116 | "s3:GetAccessPointPolicy", 117 | "s3:DeleteAccessPointPolicy", 118 | "s3:CreateAccessPointForObjectLambda", 119 | "s3:DeleteAccessPointForObjectLambda", 120 | "s3:GetAccessPointForObjectLambda", 121 | "s3:GetAccessPointConfigurationForObjectLambda", 122 | "s3:GetAccessPointPolicyStatusForObjectLambda" 123 | ], 124 | "Effect": "Allow", 125 | "Resource": [ 126 | "arn:aws:s3:*:*:accesspoint/*", 127 | "arn:aws:s3-object-lambda:*:*:accesspoint/*" 128 | ] 129 | }, 130 | { 131 | "Sid": "S3ObjectPermissions", 132 | "Action": [ 133 | "s3:GetObject" 134 | ], 135 | "Effect": "Allow", 136 | "Resource": "arn:aws:s3:::*/*" 137 | }, 138 | { 139 | "Sid": "SNSTopicPermissions", 140 | "Action": [ 141 | "sns:TagResource", 142 | "sns:UntagResource", 143 | "sns:GetTopicAttributes", 144 | "sns:DeleteTopic", 145 | "sns:CreateTopic", 146 | "sns:SetTopicAttributes", 147 | "sns:Subscribe", 148 | "sns:Unsubscribe", 149 | "sns:ListSubscriptionsByTopic" 150 | ], 151 | "Effect": "Allow", 152 | "Resource": "arn:aws:sns:*:*:*" 153 | } 154 | ] 155 | } 156 | -------------------------------------------------------------------------------- /gcp/docs/deployment_tutorial_scanner.md: -------------------------------------------------------------------------------- 1 | # Cloud One File Storage Security 2 | 3 | # Deploy scanner stack 4 | 5 | ## Overview 6 | 7 | 8 | 9 | This tutorial will guide you to deploy the Cloud One File Storage Security scanner stack. 10 | 11 | -------------------------------- 12 | 13 | ### Permissions 14 | 15 | The permissions that File Storage Security management roles will have after it has been deployed and configured are defined in: 16 | 17 | * Management roles 18 | 19 | ### Backend updates 20 | 21 | For automatic backend updates that will be pushed, see [Update components](https://cloudone.trendmicro.com/docs/file-storage-security/component-update-gcp/). 22 | 23 | After the scanner stack deployment is complete, you will need to add a storage stack to your bucket to start scanning. 24 | 25 | ## Project setup 26 | 27 | 1. Select the project from the drop-down list. 28 | 1. Copy and execute the script below in the Cloud Shell to complete the project setup. 29 | 30 | 31 | 32 | ```sh 33 | gcloud config set project 34 | ``` 35 | 36 | ## Enable permissions for deployment 37 | 38 | You need the following permissions before deployment: 39 | 40 | ### Step 1: Enable the following APIs: 41 | 42 | * Cloud Build API 43 | * Cloud Deployment Manager V2 API 44 | * Cloud Functions API 45 | * Cloud Pub/Sub API 46 | * Cloud Resource Manager API 47 | * Cloud Scheduler API 48 | * IAM Service Account Credentials API 49 | * Identity and Access Management API 50 | * Secret Manager API 51 | 52 | List the APIs that are enabled: 53 | 54 | ```sh 55 | gcloud service list --enabled 56 | ``` 57 | 58 | Enable all the needed APIs at once: 59 | 60 | ```sh 61 | gcloud services enable cloudbuild.googleapis.com deploymentmanager.googleapis.com cloudfunctions.googleapis.com pubsub.googleapis.com cloudresourcemanager.googleapis.com cloudscheduler.googleapis.com iamcredentials.googleapis.com iam.googleapis.com secretmanager.googleapis.com 62 | ``` 63 | 64 | -------------------------------- 65 | 66 | ### Step 2: Create a custom role containing the permissions below: 67 | 68 | * cloudfunctions.functions.setIamPolicy 69 | * iam.roles.create 70 | * iam.serviceAccounts.setIamPolicy 71 | * pubsub.topics.setIamPolicy 72 | * resourcemanager.projects.setIamPolicy 73 | 74 | Naming rules: 75 | 76 | 1. **ROLE_ID length**: 3~64. ID can only include letters, numbers, periods and underscores. 77 | 1. **ROLE_TITLE length**: 1~100. 78 | 79 | ```sh 80 | gcloud iam roles create --project= \ 81 | --title= --description="Custom role for deployment" \ 82 | --permissions="cloudfunctions.functions.setIamPolicy,iam.roles.create,iam.serviceAccounts.setIamPolicy,pubsub.topics.setIamPolicy,resourcemanager.projects.setIamPolicy" --stage=GA 83 | ``` 84 | 85 | -------------------------------- 86 | 87 | ### Step 3: Bind the custom role to the service account: 88 | 89 | Bind the custom role to @cloudservices.gserviceaccount.com. This service account is created by GCP, and its name is Google APIs Service Agent. 90 | 91 | 1. Get project number: 92 | 93 | ```sh 94 | gcloud projects list --filter= --format="value(PROJECT_NUMBER)" 95 | ``` 96 | 97 | 2. Bind service account: 98 | 99 | ```sh 100 | gcloud projects add-iam-policy-binding \ 101 | --member=serviceAccount:@cloudservices.gserviceaccount.com 102 | --role= 103 | ``` 104 | 105 | -------------------------------- 106 | 107 | For more information, see [Permissions for deployment](https://cloudone.trendmicro.com/docs/file-storage-security/gs-before-gcp/). 108 | 109 | ## Configure and deploy the stack 110 | 111 | Specify the following fields and execute the deployment script in the Cloud Shell: 112 | 113 | 1. **Deployment name:** Specify the name of this deployment. Please keep it under 22 characters. 114 | 1. **Region:** Specify the region of your bucket. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/#GCPRegion). 115 | 1. **Cloud One region:** Specify the region ID of your Trend Micro Cloud One account. For the list of supported Cloud One regions, see [Trend Micro Cloud One regions](https://cloudone.trendmicro.com/docs/identity-and-account-management/c1-regions/). The default region is `us-1`. 116 | 1. **Service account:** Copy and paste the service account information from the File Storage Security console. 117 | 1. **Function auto update:** Enable or disable automatic remote code update. The default value is `True`. Allow values: `True`, `False`. 118 | 119 | ```sh 120 | ./deployment-script-scanner.sh -d -r -c -m -f 121 | ``` 122 | 123 | ## Configure JSON in File Storage Security console 124 | 125 | To complete the deployment process, once the stacks are deployed, follow the steps to configure management role: 126 | 127 | 1. Copy the content of .json from the Cloud Shell script output. 128 | 1. Paste the content back to the File Storage Security console - Step 4. Scanner Stack 129 | 130 | -------------------------------- 131 | 132 | ### Deployment Status 133 | 134 | To find out the status of your deployment, go to [Deployment Manager](https://console.cloud.google.com/dm) and search for: 135 | 136 | * 137 | 138 | ## Protect an existing bucket 139 | 140 | You have now deployed File Storage Security scanner stack successfully. 141 | 142 | To start scanning, you’ll need to add a storage stack to the scanner stack you’ve just deployed. To add a storage stack: 143 | 144 | 1. Go to the Cloud One File Storage Security console Stack Management page. 145 | 1. Select the scanner stack you deployed. 146 | 1. Click on “Add Storage” and follow the steps to complete the deployment. 147 | -------------------------------------------------------------------------------- /gcp/deployment-script-storage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | while getopts s:d:r:i:u:k:m:f: args 5 | do 6 | case "${args}" in 7 | s) SCANNING_BUCKET_NAME=${OPTARG};; 8 | d) DEPLOYMENT_NAME_STORAGE=${OPTARG};; 9 | r) REGION=${OPTARG};; 10 | i) SCANNER_INFO_JSON=${OPTARG};; 11 | u) PACKAGE_URL=${OPTARG};; 12 | k) REPORT_OBJECT_KEY=${OPTARG};; 13 | m) MANAGEMENT_SERVICE_ACCOUNT=${OPTARG};; 14 | f) FUNCTION_AUTO_UPDATE=${OPTARG};; 15 | esac 16 | done 17 | 18 | while IFS== read key value 19 | do 20 | printf -v "$key" "$value" 21 | done < <(echo $SCANNER_INFO_JSON | jq -r 'to_entries|map("\(.key)=\(.value|tostring)")|.[]') 22 | 23 | GCP_PROJECT_ID=$(gcloud config list --format 'value(core.project)' 2> /dev/null) 24 | ARTIFACT_BUCKET_NAME='fss-artifact'-$(cat /proc/sys/kernel/random/uuid || uuidgen | tr '[:upper:]' '[:lower:]') 25 | 26 | echo "Scanning bucket name: $SCANNING_BUCKET_NAME"; 27 | echo "Artifact bucket name: $ARTIFACT_BUCKET_NAME"; 28 | echo "Scanner info JSON: $SCANNER_INFO_JSON" 29 | echo "Storage Deployment Name: $DEPLOYMENT_NAME_STORAGE"; 30 | echo "GCP Project ID: $GCP_PROJECT_ID"; 31 | echo "Region: $REGION"; 32 | echo "Package URL: $PACKAGE_URL"; 33 | echo "Report Object Key: $REPORT_OBJECT_KEY"; 34 | echo "Management Service Account: $MANAGEMENT_SERVICE_ACCOUNT"; 35 | 36 | echo "Will deploy file storage security protection unit storage stack, Ctrl-C to cancel..." 37 | sleep 5 38 | 39 | if [ -z "$PACKAGE_URL" ]; then 40 | PACKAGE_URL='https://file-storage-security.s3.amazonaws.com/latest/' 41 | fi 42 | 43 | if [ -z "$REPORT_OBJECT_KEY" ]; then 44 | REPORT_OBJECT_KEY='False' 45 | else 46 | REPORT_OBJECT_KEY=$(echo $REPORT_OBJECT_KEY | tr '[:upper:]' '[:lower:]') 47 | REPORT_OBJECT_KEY=$(echo ${REPORT_OBJECT_KEY:0:1} | tr '[a-z]' '[A-Z]')${REPORT_OBJECT_KEY:1} 48 | fi 49 | 50 | if [ -z "$FUNCTION_AUTO_UPDATE" ]; then 51 | FUNCTION_AUTO_UPDATE='True' 52 | fi 53 | 54 | TEMPLATES_FILE='gcp-templates.zip' 55 | LISTENER_FILE='gcp-listener.zip' 56 | ACTION_TAG_FILE='gcp-action-tag.zip' 57 | 58 | # Check Project Setting 59 | gcloud deployment-manager deployments list > /dev/null 60 | 61 | # Download the templates package 62 | wget $PACKAGE_URL'gcp-templates/'$TEMPLATES_FILE 63 | 64 | # Unzip the templates package 65 | unzip $TEMPLATES_FILE && rm $TEMPLATES_FILE 66 | 67 | # Create an artifact Google Cloud Storage bucket 68 | gsutil mb --pap enforced -b on gs://$ARTIFACT_BUCKET_NAME 69 | 70 | prepareArtifact() { 71 | # Download FSS functions artifacts 72 | wget $PACKAGE_URL'cloud-functions/'$1 73 | # Upload functions artifacts to the artifact bucket 74 | gsutil cp $1 gs://$ARTIFACT_BUCKET_NAME/$1 && rm $1 75 | } 76 | 77 | prepareArtifact $LISTENER_FILE 78 | prepareArtifact $ACTION_TAG_FILE 79 | 80 | # Deploy or update File Storage Security roles 81 | echo "Deploying File Storage Security roles..." 82 | FSS_ROLES_DEPLOYMENT='trend-micro-file-storage-security-roles' 83 | # Deploy the roles if they don't exist 84 | roleDeployment=$(gcloud deployment-manager deployments describe $FSS_ROLES_DEPLOYMENT --format json) \ 85 | || gcloud deployment-manager deployments create $FSS_ROLES_DEPLOYMENT --config templates/fss-roles.yaml 86 | # Update the roles if they are not being updated 87 | ([[ ! -z "$roleDeployment" && "DONE" == $(echo "$roleDeployment" | jq -r '.deployment.operation.status') ]] \ 88 | && gcloud deployment-manager deployments update $FSS_ROLES_DEPLOYMENT --config templates/fss-roles.yaml) \ 89 | || echo "$FSS_ROLES_DEPLOYMENT is updating. Skip updating the roles." 90 | 91 | STORAGE_YAML_PATH=templates/storage/storage.yaml 92 | sed -i.bak "s//$REGION/g" $STORAGE_YAML_PATH 93 | sed -i.bak "s//$ARTIFACT_BUCKET_NAME/g" $STORAGE_YAML_PATH 94 | sed -i.bak "s//$SCANNING_BUCKET_NAME/g" $STORAGE_YAML_PATH 95 | sed -i.bak "s//$SCANNER_TOPIC/g" $STORAGE_YAML_PATH 96 | sed -i.bak "s//$SCANNER_PROJECT_ID/g" $STORAGE_YAML_PATH 97 | sed -i.bak "s//$SCANNER_SERVICE_ACCOUNT_ID/g" $STORAGE_YAML_PATH 98 | sed -i.bak "s//$DEPLOYMENT_NAME_STORAGE/g" $STORAGE_YAML_PATH 99 | sed -i.bak "s//$REPORT_OBJECT_KEY/g" $STORAGE_YAML_PATH 100 | sed -i.bak "s//$MANAGEMENT_SERVICE_ACCOUNT/g" $STORAGE_YAML_PATH 101 | sed -i.bak "s//$FUNCTION_AUTO_UPDATE/g" $STORAGE_YAML_PATH 102 | 103 | cat $STORAGE_YAML_PATH 104 | 105 | # Create storage stack 106 | gcloud deployment-manager deployments create $DEPLOYMENT_NAME_STORAGE --config $STORAGE_YAML_PATH 107 | 108 | STORAGE_DEPLOYMENT=$(gcloud deployment-manager deployments describe $DEPLOYMENT_NAME_STORAGE --format "json") 109 | 110 | searchStorageJSONOutputs() { 111 | echo $STORAGE_DEPLOYMENT | jq -r --arg v "$1" '.outputs[] | select(.name==$v).finalValue' 112 | } 113 | 114 | STORAGE_PROJECT_ID=$(searchStorageJSONOutputs storageProjectID) 115 | BUCKET_LISTENER_SERVICE_ACCOUNT_ID=$(searchStorageJSONOutputs bucketListenerServiceAccountID) 116 | SCAN_RESULT_TOPIC=$(searchStorageJSONOutputs scanResultTopic) 117 | 118 | # Binding appspot service account 119 | APPSPOT_SERVICE_ACCOUNT=$STORAGE_PROJECT_ID@appspot.gserviceaccount.com 120 | bindingCount=$(gcloud iam service-accounts get-iam-policy $APPSPOT_SERVICE_ACCOUNT --flatten=bindings --filter="bindings.members=serviceAccount:$MANAGEMENT_SERVICE_ACCOUNT AND bindings.role=roles/iam.serviceAccountUser" --format='json' | jq length) 121 | [[ 0 < $bindingCount ]] \ 122 | || gcloud iam service-accounts add-iam-policy-binding $APPSPOT_SERVICE_ACCOUNT \ 123 | --member="serviceAccount:$MANAGEMENT_SERVICE_ACCOUNT" --role=roles/iam.serviceAccountUser 124 | 125 | # Remove the artifact bucket 126 | gsutil rm -r gs://$ARTIFACT_BUCKET_NAME 127 | rm -rf templates 128 | 129 | printStorageJSON() { 130 | STORAGE_JSON=$(jq --null-input \ 131 | --arg projectID "$STORAGE_PROJECT_ID" \ 132 | --arg deploymentName "$DEPLOYMENT_NAME_STORAGE" \ 133 | '{"projectID": $projectID, "deploymentName": $deploymentName}') 134 | echo $STORAGE_JSON > $DEPLOYMENT_NAME_STORAGE.json 135 | cat $DEPLOYMENT_NAME_STORAGE.json 136 | } 137 | 138 | echo "The storage stack has been deployed successfully. Below is the content required to configure on File Storage Security console." 139 | 140 | echo "--- Content of $DEPLOYMENT_NAME_STORAGE.json ---" 141 | printStorageJSON 142 | echo "--- End of the content ---" 143 | -------------------------------------------------------------------------------- /gcp/docs/deployment_tutorial_storage.md: -------------------------------------------------------------------------------- 1 | # Cloud One File Storage Security 2 | 3 | # Deploy storage stack 4 | 5 | ## Overview 6 | 7 | 8 | 9 | This tutorial will guide you to deploy the Cloud One File Storage Security storage stack. 10 | 11 | -------------------------------- 12 | 13 | ### Permissions 14 | 15 | The permissions that File Storage Security management roles will have after it has been deployed and configured are defined in: 16 | 17 | * Management roles 18 | * Storage stack management roles 19 | 20 | ### Backend updates 21 | 22 | For automatic backend updates that will be pushed, see [Update components](https://cloudone.trendmicro.com/docs/file-storage-security/component-update-gcp/). 23 | 24 | ## Project setup 25 | 26 | 1. Select the project from the drop-down list. 27 | 1. Copy and execute the script below in the Cloud Shell to complete the project setup. 28 | 29 | 30 | 31 | ```sh 32 | gcloud config set project 33 | ``` 34 | 35 | ## Enable permissions for deployment 36 | 37 | You need the following permissions before deployment: 38 | 39 | ### Step 1: Enable the following APIs: 40 | 41 | * Cloud Build API 42 | * Cloud Deployment Manager V2 API 43 | * Cloud Functions API 44 | * Cloud Pub/Sub API 45 | * Cloud Resource Manager API 46 | * Cloud Scheduler API 47 | * IAM Service Account Credentials API 48 | * Identity and Access Management API 49 | * Secret Manager API 50 | 51 | List the APIs that are enabled: 52 | 53 | ```sh 54 | gcloud service list --enabled 55 | ``` 56 | 57 | Enable all the needed APIs at once: 58 | 59 | ```sh 60 | gcloud services enable cloudbuild.googleapis.com deploymentmanager.googleapis.com cloudfunctions.googleapis.com pubsub.googleapis.com cloudresourcemanager.googleapis.com cloudscheduler.googleapis.com iamcredentials.googleapis.com iam.googleapis.com secretmanager.googleapis.com 61 | ``` 62 | 63 | -------------------------------- 64 | 65 | ### Step 2: Create a custom role containing the permissions below: 66 | 67 | * cloudfunctions.functions.setIamPolicy 68 | * iam.roles.create 69 | * iam.serviceAccounts.setIamPolicy 70 | * pubsub.topics.setIamPolicy 71 | * resourcemanager.projects.setIamPolicy 72 | 73 | Naming rules: 74 | 75 | 1. **ROLE_ID length**: 3~64. ID can only include letters, numbers, periods and underscores. 76 | 1. **ROLE_TITLE length**: 1~100. 77 | 78 | ```sh 79 | gcloud iam roles create --project= \ 80 | --title= --description="Custom role for deployment" \ 81 | --permissions="cloudfunctions.functions.setIamPolicy,iam.roles.create,iam.serviceAccounts.setIamPolicy,pubsub.topics.setIamPolicy,resourcemanager.projects.setIamPolicy" --stage=GA 82 | ``` 83 | 84 | -------------------------------- 85 | 86 | ### Step 3: Bind the custom role to the service account: 87 | 88 | Bind the custom role to @cloudservices.gserviceaccount.com. This service account is created by GCP, and its name is Google APIs Service Agent. 89 | 90 | 1. Get project number: 91 | 92 | ```sh 93 | gcloud projects list --filter= --format="value(PROJECT_NUMBER)" 94 | ``` 95 | 96 | 2. Bind service account: 97 | 98 | ```sh 99 | gcloud projects add-iam-policy-binding \ 100 | --member=serviceAccount:@cloudservices.gserviceaccount.com 101 | --role= 102 | ``` 103 | 104 | -------------------------------- 105 | 106 | For more information, see [Permissions for deployment](https://cloudone.trendmicro.com/docs/file-storage-security/gs-before-gcp/). 107 | 108 | ## Configure and deploy the stack 109 | 110 | Specify the following fields and execute the deployment script in the Cloud Shell: 111 | 112 | 1. **Scanning bucket name:** Specify the existing bucket name that you wish to protect. 113 | 1. **Deployment name:** Specify the name of this deployment. Please keep it under 22 characters. 114 | 1. **Region:** Specify the region of your bucket. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/#GCPRegion). 115 | 1. **Scanner information JSON:** Copy and paste the scanner information from the File Storage Security console. 116 | 1. **Service account:** Copy and paste the service account information from the File Storage Security console. 117 | 1. **Function auto update:** Enable or disable automatic remote code update. The default value is `True`. Allow values: `True`, `False`. 118 | 119 | ```sh 120 | ./deployment-script-storage.sh -s -d -r -i -m -f 121 | ``` 122 | 123 | ## Configure JSON in File Storage Security console 124 | 125 | To complete the deployment process, once the stacks are deployed, follow the steps to configure management role: 126 | 127 | 1. Copy the content of .json from the Cloud Shell script output. 128 | 1. Paste the content back to the File Storage Security console - Step 5. Storage Stack 129 | 130 | -------------------------------- 131 | 132 | ### Deployment Status 133 | 134 | To find out the status of your deployment, go to [Deployment Manager](https://console.cloud.google.com/dm) and search for: 135 | 136 | * 137 | 138 | ## Start scanning 139 | 140 | You have now deployed File Storage Security scanner and storage stacks successfully. To test your deployment, you'll need to generate a malware detection using the eicar file. 141 | 142 | 1. Download the eicar file from eicar file page into your scanning bucket with the script. 143 | 144 | ```sh 145 | wget https://secure.eicar.org/eicar.com.txt 146 | gsutil cp eicar.com.txt gs:///eicar 147 | ``` 148 | 149 | 1. File Storage Security scans the file and detects the malware. 150 | 151 | 1. Execute the script to examine the scan result: 152 | 153 | ```sh 154 | gsutil stat 'gs:///eicar' 155 | ``` 156 | 157 | 1. In Metadata, look for the following tags: 158 | * **fss-scan-date**: date_and_time 159 | * **fss-scan-result**: malicious 160 | * **fss-scanned**: true 161 | 162 | The tags indicate that File Storage Security scanned the file and tagged it correctly as malware. The scan results are also available in the console on the Scan Activity page. 163 | 164 | -------------------------------- 165 | 166 | ### Next Step 167 | 168 | [Quarantine or promote files based on the scan results](https://cloudone.trendmicro.com/docs/file-storage-security/github-sample-code/#post-scan) 169 | -------------------------------------------------------------------------------- /gcp/docs/deployment_tutorial_all_in_one.md: -------------------------------------------------------------------------------- 1 | # Cloud One File Storage Security 2 | 3 | # Deploy scanner and storage stacks 4 | 5 | ## Overview 6 | 7 | 8 | 9 | This tutorial will guide you to protect an existing GCP bucket from malware by deploying Cloud One File Storage Security scanner and storage stacks. 10 | 11 | -------------------------------- 12 | 13 | ### Permissions 14 | 15 | The permissions that File Storage Security management roles will have after it has been deployed and configured are defined in: 16 | 17 | * Management roles 18 | * Storage stack management roles 19 | 20 | ### Backend updates 21 | 22 | For automatic backend updates that will be pushed, see [Update components](https://cloudone.trendmicro.com/docs/file-storage-security/component-update-gcp/). 23 | 24 | ## Project setup 25 | 26 | 1. Select the project from the drop-down list. 27 | 1. Copy and execute the script below in the Cloud Shell to complete the project setup. 28 | 29 | 30 | 31 | ```sh 32 | gcloud config set project 33 | ``` 34 | 35 | ## Enable permissions for deployment 36 | 37 | You need the following permissions before deployment: 38 | 39 | ### Step 1: Enable the following APIs: 40 | 41 | * Cloud Build API 42 | * Cloud Deployment Manager V2 API 43 | * Cloud Functions API 44 | * Cloud Pub/Sub API 45 | * Cloud Resource Manager API 46 | * Cloud Scheduler API 47 | * IAM Service Account Credentials API 48 | * Identity and Access Management API 49 | * Secret Manager API 50 | 51 | List the APIs that are enabled: 52 | 53 | ```sh 54 | gcloud service list --enabled 55 | ``` 56 | 57 | Enable all the needed APIs at once: 58 | 59 | ```sh 60 | gcloud services enable cloudbuild.googleapis.com deploymentmanager.googleapis.com cloudfunctions.googleapis.com pubsub.googleapis.com cloudresourcemanager.googleapis.com cloudscheduler.googleapis.com iamcredentials.googleapis.com iam.googleapis.com secretmanager.googleapis.com 61 | ``` 62 | 63 | -------------------------------- 64 | 65 | ### Step 2: Create a custom role containing the permissions below: 66 | 67 | * cloudfunctions.functions.setIamPolicy 68 | * iam.roles.create 69 | * iam.serviceAccounts.setIamPolicy 70 | * pubsub.topics.setIamPolicy 71 | * resourcemanager.projects.setIamPolicy 72 | 73 | Naming rules: 74 | 75 | 1. **ROLE_ID length**: 3~64. ID can only include letters, numbers, periods and underscores. 76 | 1. **ROLE_TITLE length**: 1~100. 77 | 78 | ```sh 79 | gcloud iam roles create --project= \ 80 | --title= --description="Custom role for deployment" \ 81 | --permissions="cloudfunctions.functions.setIamPolicy,iam.roles.create,iam.serviceAccounts.setIamPolicy,pubsub.topics.setIamPolicy,resourcemanager.projects.setIamPolicy" --stage=GA 82 | ``` 83 | 84 | -------------------------------- 85 | 86 | ### Step 3: Bind the custom role to the service account: 87 | 88 | Bind the custom role to @cloudservices.gserviceaccount.com. This service account is created by GCP, and its name is Google APIs Service Agent. 89 | 90 | 1. Get project number: 91 | 92 | ```sh 93 | gcloud projects list --filter= --format="value(PROJECT_NUMBER)" 94 | ``` 95 | 96 | 2. Bind service account: 97 | 98 | ```sh 99 | gcloud projects add-iam-policy-binding \ 100 | --member=serviceAccount:@cloudservices.gserviceaccount.com 101 | --role= 102 | ``` 103 | 104 | -------------------------------- 105 | 106 | For more information, see [Permissions for deployment](https://cloudone.trendmicro.com/docs/file-storage-security/gs-before-gcp/). 107 | 108 | ## Configure and deploy the stacks 109 | 110 | Specify the following fields and execute the deployment script in the Cloud Shell: 111 | 112 | 1. **Scanning bucket name:** Specify the existing bucket name that you wish to protect. 113 | 1. **Deployment name prefix:** Specify the prefix of this deployment. Please keep it under 22 characters. 114 | 1. **Region:** Specify the region of your bucket. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/#GCPRegion). 115 | 1. **Cloud One region:** Specify the region ID of your Trend Micro Cloud One account. For the list of supported Cloud One regions, see [Trend Micro Cloud One regions](https://cloudone.trendmicro.com/docs/identity-and-account-management/c1-regions/). The default region is `us-1`. 116 | 1. **Service account:** Copy and paste the service account information from the File Storage Security console. 117 | 1. **Function auto update:** Enable or disable automatic remote code update. The default value is `True`. Allow values: `True`, `False`. 118 | 119 | ```sh 120 | ./deployment-script.sh -s -d -r -c -m -f 121 | ``` 122 | 123 | ## Configure JSON in File Storage Security console 124 | 125 | To complete the deployment process, once the stacks are deployed, follow the steps to configure management role: 126 | 127 | 1. Copy the content of -scanner.json from the Cloud Shell script output. 128 | 1. Paste the content back to the File Storage Security console - Step 4. Scanner Stack 129 | 1. Copy the content of -storage.json from the Cloud Shell script output. 130 | 1. Paste the content back to the File Storage Security console - Step 5. Storage Stack 131 | 132 | -------------------------------- 133 | 134 | ### Deployment Status 135 | 136 | To find out the status of your deployment, go to [Deployment Manager](https://console.cloud.google.com/dm) and search for: 137 | 138 | * -scanner 139 | * -storage 140 | 141 | ## Start scanning 142 | 143 | You have now deployed File Storage Security scanner and storage stacks successfully. To test your deployment, you'll need to generate a malware detection using the eicar file. 144 | 145 | 1. Download the eicar file from eicar file page into your scanning bucket with the script. 146 | 147 | ```sh 148 | wget https://secure.eicar.org/eicar.com.txt 149 | gsutil cp eicar.com.txt gs:///eicar 150 | ``` 151 | 152 | 1. File Storage Security scans the file and detects the malware. 153 | 154 | 1. Execute the script to examine the scan result: 155 | 156 | ```sh 157 | gsutil stat 'gs:///eicar' 158 | ``` 159 | 160 | 1. In Metadata, look for the following tags: 161 | * **fss-scan-date**: date_and_time 162 | * **fss-scan-result**: malicious 163 | * **fss-scanned**: true 164 | 165 | The tags indicate that File Storage Security scanned the file and tagged it correctly as malware. The scan results are also available in the console on the Scan Activity page. 166 | 167 | -------------------------------- 168 | 169 | ### Next Step 170 | 171 | [Quarantine or promote files based on the scan results](https://cloudone.trendmicro.com/docs/file-storage-security/github-sample-code/#post-scan) 172 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/cloud-functions.tf: -------------------------------------------------------------------------------- 1 | resource "null_resource" "gcp_scanner_pattern_updater" { 2 | provisioner "local-exec" { 3 | command = "curl ${var.packageURL}gcp-scanner-pattern-updater.zip --output gcp-scanner-pattern-updater.zip" 4 | } 5 | } 6 | 7 | resource "null_resource" "gcp_scanner" { 8 | provisioner "local-exec" { 9 | command = "curl ${var.packageURL}gcp-scanner.zip --output gcp-scanner.zip" 10 | } 11 | } 12 | 13 | resource "null_resource" "gcp_scanner_dlt" { 14 | provisioner "local-exec" { 15 | command = "curl ${var.packageURL}gcp-scanner-dlt.zip --output gcp-scanner-dlt.zip" 16 | } 17 | } 18 | 19 | resource "google_storage_bucket" "pattern_update_bucket" { 20 | for_each = local.scanner_stacks 21 | location = each.value.region 22 | project = var.projectID 23 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-pattern-update-bucket" 24 | uniform_bucket_level_access = true 25 | force_destroy = true 26 | } 27 | 28 | resource "google_storage_bucket" "artifact_bucket" { 29 | for_each = local.scanner_stacks 30 | location = each.value.region 31 | project = var.projectID 32 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-artifact" 33 | uniform_bucket_level_access = true 34 | force_destroy = true 35 | } 36 | 37 | resource "google_storage_bucket_object" "gcp_scanner_pattern_updater_source_zip" { 38 | for_each = local.scanner_stacks 39 | source = "gcp-scanner-pattern-updater.zip" 40 | content_type = "application/zip" 41 | 42 | name = "gcp-scanner-pattern-updater.zip" 43 | bucket = google_storage_bucket.artifact_bucket[each.key].name 44 | 45 | depends_on = [ 46 | null_resource.gcp_scanner_pattern_updater 47 | ] 48 | 49 | lifecycle { 50 | ignore_changes = all 51 | } 52 | } 53 | 54 | resource "google_storage_bucket_object" "gcp_scanner_source_zip" { 55 | for_each = local.scanner_stacks 56 | source = "gcp-scanner.zip" 57 | content_type = "application/zip" 58 | 59 | name = "gcp-scanner.zip" 60 | bucket = google_storage_bucket.artifact_bucket[each.key].name 61 | 62 | depends_on = [ 63 | null_resource.gcp_scanner 64 | ] 65 | 66 | lifecycle { 67 | ignore_changes = all 68 | } 69 | } 70 | 71 | resource "google_storage_bucket_object" "gcp_scanner_dlt_source_zip" { 72 | for_each = local.scanner_stacks 73 | source = "gcp-scanner-dlt.zip" 74 | content_type = "application/zip" 75 | 76 | name = "gcp-scanner-dlt.zip" 77 | bucket = google_storage_bucket.artifact_bucket[each.key].name 78 | 79 | depends_on = [ 80 | null_resource.gcp_scanner_dlt 81 | ] 82 | 83 | lifecycle { 84 | ignore_changes = all 85 | } 86 | } 87 | 88 | resource "google_cloudfunctions_function" "pattern_updater_function" { 89 | for_each = local.scanner_stacks 90 | 91 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-pattern-updater" 92 | 93 | source_archive_bucket = google_storage_bucket.artifact_bucket[each.key].name 94 | source_archive_object = google_storage_bucket_object.gcp_scanner_pattern_updater_source_zip[each.key].name 95 | 96 | entry_point = "main" 97 | runtime = "python312" 98 | available_memory_mb = 2048 99 | service_account_email = google_service_account.pattern_updater_service_account[each.key].email 100 | timeout = 120 101 | region = each.value.region 102 | 103 | environment_variables = { 104 | "LD_LIBRARY_PATH" = "./:./lib" 105 | "PATTERN_UPDATE_BUCKET" = google_storage_bucket.pattern_update_bucket[each.key].name 106 | } 107 | 108 | event_trigger { 109 | event_type = "providers/cloud.pubsub/eventTypes/topic.publish" 110 | resource = google_pubsub_topic.pattern_updater_topic[each.key].name 111 | } 112 | 113 | lifecycle { 114 | ignore_changes = [ 115 | labels, 116 | environment_variables 117 | ] 118 | } 119 | } 120 | 121 | 122 | resource "google_cloud_scheduler_job" "pattern_updater_scheduler" { 123 | for_each = local.scanner_stacks 124 | 125 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scheduler" 126 | 127 | description = "pattern update" 128 | region = each.value.region 129 | schedule = "0 * * * *" 130 | time_zone = "UTC" 131 | 132 | pubsub_target { 133 | topic_name = google_pubsub_topic.pattern_updater_topic[each.key].id 134 | data = base64encode("Pattern Update") 135 | } 136 | } 137 | 138 | resource "google_cloudfunctions_function" "scanner_function" { 139 | for_each = local.scanner_stacks 140 | 141 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scanner" 142 | 143 | source_archive_bucket = google_storage_bucket.artifact_bucket[each.key].name 144 | source_archive_object = google_storage_bucket_object.gcp_scanner_source_zip[each.key].name 145 | 146 | entry_point = "main" 147 | runtime = "python312" 148 | available_memory_mb = 2048 149 | service_account_email = google_service_account.scanner_service_account[each.key].email 150 | timeout = 120 151 | region = each.value.region 152 | 153 | environment_variables = { 154 | "DEPLOYMENT_NAME" = each.key 155 | "LD_LIBRARY_PATH" = "/workspace:/workspace/lib" 156 | "PATTERN_PATH" = "./patterns" 157 | "PROJECT_ID" = var.projectID 158 | "REGION" = each.value.region 159 | "PATTERN_UPDATE_BUCKET" = google_storage_bucket.pattern_update_bucket[each.key].name 160 | } 161 | 162 | secret_environment_variables { 163 | key = "SCANNER_SECRETS" 164 | project_id = data.google_project.project.number 165 | secret = google_secret_manager_secret.scanner_secret[each.key].secret_id 166 | version = "latest" 167 | } 168 | 169 | timeouts { 170 | create = "60m" 171 | delete = "2h" 172 | } 173 | 174 | event_trigger { 175 | event_type = "providers/cloud.pubsub/eventTypes/topic.publish" 176 | resource = google_pubsub_topic.scanner_topic[each.key].name 177 | failure_policy { 178 | retry = true 179 | } 180 | } 181 | 182 | lifecycle { 183 | ignore_changes = [ 184 | labels, 185 | secret_environment_variables 186 | ] 187 | } 188 | } 189 | 190 | resource "google_cloudfunctions_function" "scanner_dlt_function" { 191 | for_each = local.scanner_stacks 192 | 193 | name = "${each.value.prefix}-${random_id.stack_id[each.key].hex}-scanner-dlt" 194 | 195 | source_archive_bucket = google_storage_bucket.artifact_bucket[each.key].name 196 | source_archive_object = google_storage_bucket_object.gcp_scanner_dlt_source_zip[each.key].name 197 | 198 | entry_point = "main" 199 | runtime = "python312" 200 | service_account_email = google_service_account.scanner_service_account[each.key].email 201 | region = each.value.region 202 | 203 | event_trigger { 204 | event_type = "providers/cloud.pubsub/eventTypes/topic.publish" 205 | resource = google_pubsub_topic.scanner_topic_dlt[each.key].name 206 | } 207 | 208 | lifecycle { 209 | ignore_changes = [ 210 | labels 211 | ] 212 | } 213 | } 214 | -------------------------------------------------------------------------------- /gcp-terraform/docs/deployment_tutorial_storage.md: -------------------------------------------------------------------------------- 1 | # Cloud One File Storage Security 2 | 3 | ## Deploy storage stack 4 | 5 | ## Overview 6 | 7 | 8 | 9 | This tutorial will guide you to deploy the Trend Micro Cloud One File Storage Security storage stack. 10 | 11 | -------------------------------- 12 | 13 | ### Permissions 14 | 15 | The permissions that File Storage Security management roles will have after it has been deployed and configured are defined in: 16 | 17 | * Management roles 18 | 19 | ### Backend updates 20 | 21 | For automatic backend updates that will be pushed, see [Update GCP components](https://cloudone.trendmicro.com/docs/file-storage-security/component-update-gcp/). 22 | 23 | ## Project setup 24 | 25 | 1. Select the project from the drop-down list at the top of the GCP console. 26 | 2. Copy and execute the script below in the Cloud Shell to complete the project setup. 27 | 28 | 29 | 30 | ```sh 31 | gcloud config set project 32 | ``` 33 | 34 | ## Enable permissions for deployment 35 | 36 | You need to apply the settings and create the custom roles in the project before File Storage Security stack deployment. This only needs to be done once on a GCP project for File Storage Security stack deployment: 37 | 38 | ### Step 1: Apply the GCP configuration deployment 39 | 40 | Enable all the needed APIs and create required custom roles by Terraform. 41 | 42 | * Specify the GCP project ID in terraform.tfvars.json under `gcp-configuration` folder. 43 | 44 | * Apply the Terraform template in the Cloud Shell: 45 | 46 | ```sh 47 | terraform -chdir=gcp-configuration init && \ 48 | terraform -chdir=gcp-configuration apply 49 | ``` 50 | 51 | -------------------------------- 52 | 53 | For more information, see [Permissions for deployment](https://cloudone.trendmicro.com/docs/file-storage-security/gs-before-gcp/). 54 | 55 | ## Configure and deploy the stack 56 | 57 | Specify the following fields in terraform.tfvars.json under `storages` folder and apply the Terraform template in the Cloud Shell: 58 | 59 | 1. **projectID** Specify the project for this deployment. 60 | 2. **functionAutoUpdate:** Enable or disable automatic remote code update. The default value is `true`. Allow values: `true`, `false`. 61 | 62 | The stack in JSON object `storageStacks` could be multiples. You can have 20 storage stacks in a single Terraform deployment. 63 | 64 | Storage stack: 65 | 1. **storageStackName**: Specify the name of the storage stack. 66 | 2. **scannerStackName**: Specify the existing bucket name that you wish to protect. 67 | 3. **region**: Specify the region of your bucket. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/). 68 | 4. **managementServiceAccountProjectID**: Copy and paste the service account information from the File Storage Security console. 69 | 5. **managementServiceAccountID**: Copy and paste the service account information from the File Storage Security console. 70 | 6. **scannerProjectID**: Copy and paste the service account information from the File Storage Security console. 71 | 7. **scannerServiceAccountID**: Copy and paste the service account information from the File Storage Security console. 72 | 8. **scannerTopic**: Copy and paste the service account information from the File Storage Security console. 73 | 9. **reportObjectKey**: Select `true` to report the object keys of the scanned objects to File Storage Security backend services. File Storage Security can then display the object keys of the malicious objects in the response of events API. Allows values `true`, `true`. 74 | 10. **objectFilterPrefix**: Limit the scan to objects whose name starts with the specified characters. Specify `""` to scan without filters. 75 | 76 | > **Tips**: 77 | `scanner` is only required in all-in-one deployment, so the default value should be `null`. `disableScanningBucketIAMBinding` is required by converting from the GCP Deployment Manager's deployment, if it's a new deployment should be `false`. 78 | 79 | ```sh 80 | { 81 | "projectID": "", 82 | "functionAutoUpdate": true, 83 | "storageStacks": { 84 | "": { 85 | "scanningBucketName": "", 86 | "region": "", 87 | "managementServiceAccountProjectID": "", 88 | "managementServiceAccountID": "", 89 | "scannerProjectID": "", 90 | "scannerTopic": "", 91 | "scannerServiceAccountID": "", 92 | "reportObjectKey": false, 93 | "disableScanningBucketIAMBinding": false, 94 | "scanner": null, 95 | "objectFilterPrefix": "" 96 | } 97 | } 98 | } 99 | ``` 100 | 101 | ### Apply the deployment 102 | 103 | ```sh 104 | terraform -chdir=storages init && \ 105 | terraform -chdir=storages apply 106 | ``` 107 | 108 | > Please save `terraform.tfstate` and `terraform.tfvars.json` for managing the deployment (You will need them for updating and deleting stack). We recommend you use [remote configuration](https://developer.hashicorp.com/terraform/language/settings/backends/configuration) to keep your tfstate somewhere safe. 109 | 110 | ## Configure JSON in File Storage Security console 111 | 112 | To complete the deployment process, once the stacks are deployed, follow the steps to configure management role: 113 | 114 | 1. Copy the JSON content of `storage_stacks_outputs` from the Cloud Shell output of Terraform. 115 | 2. Paste the content back to the File Storage Security console. 116 | 117 | > **Tip**: 118 | > You can get Terraform output by the command. 119 | > ```sh 120 | > terraform -chdir=storages output 121 | > ``` 122 | 123 | -------------------------------- 124 | 125 | ## Start scanning 126 | 127 | You have now deployed File Storage Security scanner and storage stacks successfully. To test your deployment, you'll need to generate a malware detection using the eicar file. 128 | 129 | 1. Download the eicar file from eicar file page into your scanning bucket with the script. 130 | 131 | ```sh 132 | wget https://secure.eicar.org/eicar.com.txt 133 | gsutil cp eicar.com.txt gs:///eicar 134 | ``` 135 | 136 | 2. Execute the script to examine the scan result: 137 | 138 | ```sh 139 | gsutil stat 'gs:///eicar' 140 | ``` 141 | 142 | 3. In Metadata, look for the following tags: 143 | * **fss-scan-date**: date_and_time 144 | * **fss-scan-result**: malicious 145 | * **fss-scanned**: true 146 | 147 | The tags indicate that File Storage Security scanned the file and tagged it correctly as malware. The scan results are also available in the console on the Scan Activity page. 148 | 149 | -------------------------------- 150 | 151 | ### Next Step 152 | 153 | [Quarantine or promote files based on the scan results](https://cloudone.trendmicro.com/docs/file-storage-security/github-sample-code/#post-scan) 154 | -------------------------------------------------------------------------------- /gcp-terraform/modules/management-roles/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | custom_role_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${var.customRolePrefix}_" 3 | custom_role_title_prefix = var.customRolePrefix == "" ? var.customRolePrefix : "${replace(var.customRolePrefix, "_", "-")}-" 4 | } 5 | 6 | resource "google_project_iam_custom_role" "trend_micro_fss_cloud_function_management_role" { 7 | project = var.projectID 8 | 9 | role_id = "${local.custom_role_prefix}trend_micro_fss_cloud_function_management_role" 10 | description = "Trend Micro File Storage Security Cloud Function Management Role" 11 | title = "${local.custom_role_title_prefix}trend-micro-fss-cloud-function-management-role" 12 | permissions = [ 13 | "cloudfunctions.functions.get", 14 | "cloudfunctions.functions.list", 15 | "cloudfunctions.functions.sourceCodeGet", 16 | "cloudfunctions.functions.sourceCodeSet", 17 | "cloudfunctions.functions.update", 18 | "cloudbuild.builds.get", 19 | "cloudbuild.builds.list" 20 | ] 21 | 22 | lifecycle { 23 | prevent_destroy = true 24 | } 25 | } 26 | 27 | resource "google_project_iam_custom_role" "trend_micro_fss_log_management_role" { 28 | project = var.projectID 29 | 30 | role_id = "${local.custom_role_prefix}trend_micro_fss_log_management_role" 31 | description = "Trend Micro File Storage Security Log Management Role" 32 | title = "${local.custom_role_title_prefix}trend-micro-fss-log-management-role" 33 | permissions = [ 34 | "logging.logs.list", 35 | "logging.queries.create", 36 | "logging.queries.get", 37 | "logging.queries.list" 38 | ] 39 | 40 | lifecycle { 41 | prevent_destroy = true 42 | } 43 | } 44 | 45 | resource "google_project_iam_custom_role" "trend_micro_fss_pubsub_iam_management_role" { 46 | project = var.projectID 47 | 48 | role_id = "${local.custom_role_prefix}trend_micro_fss_pubsub_iam_management_role" 49 | description = "Trend Micro File Storage Security PubSub IAM Management Role" 50 | title = "${local.custom_role_title_prefix}trend-micro-fss-pubsub-iam-management-role" 51 | permissions = [ 52 | "pubsub.topics.getIamPolicy", 53 | "pubsub.topics.setIamPolicy" 54 | ] 55 | 56 | lifecycle { 57 | prevent_destroy = true 58 | } 59 | } 60 | 61 | 62 | resource "google_project_iam_custom_role" "trend_micro_fss_pubsub_management_role" { 63 | project = var.projectID 64 | 65 | role_id = "${local.custom_role_prefix}trend_micro_fss_pubsub_management_role" 66 | description = "Trend Micro File Storage Security PubSub Management Role" 67 | title = "${local.custom_role_title_prefix}trend-micro-fss-pubsub-management-role" 68 | permissions = [ 69 | "pubsub.topics.get", 70 | "pubsub.topics.list", 71 | "pubsub.subscriptions.get", 72 | "pubsub.subscriptions.list" 73 | ] 74 | 75 | lifecycle { 76 | prevent_destroy = true 77 | } 78 | } 79 | 80 | resource "google_project_iam_custom_role" "trend_micro_fss_secret_management_role" { 81 | project = var.projectID 82 | 83 | role_id = "${local.custom_role_prefix}trend_micro_fss_secret_management_role" 84 | description = "Trend Micro File Storage Security Secret Management Role" 85 | title = "${local.custom_role_title_prefix}trend-micro-fss-secret-management-role" 86 | permissions = [ 87 | "secretmanager.secrets.get", 88 | "secretmanager.versions.add", 89 | "secretmanager.versions.enable", 90 | "secretmanager.versions.destroy", 91 | "secretmanager.versions.disable", 92 | "secretmanager.versions.get", 93 | "secretmanager.versions.list", 94 | "secretmanager.versions.access" 95 | ] 96 | 97 | lifecycle { 98 | prevent_destroy = true 99 | } 100 | } 101 | 102 | resource "google_project_iam_custom_role" "trend_micro_fss_service_account_management_role" { 103 | project = var.projectID 104 | 105 | role_id = "${local.custom_role_prefix}trend_micro_fss_service_account_management_role" 106 | description = "Trend Micro File Storage Security Service Account Management Role" 107 | title = "${local.custom_role_title_prefix}trend-micro-fss-service-account-management-role" 108 | permissions = [ 109 | "iam.serviceAccounts.actAs", 110 | "iam.serviceAccounts.get", 111 | "iam.serviceAccounts.getIamPolicy", 112 | "iam.serviceAccounts.list" 113 | ] 114 | 115 | lifecycle { 116 | prevent_destroy = true 117 | } 118 | } 119 | 120 | resource "google_project_iam_custom_role" "trend_micro_fss_source_code_set_role" { 121 | project = var.projectID 122 | 123 | role_id = "${local.custom_role_prefix}trend_micro_fss_source_code_set_role" 124 | description = "Trend Micro File Storage Security Source Code Set Role" 125 | title = "${local.custom_role_title_prefix}trend-micro-fss-source-code-set-role" 126 | permissions = [ 127 | "cloudfunctions.functions.sourceCodeSet" 128 | ] 129 | 130 | lifecycle { 131 | prevent_destroy = true 132 | } 133 | } 134 | 135 | resource "google_project_iam_custom_role" "trend_micro_fss_pattern_update_role" { 136 | project = var.projectID 137 | 138 | role_id = "${local.custom_role_prefix}trend_micro_fss_pattern_update_role" 139 | description = "Trend Micro File Storage Security Pattern Update Role" 140 | title = "${local.custom_role_title_prefix}trend-micro-fss-pattern-update-role" 141 | permissions = [ 142 | "storage.objects.create", 143 | "storage.objects.delete", 144 | "storage.objects.get", 145 | "storage.objects.list", 146 | "storage.objects.update" 147 | ] 148 | 149 | lifecycle { 150 | prevent_destroy = true 151 | } 152 | } 153 | 154 | resource "google_project_iam_custom_role" "trend_micro_fss_get_pattern_update_scanner_role" { 155 | project = var.projectID 156 | 157 | role_id = "${local.custom_role_prefix}trend_micro_fss_get_pattern_update_scanner_role" 158 | description = "Trend Micro File Storage Security Get Pattern Update Role" 159 | title = "${local.custom_role_title_prefix}trend-micro-fss-get-pattern-update-scanner-role" 160 | permissions = [ 161 | "storage.objects.get", 162 | "storage.objects.list" 163 | ] 164 | 165 | lifecycle { 166 | prevent_destroy = true 167 | } 168 | } 169 | 170 | resource "google_project_iam_custom_role" "trend_micro_fss_bucket_listener_role" { 171 | project = var.projectID 172 | 173 | role_id = "${local.custom_role_prefix}trend_micro_fss_bucket_listener_role" 174 | description = "Trend Micro File Storage Security Bucket Listener Role" 175 | title = "${local.custom_role_title_prefix}trend-micro-fss-bucket-listener-role" 176 | permissions = [ 177 | "iam.serviceAccounts.signBlob" 178 | ] 179 | 180 | lifecycle { 181 | prevent_destroy = true 182 | } 183 | } 184 | 185 | resource "google_project_iam_custom_role" "trend_micro_fss_bucket_listener_storage_role" { 186 | project = var.projectID 187 | 188 | role_id = "${local.custom_role_prefix}trend_micro_fss_bucket_listener_storage_role" 189 | description = "Trend Micro File Storage Security Bucket Listener Storage Role" 190 | title = "${local.custom_role_title_prefix}trend-micro-fss-bucket-listener-storage-role" 191 | permissions = [ 192 | "storage.objects.get" 193 | ] 194 | 195 | lifecycle { 196 | prevent_destroy = true 197 | } 198 | } 199 | 200 | resource "google_project_iam_custom_role" "trend_micro_fss_post_action_tag_role" { 201 | project = var.projectID 202 | 203 | role_id = "${local.custom_role_prefix}trend_micro_fss_post_action_tag_role" 204 | description = "Trend Micro File Storage Security Post Action Tag Role" 205 | title = "${local.custom_role_title_prefix}trend-micro-fss-post-action-tag-role" 206 | permissions = [ 207 | "storage.objects.get", 208 | "storage.objects.update" 209 | ] 210 | 211 | lifecycle { 212 | prevent_destroy = true 213 | } 214 | } 215 | -------------------------------------------------------------------------------- /gcp-terraform/modules/scanner-stacks/iam-bindings.tf: -------------------------------------------------------------------------------- 1 | data "google_service_account" "management_service_account" { 2 | for_each = local.scanner_stacks 3 | project = each.value.managementServiceAccountProjectID 4 | account_id = each.value.managementServiceAccountID 5 | } 6 | 7 | resource "google_service_account_iam_binding" "scanner_gcf_service_account_iam" { 8 | for_each = local.scanner_stacks 9 | service_account_id = google_service_account.scanner_service_account[each.key].name 10 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_service_account_management_role" 11 | 12 | members = [ 13 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 14 | ] 15 | } 16 | 17 | resource "google_service_account_iam_binding" "pattern_updater_service_account_iam" { 18 | for_each = local.scanner_stacks 19 | service_account_id = google_service_account.pattern_updater_service_account[each.key].name 20 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_service_account_management_role" 21 | 22 | members = [ 23 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 24 | ] 25 | } 26 | 27 | resource "google_pubsub_topic_iam_binding" "scanner_topic_management_iam_binding" { 28 | for_each = local.scanner_stacks 29 | topic = google_pubsub_topic.scanner_topic[each.key].name 30 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_pubsub_management_role" 31 | members = [ 32 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 33 | ] 34 | } 35 | 36 | resource "google_pubsub_topic_iam_binding" "scanner_topic_iam_management_iam_binding" { 37 | for_each = local.scanner_stacks 38 | topic = google_pubsub_topic.scanner_topic[each.key].name 39 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_pubsub_iam_management_role" 40 | members = [ 41 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 42 | ] 43 | } 44 | 45 | resource "google_pubsub_topic_iam_binding" "scanner_topic_publisher_iam_binding" { 46 | for_each = local.scanner_stacks 47 | topic = google_pubsub_topic.scanner_topic[each.key].name 48 | role = "roles/pubsub.publisher" 49 | members = [ 50 | "serviceAccount:${google_service_account.scanner_service_account[each.key].email}" 51 | ] 52 | 53 | lifecycle { 54 | ignore_changes = [ 55 | members, // Prevent the policy is overwritten by stack updating beacuse TF will replace bucket listener's service account by scaner service account defined in here 56 | ] 57 | } 58 | } 59 | 60 | resource "google_pubsub_topic_iam_binding" "scanner_dlt_topic_management_iam_binding" { 61 | for_each = local.scanner_stacks 62 | topic = google_pubsub_topic.scanner_topic_dlt[each.key].name 63 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_pubsub_management_role" 64 | members = [ 65 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 66 | ] 67 | } 68 | 69 | resource "google_pubsub_topic_iam_binding" "scanner_dlt_topic_iam_management_iam_binding" { 70 | for_each = local.scanner_stacks 71 | topic = google_pubsub_topic.scanner_topic_dlt[each.key].name 72 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_pubsub_iam_management_role" 73 | members = [ 74 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 75 | ] 76 | } 77 | 78 | resource "google_pubsub_topic_iam_binding" "scanner_dlt_topic_publisher_iam_binding" { 79 | for_each = local.scanner_stacks 80 | topic = google_pubsub_topic.scanner_topic_dlt[each.key].name 81 | role = "roles/pubsub.publisher" 82 | members = [ 83 | "serviceAccount:service-${data.google_project.project.number}@gcp-sa-pubsub.iam.gserviceaccount.com" 84 | ] 85 | } 86 | 87 | resource "google_storage_bucket_iam_binding" "pattern_update_scanner_iam_binding" { 88 | for_each = local.scanner_stacks 89 | bucket = google_storage_bucket.pattern_update_bucket[each.key].name 90 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_get_pattern_update_scanner_role" 91 | members = [ 92 | "serviceAccount:${google_service_account.scanner_service_account[each.key].email}" 93 | ] 94 | } 95 | 96 | resource "google_storage_bucket_iam_binding" "pattern_updater_iam_binding" { 97 | for_each = local.scanner_stacks 98 | bucket = google_storage_bucket.pattern_update_bucket[each.key].name 99 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_pattern_update_role" 100 | members = [ 101 | "serviceAccount:${google_service_account.pattern_updater_service_account[each.key].email}" 102 | ] 103 | } 104 | 105 | resource "google_cloudfunctions_function_iam_binding" "pattern_updater_function_iam_binding" { 106 | for_each = local.scanner_stacks 107 | region = each.value.region 108 | cloud_function = google_cloudfunctions_function.pattern_updater_function[each.key].name 109 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_cloud_function_management_role" 110 | members = [ 111 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 112 | ] 113 | } 114 | 115 | resource "google_cloudfunctions_function_iam_binding" "scanner_function_iam_binding" { 116 | for_each = local.scanner_stacks 117 | region = each.value.region 118 | cloud_function = google_cloudfunctions_function.scanner_function[each.key].name 119 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_cloud_function_management_role" 120 | members = [ 121 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 122 | ] 123 | } 124 | 125 | resource "google_cloudfunctions_function_iam_binding" "scanner_dlt_function_iam_binding" { 126 | for_each = local.scanner_stacks 127 | region = each.value.region 128 | cloud_function = google_cloudfunctions_function.scanner_dlt_function[each.key].name 129 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_cloud_function_management_role" 130 | members = [ 131 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 132 | ] 133 | } 134 | 135 | resource "google_secret_manager_secret_iam_binding" "scanner_secret_management_service_account_iam_binding" { 136 | for_each = local.scanner_stacks 137 | secret_id = google_secret_manager_secret.scanner_secret[each.key].secret_id 138 | role = "projects/${var.projectID}/roles/${local.custom_role_prefix}trend_micro_fss_secret_management_role" 139 | members = [ 140 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 141 | ] 142 | } 143 | 144 | resource "google_secret_manager_secret_iam_binding" "scanner_secret_scanner_service_account_iam_binding" { 145 | for_each = local.scanner_stacks 146 | secret_id = google_secret_manager_secret.scanner_secret[each.key].secret_id 147 | role = "roles/secretmanager.secretAccessor" 148 | members = [ 149 | "serviceAccount:${google_service_account.scanner_service_account[each.key].email}" 150 | ] 151 | } 152 | 153 | resource "google_secret_manager_secret_iam_binding" "scanner_outputs_management_service_account_iam_binding" { 154 | for_each = local.scanner_stacks 155 | secret_id = google_secret_manager_secret.scanner_outputs_secret[each.key].secret_id 156 | role = "roles/secretmanager.secretAccessor" 157 | members = [ 158 | "serviceAccount:${data.google_service_account.management_service_account[each.key].email}" 159 | ] 160 | } 161 | -------------------------------------------------------------------------------- /gcp-terraform/docs/deployment_tutorial_all_in_one.md: -------------------------------------------------------------------------------- 1 | # Cloud One File Storage Security 2 | 3 | ## Deploy scanner and storage stacks 4 | 5 | ## Overview 6 | 7 | 8 | 9 | This tutorial will guide you to protect an existing GCS (Google Cloud Storage) from malware by deploying Trend Micro Cloud One File Storage Security scanner and storage stacks. 10 | 11 | -------------------------------- 12 | 13 | ### Permissions 14 | 15 | The permissions that File Storage Security management roles will have after it has been deployed and configured are defined in: 16 | 17 | * Management roles 18 | 19 | ### Backend updates 20 | 21 | For automatic backend updates that will be pushed, see [Update GCP components](https://cloudone.trendmicro.com/docs/file-storage-security/component-update-gcp/). 22 | 23 | ## Project setup 24 | 25 | 1. Select the project from the drop-down list at the top of the GCP console. 26 | 2. Copy and execute the script below in the Cloud Shell to complete the project setup. 27 | 28 | 29 | 30 | ```sh 31 | gcloud config set project 32 | ``` 33 | 34 | ## Enable permissions for deployment 35 | 36 | You need to apply the settings and create the custom roles in the project before File Storage Security stack deployment. This only needs to be done once on a GCP project for File Storage Security stack deployment: 37 | 38 | ### Step 1: Apply the GCP configuration deployment: 39 | 40 | Enable all the needed APIs and create required custom roles by Terraform. 41 | 42 | * Specify the GCP project ID in terraform.tfvars.json under `gcp-configuration` folder. 43 | 44 | * Apply the Terraform template in the Cloud Shell: 45 | 46 | ```sh 47 | terraform -chdir=gcp-configuration init && \ 48 | terraform -chdir=gcp-configuration apply 49 | ``` 50 | 51 | -------------------------------- 52 | 53 | For more information, see [Permissions for deployment](https://cloudone.trendmicro.com/docs/file-storage-security/gs-before-gcp/). 54 | 55 | ## Configure and deploy the stacks 56 | 57 | Specify the following fields in terraform.tfvars.json under `all-in-one` folder and apply the Terraform template in the Cloud Shell: 58 | 59 | 1. **projectID**: Specify the project for this deployment. 60 | 2. **functionAutoUpdate**: Enable or disable automatic remote code update. The default value is `true`. Allow values: `true`, `false`. 61 | 62 | The stack in JSON object `scannerStacks` and `storageStacks` could be multiples. You can have 5 scanner stacks with 20 storage stacks in a single Terraform deployment. 63 | 64 | Scanner stack: 65 | 66 | 1. **scannerStackName**: Specify the name of the scanner stack. 67 | 2. **region**: Specify the region for the scanner stack. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/). 68 | 3. **managementServiceAccountProjectID**: Copy and paste the service account information from the File Storage Security console. 69 | 4. **managementServiceAccountID**: Copy and paste the service account information from the File Storage Security console. 70 | 71 | Storage stack: 72 | 73 | 1. **storageStackName**: Specify the name of the storage stack. 74 | 2. **scannerStackName**: Specify the name of the scanner stack. 75 | 3. **scanningBucketName**: Specify the existing bucket name that you wish to protect. 76 | 4. **region**: Specify the region of your bucket. For the list of supported GCP regions, please see [Supported GCP Regions](https://cloudone.trendmicro.com/docs/file-storage-security/supported-gcp/). 77 | 5. **managementServiceAccountProjectID**: Copy and paste the service account information from the File Storage Security console. 78 | 6. **managementServiceAccountID**: Copy and paste the service account information from the File Storage Security console. 79 | 7. **reportObjectKey**: Select `true` to report the object keys of the scanned objects to File Storage Security backend services. File Storage Security can then display the object keys of the malicious objects in the response of events API. Allows values `true`, `false`. 80 | 8. **objectFilterPrefix**: Limit the scan to objects whose name starts with the specified characters. Specify `""` to scan without filters. 81 | 82 | > **Tips**: 83 | `scannerProjectID`, `scannerTopic`, `scannerServiceAccountID` should be `null` in All-in-One deployment. `disableScanningBucketIAMBinding` is required by converting from the GCP Deployment Manager's deployment, if it's a new deployment should be `false`. 84 | 85 | ```sh 86 | { 87 | "projectID": "", 88 | "functionAutoUpdate": true, 89 | "scannerStacks": { 90 | "": { 91 | "region": "", 92 | "managementServiceAccountProjectID": "", 93 | "managementServiceAccountID": "" 94 | } 95 | }, 96 | "storageStacks": { 97 | "": { 98 | "scanner": "", 99 | "scanningBucketName": "", 100 | "region": "", 101 | "managementServiceAccountProjectID": "", 102 | "managementServiceAccountID": "", 103 | "scannerProjectID": null, 104 | "scannerTopic": null, 105 | "scannerServiceAccountID": null, 106 | "reportObjectKey": false, 107 | "disableScanningBucketIAMBinding": false, 108 | "objectFilterPrefix": "" 109 | } 110 | } 111 | } 112 | ``` 113 | 114 | ### Initialize and apply the deployment 115 | 116 | ```sh 117 | terraform -chdir=all-in-one init && \ 118 | terraform -chdir=all-in-one apply 119 | ``` 120 | 121 | > Please save `terraform.tfstate` and `terraform.tfvars.json` for managing the deployment (You will need them for updating and deleting stack). We recommend you use [remote configuration](https://developer.hashicorp.com/terraform/language/settings/backends/configuration) to keep your tfstate somewhere safe. 122 | 123 | ## Configure JSON in File Storage Security console 124 | 125 | To complete the deployment process, once the stacks are deployed, follow the steps to configure management role: 126 | 127 | 1. Copy the JSON content of `all_in_one_outputs` from the Cloud Shell output of Terraform. 128 | 2. Paste the content back to the File Storage Security console. 129 | 130 | > **Tip**: 131 | > You can get Terraform output by the command. 132 | > ```sh 133 | > terraform -chdir=all-in-one output 134 | > ``` 135 | 136 | -------------------------------- 137 | 138 | ## Start scanning 139 | 140 | You have now deployed File Storage Security scanner and storage stacks successfully. To test your deployment, you'll need to generate a malware detection using the eicar file. 141 | 142 | 1. Download the eicar file from eicar file page into your scanning bucket with the script. 143 | 144 | ```sh 145 | wget https://secure.eicar.org/eicar.com.txt 146 | gsutil cp eicar.com.txt gs:///eicar 147 | ``` 148 | 149 | 2. Execute the script to examine the scan result: 150 | 151 | ```sh 152 | gsutil stat 'gs:///eicar' 153 | ``` 154 | 155 | 3. In Metadata, look for the following tags: 156 | * **fss-scan-date**: date_and_time 157 | * **fss-scan-result**: malicious 158 | * **fss-scanned**: true 159 | 160 | The labels indicate that File Storage Security scanned the file and labeled it correctly as malware. The scan results are also available in the File Storage Security web console on the Scan Activity page. 161 | 162 | -------------------------------- 163 | 164 | ### Next Step 165 | 166 | [Quarantine or promote files based on the scan results](https://cloudone.trendmicro.com/docs/file-storage-security/github-sample-code/#post-scan) 167 | -------------------------------------------------------------------------------- /gcp/deployment-script-scanner.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | while getopts d:r:u:m:c:a:f: args 5 | do 6 | case "${args}" in 7 | d) DEPLOYMENT_NAME_SCANNER=${OPTARG};; 8 | r) REGION=${OPTARG};; 9 | u) PACKAGE_URL=${OPTARG};; 10 | m) MANAGEMENT_SERVICE_ACCOUNT=${OPTARG};; 11 | c) CLOUD_ONE_REGION=${OPTARG};; 12 | a) CLOUD_ONE_ACCOUNT=${OPTARG};; # deprecated 13 | f) FUNCTION_AUTO_UPDATE=${OPTARG};; 14 | esac 15 | done 16 | 17 | GCP_PROJECT_ID=$(gcloud config list --format 'value(core.project)' 2> /dev/null) 18 | ARTIFACT_BUCKET_NAME='fss-artifact'-$(cat /proc/sys/kernel/random/uuid || uuidgen | tr '[:upper:]' '[:lower:]') 19 | 20 | echo "Artifact bucket name: $ARTIFACT_BUCKET_NAME"; 21 | echo "Scanner Deployment Name: $DEPLOYMENT_NAME_SCANNER"; 22 | echo "GCP Project ID: $GCP_PROJECT_ID"; 23 | echo "Region: $REGION"; 24 | echo "Package URL: $PACKAGE_URL"; 25 | echo "Management Service Account: $MANAGEMENT_SERVICE_ACCOUNT"; 26 | echo "Cloud One Region: $CLOUD_ONE_REGION"; 27 | echo "Function Auto Update: $FUNCTION_AUTO_UPDATE"; 28 | echo "Will deploy file storage security protection unit scanner stack, Ctrl-C to cancel..." 29 | sleep 5 30 | 31 | if [ -z "$PACKAGE_URL" ]; then 32 | PACKAGE_URL='https://file-storage-security.s3.amazonaws.com/latest/' 33 | fi 34 | 35 | if [ -z "$CLOUD_ONE_REGION" ]; then 36 | CLOUD_ONE_REGION='us-1' 37 | fi 38 | 39 | if [ ! -z "$CLOUD_ONE_ACCOUNT" ]; then 40 | echo "Option -a has deprecated" 41 | fi 42 | 43 | if [ -z "$FUNCTION_AUTO_UPDATE" ]; then 44 | FUNCTION_AUTO_UPDATE='True' 45 | fi 46 | 47 | TEMPLATES_FILE='gcp-templates.zip' 48 | SCANNER_FILE='gcp-scanner.zip' 49 | SCANNER_DLT_FILE='gcp-scanner-dlt.zip' 50 | SCANNER_PATTERN_UPDATER_FILE='gcp-scanner-pattern-updater.zip' 51 | 52 | # Check Project Setting 53 | gcloud deployment-manager deployments list > /dev/null 54 | 55 | # Download the templates package 56 | wget $PACKAGE_URL'gcp-templates/'$TEMPLATES_FILE 57 | 58 | # Unzip the templates package 59 | unzip $TEMPLATES_FILE && rm $TEMPLATES_FILE 60 | 61 | # Create an artifact Google Cloud Storage bucket 62 | gsutil mb --pap enforced -b on gs://$ARTIFACT_BUCKET_NAME 63 | 64 | prepareArtifact() { 65 | # Download FSS functions artifacts 66 | wget $PACKAGE_URL'cloud-functions/'$1 67 | # Upload functions artifacts to the artifact bucket 68 | gsutil cp $1 gs://$ARTIFACT_BUCKET_NAME/$1 && rm $1 69 | } 70 | 71 | prepareArtifact $SCANNER_FILE 72 | prepareArtifact $SCANNER_DLT_FILE 73 | prepareArtifact $SCANNER_PATTERN_UPDATER_FILE 74 | 75 | # Deploy or update File Storage Security roles 76 | echo "Deploying File Storage Security roles..." 77 | FSS_ROLES_DEPLOYMENT='trend-micro-file-storage-security-roles' 78 | # Deploy the roles if they don't exist 79 | roleDeployment=$(gcloud deployment-manager deployments describe $FSS_ROLES_DEPLOYMENT --format json) \ 80 | || gcloud deployment-manager deployments create $FSS_ROLES_DEPLOYMENT --config templates/fss-roles.yaml 81 | # Update the roles if they are not being updated 82 | ([[ ! -z "$roleDeployment" && "DONE" == $(echo "$roleDeployment" | jq -r '.deployment.operation.status') ]] \ 83 | && gcloud deployment-manager deployments update $FSS_ROLES_DEPLOYMENT --config templates/fss-roles.yaml) \ 84 | || echo "$FSS_ROLES_DEPLOYMENT is updating. Skip updating the roles." 85 | 86 | SCANNER_YAML_PATH=templates/scanner/scanner.yaml 87 | SCANNER_SA_YAML_PATH=templates/scanner/scanner-stack-service-accounts.yaml 88 | sed -i.bak "s//$REGION/g" $SCANNER_YAML_PATH 89 | sed -i.bak "s//$ARTIFACT_BUCKET_NAME/g" $SCANNER_YAML_PATH 90 | sed -i.bak "s//$DEPLOYMENT_NAME_SCANNER/g" $SCANNER_YAML_PATH 91 | sed -i.bak "s//$MANAGEMENT_SERVICE_ACCOUNT/g" $SCANNER_YAML_PATH 92 | sed -i.bak "s//$MANAGEMENT_SERVICE_ACCOUNT/g" $SCANNER_SA_YAML_PATH 93 | sed -i.bak "s//$FUNCTION_AUTO_UPDATE/g" $SCANNER_YAML_PATH 94 | 95 | cat $SCANNER_SA_YAML_PATH 96 | cat $SCANNER_YAML_PATH 97 | 98 | # Deploy scanner stack service account template 99 | gcloud deployment-manager deployments create $DEPLOYMENT_NAME_SCANNER --config $SCANNER_SA_YAML_PATH 100 | 101 | SCANNER_DEPLOYMENT=$(gcloud deployment-manager deployments describe $DEPLOYMENT_NAME_SCANNER --format "json") 102 | 103 | searchScannerJSONOutputs() { 104 | echo $SCANNER_DEPLOYMENT | jq -r --arg v "$1" '.outputs[] | select(.name==$v).finalValue' 105 | } 106 | 107 | SCANNER_PROJECT_ID=$(searchScannerJSONOutputs scannerProjectID) 108 | SCANNER_SERVICE_ACCOUNT_ID=$(searchScannerJSONOutputs scannerServiceAccountID) 109 | 110 | SECRET_STRING=$( jq -n \ 111 | --arg fssAPIEndpoint "https://filestorage.$CLOUD_ONE_REGION.cloudone.trendmicro.com/api/" \ 112 | '{FSS_API_ENDPOINT: $fssAPIEndpoint}' ) 113 | 114 | # Create scanner secrets environment variable 115 | echo -n "$SECRET_STRING" | \ 116 | gcloud secrets create $DEPLOYMENT_NAME_SCANNER-scanner-secrets \ 117 | --replication-policy=user-managed --locations=$REGION \ 118 | --data-file=- 119 | 120 | # Allow scanner service account to access the secrets 121 | gcloud secrets add-iam-policy-binding $DEPLOYMENT_NAME_SCANNER-scanner-secrets \ 122 | --member="serviceAccount:$SCANNER_SERVICE_ACCOUNT_ID@$SCANNER_PROJECT_ID.iam.gserviceaccount.com" \ 123 | --role="roles/secretmanager.secretAccessor" 124 | # Allow management service account to access the secrets 125 | gcloud secrets add-iam-policy-binding $DEPLOYMENT_NAME_SCANNER-scanner-secrets \ 126 | --member="serviceAccount:$MANAGEMENT_SERVICE_ACCOUNT" \ 127 | --role="projects/$SCANNER_PROJECT_ID/roles/trend_micro_fss_secret_management_role" 128 | 129 | sed -i.bak "s//$DEPLOYMENT_NAME_SCANNER-scanner-secrets/g" $SCANNER_YAML_PATH 130 | 131 | # Update scanner template 132 | gcloud deployment-manager deployments update $DEPLOYMENT_NAME_SCANNER --config $SCANNER_YAML_PATH 133 | 134 | SCANNER_DEPLOYMENT=$(gcloud deployment-manager deployments describe $DEPLOYMENT_NAME_SCANNER --format "json") 135 | 136 | SCANNER_TOPIC=$(searchScannerJSONOutputs scannerTopic) 137 | SCANNER_TOPIC_DLT=$(searchScannerJSONOutputs scannerTopicDLT) 138 | 139 | SCANNER_PROJECT_NUMBER=$(gcloud projects list --filter=$SCANNER_PROJECT_ID --format="value(PROJECT_NUMBER)") 140 | PUBSUB_SERVICE_ACCOUNT="service-$SCANNER_PROJECT_NUMBER@gcp-sa-pubsub.iam.gserviceaccount.com" 141 | SUBSCRIPTIONS=$(gcloud pubsub topics list-subscriptions $SCANNER_TOPIC) 142 | SCANNER_SUBSCRIPTION_ID=${SUBSCRIPTIONS#*/*/*/} 143 | 144 | # Update scanner topic dead letter config 145 | gcloud pubsub subscriptions update $SCANNER_SUBSCRIPTION_ID \ 146 | --dead-letter-topic=$SCANNER_TOPIC_DLT \ 147 | --max-delivery-attempts=5 148 | 149 | # Binding Pub/Sub service account 150 | gcloud pubsub subscriptions add-iam-policy-binding $SCANNER_SUBSCRIPTION_ID \ 151 | --member="serviceAccount:$PUBSUB_SERVICE_ACCOUNT"\ 152 | --role="roles/pubsub.subscriber" 153 | 154 | # Binding appspot service account 155 | APPSPOT_SERVICE_ACCOUNT=$SCANNER_PROJECT_ID@appspot.gserviceaccount.com 156 | bindingCount=$(gcloud iam service-accounts get-iam-policy $APPSPOT_SERVICE_ACCOUNT --flatten=bindings --filter="bindings.members=serviceAccount:$MANAGEMENT_SERVICE_ACCOUNT AND bindings.role=roles/iam.serviceAccountUser" --format='json' | jq length) 157 | [[ 0 < $bindingCount ]] \ 158 | || gcloud iam service-accounts add-iam-policy-binding $APPSPOT_SERVICE_ACCOUNT \ 159 | --member="serviceAccount:$MANAGEMENT_SERVICE_ACCOUNT" --role=roles/iam.serviceAccountUser 160 | 161 | # Remove the artifact bucket 162 | gsutil rm -r gs://$ARTIFACT_BUCKET_NAME 163 | rm -rf templates 164 | 165 | printScannerJSON() { 166 | SCANNER_JSON=$(jq --null-input \ 167 | --arg projectID "$SCANNER_PROJECT_ID" \ 168 | --arg deploymentName "$DEPLOYMENT_NAME_SCANNER" \ 169 | '{"projectID": $projectID, "deploymentName": $deploymentName}') 170 | echo $SCANNER_JSON > $DEPLOYMENT_NAME_SCANNER.json 171 | cat $DEPLOYMENT_NAME_SCANNER.json 172 | } 173 | 174 | printScannerInfo() { 175 | SCANNER_INFO=$(jq --null-input \ 176 | --arg scannerTopic "$SCANNER_TOPIC" \ 177 | --arg scannerProjectID "$SCANNER_PROJECT_ID" \ 178 | --arg scannerSAID "$SCANNER_SERVICE_ACCOUNT_ID" \ 179 | '{"SCANNER_TOPIC": $scannerTopic, "SCANNER_PROJECT_ID": $scannerProjectID, "SCANNER_SERVICE_ACCOUNT_ID": $scannerSAID}') 180 | echo $SCANNER_INFO > $DEPLOYMENT_NAME_SCANNER-info.json 181 | cat $DEPLOYMENT_NAME_SCANNER-info.json 182 | } 183 | 184 | echo "FSS Protection Unit Information:" 185 | printScannerInfo 186 | 187 | echo "The scanner stack has been deployed successfully. Below is the content required to configure on File Storage Security console." 188 | 189 | echo "--- Content of $DEPLOYMENT_NAME_SCANNER.json ---" 190 | printScannerJSON 191 | echo "--- End of the content ---" 192 | -------------------------------------------------------------------------------- /gcp/storage/storage.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import common 3 | import management_roles 4 | import role 5 | import storage_stack_roles 6 | 7 | def create_storage_stack_resources(context): 8 | prefix = common.get_prefix(context, 'storage') 9 | 10 | properties = context.properties 11 | 12 | project_id = context.env['project'] 13 | region = properties['region'] 14 | management_service_account_id = properties['managementServiceAccountID'] 15 | 16 | scan_result_topic_name = f'{prefix}-scan-result-topic' 17 | scan_result_topic = { 18 | 'name': scan_result_topic_name, 19 | 'type': 'pubsub.v1.topic', 20 | 'properties': { 21 | 'name': f"projects/{project_id}/topics/{scan_result_topic_name}", 22 | 'topic': scan_result_topic_name 23 | }, 24 | 'accessControl': { 25 | 'gcpIamPolicy': { 26 | 'bindings': [ 27 | { 28 | 'role': role.get_role_name_ref(project_id, management_roles.PUBSUB_MANAGEMENT_ROLE), 29 | 'members': [ 30 | f"serviceAccount:{management_service_account_id}" 31 | ] 32 | }, 33 | { 34 | 'role': 'roles/pubsub.publisher', 35 | 'members': [ 36 | f'serviceAccount:$(ref.{prefix}-bucket-listener-service-account.email)', 37 | f'serviceAccount:$(ref.{prefix}-post-action-tag-service-account.email)', 38 | f"serviceAccount:{properties['scannerServiceAccountID']}@{properties['scannerProjectID']}.iam.gserviceaccount.com" 39 | ] 40 | } 41 | ] 42 | } 43 | } 44 | } 45 | 46 | bucket_listener = { 47 | 'name': f'{prefix}-bucket-listener', 48 | # https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions 49 | 'type': 'gcp-types/cloudfunctions-v1:projects.locations.functions', 50 | 'properties': { 51 | 'parent': f"projects/{project_id}/locations/{region}", 52 | 'function': f'{prefix}-bucket-listener', 53 | 'entryPoint': 'handler', 54 | 'sourceArchiveUrl': f'gs://{properties["artifactBucket"]}/gcp-listener.zip', 55 | 'serviceAccountEmail': f'$(ref.{prefix}-bucket-listener-service-account.email)', 56 | 'runtime': 'nodejs20', 57 | 'eventTrigger': { 58 | 'eventType': 'google.storage.object.finalize', 59 | 'resource': f"projects/{project_id}/buckets/{properties['scanningBucket']}", 60 | }, 61 | 'environmentVariables': { 62 | 'SCANNER_PUBSUB_TOPIC': properties['scannerTopic'], 63 | 'SCANNER_PROJECT_ID': properties['scannerProjectID'], 64 | 'SCAN_RESULT_TOPIC': f'projects/{project_id}/topics/{scan_result_topic["name"]}', 65 | 'DEPLOYMENT_NAME': properties['deploymentName'], 66 | 'REPORT_OBJECT_KEY': properties['reportObjectKey'] 67 | } 68 | } 69 | } 70 | 71 | bucket_listener_management_account_role_binding = { 72 | 'name': 'bucket-listener-management-account-role-binding', 73 | 'type': 'gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding', 74 | 'properties': { 75 | 'resource': f"$(ref.{bucket_listener['name']}.name)", 76 | 'role': role.get_role_name_ref(project_id, management_roles.CLOUD_FUNCTION_MANAGEMENT_ROLE), 77 | 'member': f'serviceAccount:{management_service_account_id}' 78 | } 79 | } 80 | 81 | bucket_listener_service_account_binding = { 82 | 'name': 'bucket-listener-service-account-binding', 83 | 'type': 'gcp-types/storage-v1:virtual.buckets.iamMemberBinding', 84 | 'properties': { 85 | 'bucket': properties['scanningBucket'], 86 | 'role': "roles/storage.legacyObjectReader", 87 | 'member': f'serviceAccount:$(ref.{prefix}-bucket-listener-service-account.email)' 88 | } 89 | } 90 | 91 | post_action_tag = { 92 | 'name': f'{prefix}-post-action-tag', 93 | # https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions 94 | 'type': 'gcp-types/cloudfunctions-v1:projects.locations.functions', 95 | 'properties': { 96 | 'parent': f"projects/{project_id}/locations/{region}", 97 | 'function': f'{prefix}-post-action-tag', 98 | 'entryPoint': 'main', 99 | 'sourceArchiveUrl': f'gs://{properties["artifactBucket"]}/gcp-action-tag.zip', 100 | 'serviceAccountEmail': f'$(ref.{prefix}-post-action-tag-service-account.email)', 101 | 'runtime': 'python38', 102 | 'eventTrigger': { 103 | 'eventType': 'providers/cloud.pubsub/eventTypes/topic.publish', 104 | 'resource': f"projects/{project_id}/topics/{scan_result_topic['name']}", 105 | 'failurePolicy': { 106 | 'retry': {} 107 | } 108 | } 109 | }, 110 | 'metadata': { 111 | 'dependsOn': [scan_result_topic['name']] 112 | } 113 | } 114 | 115 | post_action_tag_management_account_role_binding = { 116 | 'name': 'post-action-tag-management-account-role-binding', 117 | 'type': 'gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding', 118 | 'properties': { 119 | 'resource': f"$(ref.{post_action_tag['name']}.name)", 120 | 'role': role.get_role_name_ref(project_id, management_roles.CLOUD_FUNCTION_MANAGEMENT_ROLE), 121 | 'member': f'serviceAccount:{management_service_account_id}' 122 | } 123 | } 124 | 125 | post_action_tag_service_account_binding = { 126 | 'name': 'post-action-tag-service-account-binding', 127 | 'type': 'gcp-types/storage-v1:virtual.buckets.iamMemberBinding', 128 | 'properties': { 129 | 'bucket': properties['scanningBucket'], 130 | 'role': role.get_role_name_ref(project_id, storage_stack_roles.POST_ACTION_TAG_ROLE), 131 | 'member': f'serviceAccount:$(ref.{prefix}-post-action-tag-service-account.email)' 132 | } 133 | } 134 | 135 | storage_stack_function_update_role_binding = { 136 | 'name':'storage-stack-function-update-role-binding', 137 | 'type': 'gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding', 138 | 'properties': { 139 | 'resource': project_id, 140 | 'role': role.get_role_name_ref(project_id, management_roles.SOURCE_CODE_SET_ROLE), 141 | 'member': f'serviceAccount:{management_service_account_id}' 142 | } 143 | } 144 | 145 | resources = [ 146 | bucket_listener, 147 | bucket_listener_management_account_role_binding, 148 | bucket_listener_service_account_binding, 149 | post_action_tag, 150 | post_action_tag_management_account_role_binding, 151 | post_action_tag_service_account_binding, 152 | scan_result_topic, 153 | ] 154 | 155 | if properties['functionAutoUpdate']: 156 | resources.append(storage_stack_function_update_role_binding) 157 | 158 | outputs = [ 159 | { 160 | 'name': 'storageProjectID', 161 | 'value': project_id 162 | }, 163 | { 164 | 'name': 'bucketListenerSourceArchiveUrl', 165 | 'value': f'$(ref.{bucket_listener["name"]}.sourceArchiveUrl)' 166 | }, 167 | { 168 | 'name': 'scanResultTopic', 169 | 'value': scan_result_topic["name"] 170 | }, 171 | { 172 | 'name': 'bucketListenerFunctionName', 173 | 'value': '$(ref.{}.name)'.format(bucket_listener['name']) 174 | }, 175 | { 176 | 'name': 'postScanActionTagFunctionName', 177 | 'value': '$(ref.{}.name)'.format(post_action_tag['name']) 178 | }, 179 | { 180 | 'name': 'region', 181 | 'value': region 182 | }, 183 | { 184 | 'name': storage_stack_roles.get_role(storage_stack_roles.BUCKET_LISTENER_ROLE)['key'], 185 | 'value': role.get_role_id(storage_stack_roles.BUCKET_LISTENER_ROLE) 186 | }, 187 | { 188 | 'name': storage_stack_roles.get_role(storage_stack_roles.POST_ACTION_TAG_ROLE)['key'], 189 | 'value': role.get_role_id(storage_stack_roles.POST_ACTION_TAG_ROLE) 190 | }, 191 | { 192 | 'name': 'functionAutoUpdate', 193 | 'value': properties['functionAutoUpdate'] 194 | } 195 | ] 196 | return (resources, outputs) 197 | 198 | def generate_config(context): 199 | """ Entry point for the deployment resources. """ 200 | 201 | (resources, outputs) = create_storage_stack_resources(context) 202 | 203 | return { 204 | 'resources': resources, 205 | 'outputs': outputs 206 | } 207 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Trend Micro 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /gcp/scanner/scanner.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2022 Trend Micro Inc. All rights reserved. 2 | import common 3 | import management_roles 4 | import role 5 | import scanner_stack_roles 6 | 7 | def create_scanner_stack_resources(context): 8 | prefix = common.get_prefix(context, 'scanner') 9 | 10 | properties = context.properties 11 | 12 | project_id = context.env['project'] 13 | region = properties['region'] 14 | management_service_account_id = properties['managementServiceAccountID'] 15 | 16 | scanner_topic_name = f'{prefix}-scanner-topic' 17 | scanner_topic = { 18 | 'name': scanner_topic_name, 19 | 'type': 'pubsub.v1.topic', 20 | 'properties': { 21 | 'name': f"projects/{project_id}/topics/{scanner_topic_name}", 22 | 'topic': scanner_topic_name 23 | }, 24 | 'accessControl': { 25 | 'gcpIamPolicy': { 26 | 'bindings': [ 27 | { 28 | 'role': role.get_role_name_ref(project_id, management_roles.PUBSUB_MANAGEMENT_ROLE), 29 | 'members': [ 30 | f"serviceAccount:{management_service_account_id}" 31 | ] 32 | }, 33 | { 34 | 'role': role.get_role_name_ref(project_id, management_roles.PUBSUB_IAM_MANAGEMENT_ROLE), 35 | 'members': [ 36 | f"serviceAccount:{management_service_account_id}" 37 | ] 38 | }, 39 | { 40 | 'role': 'roles/pubsub.publisher', 41 | 'members': [ 42 | f'serviceAccount:$(ref.{prefix}-scanner-service-account.email)', 43 | ] 44 | } 45 | ] 46 | } 47 | } 48 | } 49 | 50 | pattern_updater_topic_name = f'{prefix}-pattern-updater-topic' 51 | pattern_updater_topic = { 52 | 'name': pattern_updater_topic_name, 53 | 'type': 'pubsub.v1.topic', 54 | 'properties': { 55 | 'name': f"projects/{project_id}/topics/{pattern_updater_topic_name}", 56 | 'topic': pattern_updater_topic_name 57 | } 58 | } 59 | 60 | pattern_update_bucket_name = f'{prefix}-pattern-update-bucket' 61 | pattern_update_bucket= { 62 | 'name': pattern_update_bucket_name, 63 | 'type': 'gcp-types/storage-v1:buckets', 64 | 'properties': { 65 | 'name': pattern_update_bucket_name, 66 | 'iamConfiguration': { 67 | 'uniformBucketLevelAccess' : { 68 | 'enabled': True 69 | } 70 | } 71 | } 72 | } 73 | 74 | pattern_update_bucket_scanner_role_binding = { 75 | 'name': 'pattern-update-bucket-scanner-role-binding', 76 | 'type': 'gcp-types/storage-v1:virtual.buckets.iamMemberBinding', 77 | 'properties': 78 | { 79 | 'bucket': f"$(ref.{pattern_update_bucket['name']}.name)", 80 | 'role': role.get_role_name_ref(project_id, scanner_stack_roles.GET_PATTERN_UPDATE_SCANNER_ROLE), 81 | 'member': f'serviceAccount:$(ref.{prefix}-scanner-service-account.email)' 82 | } 83 | } 84 | 85 | pattern_update_bucket_role_binding = { 86 | 'name': 'pattern-update-bucket-role-binding', 87 | 'type': 'gcp-types/storage-v1:virtual.buckets.iamMemberBinding', 88 | 'properties': 89 | { 90 | 'bucket': f"$(ref.{pattern_update_bucket['name']}.name)", 91 | 'role': role.get_role_name_ref(project_id, scanner_stack_roles.PATTERN_UPDATE_ROLE), 92 | 'member': f'serviceAccount:$(ref.{prefix}-pattern-updater-service-account.email)' 93 | } 94 | } 95 | 96 | pattern_updater = { 97 | 'name': f'{prefix}-pattern-updater', 98 | 'type': 'gcp-types/cloudfunctions-v1:projects.locations.functions', 99 | 'properties': { 100 | 'parent': f'projects/{project_id}/locations/{region}', 101 | 'function': f'{prefix}-pattern-updater', 102 | 'entryPoint': 'main', 103 | 'serviceAccountEmail': f'$(ref.{prefix}-pattern-updater-service-account.email)', 104 | 'sourceArchiveUrl': f"gs://{properties['artifactBucket']}/gcp-scanner-pattern-updater.zip", 105 | 'runtime': 'python38', 106 | 'availableMemoryMb': 2048, 107 | 'timeout': '120s', 108 | 'environmentVariables': { 109 | 'LD_LIBRARY_PATH': './:./lib', 110 | 'PATTERN_UPDATE_BUCKET': pattern_update_bucket['name'] 111 | }, 112 | 'eventTrigger': { 113 | 'eventType': 'providers/cloud.pubsub/eventTypes/topic.publish', 114 | 'resource': f"$(ref.{pattern_updater_topic_name}.name)", 115 | 'failurePolicy': { 116 | 'retry': {} 117 | } 118 | } 119 | } 120 | } 121 | 122 | pattern_updater_scheduler = { 123 | 'name': f'{prefix}-scheduler', 124 | 'type': 'gcp-types/cloudscheduler-v1:projects.locations.jobs', 125 | 'properties': { 126 | 'parent': f'projects/{project_id}/locations/{region}', 127 | 'name': f'{prefix}-pattern-update', 128 | 'description': 'pattern update', 129 | 'schedule': "0 * * * *", 130 | 'timeZone': 'UTC', 131 | 'pubsubTarget': { 132 | 'topicName': f"projects/{project_id}/topics/{pattern_updater_topic['name']}", 133 | 'data': 'UGF0dGVybiBVcGRhdGU=', 134 | } 135 | }, 136 | 'metadata': { 137 | 'dependsOn': [pattern_updater_topic['name']] 138 | } 139 | } 140 | 141 | scanner = { 142 | 'name': f'{prefix}-scanner', 143 | # https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions 144 | 'type': 'gcp-types/cloudfunctions-v1:projects.locations.functions', 145 | 'properties': { 146 | 'parent': f'projects/{project_id}/locations/{region}', 147 | 'function': f'{prefix}-scanner', 148 | 'entryPoint': 'main', 149 | 'sourceArchiveUrl': f"gs://{properties['artifactBucket']}/gcp-scanner.zip", 150 | 'serviceAccountEmail': f'$(ref.{prefix}-scanner-service-account.email)', 151 | 'runtime': 'python38', 152 | 'availableMemoryMb': 2048, 153 | 'timeout': '120s', 154 | 'environmentVariables': { 155 | 'LD_LIBRARY_PATH': '/workspace:/workspace/lib', 156 | 'PATTERN_PATH': './patterns', 157 | 'PROJECT_ID': project_id, 158 | 'REGION': region, 159 | 'DEPLOYMENT_NAME': properties['deploymentName'], 160 | 'PATTERN_UPDATE_BUCKET': pattern_update_bucket['name'] 161 | }, 162 | 'secretEnvironmentVariables': [ 163 | { 164 | 'key': 'SCANNER_SECRETS', 165 | 'projectId': project_id, 166 | 'secret': f'{properties["scannerSecretsName"]}', 167 | 'version': 'latest' 168 | } 169 | ], 170 | 'eventTrigger': { 171 | 'eventType': 'providers/cloud.pubsub/eventTypes/topic.publish', 172 | 'resource': f"projects/{project_id}/topics/{scanner_topic['name']}", 173 | 'failurePolicy': { 174 | 'retry': {} 175 | } 176 | } 177 | }, 178 | 'metadata': { 179 | 'dependsOn': [scanner_topic['name']] 180 | } 181 | } 182 | 183 | scanner_management_account_role_binding = { 184 | 'name': 'scanner-management-account-role-binding', 185 | 'type': 'gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding', 186 | 'properties': { 187 | 'resource': f"$(ref.{scanner['name']}.name)", 188 | 'role': role.get_role_name_ref(project_id, management_roles.CLOUD_FUNCTION_MANAGEMENT_ROLE), 189 | 'member': f'serviceAccount:{management_service_account_id}' 190 | } 191 | } 192 | 193 | pattern_updater_management_account_role_binding = { 194 | 'name': 'pattern-updater-management-account-role-binding', 195 | 'type': 'gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding', 196 | 'properties': { 197 | 'resource': f"$(ref.{pattern_updater['name']}.name)", 198 | 'role': role.get_role_name_ref(project_id, management_roles.CLOUD_FUNCTION_MANAGEMENT_ROLE), 199 | 'member': f'serviceAccount:{management_service_account_id}' 200 | } 201 | } 202 | 203 | scanner_topic_dlt_name = f'{prefix}-scanner-topic-dlt' 204 | scanner_topic_dlt = { 205 | 'name': scanner_topic_dlt_name, 206 | 'type': 'pubsub.v1.topic', 207 | 'properties': { 208 | 'name': f"projects/{project_id}/topics/{scanner_topic_dlt_name}", 209 | 'topic': scanner_topic_dlt_name 210 | }, 211 | 'accessControl': { 212 | 'gcpIamPolicy': { 213 | 'bindings': [ 214 | { 215 | 'role': role.get_role_name_ref(project_id, management_roles.PUBSUB_MANAGEMENT_ROLE), 216 | 'members': [ 217 | f"serviceAccount:{management_service_account_id}" 218 | ] 219 | }, 220 | { 221 | 'role': role.get_role_name_ref(project_id, management_roles.PUBSUB_IAM_MANAGEMENT_ROLE), 222 | 'members': [ 223 | f"serviceAccount:{management_service_account_id}" 224 | ] 225 | }, 226 | { 227 | 'role': 'roles/pubsub.publisher', 228 | 'members': [ 229 | f"serviceAccount:service-{context.env['project_number']}@gcp-sa-pubsub.iam.gserviceaccount.com", 230 | ] 231 | } 232 | ] 233 | } 234 | } 235 | } 236 | 237 | scanner_dlt = { 238 | 'name': f'{prefix}-scanner-dlt', 239 | # https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions 240 | 'type': 'gcp-types/cloudfunctions-v1:projects.locations.functions', 241 | 'properties': { 242 | 'parent': f'projects/{project_id}/locations/{region}', 243 | 'function': f'{prefix}-scanner-dlt', 244 | 'entryPoint': 'main', 245 | 'sourceArchiveUrl': f"gs://{properties['artifactBucket']}/gcp-scanner-dlt.zip", 246 | 'serviceAccountEmail': f'$(ref.{prefix}-scanner-service-account.email)', 247 | 'runtime': 'python38', 248 | 'eventTrigger': { 249 | 'eventType': 'providers/cloud.pubsub/eventTypes/topic.publish', 250 | 'resource': f"projects/{project_id}/topics/{scanner_topic_dlt['name']}", 251 | }, 252 | 'environmentVariables': {} 253 | }, 254 | 'metadata': { 255 | 'dependsOn': [scanner_topic_dlt['name']] 256 | } 257 | } 258 | 259 | scanner_dlt_management_account_role_binding = { 260 | 'name': 'scanner-dlt-management-account-role-binding', 261 | 'type': 'gcp-types/cloudfunctions-v1:virtual.projects.locations.functions.iamMemberBinding', 262 | 'properties': { 263 | 'resource': f"$(ref.{scanner_dlt['name']}.name)", 264 | 'role': role.get_role_name_ref(project_id, management_roles.CLOUD_FUNCTION_MANAGEMENT_ROLE), 265 | 'member': f'serviceAccount:{management_service_account_id}' 266 | } 267 | } 268 | 269 | scanner_stack_function_update_role_binding = { 270 | 'name':'scanner-stack-function-update-role-binding', 271 | 'type': 'gcp-types/cloudresourcemanager-v1:virtual.projects.iamMemberBinding', 272 | 'properties': { 273 | 'resource': project_id, 274 | 'role': role.get_role_name_ref(project_id, management_roles.SOURCE_CODE_SET_ROLE), 275 | 'member': f'serviceAccount:{management_service_account_id}' 276 | } 277 | } 278 | 279 | resources = [ 280 | scanner, 281 | scanner_dlt, 282 | scanner_topic, 283 | scanner_topic_dlt, 284 | scanner_management_account_role_binding, 285 | scanner_dlt_management_account_role_binding, 286 | pattern_updater_topic, 287 | pattern_update_bucket, 288 | pattern_updater, 289 | pattern_updater_scheduler, 290 | pattern_update_bucket_scanner_role_binding, 291 | pattern_update_bucket_role_binding, 292 | pattern_updater_management_account_role_binding 293 | ] 294 | 295 | if properties['functionAutoUpdate']: 296 | resources.append(scanner_stack_function_update_role_binding) 297 | 298 | outputs = [{ 299 | 'name': 'scannerTopic', 300 | 'value': scanner_topic['name'] 301 | },{ 302 | 'name': 'scannerTopicDLT', 303 | 'value': scanner_topic_dlt['name'] 304 | },{ 305 | 'name': 'scannerProjectID', 306 | 'value': project_id 307 | },{ 308 | 'name': 'scannerFunctionName', 309 | 'value': '$(ref.{}.name)'.format(scanner['name']) 310 | },{ 311 | 'name': 'patternUpdaterFunctionName', 312 | 'value': '$(ref.{}.name)'.format(pattern_updater['name']) 313 | },{ 314 | 'name': 'scannerDLTFunctionName', 315 | 'value': '$(ref.{}.name)'.format(scanner_dlt['name']) 316 | },{ 317 | 'name': 'region', 318 | 'value': region 319 | },{ 320 | 'name': 'scannerSecretsName', 321 | 'value': properties['scannerSecretsName'] 322 | },{ 323 | 'name': 'patternUpdateSchedulerJobName', 324 | 'value': pattern_updater_scheduler['properties']['name'] 325 | },{ 326 | 'name': 'patternUpdateBucket', 327 | 'value': '$(ref.{}.name)'.format(pattern_update_bucket['name']) 328 | },{ 329 | 'name': 'functionAutoUpdate', 330 | 'value': properties['functionAutoUpdate'] 331 | }] 332 | return (resources, outputs) 333 | 334 | 335 | def generate_config(context): 336 | """ Entry point for the deployment resources. """ 337 | 338 | resources, outputs = create_scanner_stack_resources(context) 339 | 340 | return { 341 | 'resources': resources, 342 | 'outputs': outputs 343 | } 344 | -------------------------------------------------------------------------------- /aws/FSS-All-In-One.template: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: 2010-09-09 2 | 3 | Description: Trend Micro File Storage Security scanner and storage stacks 4 | 5 | Metadata: 6 | AWS::CloudFormation::Interface: 7 | ParameterGroups: 8 | - Label: 9 | default: "[ Customizable section ]" 10 | Parameters: 11 | - S3BucketToScan 12 | - ObjectFilterPrefix 13 | - KMSKeyARNForBucketSSE 14 | - KMSKeyARNForQueueSSE 15 | - KMSKeyARNForTopicSSE 16 | - ScannerEphemeralStorage 17 | - TriggerWithObjectCreatedEvent 18 | - ReportObjectKey 19 | - ScanOnGetObject 20 | - ScanResultTagFormat 21 | - Label: 22 | default: "[ Optional: Permissions control ]" 23 | Parameters: 24 | - PermissionsBoundary 25 | - AdditionalIAMPolicies 26 | - Label: 27 | default: "[ Optional: Resource prefixes ] Warning: Do not modify these fields when you update the stack. This may cause management problems. The maximum prefix length is 50 characters." 28 | Parameters: 29 | - IAMRolePrefix 30 | - IAMPolicyPrefix 31 | - LambdaFunctionPrefix 32 | - LambdaLayerPrefix 33 | - SQSQueuePrefix 34 | - SNSTopicPrefix 35 | - Label: 36 | default: "[ Optional: Deploy in VPC ] Warning: Make sure the subnets have access to domains .amazonaws.com and .trendmicro.com over HTTPS" 37 | Parameters: 38 | - SubnetIDs 39 | - SecurityGroupIDs 40 | - NetworkProxy 41 | - Label: 42 | default: "[ Optional: Storage stack dead-letter queues ARNs ] The SQS ARNs for dead-letter queues can all be the same value. They have to be both deployed in the same region and managed by the same account as the storage stack." 43 | Parameters: 44 | - BucketListenerDLQARN 45 | - PostScanActionTagDLQARN 46 | - ScanResultTopicDLQARN 47 | - KMSKeyARNForDLQSSE 48 | - Label: 49 | default: "[ Warning: Do not modify the fields below. Modifications may cause your deployment to fail. ]" 50 | Parameters: 51 | - FSSBucketName 52 | - FSSKeyPrefix 53 | - TrendMicroManagementAccount 54 | - CloudOneRegion 55 | - ExternalID 56 | 57 | ParameterLabels: 58 | AdditionalIAMPolicies: 59 | default: AdditionalIAMPolicies 60 | BucketListenerDLQARN: 61 | default: SQS ARN for BucketListenerLambda DLQ 62 | CloudOneRegion: 63 | default: Trend Micro Cloud One region 64 | ExternalID: 65 | default: ExternalID 66 | FSSBucketName: 67 | default: Stack package location 68 | FSSKeyPrefix: 69 | default: Version 70 | IAMPolicyPrefix: 71 | default: Prefix for IAM policy name 72 | IAMRolePrefix: 73 | default: Prefix for IAM role name 74 | KMSKeyARNForBucketSSE: 75 | default: KMSKeyARNForBucketSSE 76 | KMSKeyARNForDLQSSE: 77 | default: KMSKeyARNForDLQSSE 78 | KMSKeyARNForQueueSSE: 79 | default: KMSKeyARNForQueueSSE 80 | KMSKeyARNForTopicSSE: 81 | default: KMSKeyARNForTopicSSE 82 | LambdaFunctionPrefix: 83 | default: "Prefix for Lambda function name [ Warning: Do not modify this field when you update the stack. Modifications may cause your update to fail. ]" 84 | LambdaLayerPrefix: 85 | default: Prefix for Lambda layer name 86 | NetworkProxy: 87 | default: NetworkProxy 88 | ObjectFilterPrefix: 89 | default: ObjectFilterPrefix 90 | PermissionsBoundary: 91 | default: PermissionsBoundary 92 | PostScanActionTagDLQARN: 93 | default: SQS ARN for PostScanActionTagLambda DLQ 94 | ReportObjectKey: 95 | default: ReportObjectKey 96 | S3BucketToScan: 97 | default: S3BucketToScan 98 | ScannerEphemeralStorage: 99 | default: "ScannerEphemeralStorage [ In Preview ]" 100 | ScanOnGetObject: 101 | default: "ScanOnGetObject [ In Preview ]" 102 | ScanResultTagFormat: 103 | default: ScanResultTagFormat 104 | ScanResultTopicDLQARN: 105 | default: ScanResultTopicDLQARN 106 | SecurityGroupIDs: 107 | default: SecurityGroupIDs 108 | SNSTopicPrefix: 109 | default: Prefix for SNS topic name 110 | SQSQueuePrefix: 111 | default: Prefix for SQS queue name 112 | SubnetIDs: 113 | default: SubnetIDs 114 | TrendMicroManagementAccount: 115 | default: File Storage Security management account 116 | TriggerWithObjectCreatedEvent: 117 | default: TriggerWithObjectCreatedEvent 118 | 119 | Parameters: 120 | AdditionalIAMPolicies: 121 | Default: '' 122 | Description: A comma-separated list of IAM policy ARNs to attach to all the roles that will be created. 123 | Type: CommaDelimitedList 124 | BucketListenerDLQARN: 125 | Default: '' 126 | Description: The SQS ARN for BucketListenerLambda DLQ. 127 | Type: String 128 | CloudOneRegion: 129 | Description: The region of the Trend Micro Cloud One services. 130 | Type: String 131 | Default: us-1 132 | ExternalID: 133 | Description: "The External ID is for future use with updating Lambdas and also to address and prevent the 'confused deputy' problem." 134 | Type: String 135 | FSSBucketName: 136 | ConstraintDescription: 137 | File Storage Security bucket name can include numbers, lowercase 138 | letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen 139 | (-). 140 | Default: file-storage-security 141 | Description: "" 142 | Type: String 143 | FSSKeyPrefix: 144 | ConstraintDescription: 145 | File Storage Security key prefix can include numbers, lowercase letters, 146 | uppercase letters, hyphens (-), and forward slash (/). 147 | Default: latest/ 148 | Description: "" 149 | Type: String 150 | IAMPolicyPrefix: 151 | AllowedPattern: ^$|^[a-zA-Z0-9+=,.@\-_]+-$ 152 | ConstraintDescription: Prefix for IAM policy name can be empty or include alphanumeric and '+=,.@-_' characters and must end with a hyphen. The maximum length is 50 characters. 153 | Default: '' 154 | Description: Prefix for the name of the IAM Policies. Must end with a hyphen (-). 155 | Type: String 156 | MaxLength: 50 157 | IAMRolePrefix: 158 | AllowedPattern: ^$|^[a-zA-Z0-9+=,.@\-_]+-$ 159 | ConstraintDescription: Prefix for IAM role name can be empty or include alphanumeric and '+=,.@-_' characters and must end with a hyphen. The maximum length is 50 characters. 160 | Default: '' 161 | Description: Prefix for the name of the IAM roles being deployed. Must end with a hyphen (-). 162 | Type: String 163 | MaxLength: 50 164 | KMSKeyARNForBucketSSE: 165 | Default: '' 166 | Description: The ARN for the KMS master key used to encrypt S3 bucket objects. Leave it blank if you haven't enabled SSE-KMS for the bucket. 167 | Type: String 168 | KMSKeyARNForDLQSSE: 169 | Default: '' 170 | Description: The ARN for the KMS master key used to encrypt messages of DLQ for storage stack. Leave it blank if you haven't used your own CMK for SQS server-side encryption on the queue ARNs you provided. 171 | Type: String 172 | KMSKeyARNForQueueSSE: 173 | Default: '' 174 | Description: The ARN for the KMS master key used to encrypt messages in SQS. Leave it blank if you haven't used your own CMK for SQS server-side encryption. 175 | Type: String 176 | KMSKeyARNForTopicSSE: 177 | Default: '' 178 | Description: The ARN for the KMS master key used to encrypt messages in SNS. Leave it blank if you haven't used your own CMK for SNS server-side encryption. 179 | Type: String 180 | LambdaFunctionPrefix: 181 | AllowedPattern: ^$|^[a-zA-Z0-9_\-]+-$ 182 | ConstraintDescription: Prefix for Lambda function name can be empty or include letters, numbers, hyphens (-), and underscores (_) and must end with a hyphen. The maximum length is 50 characters. 183 | Default: '' 184 | Description: Prefix for the name of the Lambda functions being deployed. Must end with a hyphen (-). 185 | Type: String 186 | MaxLength: 50 187 | LambdaLayerPrefix: 188 | AllowedPattern: ^$|^[a-zA-Z0-9_\-]+-$ 189 | ConstraintDescription: Prefix for Lambda layer name can be empty or include letters, numbers, hyphens (-), and underscores (_) and must end with a hyphen. The maximum length is 50 characters. 190 | Default: '' 191 | Description: Prefix for the name of the Lambda layers being deployed. Must end with a hyphen (-). 192 | Type: String 193 | MaxLength: 50 194 | NetworkProxy: 195 | Default: '' 196 | Description: Network proxy setting in the format scheme://[user:pass@]host:port, for example http://proxy.server:8080. Leave it blank if you don't want Lambda functions to connect to an explicit proxy in the VPC. 197 | Type: String 198 | ObjectFilterPrefix: 199 | Default: '' 200 | Description: Limit the scan to objects whose key starts with the specified characters. 201 | Type: String 202 | PermissionsBoundary: 203 | Default: '' 204 | Description: The ARN of the policy used to set the permissions boundary for all the roles that will be created. 205 | Type: String 206 | PostScanActionTagDLQARN: 207 | Default: '' 208 | Description: The SQS ARN for PostScanActionTag DLQ. 209 | Type: String 210 | ReportObjectKey: 211 | Default: 'false' 212 | AllowedValues: 213 | - 'true' 214 | - 'false' 215 | Description: |- 216 | Enable this to report the object keys of the scanned objects to File Storage Security backend services. 217 | File Storage Security can then display the object keys of the malicious objects in the response of events API. 218 | Type: String 219 | S3BucketToScan: 220 | Description: The S3 bucket to scan. Specify an existing S3 bucket. 221 | Type: String 222 | ScannerEphemeralStorage: 223 | Default: 512 224 | Description: | 225 | The size of the scanner lambda function's temp directory in MB. The default value is 512, but it can be any whole number between 512 and 2048 MB. 226 | Configure a large ephemeral storage to scan larger files in zip files. 227 | For more information, see https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html#configuration-ephemeral-storage 228 | Type: Number 229 | MinValue: 512 230 | MaxValue: 2048 231 | ScanOnGetObject: 232 | Default: 'false' 233 | AllowedValues: 234 | - 'true' 235 | - 'false' 236 | Description: | 237 | Scan objects retrieved (GET requests) from S3 with the Object Lambda Access Point. 238 | This option requires that the storage stack is deployed in both the same account and the same region as the scanner stack. 239 | For more information, see https://cloudone.trendmicro.com/docs/file-storage-security/aws-scan-on-get-object/ 240 | Type: String 241 | ScanResultTagFormat: 242 | Default: Separated tags 243 | Description: | 244 | The format of the scan result tags tagged on the scanned object. 245 | Select "Separated tags" to add each FSS tag as a standalone tag. Select "Merged tag" to add all FSS tags in one tag. Select "No tag" to disable the tagging feature. 246 | For more information, see https://cloudone.trendmicro.com/docs/file-storage-security/scan-tag-overview/#ViewTag. 247 | Type: String 248 | AllowedValues: 249 | - Separated tags 250 | - Merged tag 251 | - No tag 252 | ScanResultTopicDLQARN: 253 | Default: '' 254 | Description: The SQS ARN for ScanResultTopic DLQ. 255 | Type: String 256 | SecurityGroupIDs: 257 | Default: '' 258 | Description: A comma-separated list of VPC Security Group IDs that are attached to Lambda functions. Leave it blank if you don't want to attach Lambda functions to a VPC. 259 | Type: CommaDelimitedList 260 | SNSTopicPrefix: 261 | AllowedPattern: ^$|^[a-zA-Z0-9_\-]+-$ 262 | ConstraintDescription: Prefix for SNS topic name can be empty or include include alphanumeric characters, hyphens (-) and underscores (_) and must end with a hyphen. The maximum length is 50 characters. 263 | Default: '' 264 | Description: Prefix for the name of SNS topics being deployed. Must end with a hyphen (-). 265 | Type: String 266 | MaxLength: 50 267 | SQSQueuePrefix: 268 | AllowedPattern: ^$|^[a-zA-Z0-9_\-]+-$ 269 | ConstraintDescription: Prefix for SQS queue name can be empty or include alphanumeric characters, hyphens (-), and underscores (_) and must end with a hyphen. The maximum length is 50 characters. 270 | Default: '' 271 | Description: Prefix for the name of SQS queues being deployed. Must end with a hyphen (-). 272 | Type: String 273 | MaxLength: 50 274 | SubnetIDs: 275 | Default: '' 276 | Description: A comma-separated list of VPC Subnet IDs that are attached to Lambda functions. Leave it blank if you don't want to attach Lambda functions to a VPC. 277 | Type: CommaDelimitedList 278 | TrendMicroManagementAccount: 279 | ConstraintDescription: AWS account ID. 280 | Default: 415485722356 281 | Description: This account will be given permission to modify the stacks for upgrades and troubleshooting purposes. 282 | Type: String 283 | TriggerWithObjectCreatedEvent: 284 | Default: 'true' 285 | AllowedValues: 286 | - 'true' 287 | - 'false' 288 | Description: If the s3:ObjectCreated:* event of the S3BucketToScan is in use, set this option to false. Then trigger the scans by invoking the deployed BucketListenerLambda. 289 | Type: String 290 | 291 | Conditions: 292 | IsScanOnGetObjectEnabled: 293 | !Equals ['true', !Ref ScanOnGetObject] 294 | 295 | Resources: 296 | StorageStack: 297 | Type: AWS::CloudFormation::Stack 298 | Properties: 299 | Parameters: 300 | AdditionalIAMPolicies: !Join [',', !Ref AdditionalIAMPolicies] 301 | BucketListenerDLQARN: !Ref BucketListenerDLQARN 302 | CloudOneRegion: !Ref CloudOneRegion 303 | ExternalID: !Ref ExternalID 304 | FSSBucketName: !Ref FSSBucketName 305 | FSSKeyPrefix: !Ref FSSKeyPrefix 306 | IAMPolicyPrefix: !Ref IAMPolicyPrefix 307 | IAMRolePrefix: !Ref IAMRolePrefix 308 | KMSKeyARNForBucketSSE: !Ref KMSKeyARNForBucketSSE 309 | KMSKeyARNForDLQSSE: !Ref KMSKeyARNForDLQSSE 310 | KMSKeyARNForQueueSSE: !Ref KMSKeyARNForQueueSSE 311 | KMSKeyARNForTopicSSE: !Ref KMSKeyARNForTopicSSE 312 | LambdaFunctionPrefix: !Ref LambdaFunctionPrefix 313 | NetworkProxy: !Ref NetworkProxy 314 | ObjectFilterPrefix: !Ref ObjectFilterPrefix 315 | PermissionsBoundary: !Ref PermissionsBoundary 316 | PostScanActionTagDLQARN: !Ref PostScanActionTagDLQARN 317 | ReportObjectKey: !Ref ReportObjectKey 318 | S3BucketToScan: !Ref S3BucketToScan 319 | ScannerAWSAccount: !Ref AWS::AccountId 320 | ScannerLambdaAliasARN: !GetAtt ScannerStack.Outputs.ScannerLambdaAliasARN 321 | ScannerSQSURL: !GetAtt ScannerStack.Outputs.ScannerQueueURL 322 | ScanOnGetObject: !Ref ScanOnGetObject 323 | ScanResultTagFormat: !Ref ScanResultTagFormat 324 | ScanResultTopicDLQARN: !Ref ScanResultTopicDLQARN 325 | SecurityGroupIDs: !Join [',', !Ref SecurityGroupIDs] 326 | SNSTopicPrefix: !Ref SNSTopicPrefix 327 | SubnetIDs: !Join [',', !Ref SubnetIDs] 328 | TrendMicroManagementAccount: !Ref TrendMicroManagementAccount 329 | TriggerWithObjectCreatedEvent: !Ref TriggerWithObjectCreatedEvent 330 | Tags: 331 | - Key: Name 332 | Value: FSS-Storage-Stack 333 | TemplateURL: 334 | Fn::Sub: https://${FSSBucketName}-${AWS::Region}.s3.${AWS::Region}.amazonaws.com/${FSSKeyPrefix}templates/FSS-Storage-Stack.template 335 | TimeoutInMinutes: 30 336 | 337 | ScannerStack: 338 | Type: AWS::CloudFormation::Stack 339 | Properties: 340 | Parameters: 341 | AdditionalIAMPolicies: !Join [',', !Ref AdditionalIAMPolicies] 342 | CloudOneRegion: !Ref CloudOneRegion 343 | ExternalID: !Ref ExternalID 344 | FSSBucketName: !Ref FSSBucketName 345 | FSSKeyPrefix: !Ref FSSKeyPrefix 346 | IAMPolicyPrefix: !Ref IAMPolicyPrefix 347 | IAMRolePrefix: !Ref IAMRolePrefix 348 | KMSKeyARNForQueueSSE: !Ref KMSKeyARNForQueueSSE 349 | KMSKeyARNsForTopicSSE: !Ref KMSKeyARNForTopicSSE 350 | LambdaFunctionPrefix: !Ref LambdaFunctionPrefix 351 | LambdaLayerPrefix: !Ref LambdaLayerPrefix 352 | NetworkProxy: !Ref NetworkProxy 353 | PermissionsBoundary: !Ref PermissionsBoundary 354 | ScannerEphemeralStorage: !Ref ScannerEphemeralStorage 355 | SecurityGroupIDs: !Join [',', !Ref SecurityGroupIDs] 356 | SQSQueuePrefix: !Ref SQSQueuePrefix 357 | SubnetIDs: !Join [',', !Ref SubnetIDs] 358 | TrendMicroManagementAccount: !Ref TrendMicroManagementAccount 359 | Tags: 360 | - Key: Name 361 | Value: FSS-Scanner-Stack 362 | TemplateURL: 363 | Fn::Sub: https://${FSSBucketName}-${AWS::Region}.s3.${AWS::Region}.amazonaws.com/${FSSKeyPrefix}templates/FSS-Scanner-Stack.template 364 | TimeoutInMinutes: 30 365 | 366 | Outputs: 367 | BucketListenerRoleARN: 368 | Value: !GetAtt StorageStack.Outputs.BucketListenerRoleARN 369 | Description: The ARNs of the lambda execution role for SQS in scanner stack to accept scan requests from. 370 | CloudOneRegion: 371 | Value: !Ref CloudOneRegion 372 | Description: The region of the Trend Micro Cloud One services. 373 | ScannerQueueURL: 374 | Value: !GetAtt ScannerStack.Outputs.ScannerQueueURL 375 | Description: The SQS URL for storage stacks to publish events to. 376 | ScannerExecutionRoleARN: 377 | Value: !GetAtt ScannerStack.Outputs.ScannerExecutionRoleARN 378 | Description: The ARNs of the lambda execution role for Lambda in the scanner stack to execute scan requests. 379 | ScannerStackManagementRoleARN: 380 | Value: !GetAtt ScannerStack.Outputs.ScannerStackManagementRoleARN 381 | Description: The ARN of the IAM role for File Storage Security backend services to manage the deployed resources. 382 | ScanningBucket: 383 | Value: !GetAtt StorageStack.Outputs.ScanningBucket 384 | Description: The name of the scanning bucket in storage stack. 385 | ScanOnGetObjectAccessPointARN: 386 | Condition: IsScanOnGetObjectEnabled 387 | Value: !GetAtt StorageStack.Outputs.ScanOnGetObjectAccessPointARN 388 | Description: Using this ARN to get objects will have them scanned by File Storage Security before they are returned. 389 | ScanResultTopicARN: 390 | Value: !GetAtt StorageStack.Outputs.ScanResultTopicARN 391 | Description: The ARN of the scan result SNS topic in storage stack. 392 | StorageStackManagementRoleARN: 393 | Value: !GetAtt StorageStack.Outputs.StorageStackManagementRoleARN 394 | Description: The ARN of the IAM role for File Storage Security backend services to manage the deployed resources. 395 | --------------------------------------------------------------------------------