Tempkey Blog
Zero Standing Privileges: How to Manage Contractor Access to Google Cloud Run
A technical guide for engineering leads and ops teams looking to grant external developers scoped, temporary deployment privileges on Google Cloud Run without exposing production infrastructure.
To safely manage contractor access to Google Cloud Run, enforce Zero Standing Privileges (ZSP) by binding granular IAM roles directly at the service level, replacing static credentials with short-lived service account impersonation, and attaching automated expiration policies. Learning how to manage contractor access to Google Cloud Run without exposing production infrastructure ensures external developers receive only the precise permissions required to deploy code, while completely eliminating the risk of lingering access.
Engineering teams frequently rely on freelance talent, agencies, and specialized contractors to build or maintain serverless microservices. However, serverless execution environments present unique identity boundaries. Granting external developers broad permissions or long-lived credentials can quickly lead to configuration drift, credential leakage, and compliance vulnerabilities. Implementing rigorous contractor cloud access control establishes clean operational isolation between code authoring and infrastructure governance.
The Security Risks of Overprivileged External Developers on Serverless Infrastructure
Serverless compute platforms like Google Cloud Run abstract away physical and virtual machine boundaries, but they shift the primary security perimeter entirely to the Identity and Access Management (IAM) layer. Unlike traditional compute clusters where an engineer might operate within a localized network subnet or isolated bastion host, a developer with permissions on Cloud Run interacts directly with the Google Cloud control plane. If an external contributor possesses broad IAM privileges, a single misstep or compromised account can impact services across your entire organization.
A common operational failure mode is assigning project-level Editor (roles/editor) or Owner (roles/owner) roles to freelance developers during onboarding. Engineering leads often choose broad roles to avoid debugging granular permission errors during tight project sprints. However, this grants contractors the ability to:
- Modify routing rules, domain mappings, and traffic allocations across production workloads.
- Deploy arbitrary container images containing untested code or malicious binaries.
- Exfiltrate sensitive environment variables, secrets, and database credentials mounted into Cloud Run runtime environments.
- Provision unintended ancillary resources, such as high-cost Compute Engine instances or unmonitored storage buckets.
The most persistent risk in freelance developer engagements is the accumulation of orphaned credentials. When a contractor finishes their scope of work, their user account or static credential frequently remains active in the GCP project. If that developer's personal machine, local token cache, or workstation is later compromised, attackers inherit unmonitored access to your deployment pipeline. Furthermore, when external contributors use static JSON service account keys, credential governance leaves your security perimeter entirely. Establishing a workflow that avoids permanent credentials while enforcing strict time-to-live (TTL) limits on every permission grant is essential for maintaining infrastructure integrity.
Understanding Google Cloud Run IAM Roles and Resource Scoping
Securing developer workflows requires navigating the hierarchy of predefined roles within Google Cloud Run IAM. Rather than applying broad project-level permissions, administrators must understand the specific responsibilities mapped to each role and scope them strictly to the target service.
Predefined Cloud Run Roles
- Cloud Run Admin (
roles/run.admin): Grants full control over all Cloud Run services, revisions, jobs, domain mappings, and underlying configurations within the scope of the binding. Contractors should rarely receive this role, as it permits service deletion, configuration of custom domains, and modification of IAM policies themselves. - Cloud Run Developer (
roles/run.developer): Allows creating and deploying new revisions of existing Cloud Run services, reading runtime configurations, and inspecting metadata. This is the standard role required by external developers who need to iterate on containerized services without altering administrative boundaries. - Cloud Run Invoker (
roles/run.invoker): Provides read-only trigger access to send HTTP requests or Pub/Sub events to ingress-restricted (private) Cloud Run services. This role does not grant deployment or configuration capabilities. - Cloud Run Viewer (
roles/run.viewer): Provides read-only visibility into service configurations, metrics, and revision histories without allowing any modifications or container deployments.
Granular Resource Binding vs. Project-Level Granting
IAM bindings in Google Cloud can be applied at the Organization, Folder, Project, or Resource level. Granting roles/run.developer at the Project level allows an external developer to deploy revisions to every service within that project, including sensitive authentication gateways or billing microservices.
Instead, apply resource-level IAM bindings directly to the specific Cloud Run service the contractor is assigned to modify. For example, if a contractor is hired solely to optimize an image-processing service named media-transformer, the binding should be attached strictly to that resource:
# Correct: Service-scoped binding
projects/my-prod-project/locations/us-central1/services/media-transformer
# Incorrect: Project-wide binding
projects/my-prod-project
Ancillary Permissions: Artifact Registry, Secret Manager, and Logging
A Cloud Run service does not operate in a vacuum. A developer deploying a revision typically needs to push container images, reference environment configurations, and debug runtime output. To build a secure, functional role profile for a contractor, you must configure granular bindings across these ancillary services:
| Resource | Recommended Contractor Role | Scope / Boundary |
|---|---|---|
| Artifact Registry | roles/artifactregistry.writer |
Scoped strictly to the specific repository containing the service's container images, preventing writes to unrelated application images. |
| Secret Manager | roles/secretmanager.secretAccessor |
Bound only to the runtime Service Account—never directly to the contractor—ensuring developers cannot read production database passwords locally. |
| Cloud Logging | roles/logging.viewer |
Granted with a log-viewing filter restricted to resource.type="cloud_run_revision" and the specific service name. |
| IAM Service Account | roles/iam.serviceAccountUser |
Scoped strictly to the runtime service account identity assigned to execute the specific Cloud Run service. |
Core Principles for Contractor Cloud Access Control on GCP
Implementing effective contractor cloud access control requires moving away from ad-hoc access provisioning. Structuring contractor access around modern identity patterns prevents credential proliferation and limits lateral movement.
1. Applying the Principle of Least Privilege (PoLP)
Every permission granted to an external developer must have a clear architectural justification. If a freelancer is tasked with refactoring an API endpoint, they require deployment permissions on that specific microservice and write access to its container registry repository. They do not require visibility into Cloud SQL databases, VPC network firewall configurations, or billing accounts. If a task does not explicitly require modifying a resource, access to that resource should default to zero.
2. Eliminating Static JSON Service Account Keys
The single most severe threat vector in Google Cloud security is the proliferation of static JSON service account keys. Keys downloaded to local developer machines lack built-in expiration dates, bypass centralized identity providers, and cannot be conditionally restricted by client posture. Once exported, a JSON key can be leaked via unsecured dotfiles, committed into public Git repositories, or compromised by local workstation malware.
Instead of distributing JSON keys, enforce IAM service account impersonation or Workload Identity Federation. Under this model, contractors authenticate using their personal Google identity (e.g., their Google Workspace or corporate email) and temporarily generate short-lived OAuth 2.0 access tokens to perform deployment tasks. The temporary credentials expire automatically within one hour, eliminating the existence of static credentials on developer workstations.
3. Strict Separation of Staging and Production Projects
Contractors should rarely have direct deployment access to production Google Cloud projects. The optimal architecture uses dedicated, isolated GCP projects for each environment (e.g., app-staging, app-prod). External contributors should be granted deployment capabilities strictly in the staging environment. Production deployments should be handled entirely by automated continuous deployment (CD) pipelines triggered only after internal peer review and security approval gates have been satisfied.
Step-by-Step: How to Manage Contractor Access to Google Cloud Run via IAM Conditions
Google Cloud IAM Conditions allow administrators to define conditional, attribute-based access controls using Common Expression Language (CEL). By attaching temporal conditions to IAM policy bindings, you can grant temporary access that expires automatically at a set date and time, preventing standing privileges if manual deprovisioning is delayed.
Follow this step-by-step implementation to learn how to manage contractor access to google cloud run using scoped roles, the gcloud command-line interface, and temporary CEL IAM Conditions.
Step 1: Identify Resource and Contractor Identifiers
Define the operational variables for your deployment environment:
export PROJECT_ID="acme-saas-staging"
export REGION="us-central1"
export SERVICE_NAME="payment-webhook"
export CONTRACTOR_EMAIL="contractor-alex@external-agency.com"
export RUNTIME_SA="sa-payment-webhook@${PROJECT_ID}.iam.gserviceaccount.com"
# Define expiration timestamp in RFC 3339 format (e.g., 2026-10-15T18:00:00Z)
export EXPIRATION_DATE="2026-10-15T18:00:00Z"
Step 2: Grant Temporary Cloud Run Developer Access to the Specific Service
Bind the roles/run.developer role directly to the target Cloud Run service, attaching a CEL expression that restricts access to the agreed contract duration:
gcloud run services add-iam-policy-binding ${SERVICE_NAME} \
--project=${PROJECT_ID} \
--region=${REGION} \
--member="user:${CONTRACTOR_EMAIL}" \
--role="roles/run.developer" \
--condition="expression=request.time < timestamp('${EXPIRATION_DATE}'),title=contractor_run_dev_ttl,description=Temporary access for Q4 refactor"
Step 3: Grant Scoped Service Account User Permissions
To deploy a new revision to Cloud Run, a developer must possess the roles/iam.serviceAccountUser role on the runtime service account attached to that service. This permission allows the Cloud Run service to assume its designated execution identity.
Warning: rarely grant roles/iam.serviceAccountUser at the project level. Doing so allows the user to run compute workloads as any service account in the project, including high-privilege default service accounts. Bind the role strictly to the specific runtime service account:
gcloud iam service-accounts add-iam-policy-binding ${RUNTIME_SA} \
--project=${PROJECT_ID} \
--member="user:${CONTRACTOR_EMAIL}" \
--role="roles/iam.serviceAccountUser" \
--condition="expression=request.time < timestamp('${EXPIRATION_DATE}'),title=contractor_sa_user_ttl,description=Temporary actAs permission for deployment"
Step 4: Grant Scoped Artifact Registry Access
Next, grant the contractor permission to push container images to the dedicated Artifact Registry repository associated with the service:
export REPO_NAME="webhook-images"
gcloud artifacts repositories add-iam-policy-binding ${REPO_NAME} \
--project=${PROJECT_ID} \
--location=${REGION} \
--member="user:${CONTRACTOR_EMAIL}" \
--role="roles/artifactregistry.writer" \
--condition="expression=request.time < timestamp('${EXPIRATION_DATE}'),title=contractor_repo_write_ttl,description=Temporary container push access"
Step 5: Verify the Active IAM Bindings
Verify that the IAM conditions are correctly parsed and attached to the Cloud Run service policy:
gcloud run services get-iam-policy ${SERVICE_NAME} \
--project=${PROJECT_ID} \
--region=${REGION} \
--format="yaml(bindings)"
The output will display the condition block alongside the member and role mapping:
bindings:
- condition:
description: Temporary access for Q4 refactor
expression: request.time < timestamp('2026-10-15T18:00:00Z')
title: contractor_run_dev_ttl
members:
- user:contractor-alex@external-agency.com
role: roles/run.developer
Once the clock reaches 2026-10-15T18:00:00Z, Google Cloud IAM will automatically deny all API requests issued by the contractor for this service, without requiring manual administrative intervention.
Securing CI/CD Pipelines and Service Account Impersonation for External Contributors
While IAM conditions secure direct console and CLI deployments, modern engineering teams often route contractor contributions through continuous integration pipelines. Securing CI/CD access requires preventing external contributors from gaining direct visibility into long-lived deployment secrets.
Workload Identity Federation for External Repositories
If contractors push code to GitHub Actions or GitLab CI, avoid storing GCP service account keys in repository secrets. Instead, configure Workload Identity Federation. This allows the CI runner to authenticate against Google Cloud IAM using short-lived OpenID Connect (OIDC) identity tokens issued by the source control provider.
# 1. Create a Workload Identity Pool
gcloud iam workload-identity-pools create "contractor-pool" \
--project="${PROJECT_ID}" \
--location="global" \
--display-name="Contractor CI/CD Pool"
# 2. Create an OIDC Provider for GitHub Actions
gcloud iam workload-identity-pools providers create-oidc "github-provider" \
--project="${PROJECT_ID}" \
--location="global" \
--workload-identity-pool="contractor-pool" \
--issuer-uri="https://token.actions.githubusercontent.com" \
--attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository,attribute.ref=assertion.ref"
# 3. Allow CI to impersonate the deployment Service Account strictly from the approved repository
gcloud iam service-accounts add-iam-policy-binding deployer-sa@${PROJECT_ID}.iam.gserviceaccount.com \
--role="roles/iam.workloadIdentityUser" \
--member="principalSet://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/contractor-pool/attribute.repository/your-org/payment-service"
Branch Protections and Approval Gates
To prevent malicious or untested code from deploying automatically to Cloud Run via contractor pull requests:
- Enforce Branch Protection: Require signed commits, passing unit/integration tests, and mandatory code reviews from internal team members before merging into protected deployment branches (e.g.,
mainorstaging). - Restrict Workflow Triggers: Ensure deployment workflows trigger only on merged commits, not on unreviewed
pull_requestevents originating from contractor forks. - Isolate Deployment Environments: Use protected deployment environments within your CI/CD platform that require manual approval from an engineering lead before deployment credentials or OIDC tokens are released to the pipeline.
Lifecycle Automation: How to Manage Contractor Access to Google Cloud Run Without Orphaned Permissions
While native Google Cloud IAM Conditions provide temporal bounds for individual resource bindings, managing access across an entire developer toolchain introduces significant operational complexity. A contractor modifying a Cloud Run service typically requires access across multiple disjoint systems: issue tracking boards, source control repositories, API gateways, communication channels, and identity providers.
Relying on calendar reminders and manual offboarding checklists to revoke access across distinct platforms inevitably leads to gaps. If an administrator manually revokes a contractor's Google Cloud Run IAM binding but forgets to remove their repository write permissions or Slack access, the contractor retains an entry point into your organization's development lifecycle.
To streamline external access lifecycles, teams can integrate purpose-built identity automation tools like Tempkey alongside their cloud environments. Implementing automated access management brings systematic structure to contractor offboarding:
- Centralized Access Expiration: Automatically enforce fixed-duration access grants across developer tools, ensuring that access expires simultaneously when a contract concludes.
- Automated Deprovisioning Verification: Verify that external identities are systematically removed across connected toolchains without manual inspection of individual console settings.
- Complete Offboarding Auditing: Establish an append-only audit trail you can export to CSV or PDF to support internal compliance and offboarding records, providing engineering leaders with clear visibility into who held access to specific resources and precisely when that access was removed.
For organizations managing multi-tool developer workflows, review the Tempkey product capabilities and explore flexible team plans to automate time-bound access lifecycles across external collaborators.
Auditing, Verification, and Incident Response for Contractor Deployments
Implementing perimeter controls and IAM conditions is only half of the security equation. Engineering teams must continuously monitor contractor activity and maintain rapid incident response capabilities.
Querying Cloud Audit Logs
Google Cloud automatically records control-plane actions in Cloud Audit Logs. You can inspect Cloud Run deployments, configuration changes, and traffic modifications made by external contractors by executing queries in the Google Cloud Logs Explorer.
To audit all revisions deployed by a specific contractor over the last 30 days, run the following filter:
resource.type="cloud_run_revision"
protoPayload.methodName="google.cloud.run.v1.Services.ReplaceService"
protoPayload.authenticationInfo.principalEmail="contractor-alex@external-agency.com"
severity>=NOTICE
To track any modifications made directly to Cloud Run IAM policies (such as someone attempting to add an unauthorized user or escalate privileges), use this query:
protoPayload.serviceName="run.googleapis.com"
protoPayload.methodName="SetIamPolicy"
severity>=WARNING
Setting Up Log-Based Alerts in Cloud Monitoring
Do not wait for quarterly access reviews to detect unauthorized changes. Configure Log-Based Alerts in Cloud Monitoring to notify your security team immediately if anomalous events occur:
- IAM Policy Changes: Alert on any
SetIamPolicycall across Cloud Run services or service accounts. - Traffic Allocation Shifts: Alert when a user routes a significant share of production traffic to an unvetted revision without passing standard release checkpoints.
- Permission Denials: Track spikes in
PERMISSION_DENIEDerrors associated with contractor accounts, which may indicate attempted lateral movement or probing of restricted resources.
Immediate Revocation and Incident Response Workflows
If a security incident occurs or a contractor relationship ends abruptly before scheduled IAM conditions expire, execute an immediate deprovisioning workflow:
# 1. Remove the contractor from Cloud Run IAM policy bindings immediately
gcloud run services remove-iam-policy-binding ${SERVICE_NAME} \
--project=${PROJECT_ID} \
--region=${REGION} \
--member="user:${CONTRACTOR_EMAIL}" \
--role="roles/run.developer"
# 2. Remove ActAs permissions on the service account
gcloud iam service-accounts remove-iam-policy-binding ${RUNTIME_SA} \
--project=${PROJECT_ID} \
--member="user:${CONTRACTOR_EMAIL}" \
--role="roles/iam.serviceAccountUser"
# 3. Invalidate active user tokens
# If using Google Workspace or Cloud Identity, suspend or revoke active OAuth tokens for the identity
Additionally, rotate any database connection strings, third-party API keys, or Secret Manager payloads that the contractor had access to during their engagement.
Frequently Asked Questions
What is the minimum IAM role a contractor needs to deploy a Google Cloud Run service?
To deploy a revision to an existing Google Cloud Run service, a contractor requires two specific roles: roles/run.developer bound directly to the target Cloud Run service, and roles/iam.serviceAccountUser bound directly to the runtime service account used by that service. If the contractor is also responsible for building and pushing new container images, they will additionally need roles/artifactregistry.writer scoped to the target repository in Artifact Registry.
How do IAM Conditions help enforce time-bound contractor cloud access control in Google Cloud Run?
IAM Conditions use Common Expression Language (CEL) syntax to attach programmatic constraints to IAM policy bindings. By adding an expression such as request.time < timestamp('2026-12-31T23:59:59Z') to a role binding, Google Cloud IAM automatically evaluates the current timestamp during every API request. Once the defined expiration date passes, GCP denies all subsequent access attempts automatically, eliminating orphaned standing permissions without requiring manual intervention.
Why should engineering teams avoid issuing service account JSON keys to freelance developers?
Service account JSON keys are unmanaged, static credentials that do not expire automatically. Once downloaded to a freelancer's local machine, administrators lose visibility into how those credentials are stored, backed up, or shared. If the developer's computer is compromised, or if the key is accidentally committed to a public repository, attackers can access your cloud environment undetected. Using short-lived credential delegation, such as IAM service account impersonation or Workload Identity Federation, ensures tokens expire within one hour and removes static keys from endpoints.
How can you verify that a contractor's access to Cloud Run was actually revoked after their contract ends?
You can verify deprovisioning by querying the IAM policy directly via the CLI using gcloud run services get-iam-policy SERVICE_NAME and inspecting the output to confirm the contractor's identity is no longer listed in active role bindings. Furthermore, administrators should inspect Google Cloud Audit Logs to verify that no deployment or read operations have been authorized for that principal since the contract end date.
Ready to eliminate orphaned developer credentials? Discover how Tempkey automates time-bound access lifecycles across your external tools with exportable, append-only audit trails.