Introduction: From Deployment to Production Security

In Unit 3, you successfully deployed Cloud Run services and learned the fundamentals of service lifecycle management—deploying with gcloud run deploy, viewing configurations with gcloud run services describe, managing revisions, and cleaning up with gcloud run services delete. If you need a refresher on these basic operations, please review Unit 3's "Deploying Cloud Run Services" lesson.

This lesson focuses on securing and networking your Cloud Run services for production use. While Unit 3 covered how to deploy services, this lesson covers how to secure them through authentication controls, how to grant access using IAM policies, and how to make them accessible via custom domains. These are critical skills for operating Cloud Run services in real-world environments where security, access control, and professional URLs are essential requirements.

By the end of this lesson, you'll understand Cloud Run's authentication modes, how to configure IAM policies to control who can invoke your services, how to configure network ingress settings, and how to map custom domains to give your services professional URLs instead of the default *.run.app endpoints.

Understanding Cloud Run Authentication Modes

Cloud Run provides two fundamental authentication modes that control who can access your services: unauthenticated (public) access and authenticated (private) access. This choice determines whether anyone on the internet can call your service or whether callers must provide valid Google Cloud credentials.

When you deploy a service with --allow-unauthenticated, you're creating a public endpoint that anyone can access without credentials. This is appropriate for public-facing web applications, marketing websites, or APIs that need to be accessible to external users. The service URL is publicly accessible, and Cloud Run accepts all incoming requests without verifying the caller's identity.

# Deploy a publicly accessible service (from Unit 3)
gcloud run deploy public-web-app \
  --image gcr.io/PROJECT_ID/my-app:latest \
  --region us-central1 \
  --allow-unauthenticated

Conversely, when you deploy with --no-allow-unauthenticated or omit the authentication flag entirely, you're creating a private endpoint that requires authentication. Only callers with valid Google Cloud credentials and appropriate IAM permissions can invoke the service. This is essential for internal APIs, backend services, or any application that should only be accessible to authorized users and service accounts.

# Deploy a private service requiring authentication
gcloud run deploy private-api \
  --image gcr.io/PROJECT_ID/my-api:latest \
  --region us-central1 \
  --no-allow-unauthenticated

The key difference is in the default IAM policy. Public services have allUsers granted the roles/run.invoker role, while private services have no default invokers—you must explicitly grant access through IAM policies.

Changing Authentication Mode on Existing Services

You can modify the authentication mode of an existing service without redeploying it. This is useful when you need to quickly restrict access to a service that was initially public or open up a private service for testing.

To restrict a public service to require authentication:

# Remove public access from an existing service
gcloud run services update my-web-app \
  --region us-central1 \
  --no-allow-unauthenticated

This command updates the service's IAM policy to remove the allUsers binding, immediately requiring authentication for all new requests. Existing connections are not affected, but subsequent requests will fail unless the caller provides valid credentials.

To make a private service publicly accessible:

# Allow public access to a previously private service
gcloud run services update my-api \
  --region us-central1 \
  --allow-unauthenticated

This grants the roles/run.invoker role to allUsers, making the service publicly accessible. Use this cautiously, as it exposes your service to the entire internet.

Understanding when to use each authentication mode is crucial for Cloud Run security. Public services are convenient but require additional application-level security measures like API keys or OAuth. Private services provide strong authentication by default but require you to manage IAM policies carefully to grant access to legitimate callers.

IAM Roles and Policy Bindings for Cloud Run

When you configure a Cloud Run service to require authentication, you must explicitly grant permissions to users and service accounts that need to invoke it. Cloud Run uses Identity and Access Management (IAM) to control access, with the roles/run.invoker role being the key permission for calling a service.

The IAM model for Cloud Run is straightforward: who (the member) can do what (the role) on which resource (the service). Members can be user accounts, service accounts, Google Groups, or domains. The role for invoking services is always roles/run.invoker. The resource is your specific Cloud Run service.

To grant a specific user permission to invoke your service:

# Grant invoke permission to a specific user
gcloud run services add-iam-policy-binding my-web-app \
  --region us-central1 \
  --member="user:developer@example.com" \
  --role="roles/run.invoker"

This command adds an IAM policy binding that allows developer@example.com to invoke the my-web-app service. The user can now call the service by including their Google Cloud credentials in the request. Common tools like curl with gcloud auth print-identity-token or client libraries with Application Default Credentials automatically handle this authentication.

You can also grant access to service accounts, which is essential for service-to-service communication:

# Grant invoke permission to a service account
gcloud run services add-iam-policy-binding my-web-app \
  --region us-central1 \
  --member="serviceAccount:my-service@PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/run.invoker"

This allows the specified service account to invoke your service. This is common when one Cloud Run service needs to call another, or when Cloud Scheduler, Cloud Tasks, or Pub/Sub needs to trigger your service.

For broader access within your organization, you can grant permissions to entire Google Groups or domains:

# Grant invoke permission to a Google Group
gcloud run services add-iam-policy-binding my-web-app \
  --region us-central1 \
  --member="group:developers@example.com" \
  --role="roles/run.invoker"

# Grant invoke permission to all users in a domain
gcloud run services add-iam-policy-binding my-web-app \
  --region us-central1 \
  --member="domain:example.com" \
  --role="roles/run.invoker"

These patterns are useful for internal tools where all employees should have access, or for development environments where all team members need to test services.

Viewing and Managing IAM Policies

To see who currently has permission to invoke your service, use the get-iam-policy command:

# View current IAM policy bindings
gcloud run services get-iam-policy my-web-app \
  --region us-central1

This returns the complete IAM policy in YAML format:

bindings:
- members:
  - user:developer@example.com
  - serviceAccount:my-service@PROJECT_ID.iam.gserviceaccount.com
  role: roles/run.invoker
etag: BwYH1234ABC=
version: 1

The members list shows all principals with invoke permission. The etag is used for concurrency control—it ensures policy updates don't overwrite concurrent changes.

To remove a policy binding and revoke access:

# Remove invoke permission from a user
gcloud run services remove-iam-policy-binding my-web-app \
  --region us-central1 \
  --member="user:developer@example.com" \
  --role="roles/run.invoker"

This immediately revokes the user's ability to invoke the service. Any subsequent attempts will fail with an HTTP 403 Forbidden error.

Least Privilege Principle

When configuring IAM policies, follow the principle of least privilege: grant only the minimum permissions required for each caller to perform their function. Avoid granting allUsers or overly broad domain access unless your service is truly public. For internal services, prefer specific user or service account grants. For production systems, regularly audit your IAM policies to ensure permissions remain appropriate as team members and services evolve.

Network Ingress Settings

Beyond authentication, Cloud Run provides ingress settings that control which networks can reach your service. While authentication determines who can invoke your service, ingress settings determine where requests can originate from. This provides an additional layer of security for services that should only be accessible from specific network contexts.

Cloud Run supports three ingress settings:

  1. All traffic (all) - The default setting. Your service accepts requests from the public internet, your VPC network, and other Google Cloud services. This is the most permissive setting and appropriate for public-facing services.

  2. Internal traffic only (internal) - Your service only accepts requests from other services in your Google Cloud project, VPC networks connected via VPC Service Controls, and Cloud Load Balancer. Requests from the public internet are rejected. This is ideal for backend services that should never be directly exposed to external users.

  3. Internal and Cloud Load Balancing (internal-and-cloud-load-balancing) - Similar to internal traffic only, but also accepts traffic from Google Cloud Load Balancer. This is useful when you want to use a load balancer to provide a custom domain or apply advanced routing rules while still restricting direct access.

To configure ingress settings when deploying a new service:

# Deploy a service that only accepts internal traffic
gcloud run deploy internal-api \
  --image gcr.io/PROJECT_ID/my-api:latest \
  --region us-central1 \
  --ingress internal \
  --no-allow-unauthenticated

This creates a service that's only accessible from within your Google Cloud project and VPC networks. External requests are rejected at the network level before reaching your application.

To update the ingress setting on an existing service:

# Restrict an existing service to internal traffic only
gcloud run services update my-web-app \
  --region us-central1 \
  --ingress internal

You can verify the current ingress setting by describing your service:

# Check the current ingress setting
gcloud run services describe my-web-app \
  --region us-central1 \
  --format="value(spec.template.metadata.annotations['run.googleapis.com/ingress'])"

Combining Ingress with Authentication

Ingress settings and authentication work together to provide defense in depth. Even with --ingress internal, you should still use --no-allow-unauthenticated and configure appropriate IAM policies. Network-level restrictions (ingress) prevent unauthorized networks from reaching your service, while authentication (IAM) ensures only authorized principals can invoke it.

Common patterns include:

  • Public web app: --ingress all --allow-unauthenticated - Anyone can access from anywhere
  • Internal API: --ingress internal --no-allow-unauthenticated - Only accessible from your VPC with valid credentials
  • Load-balanced service: --ingress internal-and-cloud-load-balancing --no-allow-unauthenticated - Accessed via load balancer with authentication

These settings provide flexible security models for different service types and use cases.

Custom Domain Mapping

By default, Cloud Run assigns your service a URL like https://SERVICE-NAME-HASH-REGION.a.run.app. While functional, these URLs aren't suitable for production applications where you need branded, memorable URLs like https://api.example.com or https://app.example.com. Cloud Run supports custom domain mapping to associate your services with domains you own.

Prerequisites for Domain Mapping

Before mapping a custom domain, you must:

  1. Own the domain - You must have registered the domain through a domain registrar like Google Domains, GoDaddy, or Namecheap.
  2. Verify domain ownership - You must verify that you control the domain in Google Cloud Console. This typically involves adding a TXT record to your domain's DNS configuration.
  3. Have DNS access - You need the ability to add DNS records (A, AAAA, or CNAME) to your domain's configuration.

Creating a Domain Mapping

Once you've verified domain ownership in the Google Cloud Console, you can map a domain to your Cloud Run service using the gcloud run domain-mappings create command:

# Map a custom domain to a Cloud Run service
gcloud run domain-mappings create \
  --service=my-web-app \
  --domain=app.example.com \
  --region=us-central1

This command initiates the domain mapping process. Cloud Run returns DNS records that you must add to your domain's DNS configuration:

Domain mapping created:
  Domain: app.example.com
  Service: my-web-app
  Region: us-central1

Please add the following DNS records to your domain's configuration:

Name:  app.example.com
Type:  A
Value: 216.239.32.21

Name:  app.example.com
Type:  A
Value: 216.239.34.21

Name:  app.example.com
Type:  A
Value: 216.239.36.21

Name:  app.example.com
Type:  A
Value: 216.239.38.21

Name:  app.example.com
Type:  AAAA
Value: 2001:4860:4802:32::15

Name:  app.example.com
Type:  AAAA
Value: 2001:4860:4802:34::15

Name:  app.example.com
Type:  AAAA
Value: 2001:4860:4802:36::15

Name:  app.example.com
Type:  AAAA
Value: 2001:4860:4802:38::15

You need to add these DNS records through your domain registrar's control panel. The A records provide IPv4 addresses, while AAAA records provide IPv6 addresses. Include all records for redundancy and availability.

After adding the DNS records, Cloud Run automatically provisions an SSL certificate for your domain through Google-managed certificates. This process typically completes within a few minutes but can take up to 24 hours depending on DNS propagation.

Verifying Domain Mapping Status

To check the status of your domain mapping:

# Check domain mapping status
gcloud run domain-mappings describe app.example.com \
  --region=us-central1

The output shows the mapping status and certificate provisioning state:

apiVersion: domains.cloudrun.com/v1
kind: DomainMapping
metadata:
  name: app.example.com
  namespace: '123456789012'
spec:
  certificateMode: AUTOMATIC
  forceOverride: false
  routeName: my-web-app
status:
  conditions:
  - status: 'True'
    type: Ready
  - status: 'True'
    type: CertificateProvisioned
  mappedRouteName: my-web-app
  observedGeneration: 1
  resourceRecords:
  - name: app.example.com
    rrdata: 216.239.32.21
    type: A
  url: https://app.example.com

When both Ready and CertificateProvisioned show status: 'True', your custom domain is fully configured and accessible via HTTPS.

Managing Multiple Domains

You can map multiple domains to the same service for different environments or brands:

# Map a staging domain
gcloud run domain-mappings create \
  --service=my-web-app \
  --domain=staging.example.com \
  --region=us-central1

# Map a production domain
gcloud run domain-mappings create \
  --service=my-web-app \
  --domain=www.example.com \
  --region=us-central1

This allows you to serve the same service through multiple branded URLs, useful for A/B testing or maintaining backward compatibility during migrations.

To remove a domain mapping:

# Delete a domain mapping
gcloud run domain-mappings delete app.example.com \
  --region=us-central1

This removes the mapping and stops serving traffic through that domain. The service remains accessible through its default *.run.app URL and any other mapped domains.

Best Practices for Custom Domains

When working with custom domains:

  • Use apex domains (example.com) sparingly, as they require A/AAAA records that can't be used with some DNS providers. Prefer subdomains (www.example.com, api.example.com) which support CNAME records.
  • Implement automatic HTTPS redirects in your application to ensure users always connect securely.
  • Consider using Cloud Load Balancing with Cloud Run for advanced routing, URL rewriting, or SSL offloading.
  • Monitor certificate expiration in Cloud Console, though Google-managed certificates renew automatically.
  • Test domain mappings in non-production environments first to ensure DNS configuration is correct.

Custom domains transform Cloud Run services from development prototypes into production-ready applications with professional URLs that inspire user confidence.

Summary and Production Readiness

You've now mastered the essential security and networking configurations for Cloud Run services in production environments. You learned how to control access through authentication modes, configure granular permissions using IAM policy bindings, restrict network access with ingress settings, and provide professional URLs through custom domain mapping.

These capabilities transform Cloud Run from a simple deployment platform into a production-ready environment. By combining authentication, IAM policies, and network controls, you create defense-in-depth security that protects your services at multiple layers. Custom domains complete the picture, giving your services the professional appearance and memorability that users expect.

In the next unit, you'll explore logging, monitoring, and debugging—the operational skills you need to maintain and troubleshoot these secured services in production. You'll learn how to use Cloud Logging to diagnose issues, Cloud Monitoring to track performance, and systematic debugging approaches to resolve problems quickly when they arise.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal