gcp

Realtime GCP assets and access monitoring using Cloud Asset Monitor and Cloud Log Streaming

2022-05-12

A set of scripts that allows you to monitor specific resources in real time for changes in IAM Policies or generic changes to a GCP Resource

Users normally monitor resource changes by exporting Google Cloud Audit Logs in its various flavors.

What if you wanted to directly monitor a specific set of high-value resources and see who accessed what when and what changes to those resources were made?

With the logs export and audit logs, there’s necessarily some latency in doing that and you’d have to find and parse that specific resource in that noise of logs.

What if you can tap the API and stream the data live to your client? That way, you can immediately view the necessary data while filtering out the noise.

Why would you want to do that?

Well, maybe you want to discretely and actively monitor a specific high-value resource?

Maybe you want to help debug access issues and see who is being allowed or denied access over a window? You can use the access logs to help troubleshoot since you can generally see iam permissions that were in play for access decisions live.

What is outlined here is two ways you can tap traffic/usage for a specific resource.

We will use two techniques here:

  1. Using Audit Logs Streaming API

    This will stream GCP AuditLogs with a specific filter to your client.
    This is using Streaming and live tailing log entries feature.

  2. Using Asset Inventory Feed API

    This creates a pubsub topic where changes to a named resource is sent as individual PubSub Messages.
    The client consumer read the mutations on the Assets live.
    Technique uses the features described here: Monitoring asset changes

Note, this is not a generic, scalable way to monitor all resources but its geared towards specific ones you discretely want to monitor.

Audit log and feed streaming

Setup

The set of steps will configure a project with a GCS bucket and PubSub Topic to monitor using both techniques.

For 1 we will need to enable data_access logs for GCS and PubSub.

For 2 we will enable and use Asset Inventory and Cloud Resource Manager APIs (of course). We will have to create a target topic for the feeds to get written to and then use a subscriber to read from the topic.

First enable some apis in a new project

export PROJECT_ID=`gcloud config get-value core/project`
export PROJECT_NUMBER=`gcloud projects describe $PROJECT_ID --format='value(projectNumber)'`
export GCLOUD_USER=`gcloud config get-value core/account`

gcloud services enable policyanalyzer.googleapis.com cloudasset.googleapis.com cloudresourcemanager.googleapis.com

Create a topic and gcs bucket you want to minitor:

# create a topic to monitor iam changes
gcloud pubsub topics create mytopic

# create a bucket to monitor resource changes
gsutil mb  gs://$PROJECT_ID-trace
gsutil bucketpolicyonly set on gs://$PROJECT_ID-trace

Configure the data_access logs for gcs and pubsub per configure data access logs

export the existing policy

gcloud projects get-iam-policy $PROJECT_ID > /tmp/policy.yaml

Then add the just the auditConfigs to /tmp/policy.yaml files (of course keep the etag and existing bindings)

auditConfigs:
- auditLogConfigs:
  - logType: ADMIN_READ
  - logType: DATA_WRITE
  - logType: DATA_READ
  service: storage.googleapis.com
- auditLogConfigs:
  - logType: ADMIN_READ
  - logType: DATA_WRITE
  - logType: DATA_READ
  service: pubsub.googleapis.com
bindings:
- members:
  - user:you@yourdomain.com
  role: roles/owner
etag: [your_etag_value]
version: 1

now apply

gcloud projects set-iam-policy $PROJECT_ID /tmp/policy.yaml

Streaming live Audit Logs

To stream audit logs, its just a matter of creating the audit configs above and then creating a gRPC Streaming client.

For the client, we will use a modified version of the sample provided in the official docs that keeps the stream perpetually open.

Just note that even in audit logs, the authentication data is missing from certain log types. For example, if a user in any other domain is denied IAM access on a GET request to GCS, then the authentication information is redacted in the logs. For more information on the redaction, see Caller identities in audit logs

Now that we’re done configuring the audit logs, we will configure the asset inventory stuff

Asset Inventory Feed

For the asset monitoring, we will use…well..just this:

# create a topic to monitor
gcloud pubsub topics create mytopic

# create a feed topic
gcloud pubsub topics create myfeed

# create a subscription to send the asset changes to
gcloud pubsub subscriptions create mysub --topic=myfeed

# create feed for iam-policy changes onpubsub
gcloud asset feeds create pubsubfeed --project=$PROJECT_ID \
  --asset-names="//pubsub.googleapis.com/projects/$PROJECT_ID/topics/mytopic"  \
  --content-type=iam-policy  --asset-types="pubsub.googleapis.com/Topic"  \
   --pubsub-topic="projects/$PROJECT_ID/topics/myfeed"

# create a feed for GCS resource changes
gcloud asset feeds create gcsfeed --project=$PROJECT_ID \
  --asset-names="//storage.googleapis.com/$PROJECT_ID-trace"  \
  --content-type=resource --asset-types="storage.googleapis.com/Bucket"  \
   --pubsub-topic="projects/$PROJECT_ID/topics/myfeed"

Note that we’re creating two feeds into one topic:

  • --content-type=iam-policy for pubsub to catch iam changes
  • --content-type=resource for gcs to catch asset mutations

When you create an asset feed, google places some text test data into the topic to confirm that the feed is setup.

so…we need to clear that out (since my code doens’t do error handling)

Repeatedly run the following…(maybe 6 times to flush out and ack the two messages google kindly place there)

gcloud pubsub subscriptions pull mysub --auto-ack 

Test

Subscribe to the asset inventory feed

cd asset_inventory_feed/

go run main.go --projectID=$PROJECT_ID --subscription=mysub

in a new window, tail audit log:

cd audit_log_tail
go run main.go --projectID $PROJECT_ID

Test PubSub IAM

Now we’re finally ready to test.

Pick two people in your domain (i used alice@ and bob@ by convention)

gcloud pubsub topics add-iam-policy-binding mytopic --member=user:alice@yourdomain.com --role=roles/pubsub.publisher
gcloud pubsub topics add-iam-policy-binding mytopic --member=user:bob@yourdomain.com --role=roles/pubsub.publisher

What you’ll see in the audit log stream are a pair of [GetIamPolicy, SetIamPolicy] for each operation above.

Notice the members below which shows the mutation that occured

  • AuditLog
Entry: tp27wsc6v6
   MethodName: google.iam.v1.IAMPolicy.GetIamPolicy
   AuthenticationInfo: principal_email:"admin@yourdomain.com" principal_subject:"user:admin@yourdomain.com"
   Authorization: [resource:"projects/mproject-349418/topics/mytopic" permission:"pubsub.topics.getIamPolicy" granted:true resource_attributes:{}]
   @type type.googleapis.com/google.iam.v1.GetIamPolicyRequest
   google.iam.v1.GetIamPolicyRequest resource:"projects/mproject-349418/topics/mytopic"

Entry: 1n3uf2jcepi
   MethodName: google.iam.v1.IAMPolicy.SetIamPolicy
   AuthenticationInfo: principal_email:"admin@yourdomain.com" principal_subject:"user:admin@yourdomain.com"
   Authorization: [resource:"projects/mproject-349418/topics/mytopic" permission:"pubsub.topics.setIamPolicy" granted:true resource_attributes:{}]
   @type type.googleapis.com/google.iam.v1.SetIamPolicyRequest
   google.iam.v1.SetIamPolicyRequest resource:"projects/mproject-349418/topics/mytopic" 
     policy:{
       bindings:{
           role:"roles/pubsub.publisher" 
           members:"user:alice@yourdomain.com"
         } 
       etag:"\x07\x05޳\xd7f!\x9a"
     }

Entry: 1fw6otac34g
   MethodName: google.iam.v1.IAMPolicy.GetIamPolicy
   AuthenticationInfo: principal_email:"admin@yourdomain.com" principal_subject:"user:admin@yourdomain.com"
   Authorization: [resource:"projects/mproject-349418/topics/mytopic" permission:"pubsub.topics.getIamPolicy" granted:true resource_attributes:{}]
   @type type.googleapis.com/google.iam.v1.GetIamPolicyRequest
   google.iam.v1.GetIamPolicyRequest resource:"projects/mproject-349418/topics/mytopic"

