Skip to main content

Resource Metadata for Specific Asset

In this example you are going to learn how to export GCP organization's specific assets, with extended metadata for the matching asset type.

Here is the complete main.tf file:

Complete Terraform definition file
terraform {
required_providers {
port-labs = {
source = "port-labs/port-labs"
version = "~> 0.10.3"
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 3.53, < 5.0"
}
}
}

locals {
domain = "GCP_ORGANIZATION_DOMAIN_NAME" # set the organization's domain
}

provider "port-labs" {
client_id = "PORT_CLIENT_ID" # or set the env var PORT_CLIENT_ID
secret = "PORT_CLIENT_SECRET" # or set the env var PORT_CLIENT_SECRET
}

provider "google-beta" {
credentials = "GOOGLE_APPLICATION_CREDENTIALS" # or set the env var GOOGLE_APPLICATION_CREDENTIALS
}

data "google_organization" "my_org" {
provider = google-beta
domain = local.domain
}

data "google_cloud_asset_resources_search_all" "my_folder_assets" {
provider = google-beta
scope = "organizations/${data.google_organization.my_org.org_id}"
asset_types = [
"cloudresourcemanager.googleapis.com/Folder"
]
}

data "google_folder" "my_folders" {
for_each = {for idx, result in data.google_cloud_asset_resources_search_all.my_folder_assets.results : idx => result}
folder = "folders/${reverse(split("/", each.value.name))[0]}"
}

data "google_projects" "my_projects" {
provider = google-beta
filter = "parent.id:*"
}

data "google_cloud_asset_resources_search_all" "my_assets" {
for_each = {for idx, result in data.google_projects.my_projects.projects: idx => result}
provider = google-beta
scope = "projects/${each.value.project_id}"
asset_types = [
"storage.googleapis.com/Bucket",
"iam.googleapis.com/ServiceAccount",
"compute.googleapis.com/Disk",
"redis.googleapis.com/Instance",
"compute.googleapis.com/Instance",
"run.googleapis.com/Service",
"container.googleapis.com/Cluster"
]
}

data "google_storage_bucket" "my_buckets" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => project_assets.results})) : idx => result if result.asset_type == "storage.googleapis.com/Bucket"}
name = reverse(split("/", each.value.name))[0]
}

data "google_service_account" "my_accounts" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "iam.googleapis.com/ServiceAccount"}
account_id = reverse(split("/", each.value.name))[0]
project = reverse(split("/", each.value.project_id))[0]
}

data "google_compute_disk" "my_disks" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "compute.googleapis.com/Disk"}
zone = each.value.location
name = reverse(split("/", each.value.name))[0]
project = reverse(split("/", each.value.project_id))[0]
}

data "google_redis_instance" "my_memorystores" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "redis.googleapis.com/Instance"}
name = reverse(split("/", each.value.name))[0]
region = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

data "google_compute_instance" "my_compute_instances" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "compute.googleapis.com/Instance"}
name = reverse(split("/", each.value.name))[0]
zone = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

data "google_cloud_run_service" "my_run_services" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "run.googleapis.com/Service"}
name = reverse(split("/", each.value.name))[0]
location = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

data "google_container_cluster" "my_container_clusters" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "container.googleapis.com/Cluster"}
name = reverse(split("/", each.value.name))[0]
location = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}


resource "port-labs_blueprint" "gcp_org_blueprint" {
title = "Organization"
icon = "GCP"
identifier = "organization"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
}

resource "port-labs_entity" "gcp_org_entity" {
identifier = data.google_organization.my_org.org_id
title = data.google_organization.my_org.domain
blueprint = port-labs_blueprint.gcp_org_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/welcome?organizationId=${data.google_organization.my_org.org_id}"
}
properties {
name = "createTime"
value = data.google_organization.my_org.create_time
}
}

resource "port-labs_blueprint" "gcp_folder_blueprint" {
title = "Folder"
icon = "GCP"
identifier = "folder"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
relations {
identifier = port-labs_blueprint.gcp_org_blueprint.identifier
target = port-labs_blueprint.gcp_org_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_folder_entity" {
for_each = {for idx, folder in data.google_folder.my_folders: idx => folder}
identifier = each.value.folder_id
title = each.value.display_name
blueprint = port-labs_blueprint.gcp_folder_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/welcome?folder=${each.value.folder_id}"
}
properties {
name = "createTime"
value = each.value.create_time
}
relations {
name = port-labs_blueprint.gcp_org_blueprint.identifier
identifier = data.google_organization.my_org.org_id
}
}

resource "port-labs_blueprint" "gcp_project_blueprint" {
title = "Project"
icon = "GCP"
identifier = "project"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "number"
type = "string"
title = "Number"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_org_blueprint.identifier
target = port-labs_blueprint.gcp_org_blueprint.identifier
}
relations {
identifier = port-labs_blueprint.gcp_folder_blueprint.identifier
target = port-labs_blueprint.gcp_folder_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_project_entity" {
for_each = {for idx, project in data.google_projects.my_projects.projects : idx => project}
identifier = each.value.project_id
title = each.value.name
blueprint = port-labs_blueprint.gcp_project_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/welcome?project=${each.value.project_id}"
}
properties {
name = "number"
value = each.value.number
}
properties {
name = "createTime"
value = each.value.create_time
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
dynamic "relations" {
for_each = each.value.parent.type == "organization" ? [1] : []
content {
name = port-labs_blueprint.gcp_org_blueprint.identifier
identifier = each.value.parent.id
}
}
dynamic "relations" {
for_each = each.value.parent.type == "folder" ? [1] : []
content {
name = port-labs_blueprint.gcp_folder_blueprint.identifier
identifier = each.value.parent.id
}
}
depends_on = [port-labs_entity.gcp_org_entity, port-labs_entity.gcp_folder_entity]
}

