From 5b3f70bd4363fb500d9545c5a6e43e796918276f Mon Sep 17 00:00:00 2001 From: Zach Berger Date: Fri, 31 May 2019 15:34:41 -0700 Subject: [PATCH 1/5] Add Cloud Function that deletes VM instances created without CMEK. --- examples/delete-vms-without-cmek/README.md | 66 ++++++++++ .../function_source/cmek.go | 122 ++++++++++++++++++ .../function_source/go.mod | 8 ++ examples/delete-vms-without-cmek/main.tf | 58 +++++++++ examples/delete-vms-without-cmek/variables.tf | 26 ++++ 5 files changed, 280 insertions(+) create mode 100644 examples/delete-vms-without-cmek/README.md create mode 100644 examples/delete-vms-without-cmek/function_source/cmek.go create mode 100644 examples/delete-vms-without-cmek/function_source/go.mod create mode 100644 examples/delete-vms-without-cmek/main.tf create mode 100644 examples/delete-vms-without-cmek/variables.tf diff --git a/examples/delete-vms-without-cmek/README.md b/examples/delete-vms-without-cmek/README.md new file mode 100644 index 0000000..5ba34ae --- /dev/null +++ b/examples/delete-vms-without-cmek/README.md @@ -0,0 +1,66 @@ +# Automatic Labelling from Localhost + +This example demonstrates how to use the +[root module][root-module] and the +[event-project-log-entry submodule][event-project-log-entry-submodule] +to configure a system +which responds to Compute VM creation events by deleting any VM instances created with disks not encrypted using a customer-managed encryption key. + +## Usage + +To provision this example, populate `terraform.tfvars` with the [required variables](#inputs) and run the following commands within +this directory: + +- `terraform init` to initialize the directory +- `terraform plan` to generate the execution plan +- `terraform apply` to apply the execution plan +- `terraform destroy` to destroy the infrastructure + +[^]: (autogen_docs_start) + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|:----:|:-----:|:-----:| +| project\_id | The ID of the project to which resources will be applied. | string | n/a | yes | +| region | The region in which resources will be applied. | string | n/a | yes | + +[^]: (autogen_docs_end) + +## Requirements + +The following sections describe the requirements which must be met in +order to invoke this module. The requirements of the +[root module][root-module-requirements] and the +[event-project-log-entry submodule][event-project-log-entry-submodule-requirements] +must also be met. + +### Software Dependencies + +The following software dependencies must be installed on the system +from which this module will be invoked: + +- [Terraform][terraform-site] v0.11.Z + +### IAM Roles + +The Service Account which will be used to invoke this module must have +the following IAM roles: + +- Pub/Sub Admin +- Storage Admin +- Cloud Functions Developer +- Logging Sink Admin + +### APIs + +The project against which this module will be invoked must have the +following APIs enabled: + +- Compute Engine API: `compute.googleapis.com` + +[event-project-log-entry-submodule-requirements]: ../../modules/event-project-log-entry/README.md#requirements +[event-project-log-entry-submodule]: ../../modules/event-project-log-entry +[root-module-requirements]: ../../README.md#requirements +[root-module]: ../.. +[terraform-site]: https://terraform.io/ diff --git a/examples/delete-vms-without-cmek/function_source/cmek.go b/examples/delete-vms-without-cmek/function_source/cmek.go new file mode 100644 index 0000000..051d0ab --- /dev/null +++ b/examples/delete-vms-without-cmek/function_source/cmek.go @@ -0,0 +1,122 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmek + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "log" + "time" + + "cloud.google.com/go/pubsub" + "google.golang.org/api/compute/v1" +) + +type creationEvent struct { + Resource struct { + Labels struct { + InstanceID string `json:"instance_id"` + ProjectID string `json:"project_id"` + Zone string `json:"zone"` + } `json:"labels"` + } `json:"resource"` +} + +var computeService *compute.Service + +func init() { + var err error + + computeService, err = compute.NewService(context.Background()) + if err != nil { + log.Fatalf("Could not create compute service: %v\n", err) + } +} + +func RecieveMessage(ctx context.Context, msg *pubsub.Message) error { + var event creationEvent + json.Unmarshal([]byte(msg.Data), &event) + labels := event.Resource.Labels + fmt.Printf("Checking to see if VM instance has unencrypted disks %v\n", labels) + encrypted, err := isEncrypted(labels.ProjectID, labels.Zone, labels.InstanceID) + if err != nil { + fmt.Printf("Error while trying to determine if VM is encrypted. Error: %v\n", err) + return err + } + if !encrypted { + fmt.Printf("Found VM instance with unencrypted disk %v\n", labels) + fmt.Printf("Deleting VM instance %v\n", labels) + err = deleteVM(labels.ProjectID, labels.Zone, labels.InstanceID) + if err != nil { + fmt.Printf("Error while trying to delete vm instance. Error: %v\n", err) + return err + } + fmt.Printf("Successfully deleted VM instance %v\n", labels) + } else { + fmt.Printf("No unencrypted disks found on VM instance %v\n", labels) + } + return nil +} + +func deleteVM(projectID string, zoneID string, instanceID string) error { + operation, err := computeService.Instances.Delete(projectID, zoneID, instanceID).Do() + if err != nil { + return err + } + err = waitForOperation(computeService, projectID, zoneID, operation) + return err +} + +func waitForOperation(computeService *compute.Service, projectID string, zoneID string, operation *compute.Operation) error { + for { + operation, err := computeService.ZoneOperations.Get(projectID, zoneID, operation.Name).Do() + if err != nil { + return err + } + + if operation.Status != "DONE" { + time.Sleep(2 * time.Second) + } else { + if operation.Error != nil { + fmt.Printf("%v", operation.Error) + return errors.New("Operation error") + } + return nil + } + } + return nil +} + +func isEncrypted(projectID string, zoneID string, instanceID string) (bool, error) { + ctx := context.Background() + computeService, err := compute.NewService(ctx) + if err != nil { + return true, err + } + + instance, err := computeService.Instances.Get(projectID, zoneID, instanceID).Do() + if err != nil { + return true, err + } + + for _, disk := range instance.Disks { + if disk.DiskEncryptionKey == nil { + return false, nil + } + } + + return true, nil +} diff --git a/examples/delete-vms-without-cmek/function_source/go.mod b/examples/delete-vms-without-cmek/function_source/go.mod new file mode 100644 index 0000000..a8a3726 --- /dev/null +++ b/examples/delete-vms-without-cmek/function_source/go.mod @@ -0,0 +1,8 @@ +module github.com/terraform-google-modules/terraform-google-event-function + +go 1.11 + +require ( + cloud.google.com/go v0.38.0 + google.golang.org/api v0.4.0 +) diff --git a/examples/delete-vms-without-cmek/main.tf b/examples/delete-vms-without-cmek/main.tf new file mode 100644 index 0000000..9a50abf --- /dev/null +++ b/examples/delete-vms-without-cmek/main.tf @@ -0,0 +1,58 @@ +/** + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +terraform { + required_version = "~> 0.11.0" +} + +provider "archive" { + version = "~> 1.0" +} + +provider "google" { + version = "~> 2.1" +} + +provider "random" { + version = "~> 2.0" +} + +resource "random_pet" "main" { + separator = "-" +} + +module "event_project_log_entry" { + source = "../../modules/event-project-log-entry" + + filter = "resource.type=\"gce_instance\" jsonPayload.event_subtype=\"compute.instances.insert\" jsonPayload.event_type=\"GCE_OPERATION_DONE\"" + name = "${random_pet.main.id}" + project_id = "${var.project_id}" +} + +module "localhost_function" { + source = "../.." + + description = "Deletes VMs created with disks not encrypted with CMEK" + entry_point = "RecieveMessage" + runtime = "go111" + timeout_s = "240" + + event_trigger = "${module.event_project_log_entry.function_event_trigger}" + name = "${random_pet.main.id}" + project_id = "${var.project_id}" + region = "${var.region}" + source_directory = "${path.module}/function_source" +} diff --git a/examples/delete-vms-without-cmek/variables.tf b/examples/delete-vms-without-cmek/variables.tf new file mode 100644 index 0000000..49ee8c3 --- /dev/null +++ b/examples/delete-vms-without-cmek/variables.tf @@ -0,0 +1,26 @@ +/** + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +variable "project_id" { + type = "string" + description = "The ID of the project to which resources will be applied." +} + +variable "region" { + type = "string" + description = "The region in which resources will be applied." +} + From ce083a949cde6bd3edb9535f80515cb30302e63c Mon Sep 17 00:00:00 2001 From: Zach Berger Date: Fri, 31 May 2019 15:38:59 -0700 Subject: [PATCH 2/5] =?UTF-8?q?Correct=20header=20to=20use=20block=20comme?= =?UTF-8?q?nt=20=F0=9F=99=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../function_source/cmek.go | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/examples/delete-vms-without-cmek/function_source/cmek.go b/examples/delete-vms-without-cmek/function_source/cmek.go index 051d0ab..68d4b40 100644 --- a/examples/delete-vms-without-cmek/function_source/cmek.go +++ b/examples/delete-vms-without-cmek/function_source/cmek.go @@ -1,16 +1,19 @@ -// Copyright 2019 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// https://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/** + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package cmek import ( From 74bffaadff544cde97868f0e0f97aa673f353a68 Mon Sep 17 00:00:00 2001 From: Zach Berger Date: Mon, 10 Jun 2019 14:56:49 -0700 Subject: [PATCH 3/5] Add IAM roles IDs --- examples/delete-vms-without-cmek/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/delete-vms-without-cmek/README.md b/examples/delete-vms-without-cmek/README.md index 5ba34ae..a91d717 100644 --- a/examples/delete-vms-without-cmek/README.md +++ b/examples/delete-vms-without-cmek/README.md @@ -47,10 +47,10 @@ from which this module will be invoked: The Service Account which will be used to invoke this module must have the following IAM roles: -- Pub/Sub Admin -- Storage Admin -- Cloud Functions Developer -- Logging Sink Admin +- Pub/Sub Admin: `roles/pubsub.admin` +- Storage Admin: `roles/storage.admin` +- Cloud Functions Developer: `roles/cloudfunctions.developer` +- Logging Config Writer: `roles/logging.configWriter` ### APIs From 24be6ae2fb9c98f151b737628104e22d36381c81 Mon Sep 17 00:00:00 2001 From: Zach Berger Date: Mon, 10 Jun 2019 14:59:22 -0700 Subject: [PATCH 4/5] Correct header again. --- .../function_source/cmek.go | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/delete-vms-without-cmek/function_source/cmek.go b/examples/delete-vms-without-cmek/function_source/cmek.go index 68d4b40..e82fddc 100644 --- a/examples/delete-vms-without-cmek/function_source/cmek.go +++ b/examples/delete-vms-without-cmek/function_source/cmek.go @@ -1,18 +1,18 @@ -/** - * Copyright 2019 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +/* +Copyright 2019 Google LLC + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ package cmek From b2a4306c7c774aa287b0f5166ae8b82b544f0041 Mon Sep 17 00:00:00 2001 From: Zach Berger Date: Tue, 11 Jun 2019 14:43:53 -0700 Subject: [PATCH 5/5] Correct spelling mistake --- examples/delete-vms-without-cmek/function_source/cmek.go | 2 +- examples/delete-vms-without-cmek/main.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/delete-vms-without-cmek/function_source/cmek.go b/examples/delete-vms-without-cmek/function_source/cmek.go index e82fddc..4afd936 100644 --- a/examples/delete-vms-without-cmek/function_source/cmek.go +++ b/examples/delete-vms-without-cmek/function_source/cmek.go @@ -49,7 +49,7 @@ func init() { } } -func RecieveMessage(ctx context.Context, msg *pubsub.Message) error { +func ReceiveMessage(ctx context.Context, msg *pubsub.Message) error { var event creationEvent json.Unmarshal([]byte(msg.Data), &event) labels := event.Resource.Labels diff --git a/examples/delete-vms-without-cmek/main.tf b/examples/delete-vms-without-cmek/main.tf index 9a50abf..32138f1 100644 --- a/examples/delete-vms-without-cmek/main.tf +++ b/examples/delete-vms-without-cmek/main.tf @@ -46,7 +46,7 @@ module "localhost_function" { source = "../.." description = "Deletes VMs created with disks not encrypted with CMEK" - entry_point = "RecieveMessage" + entry_point = "ReceiveMessage" runtime = "go111" timeout_s = "240"