Entry: 8vznkqd11gl
   MethodName: google.iam.v1.IAMPolicy.SetIamPolicy
   AuthenticationInfo: principal_email:"admin@yourdomain.com" principal_subject:"user:admin@yourdomain.com"
   Authorization: [resource:"projects/mproject-349418/topics/mytopic" permission:"pubsub.topics.setIamPolicy" granted:true resource_attributes:{}]
  @type type.googleapis.com/google.iam.v1.SetIamPolicyRequest
  google.iam.v1.SetIamPolicyRequest resource:"projects/mproject-349418/topics/mytopic" 
    policy:{
        bindings:{
             role:"roles/pubsub.publisher" 
             members:"user:alice@yourdomain.com" 
             members:"user:bob@yourdomain.com"  <<<<<<<<<<<<<<<<
        } 
        etag:"\x07\x05޳\xd8`]\xe1"
    }

images/pubsublog.png

Now look at the output of the subscription.

The Prior Asset and Asset describes, as the name suggests, the state of the Asset before and after.

Notice that for the operation above we suddenly see the Asset include alice and bob successively.

  • Asset Feed
Prior Asset 
  update_time:{seconds:1652238877  nanos:860250000}  
    name:"//pubsub.googleapis.com/projects/mproject-349418/topics/mytopic"  
    asset_type:"pubsub.googleapis.com/Topic"  
    iam_policy:{etag:"\x07\x05޳\xd7f!\x9a"}  <<<<<<<<<<<<<<<<
    ancestors:"projects/300824348137"  ancestors:"organizations/673208786098"

Asset
  update_time:{seconds:1652238894  nanos:259681000}  
    name:"//pubsub.googleapis.com/projects/mproject-349418/topics/mytopic"  
    asset_type:"pubsub.googleapis.com/Topic"  
    iam_policy:{
      bindings:{role:"roles/pubsub.publisher"  
      members:"user:alice@yourdomain.com"  <<<<<<<<<<<<<<<<
    }  
    etag:"\x07\x05޳\xd8`]\xe1"}  
    ancestors:"projects/300824348137"  ancestors:"organizations/673208786098"



Prior Asset 
  update_time:{seconds:1652238894  nanos:259681000}  
    name:"//pubsub.googleapis.com/projects/mproject-349418/topics/mytopic"  
    asset_type:"pubsub.googleapis.com/Topic"  
    iam_policy:{
      bindings:{role:"roles/pubsub.publisher"  
      members:"user:alice@yourdomain.com" <<<<<<<<<<<<<<<<
    }   
    etag:"\x07\x05޳\xd8`]\xe1"}  
    ancestors:"projects/300824348137"  ancestors:"organizations/673208786098"

Asset 
  update_time:{seconds:1652238915  nanos:557776000}  
    name:"//pubsub.googleapis.com/projects/mproject-349418/topics/mytopic"  
    asset_type:"pubsub.googleapis.com/Topic"  
    iam_policy:{
      bindings:{role:"roles/pubsub.publisher"  
      members:"user:alice@yourdomain.com"  
      members:"user:bob@yourdomain.com"  <<<<<<<<<<<<<<<<
    }
    etag:"\x07\x05޳٥Y\x90"}  
    ancestors:"projects/300824348137"  ancestors:"organizations/673208786098"

Nice!, we’ve just captures IAM changes in a log stream and in asset feeds.

Test GCS Asset Change

Now change the actual asset instead of the IAM permissions..for gcs change the storage class:

gsutil defstorageclass set nearline gs://$PROJECT_ID-trace
gsutil defstorageclass set standard gs://$PROJECT_ID-trace
  • AuditLog

The auditlog feed should show you the specific class change (i’m just showing the final state).