resource "port-labs_blueprint" "gcp_bucket_blueprint" {
title = "Storage Bucket"
icon = "Bucket"
identifier = "storageBucket"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "location"
type = "string"
title = "Location"
}
properties {
identifier = "publicAccessPrevention"
type = "string"
enum = ["inherited", "enforced"]
title = "Public Access Prevention"
}
properties {
identifier = "storageClass"
type = "string"
enum = ["STANDARD", "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "ARCHIVE"]
title = "Storage Class"
}
properties {
identifier = "uniformBucketLevelAccess"
type = "boolean"
title = "Uniform Bucket Level Access"
}
properties {
identifier = "lifecycleRule"
type = "array"
title = "Lifecycle Rule"
}
properties {
identifier = "encryption"
type = "array"
title = "Encryption"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_bucket_entity" {
for_each = data.google_storage_bucket.my_buckets
identifier = each.value.id
title = each.value.name
blueprint = port-labs_blueprint.gcp_bucket_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/storage/browser/${each.value.id};tab=objects?project=${each.value.project}"
}
properties {
name = "location"
value = each.value.location
}
properties {
name = "publicAccessPrevention"
value = each.value.public_access_prevention
}
properties {
name = "storageClass"
value = each.value.storage_class
}
properties {
name = "uniformBucketLevelAccess"
value = each.value.uniform_bucket_level_access
}
properties {
name = "lifecycleRule"
items = [for item in each.value.lifecycle_rule: jsonencode(item)]
}
properties {
name = "encryption"
items = [for item in each.value.encryption: jsonencode(item)]
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

resource "port-labs_blueprint" "gcp_service_account_blueprint" {

title = "Service Account"
icon = "Lock"
identifier = "serviceAccount"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "email"
type = "string"
format = "email"
title = "email"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_service_account_entity" {
for_each = data.google_service_account.my_accounts
identifier = each.value.account_id
title = each.value.display_name
blueprint = port-labs_blueprint.gcp_service_account_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/iam-admin/serviceaccounts/details/${each.value.unique_id}?project=${each.value.project}"
}
properties {
name = "email"
value = each.value.email
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

resource "port-labs_blueprint" "gcp_disk_blueprint" {
title = "Disk"
icon = "GoogleComputeEngine"
identifier = "disk"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "description"
type = "string"
title = "Description"
}
properties {
identifier = "zone"
type = "string"
title = "Zone"
}
properties {
identifier = "type"
type = "string"
title = "Type"
}
properties {
identifier = "size"
type = "number"
title = "Size"
}
properties {
identifier = "creationTimestamp"
type = "string"
title = "Creation Timestamp"
}
properties {
identifier = "users"
type = "array"
title = "Users"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_disk_entity" {
for_each = data.google_compute_disk.my_disks
identifier = "${each.value.project}_${each.value.zone}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_disk_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/compute/disksDetail/zones/${each.value.zone}/disks/${each.value.name}?project=${each.value.project}"
}
properties {
name = "description"
value = each.value.description
}
properties {
name = "zone"
value = each.value.zone
}
properties {
name = "type"
value = each.value.type
}
properties {
name = "size"
value = each.value.size
}
properties {
name = "creationTimestamp"
value = each.value.creation_timestamp
}
properties {
name = "users"
items = each.value.users
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

resource "port-labs_blueprint" "gcp_memorystore_blueprint" {
title = "Memorystore"
icon = "GoogleCloudPlatform"
identifier = "memorystore"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "region"
type = "string"
title = "Region"
}
properties {
identifier = "currentLocationId"
type = "string"
title = "Current Location ID"
}
properties {
identifier = "memorySizeGb"
type = "number"
title = "Memory Size GB"
}
properties {
identifier = "replicaCount"
type = "number"
title = "Replica Count"
}
properties {
identifier = "redisVersion"
type = "string"
title = "Redis Version"
}
properties {
identifier = "tier"
type = "string"
enum = ["BASIC", "STANDARD_HA"]
title = "Public Access Prevention"
}
properties {
identifier = "readReplicasMode"
type = "string"
enum = ["READ_REPLICAS_DISABLED", "READ_REPLICAS_ENABLED"]
title = "Read Replicas Mode"
}
properties {
identifier = "connectMode"
type = "string"
enum = ["DIRECT_PEERING", "PRIVATE_SERVICE_ACCESS"]
title = "Connect Mode"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
properties {
identifier = "authorizedNetwork"
type = "string"
title = "Authorized Network"
}
properties {
identifier = "nodes"
type = "array"
title = "Nodes"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_memorystore_entity" {
for_each = data.google_redis_instance.my_memorystores
identifier = "${each.value.project}_${each.value.location_id}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_memorystore_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/memorystore/redis/locations/${each.value.region}/instances/${each.value.name}/details/overview?project=${each.value.project}"
}
properties {
name = "region"
value = each.value.region
}
properties {
name = "currentLocationId"
value = each.value.current_location_id
}
properties {
name = "memorySizeGb"
value = each.value.memory_size_gb
}
properties {
name = "replicaCount"
value = each.value.replica_count
}
properties {
name = "redisVersion"
value = each.value.redis_version
}
properties {
name = "tier"
value = each.value.tier
}
properties {
name = "readReplicasMode"
value = each.value.read_replicas_mode
}
properties {
name = "connectMode"
value = each.value.connect_mode
}
properties {
name = "createTime"
value = each.value.create_time
}
properties {
name = "authorizedNetwork"
value = each.value.authorized_network
}
properties {
name = "nodes"
items = [for item in each.value.nodes: jsonencode(item)]
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

resource "port-labs_blueprint" "gcp_compute_instance_blueprint" {
title = "Compute Instance"
icon = "GoogleComputeEngine"
identifier = "computeInstance"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "zone"
type = "string"
title = "Zone"
}
properties {
identifier = "description"
type = "string"
title = "Description"
}
properties {
identifier = "currentStatus"
type = "string"
enum = ["PROVISIONING", "STAGING", "RUNNING", "STOPPING", "REPAIRING", "TERMINATED", "SUSPENDING", "SUSPENDED"]
enum_colors = {
PROVISIONING = "blue"
STAGING = "blue"
RUNNING = "green"
STOPPING = "red"
REPAIRING = "yellow"
TERMINATED = "red"
SUSPENDING = "yellow"
SUSPENDED = "lightGray"
}
title = "Current Status"
}
properties {
identifier = "machineType"
type = "string"
title = "Machine Type"
}
properties {
identifier = "cpuPlatform"
type = "string"
title = "CPU Platform"
}
properties {
identifier = "deletionProtection"
type = "boolean"
title = "Deletion Protection"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_compute_instance_entity" {
for_each = data.google_compute_instance.my_compute_instances
identifier = "${each.value.project}_${each.value.zone}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_compute_instance_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/compute/instancesDetail/zones/${each.value.zone}/instances/${each.value.name}?project=${each.value.project}"
}
properties {
name = "zone"
value = each.value.zone
}
properties {
name = "description"
value = each.value.description
}
properties {
name = "currentStatus"
value = each.value.current_status
}
properties {
name = "machineType"
value = each.value.machine_type
}
properties {
name = "cpuPlatform"
value = each.value.cpu_platform
}
properties {
name = "deletionProtection"
value = each.value.deletion_protection
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

resource "port-labs_blueprint" "gcp_run_service_blueprint" {
title = "Run Service"
icon = "Service"
identifier = "runService"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "location"
type = "string"
title = "Location"
}
properties {
identifier = "metadata"
type = "array"
title = "Metadata"
}
properties {
identifier = "status"
type = "array"
title = "Status"
}
properties {
identifier = "template"
type = "array"
title = "Template"
}
properties {
identifier = "traffic"
type = "array"
title = "Traffic"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_run_service_entity" {
for_each = data.google_cloud_run_service.my_run_services
identifier = "${each.value.project}_${each.value.location}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_run_service_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/run/detail/${each.value.location}/${each.value.name}?project=${each.value.project}"
}
properties {
name = "location"
value = each.value.location
}
properties {
name = "metadata"
items = [for item in each.value.metadata: jsonencode(item)]
}
properties {
name = "status"
items = [for item in each.value.status: jsonencode(item)]
}
properties {
name = "template"
items = [for item in each.value.template: jsonencode(item)]
}
properties {
name = "traffic"
items = [for item in each.value.traffic: jsonencode(item)]
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

resource "port-labs_blueprint" "gcp_container_cluster_blueprint" {
title = "Container Cluster"
icon = "Cluster"
identifier = "containerCluster"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "location"
type = "string"
title = "Location"
}
properties {
identifier = "description"
type = "string"
title = "Description"
}
properties {
identifier = "masterVersion"
type = "string"
title = "Master Version"
}
properties {
identifier = "enableAutopilot"
type = "boolean"
title = "Enable Autopilot"
}
properties {
identifier = "addonsConfig"
type = "array"
title = "Addons Config"
}
properties {
identifier = "clusterAutoscaling"
type = "array"
title = "Cluster Autoscaling"
}
properties {
identifier = "network"
type = "string"
title = "Network"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_container_cluster_entity" {
for_each = data.google_container_cluster.my_container_clusters
identifier = "${each.value.project}_${each.value.location}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_container_cluster_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/kubernetes/clusters/details/${each.value.location}/${each.value.name}?project=${each.value.project}"
}
properties {
name = "location"
value = each.value.location
}
properties {
name = "description"
value = each.value.description
}
properties {
name = "masterVersion"
value = each.value.master_version
}
properties {
name = "enableAutopilot"
value = each.value.enable_autopilot
}
properties {
name = "addonsConfig"
items = [for item in each.value.addons_config: jsonencode(item)]
}
properties {
name = "clusterAutoscaling"
items = [for item in each.value.cluster_autoscaling: jsonencode(item)]
}
properties {
name = "network"
value = each.value.network
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

To use this example yourself, simply replace the placeholders for domain, client_id, secret and credentials and then run the following commands to setup your new backend, create the new infrastructure and update the software catalog:

# install modules and create an initial state
terraform init
# To view Terraform's planned changes based on your .tf definition file:
terraform plan
# To apply the changes and update the catalog
terraform apply
GCP permissions

To be able to read the all the types of assets in this example, you need to use an organization's GCP IAM role with at least the following permissions:

cloudasset.assets.searchAllResources
compute.disks.get
compute.instanceGroupManagers.get
compute.instances.get
compute.projects.get
container.clusters.get
iam.serviceAccounts.get
redis.instances.get
resourcemanager.folders.get
resourcemanager.folders.list
resourcemanager.organizations.get
resourcemanager.projects.get
run.services.get
storage.buckets.get

Let's break down the definition file and understand the different parts:

Module importsโ€‹

This part includes importing and setting up the required Terraform providers and modules:

terraform {
required_providers {
port-labs = {
source = "port-labs/port-labs"
version = "~> 0.10.3"
}
google-beta = {
source = "hashicorp/google-beta"
version = ">= 3.53, < 5.0"
}
}
}

locals {
domain = "GCP_ORGANIZATION_DOMAIN_NAME" # set the organization's domain
}

provider "port-labs" {
client_id = "PORT_CLIENT_ID" # or set the env var PORT_CLIENT_ID
secret = "PORT_CLIENT_SECRET" # or set the env var PORT_CLIENT_SECRET
}

provider "google-beta" {
credentials = "GOOGLE_APPLICATION_CREDENTIALS" # or set the env var GOOGLE_APPLICATION_CREDENTIALS
}

Extracting the organization, folders, projects and specific assetsโ€‹

This part includes defining the datasource for the organization, folders, projects and specific assets (buckets, service accounts, disks, memorystores, compute instances, run services, container clusters):

data "google_organization" "my_org" {
provider = google-beta
domain = local.domain
}

data "google_cloud_asset_resources_search_all" "my_folder_assets" {
provider = google-beta
scope = "organizations/${data.google_organization.my_org.org_id}"
asset_types = [
"cloudresourcemanager.googleapis.com/Folder"
]
}

data "google_folder" "my_folders" {
for_each = {for idx, result in data.google_cloud_asset_resources_search_all.my_folder_assets.results : idx => result}
folder = "folders/${reverse(split("/", each.value.name))[0]}"
}

data "google_projects" "my_projects" {
provider = google-beta
filter = "parent.id:*"
}

data "google_cloud_asset_resources_search_all" "my_assets" {
for_each = {for idx, result in data.google_projects.my_projects.projects: idx => result}
provider = google-beta
scope = "projects/${each.value.project_id}"
asset_types = [
"storage.googleapis.com/Bucket",
"iam.googleapis.com/ServiceAccount",
"compute.googleapis.com/Disk",
"redis.googleapis.com/Instance",
"compute.googleapis.com/Instance",
"run.googleapis.com/Service",
"container.googleapis.com/Cluster"
]
}

data "google_storage_bucket" "my_buckets" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => project_assets.results})) : idx => result if result.asset_type == "storage.googleapis.com/Bucket"}
name = reverse(split("/", each.value.name))[0]
}

data "google_service_account" "my_accounts" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "iam.googleapis.com/ServiceAccount"}
account_id = reverse(split("/", each.value.name))[0]
project = reverse(split("/", each.value.project_id))[0]
}

data "google_compute_disk" "my_disks" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "compute.googleapis.com/Disk"}
zone = each.value.location
name = reverse(split("/", each.value.name))[0]
project = reverse(split("/", each.value.project_id))[0]
}

data "google_redis_instance" "my_memorystores" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "redis.googleapis.com/Instance"}
name = reverse(split("/", each.value.name))[0]
region = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

data "google_compute_instance" "my_compute_instances" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "compute.googleapis.com/Instance"}
name = reverse(split("/", each.value.name))[0]
zone = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

data "google_cloud_run_service" "my_run_services" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "run.googleapis.com/Service"}
name = reverse(split("/", each.value.name))[0]
location = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

data "google_container_cluster" "my_container_clusters" {
provider = google-beta
for_each = {for idx, result in flatten(values({for idx, project_assets in data.google_cloud_asset_resources_search_all.my_assets: idx => [for result in project_assets.results : merge(result, {project_id: project_assets.id})]})) : idx => result if result.asset_type == "container.googleapis.com/Cluster"}
name = reverse(split("/", each.value.name))[0]
location = each.value.location
project = reverse(split("/", each.value.project_id))[0]
}

Creating the Organization blueprint and the entity matching the organizationโ€‹

This part includes configuring the organization blueprint and creating an entity for the organization:

resource "port-labs_blueprint" "gcp_org_blueprint" {
title = "Organization"
icon = "GCP"
identifier = "organization"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
}

resource "port-labs_entity" "gcp_org_entity" {
identifier = data.google_organization.my_org.org_id
title = data.google_organization.my_org.domain
blueprint = port-labs_blueprint.gcp_org_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/welcome?organizationId=${data.google_organization.my_org.org_id}"
}
properties {
name = "createTime"
value = data.google_organization.my_org.create_time
}
}

