Skip to main content

Gateway installation guide for GCP

This guide installs the Agent Router gateway in a Google Cloud project using the tare command-line utility. The resulting ingress terminates TLS for the data plane and routes traffic to it from a customer-facing hostname.


Plan for 45--90 minutes end-to-end:

  • 10–15 minutes of CLI work.
  • 15–60 minutes of background certificate provisioning.

Architecture

┌───────────────────────────────────────────┐
│ proxy.<your-domain> ← customer DNS │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ Static IP │ ← GCP global address │
│ └────────┬───────┘ │
│ │ │
│ ┌────────▼───────┐ │
│ │ Cert Map + │ ← TLS termination │
│ │ Managed Cert │ │
│ └────────┬───────┘ │
│ │ │
│ ┌────────▼───────┐ │
│ │ Agent Router | ← installed in this │
│ │ Gateway(k8s) │ guide │
│ └────────┬───────┘ │
│ │ │
│ ┌────────▼───────┐ │
│ │ Agent Router | |
| | Dataplane │ ← installed earlier │
│ └────────────────┘ via tare CLI │
└───────────────────────────────────────────┘

The tare utility provisions everything from the static IP down to the gateway routes. The operator provides one customer-facing DNS record at the top.

Prerequisites

The following are required before starting:

  • Access to a GCP project with at least the following roles:
    • roles/compute.networkAdmin (static IP).
    • roles/certificatemanager.editor (cert map, cert, DNS auth).
  • Access to the Kubernetes cluster where the Agent Router dataplane runs. kubectl cluster-info must succeed against the target cluster.
  • Control over the DNS provider for the domain in use (for example Cloudflare, Route 53, or an internal DNS team). Two records are created during the install.
  • The Agent Router dataplane already installed. This guide assumes tare install has already run successfully against the target cluster.
  • gcloud installed and authenticated when using --apply-prereqs to let the CLI provision the GCP resources. When the platform team manages those via Terraform or another IaC tool, skip gcloud and use --ack-prereqs instead.
  • Two files from Tetrate:
    • The identity file (identity.json), issued by the management plane during onboarding.
    • A starter gcp-gateway.json. A Tetrate field engineer typically provides a template tuned to the target environment.

The tare binary ships helm and kubectl embedded; no separate install is required.

Step 1: prepare the config

The gateway install is driven by a single JSON contract: gcp-gateway.json. Every value can also be passed as a CLI flag, but the config file is the recommended unit for version control and review.

A complete example:

{
"projectId": "withfraser",
"serveDomain": "proxy.acme.tetrate.ai",
"customer": "acme",
"environment": "production",
"serveUrl": "proxy.acme.tetrate.ai",
"certificateMap": {
"name": "acme-tetrate-ai"
},
"certificate": {
"name": "acme-serve-cert"
},
"dnsAuthorization": {
"name": "proxy-acme-tetrate-ai-dns-auth"
},
"namespaces": {
"gateway": "tars-gateway",
"system": "tars-system",
"dataplane": "tars-dataplane"
},
"gcloud": {
"skipExisting": true
}
}

Commonly edited fields:

FieldDescription
projectIdThe GCP project that hosts the static IP, cert, and cert map.
serveDomainThe fully-qualified hostname customers will use. Single host only; wildcards are not yet supported.
customerThe customer identifier, matching the value in the identity file.
environmentFree-form label propagated to Helm values. Typical values: production, staging.
certificateMap.nameName for the GCP certificate map. Convention: <customer>-<domain-suffix>.
certificate.nameName for the managed certificate. Convention: <customer>-serve-cert.
gcloud.skipExistingWhen true, re-runs are idempotent; re-installs do not fail when a resource already exists. Recommended true.

For the full schema, including optional fields such as gateway.staticIpName and securityPolicy, see the gcp-gateway.json schema reference.

tip

Set gateway.staticIpName to pin the gateway to a reserved static IP. Without it, the gateway receives an ephemeral GCP address that may change on reschedule or upgrade, silently breaking the DNS A record from Step 5.

Step 2: validate the config

Lint the config before any cloud or cluster operation:

tare gateway config lint --config gcp-gateway.json

The check is hermetic (no GCP or Kubernetes calls) and safe to run in CI on every config change.

The lint command produces one of three outcomes.

All clear:

Summary: 0 error, 0 warn, 0 info

Warnings to review:

⚠ [TAREL010] gateway.staticIpName — gateway will receive an ephemeral
GCP forwarding-rule address; customer DNS A records may
break on reschedule.
Remediate: set gateway.staticIpName in gcp-gateway.json
or pass --static-ip-name on install.

Summary: 0 error, 1 warn, 0 info

Warnings are advisory; the install proceeds, but each finding should be reviewed. Findings include a remediation hint and a docs link (https://docs.tetrate.ai/tare/lint/<RULE_ID>).

Errors that block install:

✗ [TAREL001] customer — required value cannot be resolved
tried: --customer (empty), gcp-gateway.json:customer (empty),
identity.json:customerId (empty)
Remediate: add "customer" to gcp-gateway.json, or pass --customer.

Summary: 1 error, 0 warn, 0 info

Errors must be fixed before the install runs.

For the full rule list and how to suppress accepted findings (for example via a lint.ignore block in the config), see tare gateway config lint.

CI usage: tare gateway config lint --config gcp-gateway.json --fail-on-warn exits non-zero on any warning or error, making it the recommended pre-merge gate for a config repository.

Step 3: preview the install (plan)

Render a Plan before any side effects:

tare gateway install identity.json \
--type gcp \
--config gcp-gateway.json \
--plan-only

Sample output:

Plan: tare gateway install (provider=gcp)

Identity: identity.json (client_email: [email protected])
Project: withfraser (from --config)
Customer: acme (from --config)
Environment: production (from --config)
Serve host: proxy.acme.tetrate.ai (from --config:serveDomain)
serveUrl: proxy.acme.tetrate.ai (same as serveDomain)

GCP delta:
+ static IP acme-gateway-ip [will create]
+ cert map acme-tetrate-ai [will create]
+ dns auth proxy-acme-…-dns-auth [will create]
+ certificate acme-serve-cert [will create, single host]
+ map entry serve-entry [will create]

Kubernetes delta:
+ namespace tars-gateway [will create]
~ namespace tars-system [exists]
~ namespace tars-dataplane [exists]
+ helm release tars-gateway [will install, chart v1.2.5]

After install, customer must:
Create A record: proxy.acme.tetrate.ai → <address shown after install>
Create CNAME: (provided after install)

Verify the following before proceeding:

  1. Project is correct. Misclicking between acme-prod and acme-staging is the most common deploy mistake.
  2. Customer matches the identity file's owner.
  3. Serve host matches the customer-facing hostname.
  4. + rows are resources that will be created. ~ rows already exist and are left alone (or modified in place).
  5. No error findings appear in the inline lint section.

The Plan output is also available as JSON (--output json) for use by other tooling. The JSON shape is a stable contract (apiVersion: tare.tetrate.io/v1alpha1).

Step 4: apply

Two routes are supported.

Option a: CLI provisions GCP resources

When tare is permitted to run gcloud directly:

tare gateway install identity.json \
--type gcp \
--config gcp-gateway.json \
--apply-prereqs \
--wait

--apply-prereqs creates the static IP, DNS authorization, certificate map, certificate, and map entry via gcloud. --wait blocks the command until the gateway has a routable address.

Option b: GCP resources already provisioned

When the platform team owns the GCP resources via Terraform or another IaC tool, skip the prereq automation:

tare gateway install identity.json \
--type gcp \
--config gcp-gateway.json \
--ack-prereqs \
--wait

--ack-prereqs acknowledges that the static IP, certificate map, certificate, and DNS authorization are already in place. The CLI refuses to start the install without one of --apply-prereqs or --ack-prereqs.

Install sequence

The CLI prints the Plan, prompts Proceed? [y/N]: in a TTY (pass --yes in CI), then runs through the following stages:

  1. Preflight: verify Helm, kubectl, and cluster reachability.
  2. Cloud prereqs: runs only with --apply-prereqs.
  3. Namespace creation: idempotent.
  4. Helm install: applies the gateway chart.
  5. Wait for address: runs only with --wait; reports the gateway address once Kubernetes assigns one (typically under a minute).

The final output looks like:

Gateway installation complete.

Customer action required (DNS):
Create DNS A record:
Host: proxy.acme.tetrate.ai
Type: A
Value: 34.110.x.x
TTL: 300

Create DNS authorization CNAME record:
Host: _abc123.proxy.acme.tetrate.ai.
Type: CNAME
Value: abc123.<google-managed>.googleusercontent.com.

Certificate provisioning note:
Certificate may still be PROVISIONING after gateway install.
HTTPS will be fully ready once certificate state is ACTIVE.

Copy these values for use in the next step.

Step 5: configure DNS

Two DNS records are required in the DNS provider. Both must exist; HTTPS does not work without either.

Record 1: a record for customer traffic

Hostproxy.acme.tetrate.ai (the serveDomain value)
TypeA
ValueThe address printed in Step 4 (for example 34.110.x.x)
TTL300 (5 minutes) recommended

Customer clients resolve this record to reach the gateway.

Record 2: DNS authorization cname

HostThe CNAME host printed in Step 4 (for example _abc123.proxy.acme.tetrate.ai.)
TypeCNAME
ValueThe googleusercontent.com target printed in Step 4
TTL300 recommended

Google Certificate Manager uses this record to verify domain ownership before issuing a TLS certificate. Without it, the certificate stays in PROVISIONING indefinitely.

To fetch the CNAME details at any time after the install:

gcloud certificate-manager dns-authorizations describe \
proxy-acme-tetrate-ai-dns-auth \
--project withfraser \
--format='value(dnsResourceRecord.name,dnsResourceRecord.type,dnsResourceRecord.data)'

Step 6: wait for the certificate to activate

Once both DNS records are live, the managed certificate moves from PROVISIONING to ACTIVE automatically. Typical timing:

  • First 5 minutes: DNS propagation; certificate stays PROVISIONING.
  • 5–20 minutes: Google validates the DNS authorization, issues the certificate, and the certificate flips to ACTIVE.
  • Up to a few hours (rare): when DNS propagation is slow at the registrar.

Check the certificate state:

gcloud certificate-manager certificates describe acme-serve-cert \
--project withfraser \
--format="yaml(name,managed.state,managed.domainStatus)"

Expected output:

name: projects/withfraser/locations/global/certificates/acme-serve-cert
managed:
state: ACTIVE
domainStatus:
proxy.acme.tetrate.ai: ACTIVE

If state: FAILED_NOT_VISIBLE appears, the DNS authorization CNAME from Step 5 is missing or incorrect. Verify that it resolves:

dig +short CNAME _abc123.proxy.acme.tetrate.ai

The result must match the value returned by dns-authorizations describe.

Step 7: verify

Once the certificate is ACTIVE, verify end-to-end.

Cluster resources are healthy:

kubectl get gateway -n tars-gateway
kubectl get httproute -n tars-system
kubectl get httproute -n tars-dataplane

All gateways and routes should report True for the Accepted and Programmed conditions.

Hostname resolution:

dig +short A proxy.acme.tetrate.ai
# Expected: 34.110.x.x (the address from Step 4)

TLS termination and gateway response:

curl -v https://proxy.acme.tetrate.ai/healthz
# Expected: HTTP/2 200, valid certificate for proxy.acme.tetrate.ai

When the healthz endpoint is not exposed, any request that reaches the gateway and returns an Agent Router-shaped response (even 404 or 401) confirms that the gateway and TLS are working.

Troubleshooting

SymptomLikely causeResolution
customer not resolved, tried: --customer (empty), gcp-gateway.json:customer (empty), identity.json:customerId (empty)No customer set anywhere.Add "customer": "<name>" to gcp-gateway.json or pass --customer.
provider "aws" is not implemented yet--type aws passed.Use --type gcp. AWS support is on the roadmap.
Plan shows a ? row for a resourceThe CLI could not probe live state (credentials, IAM, or network issue).The install treats the resource as will-create. Check the probeError field in --output json for details.
helm deploy failedCluster not reachable, RBAC issue, or a chart-level error.Run kubectl cluster-info; when that fails, fix the kubeconfig context first.
Gateway never reports an address (--wait times out)Cloud load-balancer provisioning is slow, or the static IP is not attached.Run kubectl describe gateway -n tars-gateway and check Kubernetes events for the gateway resource.
Certificate stuck PROVISIONING for >30 minDNS authorization CNAME is missing, wrong, or not yet propagated.Re-check Step 5. Use dig to verify the CNAME resolves.
Certificate state FAILED_NOT_VISIBLEDNS authorization record cannot be resolved from Google's side.Recreate the CNAME exactly as printed by dns-authorizations describe.
curl returns a TLS error after cert is ACTIVEA record points to the wrong IP, or local DNS cache.Verify with dig; flush the local resolver.
Re-running install fails with already exists from gcloudgcloud.skipExisting is false.Set "gcloud": { "skipExisting": true } in gcp-gateway.json.

For issues not covered above, re-run the install with the Plan visible (--plan-only is sufficient) and share the output with the Tetrate contact. The Plan captures every resolved value and live state probe, which is usually enough to diagnose.

Need help?

When blocked, capture:

  1. The output of tare gateway install … --plan-only.
  2. The output of tare gateway config lint --format json.
  3. The output of gcloud certificate-manager certificates describe ….

Share these with the Tetrate contact. Together they describe the config, the live cloud state, and the certificate state, which is usually enough to unblock without further back-and-forth.