Skip to main content

GCP reference

Facts to look up while deploying and running Polaris on Google Cloud. For why GCP works the way it does, see Polaris on Google Cloud.

What Polaris offers on GCP today​

CapabilityOn GCP
AMD SEV-SNP, with the report checked directly against AMD's keys (sev-snp-direct)Available, and the default
AMD SEV-SNP with an SVSM and its vTPM (sev-snp-svsm)Available. The workload VM is created through Compute Engine's alpha API
Intel TDX (tdx)Available
NVIDIA H100 confidential GPU, with Intel TDXOnly with --local-build. The released images include no GPU-enabled proxy, so deploy refuses it otherwise
AMD SEV-SNP checked through Google's Confidential Computing verifier (sev-snp)Not available. deploy switches it to sev-snp-direct
Attestation of image, runtime and kernel, with key access withdrawn when a layer you enforce failsAvailable
Status routes and incident records readable through the endpointAvailable
Health telemetry exported from the Policy Manager over OTLPAvailable, off by default
A route for the workload to use its attestation-gated keyNot yet available
Learned allowlists and promote settings kept across a Policy Manager restartAvailable, on the Policy Manager's state disk
Learned allowlists and promote settings kept across a deployNot yet available. Each deploy writes the baseline under a new name, which starts learning again
Pinning the Policy Manager's measurement before the workload VM bootsAvailable, with cloud.gcp.pm_measurement_hex
Ending key access when the Policy Manager stops, without the Policy ManagerNot yet available
Naming your own key ring, key or KMS locationNot yet available
More than one workload VMNot yet available

Regions, zones and machine types​

Both VMs run in one zone, cloud.gcp.zone, inside cloud.gcp.region. The defaults are us-central1 and us-central1-a. The tooling does not check the region or zone against the TEE you choose, so pick a zone that offers the machine type with confidential computing. Compute Engine refuses the VM at launch otherwise.

TEE (tee.cpu)Workload VM defaultCPU platform the module requests
sev-snp-directn2d-standard-4AMD Milan or newer
sev-snp-svsmn2d-standard-4AMD Milan or newer
tdxc3-standard-4Intel Sapphire Rapids
tdx with tee.gpu: nvidia-h100a3-highgpu-1g, the only machine type the module acceptsFixed by the machine type

The Policy Manager always runs on AMD SEV-SNP, on n2d-standard-2 by default, whatever TEE the workload VM uses.

VMConfig keyDefault
Workload VMcompute.cvm_machine_typen2d-standard-4, c3-standard-4 for tdx, or a3-highgpu-1g with a GPU
Policy Manager VMcompute.pm_machine_typen2d-standard-2

For a GPU deployment, deploy fills in a3-highgpu-1g when compute.cvm_machine_type is empty. That is the only size the module takes with a GPU, so any other size you set is refused.

The GPU VM always runs as a Spot VM, with no option to change it, and it does not restart on its own. When Compute Engine preempts it, its access to your key ends once its reports stop, and the next deploy creates it again.

What a deployment creates​

Everything below is created in your project and removed by destroy, except where noted. <name> is the deployment name, metadata.name. In hardware attestation mode there is no Policy Manager, so its VM, state disk, service account, role, address and firewall rules are not created.