Entry: -mgz3j8e54pud
   MethodName: storage.buckets.update
   AuthenticationInfo: principal_email:"admin@yourdomain.com"
   Authorization: [resource:"projects/_/buckets/mproject-349418-trace" permission:"storage.buckets.update" granted:true resource_attributes:{}]
   @type type.googleapis.com/google.storage.v1.UpdateBucketRequest
   google.storage.v1.UpdateBucketRequest bucket:"mproject-349418-trace"  
     projection:NO_ACL  
     metadata:{
      id:"mproject-349418-trace"  
      name:"mproject-349418-trace"  
      storage_class:"STANDARD"   <<<<<<<<<<<<<<<<
    }


Entry: tozf2ce3m5xu
   MethodName: storage.objects.list
   AuthenticationInfo: principal_email:"admin@yourdomain.com"
   Authorization: [resource:"projects/_/buckets/mproject-349418-trace" permission:"storage.objects.list" granted:true resource_attributes:{}]
   @type type.googleapis.com/google.storage.v1.ListObjectsRequest
   google.storage.v1.ListObjectsRequest bucket:"mproject-349418-trace"  projection:NO_ACL

images/gcslog.png

(Theres also a storage.objects.list…i just think thats an extra call by gsutil or maybe internal call for some reason..)

  • Asset Inventory Feed

The asset feed will also show the change…but this will show the Prior Asset and the current Asset.

You can use these two values to determine the deltas you are intersted in

Prior Asset 
  update_time:{seconds:1652267486  nanos:301000000}  
    name:"//storage.googleapis.com/mproject-349418-trace"  
    asset_type:"storage.googleapis.com/Bucket"  
    resource:{version:"v1"  
    discovery_document_uri:"https://www.googleapis.com/discovery/v1/apis/storage/v1/rest"  
    discovery_name:"Bucket"  
    parent:"//cloudresourcemanager.googleapis.com/projects/300824348137"  
    data:
      {
      fields:{key:"acl"  value:{list_value:{}}}  
      fields:{key:"autoclass"  value:{struct_value:{}}}  
      fields:{key:"billing"  value:{struct_value:{}}}  
      fields:{key:"cors"  value:{list_value:{}}}  
      fields:{key:"defaultObjectAcl"  value:{list_value:{}}}  
      fields:{key:"encryption"  value:{struct_value:{}}}  
      fields:{key:"etag"  value:{string_value:"CLgB"}}  
      fields:{key:"iamConfiguration"  value: { struct_value:{fields:{key:"bucketPolicyOnly"  value:{struct_value:{fields:{key:"enabled"  value:{bool_value:true}}  fields:{key:"lockedTime"  value:{string_value:"2022-08-04T18:43:25.239Z"}}}}}  fields:{key:"publicAccessPrevention"  value:{string_value:"inherited"}}  fields:{key:"uniformBucketLevelAccess"  value:{struct_value:{fields:{key:"enabled"  value:{bool_value:true}}  fields:{key:"lockedTime"  value:{string_value:"2022-08-04T18:43:25.239Z"}}}}}}}}  fields:{key:"id"  value:{string_value:"mproject-349418-trace"}}  fields:{key:"kind"  value:{string_value:"storage#bucket"}}  fields:{key:"labels"  value:{struct_value:{}}}  fields:{key:"lifecycle"  value:{struct_value:{fields:{key:"rule"  value:{list_value:{}}}}}}  fields:{key:"location"  value:{string_value:"US"}}  fields:{key:"locationType"  value:{string_value:"multi-region"}}  fields:{key:"logging"  value:{struct_value:{}}}  fields:{key:"metageneration"  value:{number_value:184}}  fields:{key:"name"  value:{string_value:"mproject-349418-trace"}}  fields:{key:"owner"  value:{struct_value:{}}}  fields:{key:"projectNumber"  value:{number_value:3.00824348137e+11}}  fields:{key:"retentionPolicy"  value:{struct_value:{}}}  fields:{key:"selfLink"  value:{string_value:"https://www.googleapis.com/storage/v1/b/mproject-349418-trace"}}  
      
      fields:{key:"storageClass"  value:{string_value:"NEARLINE"}}  <<<<<<<<<<<<<<<<
      
      fields:{key:"timeCreated"  value:{string_value:"2022-05-06T18:43:20.026Z"}}  fields:{key:"updated"  value:{string_value:"2022-05-11T11:11:26.301Z"}}  fields:{key:"versioning"  value:{struct_value:{}}}  fields:{key:"website"  value:{struct_value:{}}}}  location:"us"}  ancestors:"projects/300824348137"  ancestors:"organizations/673208786098"

Asset 
  update_time:{seconds:1652267707  nanos:34000000}  
    name:"//storage.googleapis.com/mproject-349418-trace"  
    asset_type:"storage.googleapis.com/Bucket"  
    resource:{version:"v1"  
    discovery_document_uri:"https://www.googleapis.com/discovery/v1/apis/storage/v1/rest"  
    discovery_name:"Bucket"  
    parent:"//cloudresourcemanager.googleapis.com/projects/300824348137"  
    data: 
      {
        fields:{key:"acl"  value:{list_value:{}}}  
        fields:{key:"autoclass"  value:{struct_value:{}}}  
        fields:{key:"billing"  value:{struct_value:{}}}  
        fields:{key:"cors"  value:{list_value:{}}}  
        fields:{key:"defaultObjectAcl"  value:{list_value:{}}}  
        fields:{key:"encryption"  value:{struct_value:{}}}  
        fields:{key:"etag"  value:{string_value:"CLkB"}}  
        fields:{key:"iamConfiguration"  value:{struct_value:{fields:{key:"bucketPolicyOnly"  value:{struct_value:{fields:{key:"enabled"  value:{bool_value:true}}  fields:{key:"lockedTime"  value:{string_value:"2022-08-04T18:43:25.239Z"}}}}}  fields:{key:"publicAccessPrevention"  value:{string_value:"inherited"}}  fields:{key:"uniformBucketLevelAccess"  value:{struct_value:{fields:{key:"enabled"  value:{bool_value:true}}  fields:{key:"lockedTime"  value:{string_value:"2022-08-04T18:43:25.239Z"}}}}}}}}  fields:{key:"id"  value:{string_value:"mproject-349418-trace"}}  fields:{key:"kind"  value:{string_value:"storage#bucket"}}  fields:{key:"labels"  value:{struct_value:{}}}  fields:{key:"lifecycle"  value:{struct_value:{fields:{key:"rule"  value:{list_value:{}}}}}}  fields:{key:"location"  value:{string_value:"US"}}  fields:{key:"locationType"  value:{string_value:"multi-region"}}  fields:{key:"logging"  value:{struct_value:{}}}  fields:{key:"metageneration"  value:{number_value:185}}  fields:{key:"name"  value:{string_value:"mproject-349418-trace"}}  fields:{key:"owner"  value:{struct_value:{}}}  fields:{key:"projectNumber"  value:{number_value:3.00824348137e+11}}  fields:{key:"retentionPolicy"  value:{struct_value:{}}}  fields:{key:"selfLink"  value:{string_value:"https://www.googleapis.com/storage/v1/b/mproject-349418-trace"}}  
        
        fields:{key:"storageClass"  value:{string_value:"STANDARD"}}  <<<<<<<<<<<<<<<<
        
        fields:{key:"timeCreated"  value:{string_value:"2022-05-06T18:43:20.026Z"}}  fields:{key:"updated"  value:{string_value:"2022-05-11T11:15:07.034Z"}}  fields:{key:"versioning"  value:{struct_value:{}}}  fields:{key:"website"  value:{struct_value:{}}}}  location:"us"}  ancestors:"projects/300824348137"  ancestors:"organizations/673208786098"

Done…we’ve captured the mutations on a resource in two ways.

If you’re interested, try out the code and if you meet me somewhere, buy me an IPA.

References

While its not realtime, see: Cloud Run Eventarc using Cloud Events SDK

Code

Streaming live Audit Logs

The streaming api is pretty much the standard code shown in google’s official docs. The only change i made was to not close the request stream..that act left the stream open for N responses sent down by the server.

I also had to manually parse each audit log Request and Response type for the API’s in question. Its really awkward and only covers a few apis…the recommendation is for you to add on the methods you are interested in.

Asset Inventory Feed

The Asset Feed sends back an TemporalAsset which critically shows the Asset in the current and Prior state. The idea is you can use that to do what you need to see the deltas.

The code snippet just prints the output

		a := &assetpb.TemporalAsset{}
		err := protojson.Unmarshal(msg.Data, a)
		if err != nil {
			fmt.Println("Error in JSON unmarshalling from json marshalled object:", err)
			return
		}
		fmt.Printf("Prior Asset %v\n", a.PriorAsset)
		fmt.Printf("Asset %v\n", a.Asset)

AuditLogs

The following shows the raw audit logs for a sample call for both pubsub and GCS. You can use this to figure out which fields you are interested in subscribing or parsing.

PubSub

  • "google.iam.v1.IAMPolicy.GetIamPolicy"
{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "authenticationInfo": {
      "principalEmail": "admin@yourdomain.com",
      "principalSubject": "user:admin@yourdomain.com"
    },
    "requestMetadata": {
      "callerIp": "72.83.11.111",
      "callerSuppliedUserAgent": "google-cloud-sdk gcloud/382.0.0 command/gcloud.pubsub.topics.add-iam-policy-binding invocation-id/44e0f2ba52a34ffeb0524d48de794e62 environment/None environment-version/None interactive/True from-script/False python/3.9.10 term/xterm-256color (Linux 5.16.18-1rodete2-amd64),gzip(gfe)",
      "requestAttributes": {
        "time": "2022-05-11T03:14:53.707738857Z",
        "auth": {}
      },
      "destinationAttributes": {}
    },
    "serviceName": "pubsub.googleapis.com",
    "methodName": "google.iam.v1.IAMPolicy.GetIamPolicy",
    "authorizationInfo": [
      {
        "resource": "projects/mproject-349418/topics/mytopic",
        "permission": "pubsub.topics.getIamPolicy",
        "granted": true,
        "resourceAttributes": {}
      }
    ],
    "resourceName": "projects/mproject-349418/topics/mytopic",
    "request": {
      "@type": "type.googleapis.com/google.iam.v1.GetIamPolicyRequest",
      "resource": "projects/mproject-349418/topics/mytopic"
    }
  },
  "insertId": "tp27wsc6v6",
  "resource": {
    "type": "pubsub_topic",
    "labels": {
      "topic_id": "projects/mproject-349418/topics/mytopic",
      "project_id": "mproject-349418"
    }
  },
  "timestamp": "2022-05-11T03:14:53.701448156Z",
  "severity": "INFO",
  "logName": "projects/mproject-349418/logs/cloudaudit.googleapis.com%2Fdata_access",
  "receiveTimestamp": "2022-05-11T03:14:53.870472256Z"
}
  • "google.iam.v1.IAMPolicy.SetIamPolicy"
{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "authenticationInfo": {
      "principalEmail": "admin@yourdomain.com",
      "principalSubject": "user:admin@yourdomain.com"
    },
    "requestMetadata": {
      "callerIp": "72.83.11.111",
      "callerSuppliedUserAgent": "google-cloud-sdk gcloud/382.0.0 command/gcloud.pubsub.topics.add-iam-policy-binding invocation-id/786783565b93447a828e06f3b4295cab environment/None environment-version/None interactive/True from-script/False python/3.9.10 term/xterm-256color (Linux 5.16.18-1rodete2-amd64),gzip(gfe)",
      "requestAttributes": {
        "time": "2022-05-11T03:14:54.068808814Z",
        "auth": {}
      },
      "destinationAttributes": {}
    },
    "serviceName": "pubsub.googleapis.com",
    "methodName": "google.iam.v1.IAMPolicy.SetIamPolicy",
    "authorizationInfo": [
      {
        "resource": "projects/mproject-349418/topics/mytopic",
        "permission": "pubsub.topics.setIamPolicy",
        "granted": true,
        "resourceAttributes": {}
      }
    ],
    "resourceName": "projects/mproject-349418/topics/mytopic",
    "request": {
      "policy": {
        "etag": "BwXes9dmIZo=",
        "bindings": [
          {
            "role": "roles/pubsub.publisher",
            "members": [
              "user:alice@yourdomain.com"
            ]
          }
        ]
      },
      "@type": "type.googleapis.com/google.iam.v1.SetIamPolicyRequest",
      "resource": "projects/mproject-349418/topics/mytopic"
    },
    "response": {
      "bindings": [
        {
          "members": [
            "user:alice@yourdomain.com"
          ],
          "role": "roles/pubsub.publisher"
        }
      ],
      "@type": "type.googleapis.com/google.iam.v1.Policy",
      "etag": "BwXes9hgXeE="
    }
  },
  "insertId": "1n3uf2jcepi",
  "resource": {
    "type": "pubsub_topic",
    "labels": {
      "project_id": "mproject-349418",
      "topic_id": "projects/mproject-349418/topics/mytopic"
    }
  },
  "timestamp": "2022-05-11T03:14:54.062536348Z",
  "severity": "NOTICE",
  "logName": "projects/mproject-349418/logs/cloudaudit.googleapis.com%2Factivity",
  "receiveTimestamp": "2022-05-11T03:14:54.715879889Z"
}

GCS

{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "status": {},
    "authenticationInfo": {
      "principalEmail": "admin@yourdomain.com"
    },
    "requestMetadata": {
      "callerIp": "72.83.11.1111",
      "callerSuppliedUserAgent": "Boto/2.49.0 Python/3.9.10 Linux/5.16.18-1rodete2-amd64 gsutil/5.9 (linux) analytics/disabled interactive/True command/defstorageclass google-cloud-sdk/382.0.0,gzip(gfe)",
      "requestAttributes": {
        "time": "2022-05-11T11:15:06.861356060Z",
        "auth": {}
      },
      "destinationAttributes": {}
    },
    "serviceName": "storage.googleapis.com",
    "methodName": "storage.buckets.update",
    "authorizationInfo": [
      {
        "resource": "projects/_/buckets/mproject-349418-trace",
        "permission": "storage.buckets.update",
        "granted": true,
        "resourceAttributes": {}
      }
    ],
    "resourceName": "projects/_/buckets/mproject-349418-trace",
    "request": {
      "projection": "NO_ACL",
      "bucket": "mproject-349418-trace",
      "metadata": {
        "name": "mproject-349418-trace",
        "storageClass": "STANDARD",
        "id": "mproject-349418-trace"
      },
      "@type": "type.googleapis.com/google.storage.v1.UpdateBucketRequest"
    },
    "response": {
      "projectNumber": "300824348137",
      "timeCreated": "2022-05-06T18:43:20.026Z",
      "location": "US",
      "id": "mproject-349418-trace",
      "storageClass": "STANDARD",
      "name": "mproject-349418-trace",
      "iamConfiguration": {
        "publicAccessPrevention": "INHERITED",
        "uniformBucketLevelAccess": {
          "enabled": true,
          "lockedTime": "2022-08-04T18:43:25.239Z"
        }
      },
      "locationType": "multi-region",
      "@type": "type.googleapis.com/google.storage.v1.Bucket",
      "etag": "CLkB",
      "metageneration": "185",
      "updated": "2022-05-11T11:15:07.034Z"
    },
    "resourceLocation": {
      "currentLocations": [
        "us"
      ]
    }
  },
  "insertId": "-mgz3j8e54pud",
  "resource": {
    "type": "gcs_bucket",
    "labels": {
      "location": "us",
      "bucket_name": "mproject-349418-trace",
      "project_id": "mproject-349418"
    }
  },
  "timestamp": "2022-05-11T11:15:06.852753390Z",
  "severity": "NOTICE",
  "logName": "projects/mproject-349418/logs/cloudaudit.googleapis.com%2Factivity",
  "receiveTimestamp": "2022-05-11T11:15:07.153738482Z"
}

This site supports webmentions. Send me a mention via this form.