> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage Permissions Logging

### More Info:

Ensures that logging and log alerts exist for storage permission changes. Storage permissions include access to the buckets that store the logs, any changes in storage permissions should be heavily monitored to prevent unauthorized changes.

### Risk Level

High

### Address

Security

### Compliance Standards

HIPAA PCI

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Using Console" defaultOpen="true">
        To fix “Storage Permissions Logging” for Google Cloud Storage using the GCP Console, you essentially need to ensure that Cloud Audit Logs (especially **Data Access** logs) are enabled for Google Cloud Storage and that they are being routed to a log destination you retain.

        Below are the step‑by‑step instructions in the Console.

        ***

        ### 1. Enable Audit Logs for Google Cloud Storage

        1. Sign in to the **Google Cloud Console**.
        2. Make sure you have selected the **correct project** (top-left project selector).
        3. In the left navigation menu, go to:\
           **IAM & Admin → Audit Logs**.
        4. In the “Audit Logs” page:
           * In the **Service** list, locate and select:\
             **“Cloud Storage”** (sometimes listed as **“Storage”** or **“storage.googleapis.com”**).
        5. You will see log types for this service:
           * **Admin Read**
           * **Admin Write**
           * **Data Read**
           * **Data Write**
        6. For comprehensive permissions logging:
           * Check **Admin Read** and **Admin Write** (if not already enabled).
           * Check **Data Read** and **Data Write** (these are typically off by default and are crucial for object/permission access logging).
        7. Click **Save** at the bottom of the page.

        > This ensures that actions on buckets/objects and permission changes are written to Cloud Audit Logs.

        ***

        ### 2. Verify Logs Are Being Stored (Log Router / Sinks)

        Audit logs automatically go to **Cloud Logging**, but compliance often requires storing them longer (e.g., in a bucket, BigQuery, or Pub/Sub). To route them properly:

        1. In the left navigation menu, go to:\
           **Logging → Logs Router**.
        2. Look for an existing **sink** that captures audit logs (especially from `cloudaudit.googleapis.com`).
           * If one exists and routes to a storage bucket/BigQuery with sufficient retention for your requirements, you may not need to change anything.
        3. To create a dedicated sink (if needed):
           * Click **Create sink**.
           * **Sink name**: e.g., `gcs-audit-logs-sink`.
           * **Sink destination**: choose one, commonly:
             * **Cloud Storage bucket** (recommended for archive),
             * or **BigQuery** (for querying),
             * or **Pub/Sub** (for streaming/forwarding).
           * Click **Next**.
        4. **Choose logs to include**:
           * Under “Choose logs to include in the sink”, set a filter such as:
             ```text theme={null}
             logName:"cloudaudit.googleapis.com" 
             protoPayload.serviceName="storage.googleapis.com"
             ```
           * This captures Storage audit logs (including permission changes and access).
        5. Click **Create sink**.

        ***

        ### 3. Confirm Logs for Storage Permissions Are Appearing

        1. Go to **Logging → Logs Explorer**.
        2. In the query box, use a filter like:
           ```text theme={null}
           resource.type="gcs_bucket"
           logName:"cloudaudit.googleapis.com"
           ```
        3. Click **Run query**.
        4. Inspect entries:
           * Look for `protoPayload.methodName` values related to IAM or ACL changes (e.g., `storage.setIamPermissions`, `storage.objects.get`, `storage.buckets.update`, etc.).
           * Confirm that these actions on your buckets are being logged.

        ***

        ### 4. (Optional) Narrow to a Specific Bucket / Project

        If the misconfiguration is flagged for a specific bucket:

        1. In the **Logs Explorer** query, further filter:
           ```text theme={null}
           resource.type="gcs_bucket"
           resource.labels.bucket_name="YOUR_BUCKET_NAME"
           logName:"cloudaudit.googleapis.com"
           ```
        2. Confirm that both:
           * Permission changes (`setIamPolicy`, `update`), and
           * Access operations (`get`, `list`, `insert`, etc.)\
             are present.

        ***

        Once you have:

        * Enabled **Admin** and **Data Access** audit logs for **Cloud Storage** in IAM & Admin → Audit Logs, and
        * Ensured they are routed and stored via a **Logs Router sink**,

        the “Storage Permissions Logging” finding for GCP Storage should be remediated.
      </Accordion>

      <Accordion title="Using CLI">
        Below are concise, CLI‑only steps to enable Storage permissions logging (audit logging for Cloud Storage IAM & access) in GCP.

        ### 1. Set project ID

        ```bash theme={null}
        PROJECT_ID="your-project-id"
        gcloud config set project "$PROJECT_ID"
        ```

        ### 2. Export current IAM policy

        ```bash theme={null}
        gcloud projects get-iam-policy "$PROJECT_ID" \
          --format=json > iam-policy.json
        ```

        ### 3. Edit IAM policy to add audit logging for Cloud Storage

        Open `iam-policy.json` in an editor and add / merge this `auditConfigs` block at the top level (alongside `bindings`):

        ```json theme={null}
        "auditConfigs": [
          {
            "service": "storage.googleapis.com",
            "auditLogConfigs": [
              {
                "logType": "ADMIN_READ"
              },
              {
                "logType": "DATA_READ"
              },
              {
                "logType": "DATA_WRITE"
              }
            ]
          }
        ]
        ```

        Notes:

        * If `auditConfigs` already exists, just append or merge the `storage.googleapis.com` entry into the array.
        * Keep the rest of the file unchanged.

        ### 4. Apply the updated IAM policy

        ```bash theme={null}
        gcloud projects set-iam-policy "$PROJECT_ID" iam-policy.json
        ```

        This enables:

        * ADMIN\_READ logs: IAM / permission changes on Cloud Storage.
        * DATA\_READ logs: reads of bucket/objects.
        * DATA\_WRITE logs: writes/deletes of bucket/objects.

        ### 5. (Optional) Verify audit logs

        Use Cloud Logging to confirm logs are being generated:

        ```bash theme={null}
        gcloud logging read \
          'logName:"cloudaudit.googleapis.com" AND resource.type="gcs_bucket"' \
          --limit=10 --format="table(timestamp, protoPayload.methodName, resource.labels.bucket_name)"
        ```

        This remediates the “Storage Permissions Logging” gap by ensuring Cloud Storage access and permission changes are captured via Cloud Audit Logs.
      </Accordion>

      <Accordion title="Using Python">
        Below is how to remediate “Storage Permissions Logging” for a Google Cloud Storage bucket using Python, assuming the finding means “bucket access logging is not enabled”.

        ### 1. Prerequisites

        1. Install the client library:
           ```bash theme={null}
           pip install google-cloud-storage
           ```
        2. Authenticate:
           ```bash theme={null}
           gcloud auth application-default login
           ```
        3. Ensure your service account / ADC has `storage.buckets.update` on the target bucket and `storage.buckets.get` on the log bucket.

        ***

        ### 2. Create (or choose) a logging bucket

        You need a separate bucket to receive access logs.

        ```python theme={null}
        from google.cloud import storage

        def create_bucket_if_not_exists(project_id: str, bucket_name: str, location: str = "US"):
            storage_client = storage.Client(project=project_id)
            bucket = storage_client.bucket(bucket_name)
            if not bucket.exists():
                bucket.storage_class = "STANDARD"
                bucket.location = location
                bucket = storage_client.create_bucket(bucket)
                print(f"Created log bucket {bucket.name}")
            else:
                print(f"Log bucket {bucket.name} already exists")
            return bucket

        project_id = "YOUR_PROJECT_ID"
        log_bucket_name = "my-project-storage-logs"

        create_bucket_if_not_exists(project_id, log_bucket_name)
        ```

        ***

        ### 3. Grant write permission for logging

        GCS uses a special writer identity to store logs: `cloud-storage-analytics@google.com`\
        Grant it `roles/storage.objectCreator` on the log bucket.

        ```python theme={null}
        from google.cloud import storage

        def allow_logging_writer_on_log_bucket(log_bucket_name: str):
            storage_client = storage.Client()
            bucket = storage_client.bucket(log_bucket_name)
            bucket.iam_configuration.uniform_bucket_level_access_enabled = True
            bucket.patch()

            policy = bucket.get_iam_policy(requested_policy_version=3)
            role = "roles/storage.objectCreator"
            member = "group:cloud-storage-analytics@google.com"
            if member not in policy.get(role, []):
                policy[role].add(member)
                bucket.set_iam_policy(policy)
                print(f"Granted {role} to {member} on {log_bucket_name}")
            else:
                print(f"{member} already has {role} on {log_bucket_name}")

        log_bucket_name = "my-project-storage-logs"
        allow_logging_writer_on_log_bucket(log_bucket_name)
        ```

        ***

        ### 4. Enable logging on the source bucket

        This sets the log destination bucket and an optional log object prefix.

        ```python theme={null}
        from google.cloud import storage

        def enable_bucket_access_logging(
            source_bucket_name: str,
            log_bucket_name: str,
            log_object_prefix: str = "access_logs/"
        ):
            storage_client = storage.Client()
            bucket = storage_client.bucket(source_bucket_name)

            bucket.logging = {
                "logBucket": log_bucket_name,
                "logObjectPrefix": log_object_prefix,
            }
            bucket.patch()
            print(
                f"Enabled access logging for {source_bucket_name} "
                f"to {log_bucket_name} with prefix '{log_object_prefix}'"
            )

        source_bucket_name = "my-app-data-bucket"
        log_bucket_name = "my-project-storage-logs"

        enable_bucket_access_logging(source_bucket_name, log_bucket_name)
        ```

        ***

        ### 5. Verify configuration

        ```python theme={null}
        from google.cloud import storage

        def show_logging_config(bucket_name: str):
            storage_client = storage.Client()
            bucket = storage_client.bucket(bucket_name)
            bucket.reload()
            print("Logging configuration:", bucket.logging)

        show_logging_config("my-app-data-bucket")
        ```

        You should see something like:

        ```python theme={null}
        {'logBucket': 'my-project-storage-logs', 'logObjectPrefix': 'access_logs/'}
        ```

        If your tool checks multiple buckets, loop over all non-logging buckets and call `enable_bucket_access_logging` for each.
      </Accordion>

      <Accordion title="Using Terraform">
        ```hcl theme={null}
        resource "google_storage_bucket" "app_data" {
          name          = "APP_DATA_BUCKET_NAME"          # replace with your data bucket name
          location      = "BUCKET_LOCATION"               # e.g. "US"
          storage_class = "STANDARD"

          # ...other settings...

          # Enable access logging for this bucket
          logging {
            log_bucket        = google_storage_bucket.app_data_logs.name
            log_object_prefix = "ACCESS_LOG_PREFIX"       # e.g. "gcs-access/"
          }
        }

        # Dedicated bucket to receive access logs
        resource "google_storage_bucket" "app_data_logs" {
          name          = "APP_DATA_LOG_BUCKET_NAME"      # replace with your log bucket name
          location      = "BUCKET_LOCATION"               # usually same region
          storage_class = "STANDARD"

          uniform_bucket_level_access = true

          # Optionally restrict public access, add lifecycle rules, etc.
        }
        ```

        Enabling the `logging` block does not force replacement of the existing bucket; Terraform will show an in-place update on `google_storage_bucket.app_data` adding `logging.log_bucket` and `logging.log_object_prefix`, and creation of `google_storage_bucket.app_data_logs` if it does not yet exist.
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>

### Additional Reading:

* [https://cloud.google.com/logging/docs/logs-based-metrics/](https://cloud.google.com/logging/docs/logs-based-metrics/)