Network

  • A VPC network, <name>-net, with one subnet, <name>-subnet, 10.0.0.0/24 in the region, with Private Google Access on.
  • A reserved external address, <name>-cvm-ip, for the workload VM. It stays the same when the workload VM is replaced.
  • A reserved internal address, <name>-pm-ip, 10.0.0.253, the last usable address in the subnet, for the Policy Manager.
  • Firewall rules, applied by network tag:
    • <name>-allow-https: HTTPS on port 443 to the workload VM from any address.
    • <name>-allow-iap-ssh: SSH on port 22 to both VMs from 35.235.240.0/20, the range IAP connects from.
    • <name>-pm-allow-evidence and <name>-pm-allow-operator: ports 443 and 8443 on the Policy Manager, from the workload VM only.
    • <name>-deny-all-egress: denies all outbound traffic from both VMs, at the lowest priority, so only the allow rules below get out.
    • <name>-allow-egress-gapis and <name>-allow-egress-https: port 443 to 199.36.153.4/30 and 199.36.153.8/30, Google's restricted and private API addresses.
    • <name>-allow-egress-pki-http: port 80 to 199.36.153.8/30.
    • <name>-allow-egress-int: port 443 within the subnet.
    • <name>-allow-egress-pm-op: port 8443 from the workload VM to the Policy Manager.
    • <name>-allow-egress-custom: port 443 to the ranges in network.allowed_egress_cidrs, when set.
    • <name>-allow-egress-nras: port 443 to NVIDIA's attestation service, on GPU deployments only.
    • <name>-allow-egress-otel: from the Policy Manager to your telemetry collector, when you set one with --otel-endpoint and --otel-egress-cidrs.
  • A Cloud Router, <name>-router, and Cloud NAT, <name>-nat, for the subnet. The Policy Manager has no external address and goes out through it, within the same firewall rules.
  • Three private Cloud DNS zones, <name>-googleapis, <name>-pkg-dev and <name>-gcr-io, visible only to the deployment's network. They point googleapis.com, pkg.dev and gcr.io at 199.36.153.8 to 199.36.153.11, so the VMs reach Google APIs and Artifact Registry without a path to the internet.

Compute

  • Two confidential VMs in the zone, <name>-cvm and <name>-pm, each with a 50 GB pd-ssd boot disk that is deleted with it. Both set host maintenance to terminate rather than migrate.
  • A state disk for the Policy Manager, <name>-pm-state, pd-balanced, 10 GB, attached to the Policy Manager VM. It is a disk of its own, so it outlives the VM, and a replacement Policy Manager attaches the same disk. It holds the Policy Manager's issuer keys, its record of the workload VMs, the locks a failure put on the key, what it learned and the promote settings. destroy deletes it.
  • Shielded VM with Secure Boot on both. The Policy Manager and the sev-snp-direct and tdx workload VMs also have the Shielded vTPM and integrity monitoring. The sev-snp-svsm workload VM has the SVSM's vTPM instead, since GCP refuses the two together.
  • For sev-snp-svsm, the workload VM is created by deploy through Compute Engine's alpha API rather than by Terraform, because the SVSM setting exists only there. deploy reads the VM back and deletes it if it did not get the SVSM vTPM. deploy deletes and recreates this VM on every run, and destroy deletes it before running Terraform.

Identity

  • Two service accounts, <name>-cvm and <name>-pm, cut to 30 characters. Their roles are in The service accounts and roles.
  • A custom role, <name>PMIAMManager<suffix>, with the hyphens taken out of the name and six random hex characters added, bound to the Policy Manager's service account on the deployment's key.
  • A Workload Identity Federation pool, <name>-attest-pool, and an OIDC provider in it, <name>-cc-prov, for the issuer https://confidentialcomputing.googleapis.com, limited to tokens that name your project. Both IDs are cut to 32 characters. Both are disabled, nothing is bound to them, and the key gate does not use them. See The service accounts and roles.
  • When sandbox.operator_principal is set, an operator service account, <name>-operator, for a third party. See the same section.

Keys

  • A Cloud KMS key ring, <name>-keyring, and key, <name>-key, in the deployment's region. The key is for asymmetric decryption, RSA_DECRYPT_OAEP_4096_SHA256, with HSM protection. The Policy Manager grants and removes access to it as the verdict changes.

Created, and kept by destroy

  • The key ring and key. destroy takes them out of Terraform's state before it runs, so they remain, and a later deployment under the same name takes them back and gates the same key. If you delete the key's versions yourself, Cloud KMS keeps them restorable for 30 days.
  • The IAM bindings the Policy Manager added to the key for the workload VM's service account. See Tear down a deployment.
  • The Artifact Registry repository polaris.docker_repo, polaris-docker by default, in the deployment's region. deploy creates it with gcloud if it is missing and copies the Polaris images into it. Later deployments with the same repository name reuse it.

The service accounts and roles​

