Skip to content

Commit

Permalink
Assignment 07: Pub/Sub + Cloud Functions (#5)
Browse files Browse the repository at this point in the history
* Assignment 06:
- Created a new service account with 2 roles permissions: Logging Admin and Monitoring Metric Writer
- Attached the services account to the VM (refer the compute_instance folder)
- Created a module for Cloud DNS to translate my API Domain Address to IP Address to access the VM in GCP

* Assignment 07: Pub/Sub + Cloud Functions + Cloud Storage + IAM
- Webapp publishes to the topic when user creates a new user account
- The serverless code(a NodeJS code) subscribes for this specific topic. Since pub/sub is async event based, it gets triggered as soon as user creates new account
- It further triggers the mailing API to send a verification email
- User clicks on the verification link which triggers a GET call in webapp
  • Loading branch information
Kashyab19 authored Aug 9, 2024
1 parent b329695 commit c9c0cb4
Show file tree
Hide file tree
Showing 20 changed files with 475 additions and 19 deletions.
19 changes: 19 additions & 0 deletions .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

43 changes: 43 additions & 0 deletions cloudfunctions/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
resource "google_cloudfunctions_function" "verify_email_function" {
name = "verify_email_function"
description = "Sends verification emails and tracks them in CloudSQL"
runtime = "nodejs20"
available_memory_mb = 256
source_archive_bucket = var.function_source_bucket
source_archive_object = var.function_source_object
entry_point = "verifyEmail"
environment_variables = {
CLOUD_SQL_USER = var.db_user
CLOUD_SQL_PASSWORD = var.db_password
CLOUD_SQL_DATABASE = var.db_name
CLOUD_SQL_INSTANCE = var.db_host
POSTMARK_FROM_EMAIL = var.postmark_from_email
GCP_PROJECT_ID = var.project_id
POSTMARK_API_KEY_SECRET = "projects/${var.project_id}/secrets/postmark-api-key/versions/latest"
DOMAIN= var.domain
}
service_account_email = var.service_account_email
event_trigger {
event_type = "providers/cloud.pubsub/eventTypes/topic.publish"
resource = var.pubsub_topic
}
}

resource "google_project_iam_member" "function_pubsub_invoker" {
project = var.project_id
role = "roles/pubsub.subscriber"
member = "serviceAccount:${google_cloudfunctions_function.verify_email_function.service_account_email}"
}

resource "google_project_iam_member" "secretmanager_access" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_cloudfunctions_function.verify_email_function.service_account_email}"
}

resource "google_project_iam_member" "cloudsql_client" {
project = var.project_id
role = "roles/cloudsql.client"
member = "serviceAccount:${google_cloudfunctions_function.verify_email_function.service_account_email}"
}

4 changes: 4 additions & 0 deletions cloudfunctions/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "cloud_function_url" {
description = "The URL of the deployed Cloud Function"
value = google_cloudfunctions_function.verify_email_function.https_trigger_url
}
72 changes: 72 additions & 0 deletions cloudfunctions/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
variable "project_id" {
description = "The project ID to deploy resources into"
type = string
}

variable "region" {
description = "The region to deploy resources into"
type = string
default = "us-central1"
}

# variable "function_source" {
# description = "Path to the Cloud Function source code"
# type = string
# }

variable "db_user" {
description = "Database user"
type = string
}

variable "db_password" {
description = "Database password"
type = string
}

variable "db_name" {
description = "Database name"
type = string
}

variable "db_host" {
description = "Cloud SQL instance connection name"
type = string
}

variable "postmark_from_email" {
description = "The Postmark from email"
type = string
}

variable "service_account_email" {
description = "Service account email for the Cloud Function"
type = string
}

variable "pubsub_topic" {
description = "Pub/Sub topic to trigger the Cloud Function"
type = string
}

# variable "postmark_api_key_secret" {
# description = "The resource name of the Postmark API key secret in Secret Manager"
# type = string
# }


variable "function_source_bucket" {
description = "Pub/Sub topic to trigger the Cloud Function"
type = string
}

variable "function_source_object" {
description = "Pub/Sub topic to trigger the Cloud Function"
type = string
}

variable "domain" {
description = "domain to send emails from"
type = string
default = "http://kashyabcloudapp.me:8080"
}
4 changes: 2 additions & 2 deletions cloudsql/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ resource "google_sql_database" "default" {
instance = google_sql_database_instance.default.name
}

resource "random_password" "default" {
resource "random_password" "generated_password" {
length = 16
special = true
}

resource "google_sql_user" "default" {
name = var.db_user
instance = google_sql_database_instance.default.name
password = random_password.default.result
password = random_password.generated_password.result
}
10 changes: 9 additions & 1 deletion cloudsql/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ output "sql_user_name" {
}

output "sql_user_password" {
value = random_password.default.result
value = random_password.generated_password.result
sensitive = true
}

output "sql_instance_connection_name" {
value = google_sql_database_instance.default.connection_name
}

output "sql_instance_ip" {
value = google_sql_database_instance.default.ip_address.0.ip_address
}
2 changes: 1 addition & 1 deletion cloudsql/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ variable "private_vpc_connection" {
variable "project_id" {
description = "Project ID"
type = string
}
}
18 changes: 16 additions & 2 deletions firewall/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,33 @@ resource "google_compute_firewall" "allow_http" {

allow {
protocol = "tcp"
ports = ["80"] # Replace 80 with your application port if different
ports = ["8080", "22"] # Replace 80 with your application port if different
}

source_ranges = ["0.0.0.0/0"]
}

resource "google_compute_firewall" "allow-webapp-firewall" {
name = "allow-firewall-db-${0}"
network = var.network

allow {
protocol = "tcp"
ports = ["5432"]

}
source_ranges = ["10.62.0.0/16"]
direction = "EGRESS"
priority = 500
}

resource "google_compute_firewall" "deny_ssh" {
name = "deny-ssh"
network = var.network

deny {
protocol = "tcp"
ports = ["22"]
ports = [""]
}

source_ranges = ["0.0.0.0/0"]
Expand Down
38 changes: 38 additions & 0 deletions iam/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,41 @@ resource "google_project_iam_binding" "monitoring_metric_writer" {
"serviceAccount:${var.service_account_email}"
]
}

resource "google_project_iam_binding" "webapp_secret_accessor" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
members = [
"serviceAccount:${var.service_account_email}"
]
}

resource "google_project_iam_binding" "cloudfunctions_developer" {
project = var.project_id
role = "roles/cloudfunctions.developer"

members = [
"serviceAccount:${var.service_account_email}"
]
}

resource "google_project_iam_binding" "storage_admin" {
project = var.project_id
role = "roles/storage.admin"

members = [
"serviceAccount:${var.service_account_email}"
]
}

resource "google_project_iam_member" "function_pubsub_invoker" {
project = var.project_id
role = "roles/pubsub.subscriber"
member = "serviceAccount:${var.service_account_email}"
}

resource "google_project_iam_member" "secretmanager_access" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${var.service_account_email}"
}
59 changes: 56 additions & 3 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ provider "google" {
region = var.region
}


module "vpc" {
source = "./vpc"
vpc_name = var.vpc_name
Expand Down Expand Up @@ -52,10 +53,18 @@ module "compute_instance" {
zone = var.zone
service_account_email = module.service_account.email
startup_script = templatefile("${path.module}/startup_script.tpl", {
APPLICATION_NAME = "webapp"
SERVICE_NAME = "webapp.service"
GCP_PROJECT_ID = var.project_id
DB_USER = module.cloudsql.sql_user_name
DB_PASS = module.cloudsql.sql_user_password
DB_PASS = "tZ-.5aP}j@+fY:z("
DB_NAME = module.cloudsql.sql_database_name
DB_HOST = module.cloudsql.sql_instance_name
DB_HOST = module.cloudsql.sql_instance_ip
JWT_SECRET = ""
DB_PORT=var.port
PUBSUB_TOPIC="verify_email"
# Construct the DATABASE_URL
#DATABASE_URL = "postgres://${module.cloudsql.sql_user_name}:${module.cloudsql.sql_user_password}@/${module.cloudsql.sql_database_name}?host=/cloudsql/${module.cloudsql.sql_instance_connection_name}"
})
}

Expand All @@ -65,7 +74,7 @@ module "dns" {
webapp_dnsrecord_type = "A"
webapp_dns_ttl = 300
managed_zone_webapp = "my-new-zone" # The name of your existing managed zone
global_ip = module.vpc.private_service_connect_ip
global_ip = module.compute_instance.instance_ip
}

module "service_account" {
Expand All @@ -79,4 +88,48 @@ module "iam" {
source = "./iam"
project_id = var.project_id
service_account_email = module.service_account.email
}

module "secret_manager" {
source = "./secret_manager"
project_id = var.project_id
}

module "pubsub" {
source = "./pubsub"
# project_id = var.project_id
# region = var.region
}

resource "google_storage_bucket" "function_bucket" {
name = "numeric-gcf-source"
location = var.region
uniform_bucket_level_access = true
}

data "archive_file" "function_zip" {
type = "zip"
output_path = "/tmp/function-source.zip"
source_dir = "../serverless-fork/"
}

resource "google_storage_bucket_object" "function_zip" {
name = "function-source.zip"
bucket = google_storage_bucket.function_bucket.name
source = data.archive_file.function_zip.output_path
}

module "cloudfunctions" {
source = "./cloudfunctions"
project_id = var.project_id
region = var.region
function_source_bucket = google_storage_bucket.function_bucket.name
function_source_object = google_storage_bucket_object.function_zip.name
db_user = module.cloudsql.sql_user_name
db_password = "tZ-.5aP}j@+fY:z("
db_name = module.cloudsql.sql_database_name
db_host = module.cloudsql.sql_instance_ip
postmark_from_email = "[email protected]"
service_account_email = module.service_account.email
pubsub_topic = module.pubsub.pubsub_topic_name
}
24 changes: 24 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,27 @@ output "instance_name" {
output "instance_self_link" {
value = module.compute_instance.instance_self_link
}

output "sql_instance_connection_name" {
value = module.cloudsql.sql_instance_connection_name
}

# output "database_url_output" {
# value = module.compute_instance.database_url
# }


output "cloud_function_url" {
description = "The URL of the deployed Cloud Function"
value = module.cloudfunctions.cloud_function_url
}

output "pubsub_topic_name" {
description = "The name of the Pub/Sub topic"
value = module.pubsub.pubsub_topic_name
}

output "service_account_email" {
description = "The email of the service account"
value = module.service_account.email
}
8 changes: 8 additions & 0 deletions pubsub/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
resource "google_pubsub_topic" "verify_email" {
name = "verify_email"
}

resource "google_pubsub_subscription" "verify_email_subscription" {
name = "verify_email_subscription"
topic = google_pubsub_topic.verify_email.name
}
3 changes: 3 additions & 0 deletions pubsub/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
output "pubsub_topic_name" {
value = google_pubsub_topic.verify_email.name
}
Loading

0 comments on commit c9c0cb4

Please sign in to comment.