Responding to Cloud Logging Messages with Cloud Functions
- In Cloud Shell, run the following to create a Cloud Pub/Sub topic named vm-audit-logs:
gcloud pubsub topics create vm-audit-logs
- Set an environment variable for the Compute Engine zone:
export ZONE=us-central1-c
- Now create a virtual machine instance in your selected zone. This machine is created only to generate log messages, you can use the defaults.
gcloud compute instances create --zone $ZONE instance-1
- In order to have log messages for different VM operations, which will make the log filtering more interesting, you can now stop the instance:
gcloud compute instances stop --zone $ZONE instance-1
- In the Console, navigate to Logging > Logs:
- In the first drop-down, select Compute Engine VM Instance > All instance_id
- In the second drop-down, select cloudaudit.googleapis.com/activity. Click OK.
- Configure log export
- Click on the Create Export button.
- Sink Name: instance-insert-sink.
- Sink Service: Cloud Pub/Sub.
- Sink Destination: vm-audit-logs (the Cloud Pub/Sub topic you created earlier as the sink destination).
- Click Create sink
- Close the acknowledgement dialog
- Create a simple Cloud Function
Name: addVmCreatorMetadata
Trigger: “Cloud Pub/Sub”
Topic: select the topic you created earlier: “vm-audit-logs”
Runtime: “Python 3.7” - Update Cloud Function logic to add VM metadata
- In Cloud Shell make a new directory to hold your Cloud Function code:
mkdir ~/gcf-vm-metadata
- Execute the below command to create a new Python file called main.py with the below code in the new directory. Read through the code to understand its operation:
cat > ~/gcf-vm-metadata/main.py <<'EOF' import base64 import json import googleapiclient.discovery def tag_with_creator(event, context): """Adds a custom metadata entry for a new virtual machine. Triggered by a Cloud Pub/Sub message containing a Compute Engine audit activity Stackdriver log message """ pubsub_message = base64.b64decode(event['data']).decode('utf-8') msg_json = json.loads(pubsub_message) proto_payload = msg_json['protoPayload'] resource_name = proto_payload['resourceName'] email = proto_payload['authenticationInfo']['principalEmail'] # compute engine API compute = googleapiclient.discovery.build( 'compute', 'v1', cache_discovery=False) # full name is of the form # projects/$PROJ_NAME/zones/$ZONE/instances/$INST_NAME name_tokens = resource_name.split('/') project = name_tokens[1] zone = name_tokens[3] instance_name = name_tokens[5] # need to get current vm metadata before we can update it vm_details = compute.instances().get( project=project, zone=zone, instance=instance_name).execute() vm_metadata = vm_details['metadata'] # add/replace metadata item _update_metadata(vm_metadata, 'creator', email) response = compute.instances().setMetadata( project=project, zone=zone, instance=instance_name, body=vm_metadata).execute() print('Updated metadata for resource %s' % resource_name) def _update_metadata(vm_meta, key, value): """Update existing vm metadata with the supplied key/value pair. If the key already exists, value is overwritten. """ if 'items' not in vm_meta: vm_meta['items'] = [] for item in vm_meta['items']: if item['key'] == key: item['value'] = value return vm_meta['items'].append({ 'key': key, 'value': value }) EOF
- Execute the following to create a new requirements.txt file with the required Python dependency:
cat > ~/gcf-vm-metadata/requirements.txt <<'EOF' google-api-python-client==1.7.4 EOF
- Execute the below command to update the Cloud Function you created earlier. Note that theÂ
--source
 parameter references the directory that contains theÂmain.py
 source file andÂrequirements.txt
 dependency file:gcloud functions deploy addVmCreatorMetadata --source ~/gcf-vm-metadata --entry-point tag_with_creator
- Refresh the Cloud Functions page in the Console and verify that the Executed function field has been updated to the newÂ
tag_with_creator
 value.
- In Cloud Shell make a new directory to hold your Cloud Function code:
- Trigger the Cloud Function by creating a VM
- In Cloud Shell, restart the virtual machine you created earlier:
gcloud compute instances start --zone $ZONE instance-1
- Once the VM has completed starting, navigate to Logging > Logs.
- In the first filter drop-down, select Cloud Function. You should see some log messages relating to the creation and update of the function performed in the previous step.
- Create a new VM in Cloud Shell, which should trigger the Cloud Function:
gcloud compute instances create --zone $ZONE instance-2
- Once the VM creation has completed, go back to refresh the Logging view pane with the existing filter intact. You should now see some log messages, indicating that the Cloud Function executed.
- Examine the log messages and cross-reference with the function code to gain an understanding of the different steps.
- Navigate to Compute Engine -> VM Instances and click into the instance-2 machine. Verify that the metadata for the newly created VM has been updated to include the email of the account that created it.
- Scroll down through the details and verify that the Custom Metadata section has the creator key and expected email address added by the Cloud Function
- In Cloud Shell, restart the virtual machine you created earlier:
Tag:Google Cloud