Creating the Folder blueprint and the entities matching the foldersโ€‹

This part includes configuring the folder blueprint and creating an entities for the folders:

resource "port-labs_blueprint" "gcp_folder_blueprint" {
title = "Folder"
icon = "GCP"
identifier = "folder"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
relations {
identifier = port-labs_blueprint.gcp_org_blueprint.identifier
target = port-labs_blueprint.gcp_org_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_folder_entity" {
for_each = {for idx, folder in data.google_folder.my_folders: idx => folder}
identifier = each.value.folder_id
title = each.value.display_name
blueprint = port-labs_blueprint.gcp_folder_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/welcome?folder=${each.value.folder_id}"
}
properties {
name = "createTime"
value = each.value.create_time
}
relations {
name = port-labs_blueprint.gcp_org_blueprint.identifier
identifier = data.google_organization.my_org.org_id
}
}

Creating the Project blueprint and the entities matching the projectsโ€‹

This part includes configuring the project blueprint and creating an entities for the projects:

resource "port-labs_blueprint" "gcp_project_blueprint" {
title = "Project"
icon = "GCP"
identifier = "project"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "number"
type = "string"
title = "Number"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_org_blueprint.identifier
target = port-labs_blueprint.gcp_org_blueprint.identifier
}
relations {
identifier = port-labs_blueprint.gcp_folder_blueprint.identifier
target = port-labs_blueprint.gcp_folder_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_project_entity" {
for_each = {for idx, project in data.google_projects.my_projects.projects : idx => project}
identifier = each.value.project_id
title = each.value.name
blueprint = port-labs_blueprint.gcp_project_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/welcome?project=${each.value.project_id}"
}
properties {
name = "number"
value = each.value.number
}
properties {
name = "createTime"
value = each.value.create_time
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
dynamic "relations" {
for_each = each.value.parent.type == "organization" ? [1] : []
content {
name = port-labs_blueprint.gcp_org_blueprint.identifier
identifier = each.value.parent.id
}
}
dynamic "relations" {
for_each = each.value.parent.type == "folder" ? [1] : []
content {
name = port-labs_blueprint.gcp_folder_blueprint.identifier
identifier = each.value.parent.id
}
}
depends_on = [port-labs_entity.gcp_org_entity, port-labs_entity.gcp_folder_entity]
}

Creating the Storage Bucket blueprint and the entities matching the bucketsโ€‹

This part includes configuring the storageBucket blueprint and creating the entities for the buckets:

resource "port-labs_blueprint" "gcp_bucket_blueprint" {
title = "Storage Bucket"
icon = "Bucket"
identifier = "storageBucket"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "location"
type = "string"
title = "Location"
}
properties {
identifier = "publicAccessPrevention"
type = "string"
enum = ["inherited", "enforced"]
title = "Public Access Prevention"
}
properties {
identifier = "storageClass"
type = "string"
enum = ["STANDARD", "MULTI_REGIONAL", "REGIONAL", "NEARLINE", "COLDLINE", "ARCHIVE"]
title = "Storage Class"
}
properties {
identifier = "uniformBucketLevelAccess"
type = "boolean"
title = "Uniform Bucket Level Access"
}
properties {
identifier = "lifecycleRule"
type = "array"
title = "Lifecycle Rule"
}
properties {
identifier = "encryption"
type = "array"
title = "Encryption"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_bucket_entity" {
for_each = data.google_storage_bucket.my_buckets
identifier = each.value.id
title = each.value.name
blueprint = port-labs_blueprint.gcp_bucket_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/storage/browser/${each.value.id};tab=objects?project=${each.value.project}"
}
properties {
name = "location"
value = each.value.location
}
properties {
name = "publicAccessPrevention"
value = each.value.public_access_prevention
}
properties {
name = "storageClass"
value = each.value.storage_class
}
properties {
name = "uniformBucketLevelAccess"
value = each.value.uniform_bucket_level_access
}
properties {
name = "lifecycleRule"
items = [for item in each.value.lifecycle_rule: jsonencode(item)]
}
properties {
name = "encryption"
items = [for item in each.value.encryption: jsonencode(item)]
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Creating the Service Account blueprint and the entities matching the service accountsโ€‹

This part includes configuring the serviceAccount blueprint and creating the entities for the service accounts:

resource "port-labs_blueprint" "gcp_service_account_blueprint" {

title = "Service Account"
icon = "Lock"
identifier = "serviceAccount"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "email"
type = "string"
format = "email"
title = "email"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_service_account_entity" {
for_each = data.google_service_account.my_accounts
identifier = each.value.account_id
title = each.value.display_name
blueprint = port-labs_blueprint.gcp_service_account_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/iam-admin/serviceaccounts/details/${each.value.unique_id}?project=${each.value.project}"
}
properties {
name = "email"
value = each.value.email
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Creating the Disk blueprint and the entities matching the disksโ€‹

This part includes configuring the disk blueprint and creating the entities for the disks:

resource "port-labs_blueprint" "gcp_disk_blueprint" {
title = "Disk"
icon = "GoogleComputeEngine"
identifier = "disk"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "description"
type = "string"
title = "Description"
}
properties {
identifier = "zone"
type = "string"
title = "Zone"
}
properties {
identifier = "type"
type = "string"
title = "Type"
}
properties {
identifier = "size"
type = "number"
title = "Size"
}
properties {
identifier = "creationTimestamp"
type = "string"
title = "Creation Timestamp"
}
properties {
identifier = "users"
type = "array"
title = "Users"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_disk_entity" {
for_each = data.google_compute_disk.my_disks
identifier = "${each.value.project}_${each.value.zone}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_disk_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/compute/disksDetail/zones/${each.value.zone}/disks/${each.value.name}?project=${each.value.project}"
}
properties {
name = "description"
value = each.value.description
}
properties {
name = "zone"
value = each.value.zone
}
properties {
name = "type"
value = each.value.type
}
properties {
name = "size"
value = each.value.size
}
properties {
name = "creationTimestamp"
value = each.value.creation_timestamp
}
properties {
name = "users"
items = each.value.users
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Creating the Memorystore blueprint and the entities matching the memorystoresโ€‹

This part includes configuring the memorystore blueprint and creating the entities for the memorystores:

resource "port-labs_blueprint" "gcp_memorystore_blueprint" {
title = "Memorystore"
icon = "GoogleCloudPlatform"
identifier = "memorystore"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "region"
type = "string"
title = "Region"
}
properties {
identifier = "currentLocationId"
type = "string"
title = "Current Location ID"
}
properties {
identifier = "memorySizeGb"
type = "number"
title = "Memory Size GB"
}
properties {
identifier = "replicaCount"
type = "number"
title = "Replica Count"
}
properties {
identifier = "redisVersion"
type = "string"
title = "Redis Version"
}
properties {
identifier = "tier"
type = "string"
enum = ["BASIC", "STANDARD_HA"]
title = "Public Access Prevention"
}
properties {
identifier = "readReplicasMode"
type = "string"
enum = ["READ_REPLICAS_DISABLED", "READ_REPLICAS_ENABLED"]
title = "Read Replicas Mode"
}
properties {
identifier = "connectMode"
type = "string"
enum = ["DIRECT_PEERING", "PRIVATE_SERVICE_ACCESS"]
title = "Connect Mode"
}
properties {
identifier = "createTime"
type = "string"
format = "date-time"
title = "Create Time"
}
properties {
identifier = "authorizedNetwork"
type = "string"
title = "Authorized Network"
}
properties {
identifier = "nodes"
type = "array"
title = "Nodes"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_memorystore_entity" {
for_each = data.google_redis_instance.my_memorystores
identifier = "${each.value.project}_${each.value.location_id}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_memorystore_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/memorystore/redis/locations/${each.value.region}/instances/${each.value.name}/details/overview?project=${each.value.project}"
}
properties {
name = "region"
value = each.value.region
}
properties {
name = "currentLocationId"
value = each.value.current_location_id
}
properties {
name = "memorySizeGb"
value = each.value.memory_size_gb
}
properties {
name = "replicaCount"
value = each.value.replica_count
}
properties {
name = "redisVersion"
value = each.value.redis_version
}
properties {
name = "tier"
value = each.value.tier
}
properties {
name = "readReplicasMode"
value = each.value.read_replicas_mode
}
properties {
name = "connectMode"
value = each.value.connect_mode
}
properties {
name = "createTime"
value = each.value.create_time
}
properties {
name = "authorizedNetwork"
value = each.value.authorized_network
}
properties {
name = "nodes"
items = [for item in each.value.nodes: jsonencode(item)]
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Creating the Compute Instance blueprint and the entities matching the compute-instancesโ€‹

This part includes configuring the computeInstance blueprint and creating the entities for the compute-instances:

resource "port-labs_blueprint" "gcp_compute_instance_blueprint" {
title = "Compute Instance"
icon = "GoogleComputeEngine"
identifier = "computeInstance"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "zone"
type = "string"
title = "Zone"
}
properties {
identifier = "description"
type = "string"
title = "Description"
}
properties {
identifier = "currentStatus"
type = "string"
enum = ["PROVISIONING", "STAGING", "RUNNING", "STOPPING", "REPAIRING", "TERMINATED", "SUSPENDING", "SUSPENDED"]
enum_colors = {
PROVISIONING = "blue"
STAGING = "blue"
RUNNING = "green"
STOPPING = "red"
REPAIRING = "yellow"
TERMINATED = "red"
SUSPENDING = "yellow"
SUSPENDED = "lightGray"
}
title = "Current Status"
}
properties {
identifier = "machineType"
type = "string"
title = "Machine Type"
}
properties {
identifier = "cpuPlatform"
type = "string"
title = "CPU Platform"
}
properties {
identifier = "deletionProtection"
type = "boolean"
title = "Deletion Protection"
}
properties {
identifier = "labels"
type = "object"
title = "Labels"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_compute_instance_entity" {
for_each = data.google_compute_instance.my_compute_instances
identifier = "${each.value.project}_${each.value.zone}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_compute_instance_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/compute/instancesDetail/zones/${each.value.zone}/instances/${each.value.name}?project=${each.value.project}"
}
properties {
name = "zone"
value = each.value.zone
}
properties {
name = "description"
value = each.value.description
}
properties {
name = "currentStatus"
value = each.value.current_status
}
properties {
name = "machineType"
value = each.value.machine_type
}
properties {
name = "cpuPlatform"
value = each.value.cpu_platform
}
properties {
name = "deletionProtection"
value = each.value.deletion_protection
}
properties {
name = "labels"
value = jsonencode(each.value.labels)
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Creating the Run Service blueprint and the entities matching the run servicesโ€‹

This part includes configuring the runService blueprint and creating the entities for the run services:

resource "port-labs_blueprint" "gcp_run_service_blueprint" {
title = "Run Service"
icon = "Service"
identifier = "runService"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "location"
type = "string"
title = "Location"
}
properties {
identifier = "metadata"
type = "array"
title = "Metadata"
}
properties {
identifier = "status"
type = "array"
title = "Status"
}
properties {
identifier = "template"
type = "array"
title = "Template"
}
properties {
identifier = "traffic"
type = "array"
title = "Traffic"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_run_service_entity" {
for_each = data.google_cloud_run_service.my_run_services
identifier = "${each.value.project}_${each.value.location}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_run_service_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/run/detail/${each.value.location}/${each.value.name}?project=${each.value.project}"
}
properties {
name = "location"
value = each.value.location
}
properties {
name = "metadata"
items = [for item in each.value.metadata: jsonencode(item)]
}
properties {
name = "status"
items = [for item in each.value.status: jsonencode(item)]
}
properties {
name = "template"
items = [for item in each.value.template: jsonencode(item)]
}
properties {
name = "traffic"
items = [for item in each.value.traffic: jsonencode(item)]
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Creating the Container Cluster blueprint and the entities matching the container clustersโ€‹

This part includes configuring the containerCluster blueprint and creating the entities for the container clusters:

resource "port-labs_blueprint" "gcp_container_cluster_blueprint" {
title = "Container Cluster"
icon = "Cluster"
identifier = "containerCluster"
properties {
identifier = "link"
type = "string"
format = "url"
title = "Link"
}
properties {
identifier = "location"
type = "string"
title = "Location"
}
properties {
identifier = "description"
type = "string"
title = "Description"
}
properties {
identifier = "masterVersion"
type = "string"
title = "Master Version"
}
properties {
identifier = "enableAutopilot"
type = "boolean"
title = "Enable Autopilot"
}
properties {
identifier = "addonsConfig"
type = "array"
title = "Addons Config"
}
properties {
identifier = "clusterAutoscaling"
type = "array"
title = "Cluster Autoscaling"
}
properties {
identifier = "network"
type = "string"
title = "Network"
}
relations {
identifier = port-labs_blueprint.gcp_project_blueprint.identifier
target = port-labs_blueprint.gcp_project_blueprint.identifier
}
}

resource "port-labs_entity" "gcp_container_cluster_entity" {
for_each = data.google_container_cluster.my_container_clusters
identifier = "${each.value.project}_${each.value.location}_${each.value.name}"
title = each.value.name
blueprint = port-labs_blueprint.gcp_container_cluster_blueprint.identifier
properties {
name = "link"
value = "https://console.cloud.google.com/kubernetes/clusters/details/${each.value.location}/${each.value.name}?project=${each.value.project}"
}
properties {
name = "location"
value = each.value.location
}
properties {
name = "description"
value = each.value.description
}
properties {
name = "masterVersion"
value = each.value.master_version
}
properties {
name = "enableAutopilot"
value = each.value.enable_autopilot
}
properties {
name = "addonsConfig"
items = [for item in each.value.addons_config: jsonencode(item)]
}
properties {
name = "clusterAutoscaling"
items = [for item in each.value.cluster_autoscaling: jsonencode(item)]
}
properties {
name = "network"
value = each.value.network
}
relations {
name = port-labs_blueprint.gcp_project_blueprint.identifier
identifier = each.value.project
}

depends_on = [port-labs_entity.gcp_project_entity]
}

Resultโ€‹

After running terraform apply you will see the organization, folder, project, storageBucket, serviceAccount, disk, memorystore, computeInstance, runService, containerCluster entities in Port.