Let the VM list DNS zones so Caddy can present DNS-01 challenges
With DNS resolution fixed, issuance failed at the challenge: presenting for challenge: adding temporary record for zone "gitea.jasonmross.dev.": googleapi: Error 403: Forbidden Testing with the VM service account's own token: managedZones/main and its rrsets return 200, but managedZones (list) returns 403. The googleclouddns plugin resolves the domain to a zone by listing the project's managed zones, and listing is a project-level permission that the zone-scoped dns.admin binding cannot grant. Grant roles/dns.reader on the project. It adds read access only, in a project that holds this single zone; every write stays zone-scoped. A custom role with just dns.managedZones.list was the alternative, but managing it would need iam.roleAdmin on the cb-infra Pulumi runner, which widens a far more powerful identity to narrow a read-only one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
committed by
Jason Ross
co-authored by
Claude Opus 5.5
parent
25dda00eaf
commit
69d586bfcc
@@ -8,6 +8,7 @@ package dns
|
||||
import (
|
||||
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/compute"
|
||||
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/dns"
|
||||
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/projects"
|
||||
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
|
||||
|
||||
"gitea-infra/pkg/config"
|
||||
@@ -60,5 +61,19 @@ func New(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// The zone-scoped grant is not enough on its own: the googleclouddns plugin
|
||||
// maps the domain to a zone by LISTING the project's managed zones, and a
|
||||
// list is a project-level permission that no zone binding can confer. Without
|
||||
// this, presenting the challenge fails with a bare 403. dns.reader adds
|
||||
// read-only access and nothing else, and every write stays scoped to the zone
|
||||
// above.
|
||||
if _, err := projects.NewIAMMember(ctx, "gitea-vm-dns-reader", &projects.IAMMemberArgs{
|
||||
Project: pulumi.String(cfg.Project),
|
||||
Role: pulumi.String("roles/dns.reader"),
|
||||
Member: pulumi.Sprintf("serviceAccount:%s", vmServiceAccountEmail),
|
||||
}, pulumi.DependsOn(deps)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &DNS{Zone: zone, Record: rec}, nil
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ ${DOMAIN} {
|
||||
tls {
|
||||
dns googleclouddns {
|
||||
# Application Default Credentials come from the GCE metadata server.
|
||||
# The VM service account holds roles/dns.admin scoped to this zone only.
|
||||
# The VM service account holds roles/dns.admin scoped to this zone, plus
|
||||
# project-level dns.reader so the plugin can list zones to find it.
|
||||
gcp_project {env.GCP_PROJECT}
|
||||
}
|
||||
# Only used for propagation checks. If issuance stalls waiting for
|
||||
|
||||
Reference in New Issue
Block a user