diff --git a/app/authzed/guides/setting-up-private-networking/page.mdx b/app/authzed/guides/setting-up-private-networking/page.mdx index 0c467449..cb474891 100644 --- a/app/authzed/guides/setting-up-private-networking/page.mdx +++ b/app/authzed/guides/setting-up-private-networking/page.mdx @@ -114,60 +114,211 @@ Most users of AuthZed Dedicated on GCP privately connect to SpiceDB with GCP [Pr -### Configure the VPC Endpoint +### Onboarding + +The customer success team at AuthZed should reach out about Private Networking during +onboarding, and will provide the service attachment for your environment. + +In the case where there's any miscommunication, please reach out via Slack or [schedule a call][call]. + +### Create the Private Service Connect Endpoint 1. Navigate to “Private Service Connect” and make sure you are on the “Connected Endpoints” tab. 1. Click “Connect Endpoint” - | Option | Selection | - | ---------------------- | ---------------------------------------------- | - | Target | “Published service” | - | Target service | This will be provided to you by Authzed | - | Endpoint name | Name this whatever you want | - | Network and subnetwork | Select the networks you need connectivity from | - | IP address | Choose whatever IP you'd like | + | Option | Selection | + | ---------------------- | ---------------------------------------------------------------------------------------------------------- | + | Target | “Published service” | + | Target service | The service attachment provided to you by the AuthZed team | + | Endpoint name | Name this whatever you want | + | Network and subnetwork | The VPC your SpiceDB clients run in, and any regular subnet in that VPC in the service attachment's region | + | IP address | Any available internal address from that subnet | + +1. Check the endpoint's connection status. It can only carry traffic once it reaches + `ACCEPTED`. `PENDING` usually means the AuthZed team has not yet allowlisted your + project, and `Rejected`, `Closed` or `Needs attention` all mean the connection is not + usable. If it does not reach `ACCEPTED`, contact the AuthZed team with the endpoint's + project number and status. + +The endpoint does not have to sit in your clients' subnet, but it must be in the service +attachment's region. By default your clients must be in that region too; to connect from +other regions, enable +[global access](https://docs.cloud.google.com/vpc/docs/about-vpc-hosted-services#global-access) +on the endpoint with `--allow-psc-global-access`. + +An endpoint is reachable from the VPC it is created in, and from that VPC's Shared VPC +service projects and connected on-premises networks. It is **not** reachable over VPC +Network Peering, so unless you use +[Network Connectivity Center connection propagation](https://docs.cloud.google.com/vpc/docs/about-propagated-connections) +to share one endpoint with spoke VPCs, each VPC that needs access requires its own +endpoint. + +Permission systems in a given environment and logical region all sit behind the same +AuthZed service attachment. When each VPC has its own endpoint, what differs between them +is only the endpoint IP address. + +### Add a Permission System -### Enable DNS +1. Login to your SpiceDB management console +2. On the homepage, select "Add Permission System" +3. Configure your permission system to your liking and create it +4. If you enabled [Restricted API Access](../concepts/restricted-api-access), configure it and provision a token. Otherwise, provision a token without FGAM -1. Navigate to Cloud DNS and create a zone +Note the endpoint hostname shown for the permission system. You need it to build DNS in the +next step, and it is where the logical region and environment ID come from. - | Option | Selection | - | --------- | ------------------------------------------------------------------------- | - | Zone type | private | - | DNS Name | This will be provided to you by Authzed | - | Networks | Select the network where the Private Service Connect endpoint is deployed | +### Create the DNS Zone -1. Add record set +The AuthZed service attachment does not advertise a PSC DNS domain, so no consumer-side DNS +is created for you and you build a Cloud DNS private zone yourself. (On AWS, PrivateLink's +private DNS name covers this, which is why the AWS steps above are shorter.) Endpoint +hostnames look like this: - | Option | Selection | - | ---------- | ---------------------------------------------- | - | DNS name | This will be provided to you by Authzed | - | IP address | Enter your Private Service Connect endpoint IP | +``` +...gcp.authzed.net +``` -### Add Permission System +So a permission system reached at `my-app-b7448e.aus-se1.abcd1234.gcp.authzed.net` has +logical region `aus-se1` and environment ID `abcd1234`. The region label is a _logical_ +region and does not always match the GCP region name, as in that example. Read both values +from the endpoint hostname rather than assuming the GCP region. -1. Login to your SpiceDB management console -2. On the homepage, select "Add Permission System" -3. Configure your permission system to your liking and create it -4. If you enabled [Restricted API Access](../concepts/restricted-api-access), configure it and provision a token. Otherwise, provision a token without FGAM +Create one zone per logical region, in each VPC that needs its own DNS view: + +| Option | Selection | +| --------- | ----------------------------------------------------------------------------------- | +| Zone type | private | +| Zone name | A name of your choosing, such as `authzed-aus-se1`; you pass this to `--zone` below | +| DNS Name | `..gcp.authzed.net` | +| Networks | Select the network where the Private Service Connect endpoint is deployed | + +Or with the CLI, continuing the example above: + +```sh +gcloud dns managed-zones create authzed-aus-se1 \ + --dns-name="aus-se1.abcd1234.gcp.authzed.net." \ + --visibility=private \ + --networks=VPC_NETWORK \ + --project=PROJECT_ID +``` + +In a Shared VPC, `PROJECT_ID` is the host project, so that all service projects using that +network resolve the zone. + + + Scope the zone to the logical region. Do not create it at + `.gcp.authzed.net`: a Cloud DNS private zone is authoritative for its + entire subtree and will not fall back to public DNS for names it does not contain, so a + zone at that level stops your management console from resolving inside the VPC. If you + already created a zone at that level, delete it and recreate it at the logical region. + Adding the narrower zone alongside it is not enough, because the broader zone still wins + for your console's hostname. + + +**Which hostnames stay on public DNS.** +Your management console and Cloud API are served over the public internet and are not on +the Private Service Connect path. Their hostnames sit outside the logical region's +namespace, so scoping the zone as above is what keeps them resolving publicly. Do not add +private records for them. + +Permission system hostnames also resolve publicly, to an address that does not serve them. +The private record in your VPC is what overrides that and directs the hostname to your +endpoint. + +### Add DNS Records + +Each A record points at the endpoint address that this VPC reaches the service attachment +through. Either list each permission system explicitly: + +```sh +gcloud dns record-sets create \ + "my-app-b7448e.aus-se1.abcd1234.gcp.authzed.net." \ + --zone=authzed-aus-se1 --type=A --ttl=60 \ + --rrdatas=ENDPOINT_IP --project=PROJECT_ID +``` + +Or create a single wildcard covering every permission system in the region, including ones +you add later: + +```sh +gcloud dns record-sets create \ + "*.aus-se1.abcd1234.gcp.authzed.net." \ + --zone=authzed-aus-se1 --type=A --ttl=60 \ + --rrdatas=ENDPOINT_IP --project=PROJECT_ID +``` + +The wildcard means you do not touch DNS as permission systems come and go. It also answers +for every name under the region, including typos and permission systems this VPC has no +reason to reach. Explicit records limit which names resolve through the private zone and +let you roll out one permission system at a time, at the cost of a record each time. + +DNS is not an authorization boundary in either case. API tokens are scoped to a single +permission system, so a client that resolves a hostname it should not be using still cannot +read or write that permission system's data. See +[Restricted API Access](../concepts/restricted-api-access) for access controls. + +Nothing is served at the zone apex, so no A record is needed there; leave the auto-created +NS and SOA records alone. In the Cloud DNS console the apex is the DNS name field left +blank, not `@`. + +**Resolving from on-premises or VPN clients.** +A VPN connection does not by itself give a client visibility into a Cloud DNS private +zone. To resolve these hostnames from outside GCP you also need: + +1. An [inbound DNS server policy](https://docs.cloud.google.com/dns/docs/server-policies-overview) + in the VPC where your Cloud VPN or Interconnect terminates. If that is not the VPC + holding the endpoint, the zone must also be visible there, via Shared VPC or + [DNS peering](https://docs.cloud.google.com/dns/docs/zones/zones-overview), and the + endpoint must still be reachable from the client's network. +1. A conditional forwarder on your on-premises resolver for + `..gcp.authzed.net`, pointing at that policy's inbound + forwarding addresses. +1. On-premises routes and firewall rules permitting TCP and UDP port 53 to those forwarding + addresses, and TCP port 443 to the endpoint's IP address. If you also forward queries + outbound from Cloud DNS to on-premises resolvers, add a route for `35.199.192.0/19`. ### Verify Connectivity -Verify connectivity from client machine with the [Zed CLI tool](https://github.com/authzed/zed) +Run these from a machine that resolves through the zone you created: inside that VPC, or an +on-premises client if you configured hybrid forwarding above. Confirm egress to TCP port +443 on the endpoint address is permitted first. -```zed -zed context set permission_system_name example.com:443 sdbst_h256_123 +First confirm DNS resolves to your endpoint: + +```sh +dig +short my-app-b7448e.aus-se1.abcd1234.gcp.authzed.net ``` -```zed -zed schema write example.yaml +This should return your Private Service Connect endpoint IP address. If it returns a +public address, the private zone is not in effect for this resolver. + + + `ping` is not a useful test here. The endpoint is a TCP forwarding rule and does not answer ICMP, + so it fails whether or not your configuration is correct. `nc` is also misleading, because it can + connect to the public address and appear to succeed while the private zone is still misconfigured. + + +Then verify the service itself with [Zed]. If you don't already have zed installed, you can +follow [this guide][install-zed]. + +```sh +zed context set network-test my-app-b7448e.aus-se1.abcd1234.gcp.authzed.net:443 sdbst_h256_cef4fc239bf... ``` -```zed +```sh zed schema read ``` -The last Zed command should display the schema to your terminal. +This should display your schema. On a permission system with no schema yet you will get +the error below, which still confirms the network path is working: + +``` +code = NotFound +desc = No schema has been defined; please call WriteSchema to start +``` + +If you changed or removed a private zone immediately before testing, allow time for cached +negative answers to expire. Common resolvers cache these for up to 15 minutes.