Service accountRoleOn
<name>-cvm, the workload VMroles/artifactregistry.readerThe project
roles/confidentialcomputing.workloadUserThe project
roles/cloudkms.cryptoKeyEncrypterDecrypter and roles/cloudkms.publicKeyViewerThe deployment's key, added and removed by the Policy Manager
<name>-pm, the Policy Managerroles/artifactregistry.readerThe project
roles/confidentialcomputing.workloadUserThe project
The custom role, with cloudkms.cryptoKeys.getIamPolicy and cloudkms.cryptoKeys.setIamPolicyThe deployment's key
<name>-operator, only with sandbox.operator_principalroles/compute.viewer, roles/iap.tunnelResourceAccessor and roles/artifactregistry.writerThe project
roles/compute.osLoginThe Policy Manager VM only

Both VMs run with the cloud-platform access scope. What each can do is set by the roles above.

Older releases also gave roles/iam.workloadIdentityUser on <name>-cvm to every identity from the deployment's federation pool. The tooling no longer creates that binding, and deploy removes one an older release left on the account, from fresh state too, before it plans. If it cannot read the account's policy it says so. To check by hand: gcloud iam service-accounts get-iam-policy <name>-cvm@<project>.iam.gserviceaccount.com.

With sandbox.operator_principal set, that principal gets roles/iam.serviceAccountTokenCreator on <name>-operator and nothing else, and the Policy Manager VM turns on OS Login so that the operator account can SSH to it. The operator account has no role on the key and none that changes IAM. It is meant for letting a third party read a sandbox, and destroy removes it.

Where a deployment connects​

FromToFor
The machine that runs deployGoogle Cloud APIs in your projectCreating and checking the deployment
The machine that runs deployghcr.io/fr0ntierxCopying the Polaris images into your Artifact Registry, pinned by digest
The machine that runs deployBoth VMs on port 22, through IAPHealth checks, capturing the Policy Manager's measurement, status and promote
Workload VMGoogle APIs and Artifact Registry, through the private API addressesPulling images and Google API calls
Workload VMThe Compute Engine metadata serverIts identity and service account credentials. Only the proxy's container and the host reach it, and the workload's container does not
Workload VMThe Policy Manager on ports 443 and 8443Evidence reports, and the tunnel Polaris Desktop uses
Workload VMThe ranges in network.allowed_egress_cidrs, on port 443Your workload's outbound traffic
Policy ManagerThe same private API addresses and the ranges in network.allowed_egress_cidrsPulling images, Cloud KMS, and anything you allow
Policy ManagerYour OTLP collector, when setHealth telemetry
Both VMs, GPU deployments onlyNVIDIA's attestation service, 34.120.45.54/32 by defaultChecking the GPU's evidence

The network rules apply to the Policy Manager as well, so although it goes out through Cloud NAT, it reaches no more of the internet than the workload VM does. That includes AMD's Key Distribution Service, so the Policy Manager does not check AMD's or Intel's certificate revocation lists on GCP.

Name lookups go to the metadata server, which firewall rules do not filter, so both VMs can resolve any name.

Telemetry leaves the Policy Manager only when you set --otel-endpoint, and it carries health data such as verdict counts and latencies, never evidence or secrets. Nothing exports from the workload VM.

IAM permissions​

The identity that deploys​

deploy enables no Google Cloud APIs. Enable the APIs for Compute Engine, Cloud DNS, Cloud KMS, IAM, Cloud Resource Manager, Artifact Registry and Identity-Aware Proxy in the project first, since the deployment creates or calls resources in each.

Before it creates anything in workload or full mode, deploy checks that your active gcloud account holds two roles as direct bindings on the project, and stops if either is missing:

  • roles/iam.workloadIdentityPoolAdmin
  • roles/iam.roleAdmin

The check looks for these exact roles bound to your own account, so a role that contains their permissions, or a binding through a group, does not satisfy it.

Beyond those two, the identity that runs deploy and destroy has to be able to do the following:

