Skip to content

GCP Pub/Sub: creating a DLQ-backed channel requires project IAM admin and hard-fails without it #4354

Description

@iancooper

Summary

Creating a Pub/Sub channel whose subscription carries a DeadLetterPolicy unconditionally reads and
writes project-level IAM. If the caller's principal cannot do that, channel creation throws and the
consumer never starts — even when the dead-letter topic and its IAM binding already exist.

That makes Brighter require permissions an application service account usually does not have, because
the DLQ is normally provisioned by infrastructure-as-code rather than by the app at startup.

The path

GcpPubSubMessageGateway.EnsureSubscriptionExistsAsync (:235) calls
UpdateIAmRoleForDeadLetterAsync (:481) whenever DeadLetter != null. That method makes two calls,
neither of which is guarded or optional:

  1. ProjectsClient.GetProjectAsync — Cloud Resource Manager, used to derive the default Pub/Sub
    service account when DeadLetterPolicy.PublisherMember is unset. Needs resourcemanager.projects.get.
  2. PublisherServiceApiClient.IAMPolicyClient.GetIamPolicyAsync (then SetIamPolicy when the binding
    is missing) on the dead-letter topic. Needs pubsub.topics.getIamPolicy / setIamPolicy.

Any failure propagates out of CreateSyncChannel / CreateAsyncChannelAsync.

How it showed up

Running the FR-23 conformance behaviour (#4240 / #4297) against the Pub/Sub emulator
(gcr.io/google.com/cloudsdktool/cloud-sdk:emulators, PUBSUB_EMULATOR_HOST=localhost:8085), all
eight tests — four GCP configurations × both variants — fail in ~4 s during arrange, before any pump
runs:

call result on the emulator
ProjectsClient.GetProjectAsync Unauthenticated: Request had invalid authentication credentials — the request leaves for real GCP. Resource Manager is a different service from Pub/Sub, so PUBSUB_EMULATOR_HOST cannot redirect it
IAMPolicyClient.GetIamPolicyAsync Unimplemented — the emulator has no IAM surface at all

The second was isolated rather than inferred: setting DeadLetterPolicy.PublisherMember explicitly
skips the Resource Manager call, and the run then fails one line later on GetIamPolicy.

Suggested fix

Tolerate Unimplemented and PermissionDenied from both calls — log and continue rather than throw.
The binding may already exist, and a principal that cannot read the policy also cannot tell. Optionally
add an opt-out on DeadLetterPolicy for callers who provision IAM out of band.

Impact

  • Production: any application whose service account lacks project IAM admin cannot create a
    DLQ-backed channel, even against a correctly provisioned topic.
  • Testing: no GCP behaviour that needs a DLQ can be exercised against the Pub/Sub emulator, so the
    four GCP FR-23 conformance cells can only ever be verified by gcp-ci against a real project.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions