Cloud DNS and Certificate Manager
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. See the section bibliography for the reference material consulted while preparing these pages. |
Commands and behaviour on this page are current for the gcloud CLI 586.x line, the Cloud DNS, Cloud Domains and
Certificate Manager documentation and release notes published through 2026-09-29, and Terraform hashicorp/google v8
(checked 2026-10-01); re-verify against gcloud version and the linked reference pages before relying on them in a
pipeline. Examples use the placeholder project ID my-project-id, the placeholder domain example.com (reserved for
documentation, so it can never be registered by you) and the region us-central1; all are stand-ins for your own
values.
Two small services decide whether a user reaches Bookshelf and whether the browser trusts what answers. Cloud DNS is Google’s authoritative name service: it publishes the records for your public domains, and it also answers names that exist only inside your VPC networks. Certificate Manager issues, renews and attaches the TLS certificates that the load balancers present. This page covers both, plus the supporting pieces: DNSSEC, DNS forwarding and peering for hybrid setups, response policies, the private zones that Private Service Connect needs, domain registration with Cloud Domains and the places where domain verification is still required.
In the Bookshelf scenario (see Google Cloud) the public zone bookshelf-public for
example.com holds the records for www.example.com (the global external Application Load Balancer built on
Load Balancing and Cloud Armor and fronting the bucket described on
Cloud CDN and Media CDN) and api.example.com (the Cloud Run service on
Cloud Run). A private zone bookshelf-internal resolves catalog.internal.example.com
to an internal load balancer, only for the VPC described on VPC Networking on Google Cloud. For the
counterparts on other clouds see Route 53, DNS and ACM Certificates and
Virtual Networks.
Concepts
- Managed zone
-
The container for the records of one DNS name (for example
example.com.). Every zone has a visibility, either public or private, and its own set of name servers. A public zone is reachable from the whole internet; a private zone is visible only from the VPC networks you attach to it. - Record set
-
A name, a type (
A,AAAA,CNAME,MX,TXT,CAAand so on), a TTL and its data. Cloud DNS edits are atomic per change, which is whatgcloud dns record-sets transactionand theimportcommand use. - Forwarding zone
-
A private zone that sends queries for a name to DNS servers you name, typically on-premises resolvers reached over Cloud VPN or Cloud Interconnect.
- Peering zone
-
A private zone whose queries are answered using the name-resolution order of another VPC network (the producer), which lets one network host the zones that many networks share, without the networks being peered at the network layer.
- DNS server policy
-
A per-network setting that turns on inbound forwarding (an on-premises resolver can query Cloud DNS through a VPC address), alternative name servers and query logging.
- Response policy
-
Rules, attached to networks, that override the answer for chosen names (or skip the override with a
bypassbehaviour). Typical uses are blocking a domain, steering a Google API hostname to a Private Service Connect endpoint and testing. - Routing policy
-
A record-level feature that answers differently by weight, by the client’s geography or by health of the targets (failover).
- DNSSEC
-
Signing of a public zone so that validating resolvers can detect forged answers. It works only if the parent zone holds a matching
DSrecord. - Certificate
-
In Certificate Manager, either Google-managed (public, issued and renewed for you) or self-managed (you upload a certificate and key, and you renew it).
- Authorization
-
How a Google-managed certificate proves that you control a domain: a DNS authorization (a CNAME that you publish) or a load balancer authorization (Google observes that the domain’s traffic reaches your load balancer).
- Certificate map
-
A set of entries (hostname to certificates, plus an optional primary entry) that you attach to a target proxy, so that one proxy can present many certificates by hostname.
Derived from Cloud DNS overview and Certificate Manager overview.
Prerequisites for Bookshelf
-
A domain name you control. Register one with Cloud Domains (below) or any registrar; you need to be able to change its name servers (delegation) and, with DNSSEC, its
DSrecord. -
Permissions:
roles/dns.adminto manage zones and records (roles/dns.readerfor read-only access),roles/certificatemanager.editorfor certificates and maps, androles/domains.adminfor Cloud Domains. A project owner has them implicitly. -
Cloud DNS is a global service in a project, with the zone’s records served from Google’s anycast name servers; there is no region to pick for a zone.
export PROJECT_ID="$(gcloud config get-value project)"
export REGION=us-central1
export DOMAIN=example.com
export WWW_DOMAIN=www.example.com
gcloud services enable \
dns.googleapis.com \
certificatemanager.googleapis.com \
domains.googleapis.com \
compute.googleapis.com
Derived from gcloud services enable.
Public zones and records
A public zone is the normal case: it makes the records for your domain available to the internet. Creating the zone gives you four name servers; the zone does nothing until the registrar delegates the domain to them.
In the Google Cloud console
-
Select the project in the project picker and enable the Cloud DNS API (APIs & Services > Library). Cloud Shell has the gcloud CLI preinstalled if you prefer a terminal.
-
Open Network services > Cloud DNS and choose Create zone.
-
Choose Public, set the zone name
bookshelf-public, the DNS nameexample.com, leave DNSSEC Off for now and choose Create. -
Open the zone and note the four
NSrecords; they look likens-cloud-a1.googledomains.com.. At your registrar, replace the domain’s name servers with these (if the domain is registered in Cloud Domains, edit its DNS settings and choose Use Cloud DNS name servers). -
Choose Add standard and create
Arecords, for examplewwwpointing to the load balancer address, with a TTL of 300 seconds. Use Add standard again forCNAME,MXandTXTrecords.
Derived from Create, modify and delete zones and Manage records.
With the gcloud CLI
gcloud dns managed-zones create bookshelf-public \
--dns-name="${DOMAIN}." \
--description="Bookshelf public zone" \
--visibility=public \
--labels=app=bookshelf
# The name servers to enter at the registrar
gcloud dns managed-zones describe bookshelf-public \
--format='value(nameServers)'
# Single records
gcloud dns record-sets create "${WWW_DOMAIN}." \
--zone=bookshelf-public \
--type=A \
--ttl=300 \
--rrdatas=203.0.113.10
gcloud dns record-sets create "api.${DOMAIN}." \
--zone=bookshelf-public \
--type=CNAME \
--ttl=300 \
--rrdatas="ghs.googlehosted.com."
gcloud dns record-sets list --zone=bookshelf-public
Derived from gcloud dns managed-zones create
and gcloud dns record-sets create. The
address 203.0.113.10 is from the documentation range; use the address of your load balancer, for example from
gcloud compute addresses describe bookshelf-ip --global --format='value(address)'.
Group several changes into one atomic update with a transaction, or move a whole zone in and out as a BIND file.
gcloud dns record-sets transaction start --zone=bookshelf-public
gcloud dns record-sets transaction add "10 mail.${DOMAIN}." \
--name="${DOMAIN}." --ttl=3600 --type=MX --zone=bookshelf-public
gcloud dns record-sets transaction add '"v=spf1 -all"' \
--name="${DOMAIN}." --ttl=3600 --type=TXT --zone=bookshelf-public
gcloud dns record-sets transaction execute --zone=bookshelf-public
# Move records from another provider (BIND zone file) or back out
gcloud dns record-sets import zone.txt --zone=bookshelf-public --zone-file-format
gcloud dns record-sets export zone-backup.txt --zone=bookshelf-public --zone-file-format
Derived from gcloud dns record-sets transaction and Migrate to Cloud DNS.
Notes on records worth knowing:
-
The apex cannot be a
CNAME. To pointexample.comitself at a load balancer, use anAorAAAArecord with the load balancer’s address. Cloud DNS has no provider-specific alias record type. -
Lower the TTL before a migration. Cloud DNS has no minimum TTL beyond a small floor; set 60 to 300 seconds a day before a cutover and raise it afterwards.
-
CAArecords restrict which certificate authorities may issue for the domain. If you publish any, they must include the authorities that Certificate Manager uses; see the Google-managed certificate section below. -
Labels and descriptions on zones help cost allocation and automation; see Resource Hierarchy and Projects for labels.
Routing policies
A record can return different answers per query without extra zones.
| Policy | Behaviour | Use in Bookshelf |
|---|---|---|
Weighted round robin |
Returns each target in proportion to its weight. |
Move 10 percent of traffic to a new regional deployment before a full cutover. |
Geolocation |
Returns the target closest to the query’s source region, with a fallback. |
Send European users to a European deployment for latency or data-residency reasons. |
Failover |
Returns the primary while its health check passes and the backup otherwise (for internal load balancers). |
Fail an internal service name over to a second region. |
gcloud dns record-sets create "canary.${DOMAIN}." \
--zone=bookshelf-public \
--type=A \
--ttl=60 \
--routing-policy-type=WRR \
--routing-policy-data="90.0=203.0.113.10;10.0=203.0.113.20"
Derived from Routing policies overview and Manage routing policies. The exact data syntax differs between weighted, geolocation and failover policies; copy it from the linked page for your type.
For global traffic management with health-aware failover across regions, the global load balancer’s single anycast address is usually simpler than DNS steering, because there is no resolver cache to wait for.
DNSSEC
DNSSEC signs the answers of a public zone with keys, so a validating resolver can reject forged or tampered answers
(cache poisoning, on-path rewriting). It protects integrity, not confidentiality, and it does nothing unless the
domain’s parent zone publishes a DS record that matches your zone’s key-signing key.
Cloud DNS signs with two key types: a key-signing key (KSK) that signs the other keys, and a zone-signing key (ZSK)
that signs your records. Cloud DNS manages both, and rotates the ZSK automatically. You only need to transfer the
DS record to the registrar once, and again if you ever change the KSK.
In the Google Cloud console
-
Open Network services > Cloud DNS and choose the zone
bookshelf-public. -
Choose DNSSEC > Enable (or use Edit zone > DNSSEC > On). Leave the algorithms at the defaults unless the registrar requires different ones.
-
Open Registrar setup. The console shows the DS record values (key tag, algorithm, digest type and digest).
-
Add that
DSrecord at your registrar; for a domain registered with Cloud Domains this is done for you when the domain uses Cloud DNS. Wait for the registrar and the parent zone to publish it.
Derived from DNSSEC overview and Enable and disable DNSSEC.
With the gcloud CLI
# Turn DNSSEC on for an existing public zone (ECDSA keys are smaller and faster than RSA)
gcloud dns managed-zones update bookshelf-public \
--dnssec-state=on \
--ksk-algorithm=ecdsap256sha256 \
--zsk-algorithm=ecdsap256sha256
# The DS record to give the registrar
gcloud dns dns-keys list --zone=bookshelf-public \
--filter="type=keySigning" \
--format='value(id)'
gcloud dns dns-keys describe KEY_ID --zone=bookshelf-public \
--format='value(ds_record())'
# Verify from the outside
dig +dnssec DS "${DOMAIN}" @8.8.8.8
dig +dnssec A "${WWW_DOMAIN}" @8.8.8.8
Derived from gcloud dns managed-zones update
and gcloud dns dns-keys describe. KEY_ID
is a placeholder for the key ID printed by the previous command; the algorithm of a signed zone’s keys cannot be
changed in place without turning DNSSEC off first, so choose before enabling.
Two operational rules make DNSSEC safe to run.
-
Enable it in this order: sign the zone, then add the
DSrecord at the registrar. Adding theDSfirst, or leaving it behind after turning DNSSEC off, makes the whole domain fail validation and look down to every validating resolver. -
When moving a domain to another DNS provider, remove the
DSrecord first, wait for its TTL, move the zone, then re-enable signing at the new provider and publish itsDS.
Private zones and split-horizon DNS
A private zone answers only queries that come from the VPC networks you authorize. It is how workloads resolve
internal service names such as catalog.internal.example.com to private addresses.
Split-horizon is the practice of serving the same domain differently inside and outside: a private zone named
example.com. attached to the VPC overrides the public example.com. zone for queries coming from that VPC, and the
rest of the internet sees only the public zone. Inside the VPC, any name that is not in the private zone returns
NXDOMAIN; so a split-horizon private zone has to contain every name the VPC needs from that domain, including the
www record. Using a dedicated internal subdomain is simpler and avoids that trap.
In the Google Cloud console
-
Open Network services > Cloud DNS > Create zone.
-
Choose Private, name it
bookshelf-internal, DNS nameinternal.example.com, and under Networks select the VPCbookshelf-vpc. -
Choose Create, then Add standard to add
Arecords such ascatalogpointing to the internal load balancer address.
Derived from Create a private zone.
With the gcloud CLI
gcloud dns managed-zones create bookshelf-internal \
--dns-name="internal.${DOMAIN}." \
--description="Bookshelf private names" \
--visibility=private \
--networks=bookshelf-vpc
gcloud dns record-sets create "catalog.internal.${DOMAIN}." \
--zone=bookshelf-internal \
--type=A \
--ttl=300 \
--rrdatas=10.10.0.20
# Attach another VPC later
gcloud dns managed-zones update bookshelf-internal \
--networks=bookshelf-vpc,bookshelf-staging-vpc
Derived from gcloud dns managed-zones create.
Resources in Google Cloud also get automatic internal DNS names (INSTANCE.ZONE.c.PROJECT.internal, and the newer
zonal DNS, where each name includes the zone) with no zone to manage; use a private zone when you want stable names of
your own. In a Shared VPC setup the private zone is created in the host project, or in a service project through a
cross-project binding when a team owns its own names.
Hybrid DNS: forwarding, peering and server policies
When part of the estate is on-premises (see VPN and Hybrid Connectivity), the two sides must resolve each other’s names. Cloud DNS offers three mechanisms.
| Direction | Mechanism | What it does |
|---|---|---|
Google Cloud to on-premises |
Forwarding zone |
A private zone for |
On-premises to Google Cloud |
Inbound DNS server policy |
The policy creates an inbound forwarder address in each subnet; on-premises resolvers forward the Google Cloud names to it. |
Network to network |
Peering zone |
A private zone that delegates a name to another VPC network’s resolution order, for hub-and-spoke designs where one network owns the zones. |
# Resolve corp.example.com. against on-premises resolvers
gcloud dns managed-zones create corp-forwarding \
--dns-name="corp.${DOMAIN}." \
--description="Forward to on-premises DNS" \
--visibility=private \
--networks=bookshelf-vpc \
--forwarding-targets=192.168.0.53,192.168.1.53
# Let on-premises resolvers query Cloud DNS (inbound forwarding) and log queries
gcloud dns policies create bookshelf-dns-policy \
--description="Inbound forwarding and logging" \
--networks=bookshelf-vpc \
--enable-inbound-forwarding \
--enable-logging
# Peering zone: names under shared.example.com. are resolved in the hub network
gcloud dns managed-zones create shared-peering \
--dns-name="shared.${DOMAIN}." \
--description="Peer to hub network" \
--visibility=private \
--networks=bookshelf-vpc \
--target-network=hub-vpc \
--target-project="$PROJECT_ID"
Derived from Forwarding zones,
Server policies overview and
Peering zones. The addresses are private documentation
examples. The firewall on the on-premises side must allow UDP and TCP port 53 from the Cloud DNS source range
35.199.192.0/19, and the Cloud Router must advertise that range if you use dynamic routing.
Two behaviours surprise people. A forwarding zone does not forward queries for names that exist in a more specific private zone; the longest-suffix match wins. And a peering zone is not VPC peering: it carries only DNS queries.
Response policies and Private Service Connect names
A response policy is a set of rules that overrides what resolvers in your networks get back, without editing the authoritative zone. A response policy rule has priority over zones, and its rule types are local data (the answer you supply) or bypass (resolve normally).
gcloud dns response-policies create bookshelf-rp \
--description="Block and steer names" \
--networks=bookshelf-vpc
# Make a name resolve to a known address
gcloud dns response-policies rules create steer-api \
--response-policy=bookshelf-rp \
--dns-name="api.partner.example.net." \
--local-data=name="api.partner.example.net.",type="A",ttl=300,rrdatas="10.10.0.30"
# Never override this name
gcloud dns response-policies rules create allow-www \
--response-policy=bookshelf-rp \
--dns-name="www.example.com." \
--behavior=bypassResponsePolicy
Derived from Response policies and gcloud dns response-policies rules create.
Private Service Connect for Google APIs gives you an internal IP address in your VPC (an endpoint) that forwards to
Google APIs. Applications reach it through names in the p.googleapis.com family, or you make the standard names such
as storage.googleapis.com resolve to the endpoint address so that no application changes are needed. For that you
create either a private zone googleapis.com. with an A record for the endpoint address and a wildcard CNAME, or
a response policy; the endpoint creation can also register the names automatically, which is the least error-prone
route when available. The older Private Google Access names private.googleapis.com (199.36.153.8/30) and
restricted.googleapis.com (199.36.153.4/30), which restricted enforces for VPC Service Controls, follow the same
pattern: a private zone with a CNAME for .googleapis.com. to the chosen name and an A record for it.
Endpoints for *published services (a Cloud SQL or partner service reached over PSC) need the same: a private zone for
the service’s DNS name pointing at the endpoint address. The networking side of both is on
VPC Networking on Google Cloud.
Derived from Access Google APIs through endpoints and Configure Private Google Access: DNS.
Cloud Domains
Cloud Domains is Google Cloud’s domain registrar service. It registers and renews domains, bills them to the project,
turns on WHOIS privacy where the top-level domain allows it, and can configure Cloud DNS and DNSSEC for the domain in
one click. Registration is for domains under supported top-level domains and is yearly. Domains previously bought
through the consumer Google Domains product moved to another registrar in 2023 and are not managed by this service.
Using Cloud Domains is optional; any registrar works as long as you can change the name servers and DS record.
gcloud domains registrations search-domains "bookshelf-example"
gcloud domains registrations get-register-parameters "${DOMAIN}"
gcloud domains registrations register "${DOMAIN}" \
--contact-data-from-file=contacts.yaml \
--contact-privacy=private-contact-data \
--cloud-dns-zone=bookshelf-public \
--yearly-price="REPLACE_WITH_PRICE_FROM_get-register-parameters" \
--notices=hsts-preloaded
Derived from Register a domain and
gcloud domains registrations register.
Registering a real domain spends money and the contact file holds personal data, so do not run the register command
against example.com. contacts.yaml is a local file with the registrant, admin and technical contacts; keep it out
of source control.
Certificate Manager
Certificate Manager is the single place to create and attach TLS certificates for Google Cloud load balancers (global external and regional, internal Application Load Balancers, external proxy Network Load Balancers) and for Cloud CDN and Media CDN, and for Cloud Service Mesh. Compared with the older per-resource SSL certificates, it adds wildcard certificates, certificate maps, certificates issued before traffic arrives, certificates from your own private CA, trust configurations for mutual TLS, and one inventory with expiry and provisioning state. It is the preferred certificate service on Google Cloud.
Choosing a certificate type
| Type | When to use it | Notes |
|---|---|---|
Google-managed, DNS authorization |
Default for public sites; wildcards; issuing before the load balancer exists. |
You add one |
Google-managed, load balancer authorization |
A single hostname whose traffic already flows through the load balancer. |
No DNS record to add, but the DNS |
Google-managed, private CA (issuance config) |
Internal names that must chain to your own root, issued by Certificate Authority Service. |
Needs a CA pool in Certificate Authority Service; for key handling see Secret Manager and Cloud KMS. |
Self-managed |
Existing certificates from a commercial CA, extended validation, or a required CA. |
You upload the certificate chain and key and renew them before expiry. The key is write-only after upload. |
Classic SSL certificates ( |
Existing setups only. |
Attached per proxy, limited in number per proxy, and Google-managed ones need DNS to point at the load balancer first. Prefer Certificate Manager for new work. |
Google-managed certificates are issued by public certificate authorities (Google Trust Services, and Let’s Encrypt as an alternative CA the service may select). Publicly trusted certificate lifetimes are getting shorter by industry rule, and managed certificates renew automatically well before expiry, so they are the way to avoid an expiry outage. Self-managed certificates need your own renewal job and an alert before they expire.
In the Google Cloud console
-
Open Security > Certificate Manager (enable the API when prompted).
-
Under DNS authorizations, choose Create DNS authorization, name it
bookshelf-dns-authand enter the domainwww.example.com. Open it and copy theCNAMEname and data. -
In Cloud DNS, open
bookshelf-publicand add thatCNAMErecord. -
Under Certificates, choose Add certificate, name it
bookshelf-cert, choose Create Google-managed certificate with Scope Default, enter the domain, and under Authorization type choose DNS authorization and the authorization you created. Choose Create. -
Wait until the certificate state changes from Provisioning to Active; this usually takes minutes, and up to an hour or longer when there are mistakes.
-
Under Certificate maps, create
bookshelf-certs, add an entry for the hostnamewww.example.comwithbookshelf-cert, then attach the map to the load balancer’s target HTTPS proxy (in the load balancer’s frontend settings, select the certificate map).
Derived from Deploy a Google-managed certificate with DNS authorization and Certificate maps.
With the gcloud CLI
Create the DNS authorization and publish the CNAME in the same Cloud DNS zone.
gcloud certificate-manager dns-authorizations create bookshelf-dns-auth \
--domain="$WWW_DOMAIN"
# The name and data of the CNAME to publish
CNAME_NAME="$(gcloud certificate-manager dns-authorizations describe bookshelf-dns-auth \
--format='value(dnsResourceRecord.name)')"
CNAME_DATA="$(gcloud certificate-manager dns-authorizations describe bookshelf-dns-auth \
--format='value(dnsResourceRecord.data)')"
gcloud dns record-sets create "$CNAME_NAME" \
--zone=bookshelf-public \
--type=CNAME \
--ttl=300 \
--rrdatas="$CNAME_DATA"
Derived from gcloud certificate-manager dns-authorizations create.
Newer authorizations may be created as per-project records (a --type=PER_PROJECT_RECORD option), which let several
authorizations and certificates for the same domain share one CNAME; check the linked reference for the flags in your
gcloud version.
Create the certificate and map, and wait for it to be active.
gcloud certificate-manager certificates create bookshelf-cert \
--domains="$WWW_DOMAIN" \
--dns-authorizations=bookshelf-dns-auth
gcloud certificate-manager maps create bookshelf-certs
gcloud certificate-manager maps entries create bookshelf-www \
--map=bookshelf-certs \
--hostname="$WWW_DOMAIN" \
--certificates=bookshelf-cert
# Poll until ACTIVE
gcloud certificate-manager certificates describe bookshelf-cert \
--format='value(managed.state,managed.authorizationAttemptInfo[0].state)'
# Attach the map to an existing target proxy (the map is referenced by its full path)
gcloud compute target-https-proxies update bookshelf-https-proxy \
--certificate-map=bookshelf-certs
Derived from gcloud certificate-manager certificates create and gcloud certificate-manager maps entries create.
A wildcard certificate covers one label of subdomain and requires DNS authorization for the base domain; put it in the
map as a wildcard entry and use --set-primary on one entry as the fallback for clients that send no hostname.
gcloud certificate-manager dns-authorizations create wildcard-auth --domain="$DOMAIN"
gcloud certificate-manager certificates create wildcard-cert \
--domains="*.${DOMAIN},${DOMAIN}" \
--dns-authorizations=wildcard-auth
gcloud certificate-manager maps entries create bookshelf-wildcard \
--map=bookshelf-certs \
--hostname="*.${DOMAIN}" \
--certificates=wildcard-cert
Derived from Deploy a Google-managed certificate with DNS authorization.
Publish the CNAME of wildcard-auth the same way as before.
Load balancer authorization
When the domain already points at the load balancer, or you do not control its DNS zone, omit the DNS authorization.
Certificate Manager issues the certificate once it sees the domain’s traffic arrive on the load balancer. Create the
certificate, attach the map to the proxy, and then point the A record at the load balancer; provisioning completes
afterwards. Expect a short window in which clients see a certificate error, which is why DNS authorization is preferred
for production migrations.
gcloud certificate-manager certificates create bookshelf-lb-cert \
--domains="$WWW_DOMAIN"
Self-managed certificates
A self-managed certificate is uploaded as PEM files: the full chain (leaf first) and the unencrypted private key. Keep the key out of source control; generate it where you create it, or keep it in a managed key store and a secrets workflow (see Secret Manager and Cloud KMS). The sample below creates a throwaway self-signed certificate for a test hostname only.
openssl req -x509 -newkey rsa:2048 -nodes -days 30 \
-keyout test.key -out test.pem \
-subj "/CN=test.${DOMAIN}" \
-addext "subjectAltName=DNS:test.${DOMAIN}"
gcloud certificate-manager certificates create bookshelf-selfmanaged \
--certificate-file=test.pem \
--private-key-file=test.key
Derived from Deploy a self-managed certificate and gcloud certificate-manager certificates create. Browsers do not trust a self-signed certificate, so use it only to learn the workflow. To replace a self-managed certificate before expiry, upload a new certificate and update the map entry to reference it; the key you uploaded cannot be read back, so keep your own copy under your secret-management rules.
Certificate scope, regions and the CAA record
-
Scope. The default scope serves global external load balancers and regional ones;
EDGE_CACHEis for Media CDN andALL_REGIONSis for certificates used in every region; regional certificates for regional load balancers are created with--location=REGION. -
Trust configs and mTLS. A trust config holds the trust anchors used by a load balancer to validate client certificates; it is attached through a server TLS policy.
-
CAA. If the domain has
CAArecords, they must allow the CAs Google uses: addpki.googand, if you let Certificate Manager use it,letsencrypt.org. An overly strictCAArecord is the commonest reason a managed certificate sits in Provisioning with authorization state FAILED.
gcloud dns record-sets create "${DOMAIN}." \
--zone=bookshelf-public \
--type=CAA \
--ttl=3600 \
--rrdatas='0 issue "pki.goog"' '0 issue "letsencrypt.org"'
Derived from Troubleshooting Certificate Manager: CAA records.
Domain verification: where it is still needed
Certificate Manager does not require a separate ownership step: the DNS authorization or the load balancer path is the verification. Domain verification as a separate step now matters mainly in these places.
| Where | What is needed |
|---|---|
Cloud Run domain mappings (Preview) |
You must prove ownership of the domain, through Search Console, with the account running the command, before
|
Cloud Run through the load balancer |
No separate verification; use a Certificate Manager certificate with DNS authorization. |
Google Workspace and Cloud Identity |
A |
Firebase Hosting |
A |
Email sending (SPF, DKIM, domain authentication) |
|
Search Console and other Google services |
A |
# Check which domains your account has verified (older guides use this for App Engine and Cloud Run)
gcloud domains list-user-verified
# Start a verification in a browser (Search Console)
gcloud domains verify "$DOMAIN"
Derived from gcloud domains list-user-verified
and Mapping custom domains. Older guides present
gcloud domains verify as the central step of putting a custom domain on a Google service; today it is a niche step
that applies to domain mappings and App Engine.
Verification TXT records stay in the zone; leave them in place, because Google can re-check ownership later, and a
removed record can break the integration without any visible warning.
Infrastructure as code
The same resources in Terraform (hashicorp/google v8) are small enough to keep in a module. See
Infrastructure as Code for state, Infrastructure Manager and how to organize
modules.
resource "google_dns_managed_zone" "public" {
name = "bookshelf-public"
dns_name = "example.com."
description = "Bookshelf public zone"
visibility = "public"
dnssec_config {
state = "on"
default_key_specs {
key_type = "keySigning"
algorithm = "ecdsap256sha256"
}
default_key_specs {
key_type = "zoneSigning"
algorithm = "ecdsap256sha256"
}
}
}
resource "google_certificate_manager_dns_authorization" "www" {
name = "bookshelf-dns-auth"
domain = "www.example.com"
}
resource "google_dns_record_set" "www_auth" {
managed_zone = google_dns_managed_zone.public.name
name = google_certificate_manager_dns_authorization.www.dns_resource_record[0].name
type = google_certificate_manager_dns_authorization.www.dns_resource_record[0].type
ttl = 300
rrdatas = [google_certificate_manager_dns_authorization.www.dns_resource_record[0].data]
}
resource "google_certificate_manager_certificate" "www" {
name = "bookshelf-cert"
managed {
domains = ["www.example.com"]
dns_authorizations = [google_certificate_manager_dns_authorization.www.id]
}
}
resource "google_certificate_manager_certificate_map" "map" {
name = "bookshelf-certs"
}
resource "google_certificate_manager_certificate_map_entry" "www" {
name = "bookshelf-www"
map = google_certificate_manager_certificate_map.map.name
hostname = "www.example.com"
certificates = [google_certificate_manager_certificate.www.id]
}
Security, access and quotas
-
Least privilege. Give automation
roles/dns.adminon the one project and zone rather than on the organization; record-level control is possible through separate zones per team (delegated subdomains, each with its own IAM). -
Subdomain takeover. A dangling
CNAMEto a deleted Cloud Run domain, bucket or third-party host lets someone claim the name. Remove records when you delete the resources they point at, and review the zone as part of clean up. -
DNSSEC and CAA (above) protect integrity and issuance.
-
Audit. Admin changes to zones and records are in Cloud Audit Logs; enable query logging through a server policy for private zones, and log certificate lifecycle events from Certificate Manager.
-
Quotas. Cloud DNS limits the number of zones, record sets per zone, records per change and API request rates per project; Certificate Manager limits certificates, maps, map entries and certificates per map. The limits are listed in the quota pages and many can be raised through IAM & Admin > Quotas & System Limits; check the linked pages rather than relying on numbers from older guides.
Derived from Cloud DNS quotas and limits and Certificate Manager quotas and limits.
Pricing model and free options
Cloud DNS charges per managed zone per month (public and private alike, with the first zones costing more than additional ones), per million queries answered, and for some policy features; Certificate Manager charges for some certificate types and features (check which apply to the certificates you use); Cloud Domains charges the registration price yearly. There is no always-free allowance for Cloud DNS beyond the free-trial credits, but the cost of a small estate is a few currency units a month. Check the dated pricing pages, which change, rather than copying figures from a guide:
Cost drivers worth watching: query volume (Cloud DNS is billed per query, so a very low TTL on a busy name raises the bill), zones left running after a project is forgotten, and query logging volume in Cloud Logging.
Troubleshooting
| Symptom | Likely cause and fix |
|---|---|
|
The registrar still has the old name servers, the record is in the wrong zone, or the zone’s DNS name has a typo.
Compare |
Names fail only for some users after enabling DNSSEC |
The |
Private name does not resolve from a VM |
The zone is not attached to that VM’s VPC; the VM uses a custom resolver; or a more specific zone shadows the name. |
Split-horizon: |
The private zone for |
Forwarding zone times out |
Firewall or routes block UDP/TCP 53 from |
Managed certificate stuck in |
The DNS authorization |
Browser shows the wrong or default certificate |
The map entry hostname does not match the request host, there is no primary entry, or the proxy has no map attached. |
Certificate expired |
A self-managed certificate was not renewed; replace the file in the map entry and add an expiry alert. |
gcloud certificate-manager certificates describe bookshelf-cert \
--format='yaml(managed)'
dig CNAME "$CNAME_NAME" +short
openssl s_client -connect "${WWW_DOMAIN}:443" -servername "$WWW_DOMAIN" </dev/null 2>/dev/null \
| openssl x509 -noout -subject -issuer -dates
Derived from Troubleshooting Certificate Manager and Troubleshooting Cloud DNS.
Clean up
Delete in dependency order: detach the map from the proxy, delete entries, then maps, certificates and
authorizations; then records and zones. A Cloud DNS zone cannot be deleted while it contains record sets other than
its default NS and SOA.
# Detach the certificate map before deleting it (only if the proxy exists)
gcloud compute target-https-proxies update bookshelf-https-proxy --clear-certificate-map
gcloud certificate-manager maps entries delete bookshelf-wildcard --map=bookshelf-certs --quiet
gcloud certificate-manager maps entries delete bookshelf-www --map=bookshelf-certs --quiet
gcloud certificate-manager maps delete bookshelf-certs --quiet
gcloud certificate-manager certificates delete bookshelf-cert --quiet
gcloud certificate-manager certificates delete bookshelf-lb-cert --quiet
gcloud certificate-manager certificates delete wildcard-cert --quiet
gcloud certificate-manager certificates delete bookshelf-selfmanaged --quiet
gcloud certificate-manager dns-authorizations delete bookshelf-dns-auth --quiet
gcloud certificate-manager dns-authorizations delete wildcard-auth --quiet
rm -f test.key test.pem contacts.yaml zone.txt zone-backup.txt
# Response policy rules first, then the policy; then the DNS policy
gcloud dns response-policies rules delete steer-api --response-policy=bookshelf-rp --quiet
gcloud dns response-policies rules delete allow-www --response-policy=bookshelf-rp --quiet
gcloud dns response-policies delete bookshelf-rp --quiet
gcloud dns policies update bookshelf-dns-policy --networks="" --quiet
gcloud dns policies delete bookshelf-dns-policy --quiet
# Private, forwarding and peering zones
gcloud dns managed-zones delete shared-peering --quiet
gcloud dns managed-zones delete corp-forwarding --quiet
gcloud dns record-sets delete "catalog.internal.${DOMAIN}." --zone=bookshelf-internal --type=A --quiet
gcloud dns managed-zones delete bookshelf-internal --quiet
# Public zone: delete every record except NS and SOA, then turn DNSSEC off before the zone goes
gcloud dns record-sets list --zone=bookshelf-public \
--filter="type!=NS AND type!=SOA" \
--format='value(name,type)'
# For each row: gcloud dns record-sets delete NAME --zone=bookshelf-public --type=TYPE
gcloud dns managed-zones delete bookshelf-public --quiet
Derived from Delete a zone and gcloud certificate-manager certificates delete.
Skip the commands for resources you did not create. Before deleting a signed public zone, remove the DS record at the
registrar (or move the domain to another name server first), otherwise validating resolvers treat the domain as
broken. Remove the NS delegation at the registrar, or at the parent zone if bookshelf-public is a delegated
subdomain, so that no dangling delegation remains. A registered domain in Cloud Domains is a yearly commitment: it is
not deleted by any command above; if you registered one only for practice, turn off auto-renewal with
gcloud domains registrations configure management (setting the renewal method) or let it lapse, and delete the
registration only where the top-level domain permits. For a throwaway project, deleting the project removes zones,
certificates and maps, with the usual 30-day recovery window (see
Resource Hierarchy and Projects).
Related pages
-
Load Balancing and Cloud Armor — the load balancers that attach certificate maps.
-
Cloud CDN and Media CDN — Cloud CDN and Media CDN with certificates for the static site.
-
Cloud Run — Cloud Run custom domains and domain mappings.
-
VPC Networking on Google Cloud — VPC networks, Private Service Connect and Cloud NAT.
-
VPN and Hybrid Connectivity — the VPN and Interconnect that hybrid DNS rides on.
-
Deploying Microservices on GKE — managed certificates and Gateway API hostnames on GKE.
-
Secret Manager and Cloud KMS — storing the keys of self-managed certificates.
-
Infrastructure as Code — managing zones and certificates as code.
-
Sending Email from Google Cloud — the SPF, DKIM and DMARC records an email provider asks you to add.
-
Route 53, DNS and ACM Certificates and Virtual Networks — the AWS equivalent and the Azure networking page (Azure DNS and private zones).