Skip to main content

GCP Cloud Function Should Not Have Admin Access

More Info:

Ensure that the Cloud Function users do not have administrative privileges

Risk Level

Critical

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • HIPAA
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • NIS2 Directive
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • PCI
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Using Console

To remediate the misconfiguration in GCP where a Cloud Function has admin access, you can follow the below steps:

  1. Open the Google Cloud Console and navigate to the Cloud Functions page.

  2. Select the Cloud Function that has admin access.

  3. Click on the "Edit" button on the top of the page.

  4. Scroll down to the "Roles" section and click on the "Add Member" button.

  5. In the "New Member" field, enter the email address of the service account that you want to use to run the Cloud Function.

  6. In the "Role" field, select the "Cloud Functions Invoker" role from the drop-down menu.

  7. Click on the "Save" button to save the changes.

  8. Verify that the service account has the "Cloud Functions Invoker" role by navigating to the "IAM & Admin" page and selecting the "IAM" tab.

  9. Find the service account that you added and verify that it has the "Cloud Functions Invoker" role assigned to it.

By following these steps, you can remediate the misconfiguration in GCP where a Cloud Function has admin access.

Using CLI

To remediate the misconfiguration of a GCP Cloud Function having admin access, you can follow the below steps using GCP CLI:

  1. Open the Cloud Console and navigate to the Cloud Functions section.

  2. Identify the Cloud Function that has admin access.

  3. Determine the IAM policy bindings for the Cloud Function:

gcloud functions describe FUNCTION_NAME --format="value(iamPolicy)"

Replace FUNCTION_NAME with the name of your Cloud Function.

  1. Review the IAM policy bindings to identify any roles with admin access.

  2. Remove the admin role from the IAM policy bindings:

gcloud functions remove-iam-policy-binding FUNCTION_NAME \
--member=MEMBER \
--role=ROLE

Replace FUNCTION_NAME with the name of your Cloud Function, MEMBER with the email address of the user or service account that has admin access, and ROLE with the admin role (e.g., roles/cloudfunctions.admin).

  1. Verify that the admin role has been removed from the IAM policy bindings:
gcloud functions describe FUNCTION_NAME --format="value(iamPolicy)"
  1. Once the changes are saved, verify that the user or service account no longer has admin access by testing the function.

By following these steps, you can remediate the misconfiguration of a GCP Cloud Function having admin access using the GCP CLI, ensuring that the function has the appropriate access level to perform its intended function.

Using Python

To remediate the issue of a GCP Cloud Function having admin access, follow these steps:

  1. Open the Cloud Functions page in the GCP console.
  2. Select the Cloud Function that has admin access.
  3. Click on the "Edit" button to modify the function.
  4. In the "Permissions" section, click on "Add Member".
  5. Enter the email address of the user or service account that you want to grant access to the function.
  6. In the "Role" dropdown menu, select a role that does not have admin access, such as "Cloud Functions Developer" or "Cloud Functions Viewer".
  7. Click "Save" to apply the changes.

Here is an example Python script that can be used to remove admin access from a GCP Cloud Function:

import google.auth
from google.cloud import functions_v1
from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials

# Authenticate using the default credentials
creds, project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform"])
creds.refresh(Request())

# Initialize the Cloud Functions client
client = functions_v1.CloudFunctionsServiceClient(credentials=creds)

# Set the name of the Cloud Function that needs to be updated
function_name = "my-function"

# Get the current IAM policy for the function
resource = f"projects/{project_id}/locations/us-central1/functions/{function_name}"
policy = client.get_iam_policy(request={"resource": resource})

# Remove the "roles/cloudfunctions.admin" role from all members
for binding in policy.bindings:
if binding.role == "roles/cloudfunctions.admin":
binding.members.remove("allUsers")
binding.members.remove("allAuthenticatedUsers")
binding.members = [m for m in binding.members if not m.startswith("user:") and not m.startswith("serviceAccount:")]

# Update the IAM policy for the function
client.set_iam_policy(request={"resource": resource, "policy": policy})

This script uses the google-cloud-functions library to authenticate using the default credentials and update the IAM policy for the specified Cloud Function. It removes the "roles/cloudfunctions.admin" role from all members and updates the policy accordingly.

Using Terraform
# Cloud Function definition (replace placeholders with your values)
resource "google_cloudfunctions_function" "CLOUD_FUNCTION" {
name = "CLOUD_FUNCTION_NAME" # e.g. "my-function"
project = "GCP_PROJECT_ID" # e.g. "my-project"
region = "GCP_REGION" # e.g. "us-central1"
runtime = "RUNTIME" # e.g. "python311"
entry_point = "ENTRY_POINT" # e.g. "handler"

source_archive_bucket = "SOURCE_BUCKET_NAME"
source_archive_object = "SOURCE_ARCHIVE_OBJECT"

trigger_http = true
}

# REMOVE any existing IAM bindings/members that grant admin-level roles to users,
# such as:
# roles/owner
# roles/editor
# roles/cloudfunctions.admin
# roles/iam.serviceAccountAdmin
# roles/resourcemanager.projectIamAdmin
#
# Example of what to DELETE (if you have something like this):
#
# resource "google_cloudfunctions_function_iam_binding" "admin_binding" {
# project = google_cloudfunctions_function.CLOUD_FUNCTION.project
# region = google_cloudfunctions_function.CLOUD_FUNCTION.region
# cloud_function = google_cloudfunctions_function.CLOUD_FUNCTION.name
# role = "roles/cloudfunctions.admin"
# members = [
# "user:ADMIN_USER_EMAIL",
# ]
# }

# Replace admin-level access with a least-privilege role, typically just
# "roles/cloudfunctions.invoker" for callers of the function.
resource "google_cloudfunctions_function_iam_binding" "invoker_binding" {
project = google_cloudfunctions_function.CLOUD_FUNCTION.project
region = google_cloudfunctions_function.CLOUD_FUNCTION.region
cloud_function = google_cloudfunctions_function.CLOUD_FUNCTION.name

role = "roles/cloudfunctions.invoker"

members = [
"user:END_USER_EMAIL", # replace with the user who should invoke
# or "serviceAccount:CALLER_SA_EMAIL"
# or "allUsers" if you intentionally want public HTTP access
]
}

This change does not force replacement of the Cloud Function itself; it only updates IAM bindings on it.

For verification, terraform plan should show any google_cloudfunctions_function_*_iam_* resources with admin-level roles being destroyed or having their role changed, and a (replacement or new) IAM binding with role = "roles/cloudfunctions.invoker" (or another non‑admin, least‑privilege role) attached to the same function.

Additional Reading: