Skip to content

Deploying Portward on Google Cloud

For the person who runs Google Cloud at your company. About 25 minutes. At the end, your team asks Claude or ChatGPT about company data through a gateway that runs in your own Google Cloud project. The gateway swaps the values you mark as sensitive for tokens before the AI sees them, and records every answer in your project. Portward (the company) never receives your data and has no access to your project.

What gets created, all in your project:

One machine (e2-small, Container-Optimized OS, Shielded VM)Runs the gateway, Caddy (its HTTPS certificate) and, with the relay, the relay client.
A records disk (10 GB, encrypted)The gateway’s answer records, setup and saved connections. Snapshotted daily, kept 14 days; snapshots stay if the disk is deleted.
Secret ManagerThe gateway key, generated on the machine the first time it starts (it never leaves your project), and the secrets you add.
A new networkNothing open inbound. With your own domain, ports 80 and 443 only.
A service accountMay read its own secrets, add the key once and write logs. Nothing else.

Cost, roughly $18 a month in us-central1: about $12 for the machine, $2 for the disks, $4 for its IP address, and a few cents for snapshots and secrets.

  • A Google Cloud project, and in it roles to create the above (Owner, or Compute Admin, Service Account Admin, Service Account User, Project IAM Admin, Secret Manager Admin, Service Usage Admin).
  • Terraform 1.5 or later. With the Deploy to Google Cloud button you don’t need it, because Cloud Shell has it.
  • Your company directory, where your team already signs in: Microsoft Entra, Okta, Google Workspace or any OpenID Connect directory.
  • Your Portward license key (pwlic_…) from the key page (Get started, step 2). The gateway uses it to download its image and to connect to the relay. Your gateway’s name is part of it.
  • An address. Either the Portward relay (https://yourco.gw.portward.ai, from the license key; nothing opens inbound), or a name of your own such as portward.yourcompany.com that you can point at an IP.
  • Read-only logins for the databases you’ll connect. Portward refuses a login that can write.

1. Register the gateway in your directory (10 minutes)

Section titled “1. Register the gateway in your directory (10 minutes)”

Register one web app with the redirect address https://<your address>/auth/callback. Sign-in setup has the steps for Entra, Okta and Google. Keep its sign-in address (issuer), client id and secret.

2. Deploy (5 minutes, then about 3 for the machine)

Section titled “2. Deploy (5 minutes, then about 3 for the machine)”

The quick way: press Deploy to Google Cloud (also on the page that showed your license key). Cloud Shell opens with this module and a step-by-step tutorial beside it. Google runs repositories it doesn’t maintain in a temporary session. The tutorial has you sign in there and keeps Terraform’s state in a private bucket in your project. It asks for the license key and directory secret without showing them, and never takes them from the link. It runs the same module as below.

Or from your own Terraform:

module "portward" {
source = "https://portward-launch.s3.us-east-2.amazonaws.com/templates/1.1.1/gcp/portward-gcp.zip"
project_id = "your-project"
zone = "us-central1-a"
# Your license key from signing up (pwlic_yourco_...): the image, the relay key and the address,
# https://yourco.gw.portward.ai through the Portward relay ...
license_key = var.portward_license # e.g. TF_VAR_portward_license from your vault
# ... or your own: address_mode = "own-domain" domain = "portward.yourcompany.com"
directory_issuer = "https://login.microsoftonline.com/<tenant id>/v2.0"
directory_client_id = "<client id>"
admin_groups = ["<group object id>"] # Google Workspace: admin_subjects = ["you@yourco.com"]
user_groups = ["<group object id>"] # Google Workspace: users = ["@yourco.com"]
}
Terminal window
terraform init && terraform apply

To reach databases in an existing network, add subnetwork = "projects/<p>/regions/<r>/subnetworks/<name>"; with no public IP there (Cloud NAT instead), also public_ip = false.

If Compute Engine wasn’t turned on in the project before, Google creates a default network with SSH and RDP open to the internet when it’s turned on. The gateway doesn’t use it (it runs in its own network); delete it if nothing else does.

The deployment puts the license key in Secret Manager. It is also in Terraform’s state, so keep the state private. The directory secret can stay out of the state: terraform output secrets_to_add lists the command. From a file, so it isn’t typed on a command line:

Terminal window
gcloud secrets versions add portward-directory-secret --project your-project --data-file=directory-secret.txt

The machine checks every 30 seconds and starts the gateway once it is there. (You can instead pass it as directory_client_secret.)

With your own domain: point it at terraform output ip_address (a DNS A record). Caddy gets the certificate as soon as the name resolves.

About a minute after the last secret is in, the gateway is up; through the relay, allow another minute or two for the certificate.

Terminal window
curl -s https://<your address>/health # {"ok": true, ...}

The machine’s progress is in its serial console (gcloud compute instances get-serial-port-output portward-gateway, lines starting portward:), and the gateway’s own log in Cloud Logging (terraform output logs).

5. Make yourself the admin, connect data, give your team access

Section titled “5. Make yourself the admin, connect data, give your team access”

Your settings are the module’s values. If you deployed with your own Terraform, edit the module "portward" block. If you used the Deploy to Google Cloud button, the Cloud Shell session doesn’t keep your files. Open the tutorial again with the same project and state bucket, and enter every value in portward.auto.tfvars, including the ones you’re not changing. Then run terraform apply. It replaces the machine, which means a minute or two of downtime. The records disk and the key are kept.

  1. Add the terraform output admin_connector address in Claude or ChatGPT as a custom connector (Get started, step 7) and sign in. Members of admin_groups, and the people in admin_subjects, are admins. If you’re refused, the gateway’s log (terraform output logs) names your id in an "admin connector refused" line: add it to admin_subjects and apply.
  2. Add each database host to setup_hosts, such as ["db.internal.yourcompany.com"], and apply. Object stores, Microsoft 365 and Google Drive don’t use this list.
  3. From the admin connector, set up the connection and choose what the AI may see: Get started, step 8.
  4. Say who may use the data connector: groups in user_groups, or people in users (sign-in ids, verified emails, or "@yourcompany.com" for everyone at your domain). Apply.
  5. Each of them adds the terraform output data_connector address in Claude or ChatGPT: Get started, step 9.
  • Changing settings: edit the module’s values and terraform apply, as in step 5.
  • Update, back up and restore: Update and back up. Google Cloud takes a snapshot of the records disk every day. Back up the gateway key once and keep it apart from the snapshots, as that page shows.
  • Removing it: the key is protected from deletion. Set keep_key_on_destroy = false, terraform apply, then terraform destroy. Snapshots are kept until you delete them.
You seeFix
Serial console: waiting for secret ...Add that secret (step 3).
Serial console: couldn't pullThe license key is revoked or the trial ended. Replace the license key, or extend the trial.
/health doesn’t answer over the relayCheck the license key is current (a reissued key replaces the old one: update license_key).
/health doesn’t answer at your domainDNS isn’t pointing at ip_address yet.
Sign-in says the redirect address doesn’t matchThe directory app’s redirect address must be exactly terraform output redirect_uri.