ServiceWhat the tooling doesUsed for
Compute EngineCreate, read and delete networks, subnets, addresses, firewall rules, routers, Cloud NAT and instances. Read images in the image project. Insert and read instances through the alpha API for sev-snp-svsmThe network and both VMs
Cloud DNSCreate and delete private managed zones and their record setsRouting Google API traffic to the private addresses
Cloud KMSCreate and read a key ring and key, and set an IAM binding on the keyThe deployment's key, and the Policy Manager's role on it
IAMCreate and delete service accounts, a custom role and a federation pool and provider, set an IAM binding on a service account, and undelete a pool, provider or role left soft-deleted by an earlier deployment of the same nameThe deployment's identities
Resource ManagerRead the project's IAM policy and add project-level role bindingsThe prerequisite check, and the roles each service account gets
Artifact RegistryCreate and read a Docker repository, and push and read imagesCopying the Polaris images, and your workload's when deploy builds it
Identity-Aware ProxyOpen a TCP tunnel to port 22 on both VMs, and SSH to them with gcloud compute ssh and gcloud compute scpThe steps after Terraform, status and promote

The VMs run as the two service accounts the deployment creates, so the deploying identity also has to be allowed to attach them to instances.

An identity that can create service accounts, grant them project roles and attach them to VMs it creates can give those VMs any permission in the project. Treat the deploying identity as an administrator of the project it deploys into, and give each deployment a project of its own.

deploy also runs gcloud config set project with cloud.gcp.project_id, which changes the default project of your gcloud configuration.

What the Policy Manager gets on the key​

The Policy Manager's service account holds the custom role on the deployment's key and nothing else on it. The role lets it read and write the key's IAM policy.

When the workload VM passes, the Policy Manager adds the workload VM's service account to the key's policy under two roles:

  • roles/cloudkms.cryptoKeyEncrypterDecrypter
  • roles/cloudkms.publicKeyViewer

It removes the service account from both when a layer you enforce fails, when the workload VM stops reporting, or when the grant reaches its lifetime without a passing report. The role is not limited by an IAM condition, so nothing in Google Cloud limits which roles or members the Policy Manager's service account writes into the key's policy.

Deployment config keys​

The keys specific to GCP, under cloud.gcp:

KeyRequiredDefaultMeaning
project_idYesThe project to deploy into
regionNous-central1The region for the subnet, the addresses, the Artifact Registry repository and the key ring
zoneNous-central1-aThe zone for both VMs
pm_measurement_hexNounsetThe launch measurement the Policy Manager's SEV-SNP report must carry, 96 hex characters. Set, it is written into the workload VM's configuration before the VM boots, and the proxy refuses any other Policy Manager. Unset, the proxy trusts the first Policy Manager that answers until deploy installs the value it captured. On GCP the measurement covers Google's firmware and the vCPU shape, not the Policy Manager's software, so it describes the VM's shape and is not an identity, and a firmware rollout moves it. deploy prints the value after a deployment
pm_required_vmplNo0The privilege level, 0 to 3, the Policy Manager's report must carry. Read only when pm_measurement_hex is set

The keys that choose the TEE:

KeyDefaultMeaning on GCP
tee.cpusev-snp-direct, sev-snp-svsm or tdx. sev-snp is accepted and switched to sev-snp-direct
tee.gpunonenone or nvidia-h100. nvidia-h100 needs tee.cpu: tdx and --local-build, and runs on a3-highgpu-1g, which deploy picks when the machine type is empty
tee.svsm_measurementunsetFor sev-snp-svsm only. The SHA-384 of the SVSM firmware, 96 hex characters. Set, the platform check accepts only that firmware. A wrong value fails the platform check and withdraws access to your key, and so does a firmware update by Google until you change the value

Keys shared with the other clouds that apply on GCP:

KeyDefaultMeaning on GCP
metadata.nameThe deployment name, used in every resource name. A lowercase letter, then 1 to 24 lowercase letters, digits or hyphens
compute.cvm_machine_typen2d-standard-4, c3-standard-4 for tdx, a3-highgpu-1g with a GPUWorkload VM machine type. See Regions, zones and machine types
compute.pm_machine_typen2d-standard-2Policy Manager machine type. It must be an AMD SEV-SNP machine type
compute.cvm_image_familypolaris-cvm, and polaris-cvm-gpu on GPU deploymentsThe image family both VMs boot from. deploy warns when it is anything else
compute.cvm_image_projectthe deployment's projectThe project that holds the image family
network.allowed_egress_cidrsemptyRanges both VMs may reach over HTTPS on port 443
features.attestation_modefullhardware, workload or full. See Deploying Polaris
features.ebpffalseRuns the Sentinel agent, which collects runtime and kernel evidence. It runs only in full mode, so set it for full attestation
features.imafalseHas the Sentinel read the kernel's measurements of every executable. Takes effect only in full mode with features.ebpf: true
workload.imageA prebuilt workload image. One in Artifact Registry in the deployment's own project needs nothing else
workload.dirIn place of workload.image, a folder with a Dockerfile, relative to the top folder of the Polaris tooling. deploy builds it for linux/amd64 and pushes it to Artifact Registry in your project
workload.port3000The port your workload listens on, over plain HTTP
workload.envemptyEnvironment variables for the workload, as KEY: value pairs. They become part of the workload VM's instance metadata, so keep secrets out
workload.resources.cpus, workload.resources.memory_mbno limitHard limits for the workload container
workload.security.read_onlyfalseRuns the workload with a read-only filesystem
workload.security.capabilitiesemptyExtra Linux capabilities the workload needs, as a list
polaris.docker_repopolaris-dockerThe Artifact Registry repository the Polaris images are copied into. Deployments in one project and region that share the name share the repository
polaris.proxy_image, polaris.pm_image, polaris.sentinel_imageunsetPrebuilt Polaris images to deploy in place of the released ones. The proxy and Policy Manager images must already be in the deployment's repository
license.fileA license file for a direct contract. See Licensing
attestation.report_interval30Seconds between evidence reports, from 5 to 300
attestation.deadman_interval120Seconds of silence from the workload VM before the Policy Manager withdraws access. At least 30, and more than report_interval
attestation.grant_ttl3600Seconds a grant lasts without a passing report. At least 60
attestation.autolearn_window10mHow long Polaris must watch the workload before learning can finish, such as 30m or 2h. Under 12 hours. 0 means no window
attestation.promotion_window1dHow long a layer must be clean under advise before it may enforce. 0 turns the check off, and is the default when sandbox.ttl is set
sandbox.ttlunsetHas Compute Engine delete both VMs this long after they start, such as 4h. For trial deployments. The rest of the deployment stays until destroy
sandbox.operator_principalunsetA user:, group: or serviceAccount: principal that may act as the read-only operator account
sandbox.impersonateunsetRun gcloud and Terraform as that operator account. It can run status, and the tooling refuses deploy and destroy with it
attestation.trust_domainpolaris.<name>The name the Policy Manager writes into every certificate it issues. It is stored on the Policy Manager's state disk, so set it before the first deploy, if at all, and never change it afterwards
attestation.deployment_idderived from the trust domainA UUID naming the deployment in the Policy Manager's record of its workload VMs. The Policy Manager refuses to start when its state disk holds a record under another ID, so never change it, or the trust domain it is derived from, once the deployment exists

These keys are accepted and have no effect on GCP:

  • kms.gcp.key_ring and kms.gcp.key_id. The key ring and key are always <name>-keyring and <name>-key. These values only reach a kms block in the baseline file, which the Policy Manager does not use to find the key.
  • kms.gcp.location. The key ring is always in cloud.gcp.region.
  • compute.cvm_count. A deployment has one workload VM.
  • network.workload_ingress_cidrs. Port 443 on the workload VM is open to any address.

Commands​

Run every command from the top folder of the tooling. deploy and destroy take --config <file>. status and promote take --config <file>, or --project <id> and --name <name> in its place.

CommandWhat it does
deployCreates the deployment, or updates it. Copies the Polaris images, writes the baseline, runs Terraform, checks that the workload container and the Policy Manager are up, then reads the Policy Manager's measurement. With cloud.gcp.pm_measurement_hex set it checks the value against the pin and stops on a mismatch, and without it installs the value on the workload VM and prints the config to pin it. Both VMs are replaced when the image family has a newer image. --dry-run stops at the Terraform plan. --force-replace replaces both VMs even when nothing changed. --promotion-window <duration> and --autolearn-window <duration> set the two windows. --preflight runs only the checks and stops
statusLists the two VMs and the endpoint, and through IAP reads each layer's status, the license state and how far learning has got from the Policy Manager
watchShows each layer's status and how far learning has got, through the deployment's endpoint, with no Google Cloud access. Takes --endpoint https://<address> and --token <token>, and works with the read-only token
promoteMoves enforcement layers between advise, enforce and off, in place. --layers takes a comma-separated list of l2, l3, l31, ima_boot, l3_syscalls, l3_binaries and l3_network, and defaults to l31. --mode defaults to enforce. It refuses to enforce a layer whose allowlist is still empty, and only warns for l3_binaries, unless you pass --force. The Policy Manager also refuses enforce for a layer that has not been clean under advise for the promotion window. promote reads the settings back to confirm them
set-workloadPoints a running deployment at a new workload image with a token alone. Takes --endpoint, --token and --image, and pins the image by digest before sending it. The Policy Manager replaces the image allowlist and starts learning the workload again, and the workload VM pulls and restarts the container within about 30 seconds. The image must be pullable from the deployment's registry, and --mirror-registry copies it there first
destroyRemoves everything in What a deployment creates except the items it keeps

The GCP deployment leaves ima_boot unset, so it follows l2.

The Policy Manager keeps the settings promote makes, and everything it learned, on its state disk, so they survive a restart of its container or VM. They last only while the baseline file stays the same. Each deploy writes the baseline under a new name that carries the time of the run, so each deploy returns every layer to the settings in the baseline file and starts learning again.

up, up-polaris and down create and remove a time-limited sev-snp-svsm demonstration sandbox. They are not meant for your own workload.

Routes on the endpoint​

These are the same routes as on AWS, since the proxy serves them on every cloud.

RouteTokenReturns
/polaris-container/healthnone{"status":"ok"} while the proxy runs
/polaris-container/readynoneWhether the proxy is serving workload traffic, and the state of its gate
/polaris-container/attestationnoneThe hardware report and its certificates, for a client to check
/polaris-container/tls-infononeThe hash of the proxy's TLS public key, which the hardware report is bound to
/polaris-container/attestation-statusnoneThe latest verdict, with a status for each layer and when it was checked
/polaris-container/attestation-statusread-onlyThe same, with the reason for a failure and the alerts
/management/statusread-onlyThe Policy Manager's status for each workload VM, including its cvm_id
/management/profiles/learn, /management/ima/learn and /management/kernel/learnread-onlyEach learner's progress
/management/incidents/<cvm_id> and /management/incidents/<cvm_id>/reportread-onlyThe VM's recent incidents, as JSON or as a plain-text report
/management/checks/<cvm_id>read-onlyThe latest checks, one by one
/management/history/<cvm_id>read-onlyRecent verdicts
/management/kms/locksread-onlyThe service accounts a failure has locked out of the key
/management/kms/locks/<service account>, with DELETEmanagementLifts a lock
/management/workloadworkload-swapThe workload image the deployment should run, read with GET and changed with POST, as set-workload does

The proxy passes the management token on to every /management/ route, and the read-only token only on GET.

GCP has no key routes on the proxy's internal listener yet, so the workload has no supported way to use the gated key.

Files the tooling keeps​

deploy keeps these files for each deployment in terraform/modules/gcp/ in the tooling, so run every command from the copy of the tooling that holds them. The state and the .tfvars file carry the deployment's tokens in plain text, so keep the folder encrypted and access-controlled.

FileHoldsRemoved by destroy
terraform-<name>.tfstateThe Terraform stateNo
terraform-<name>.tfvarsThe deployment's resolved configuration, with the tokens and the baselineNo
terraform-<name>.tokenThe management token, used by status and promoteYes, though any later command writes a new, unrelated one
terraform-<name>.readonly.tokenThe read-only token, for watch and the management routesYes, though any later command writes a new, unrelated one
terraform-<name>.workload.tokenThe workload-swap token, for set-workloadNo
pm-snp-baseline-<name>.yamlAn audit copy of the Policy Manager's captured measurement, written when cloud.gcp.pm_measurement_hex is unsetNo
pm-identity-<name>.jsonThe record Polaris Desktop checks the Policy Manager againstNo

The three tokens also sit in both VMs' boot configuration, which is instance metadata. Anyone who can view the instances in the project can read them there.