@@ -32,6 +32,7 @@ const (
3232
3333 EnvServiceAccount = envNamespace + "SERVICE_ACCOUNT"
3434 EnvProject = envNamespace + "PROJECT"
35+ EnvZoneID = envNamespace + "ZONE_ID"
3536 EnvAllowPrivateZone = envNamespace + "ALLOW_PRIVATE_ZONE"
3637 EnvDebug = envNamespace + "DEBUG"
3738
@@ -44,6 +45,7 @@ const (
4445type Config struct {
4546 Debug bool
4647 Project string
48+ ZoneID string
4749 AllowPrivateZone bool
4850 PropagationTimeout time.Duration
4951 PollingInterval time.Duration
@@ -55,6 +57,7 @@ type Config struct {
5557func NewDefaultConfig () * Config {
5658 return & Config {
5759 Debug : env .GetOrDefaultBool (EnvDebug , false ),
60+ ZoneID : env .GetOrDefaultString (EnvZoneID , "" ),
5861 AllowPrivateZone : env .GetOrDefaultBool (EnvAllowPrivateZone , false ),
5962 TTL : env .GetOrDefaultInt (EnvTTL , dns01 .DefaultTTL ),
6063 PropagationTimeout : env .GetOrDefaultSecond (EnvPropagationTimeout , 180 * time .Second ),
@@ -310,24 +313,16 @@ func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
310313
311314// getHostedZone returns the managed-zone.
312315func (d * DNSProvider ) getHostedZone (domain string ) (string , error ) {
313- authZone , err := dns01 . FindZoneByFqdn ( dns01 . ToFqdn ( domain ) )
316+ authZone , zones , err := d . lookupHostedZoneID ( domain )
314317 if err != nil {
315- return "" , fmt . Errorf ( "designate: could not find zone for FQDN %q: %w" , domain , err )
318+ return "" , err
316319 }
317320
318- zones , err := d .client .ManagedZones .
319- List (d .config .Project ).
320- DnsName (authZone ).
321- Do ()
322- if err != nil {
323- return "" , fmt .Errorf ("API call failed: %w" , err )
324- }
325-
326- if len (zones .ManagedZones ) == 0 {
321+ if len (zones ) == 0 {
327322 return "" , fmt .Errorf ("no matching domain found for domain %s" , authZone )
328323 }
329324
330- for _ , z := range zones . ManagedZones {
325+ for _ , z := range zones {
331326 if z .Visibility == "public" || z .Visibility == "" || (z .Visibility == "private" && d .config .AllowPrivateZone ) {
332327 return z .Name , nil
333328 }
@@ -340,6 +335,45 @@ func (d *DNSProvider) getHostedZone(domain string) (string, error) {
340335 return "" , fmt .Errorf ("no public zone found for domain %s" , authZone )
341336}
342337
338+ // lookupHostedZoneID finds the managed zone ID in Google.
339+ //
340+ // Be careful here.
341+ // An automated system might run in a GCloud Service Account, with access to edit the zone
342+ //
343+ // (gcloud dns managed-zones get-iam-policy $zone_id) (role roles/dns.admin)
344+ //
345+ // but not with project-wide access to list all zones
346+ //
347+ // (gcloud projects get-iam-policy $project_id) (a role with permission dns.managedZones.list)
348+ //
349+ // If we force a zone list to succeed, we demand more permissions than needed.
350+ func (d * DNSProvider ) lookupHostedZoneID (domain string ) (string , []* dns.ManagedZone , error ) {
351+ // GCE_ZONE_ID override for service accounts to avoid needing zones-list permission
352+ if d .config .ZoneID != "" {
353+ zone , err := d .client .ManagedZones .Get (d .config .Project , d .config .ZoneID ).Do ()
354+ if err != nil {
355+ return "" , nil , fmt .Errorf ("API call ManagedZones.Get for explicit zone ID %q in project %q failed: %w" , d .config .ZoneID , d .config .Project , err )
356+ }
357+
358+ return zone .DnsName , []* dns.ManagedZone {zone }, nil
359+ }
360+
361+ authZone , err := dns01 .FindZoneByFqdn (dns01 .ToFqdn (domain ))
362+ if err != nil {
363+ return "" , nil , fmt .Errorf ("could not find zone for FQDN %q: %w" , domain , err )
364+ }
365+
366+ zones , err := d .client .ManagedZones .
367+ List (d .config .Project ).
368+ DnsName (authZone ).
369+ Do ()
370+ if err != nil {
371+ return "" , nil , fmt .Errorf ("API call ManagedZones.List failed: %w" , err )
372+ }
373+
374+ return authZone , zones .ManagedZones , nil
375+ }
376+
343377func (d * DNSProvider ) findTxtRecords (zone , fqdn string ) ([]* dns.ResourceRecordSet , error ) {
344378 recs , err := d .client .ResourceRecordSets .List (d .config .Project , zone ).Name (fqdn ).Type ("TXT" ).Do ()
345379 if err != nil {
0 commit comments