Skip to content

Commit

Permalink
Update GCP deployment docs with Secret Manager and dedicated Service …
Browse files Browse the repository at this point in the history
…Accounts (#142)
  • Loading branch information
fcrespel committed Mar 19, 2024
1 parent 7b19217 commit 44fe2e4
Show file tree
Hide file tree
Showing 41 changed files with 963 additions and 608 deletions.
11 changes: 6 additions & 5 deletions docs/deployment/gcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ This directory contains specific deployment instructions and examples for [Googl

1. [**Build**](build): using [Cloud Build](https://cloud.google.com/cloud-build/) to build and push a WAR file to [Cloud Storage](https://cloud.google.com/storage/), and a Docker image to [Container Registry](https://cloud.google.com/container-registry/).
2. [**SQL**](sql): using [Cloud SQL](https://cloud.google.com/sql/) to deploy a database for persistence.
3. [**GCE Classic**](gce-classic): using [Compute Engine](https://cloud.google.com/compute/) to run the WAR file with a Tomcat application server in a Managed Instance Group, and [HTTPS Load Balancing](https://cloud.google.com/load-balancing/) to expose the service.
4. [**GCE Container**](gce-container): using [Compute Engine](https://cloud.google.com/compute/) to run the Docker image in a Managed Instance Group, and [HTTPS Load Balancing](https://cloud.google.com/load-balancing/) to expose the service.
5. [**GKE**](gke): using [Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) to run the Docker image in a Kubernetes cluster, and an Ingress to expose the service over HTTPS.
6. [**GAE**](gae): using [App Engine](https://cloud.google.com/appengine/) to run the application and expose the service over HTTPS.
7. [**Cloud Run**](cloudrun): using [Cloud Run](https://cloud.google.com/run) to run the Docker image and expose the service over HTTPS.
3. [**Secret Manager**](secret-manager): using [Secret Manager](https://cloud.google.com/secret-manager) to store application configuration, including sensitive values.
4. [**GCE Classic**](gce-classic): using [Compute Engine](https://cloud.google.com/compute/) to run the WAR file with a Tomcat application server in a Managed Instance Group, and [HTTPS Load Balancing](https://cloud.google.com/load-balancing/) to expose the service.
5. [**GCE Container**](gce-container): using [Compute Engine](https://cloud.google.com/compute/) to run the Docker image in a Managed Instance Group, and [HTTPS Load Balancing](https://cloud.google.com/load-balancing/) to expose the service.
6. [**GKE**](gke): using [Kubernetes Engine](https://cloud.google.com/kubernetes-engine/) to run the Docker image in a Kubernetes cluster, and an Ingress to expose the service over HTTPS.
7. [**GAE**](gae): using [App Engine](https://cloud.google.com/appengine/) to run the application and expose the service over HTTPS.
8. [**Cloud Run**](cloudrun): using [Cloud Run](https://cloud.google.com/run) to run the Docker image and expose the service over HTTPS.
538 changes: 293 additions & 245 deletions docs/deployment/gcp/architecture.drawio

Large diffs are not rendered by default.

48 changes: 17 additions & 31 deletions docs/deployment/gcp/cloudrun/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,21 @@ This example uses [Cloud Run](https://cloud.google.com/run) to run the Docker im

## Prerequisites

Before starting, follow the [Build](../build) and [SQL](../sql) guides to create the container image and database.

Then, refer to the deployment [README](../../README.md) file for information about configuring identity providers.
Before starting, follow the [Build](../build), [SQL](../sql) and [Secret Manager](../secret-manager) guides to create the container image, database and configuration.

## Using Cloud Console

Go to [Cloud Console](https://console.cloud.google.com) and make sure the appropriate project is selected in the header menu.

In the side menu, go to **IAM & Admin > Service Accounts**:
* Click **Create Service Account**.
* Set `karaplan` as the Service Account **name** and **ID**.
* Click **Create and continue**.
* Select the following **Roles**:
* Secret Manager Secret Accessor
* Cloud SQL Client
* Click **Done**.

In the side menu, go to **Cloud Run**:
* Click **Create service**.
* Enter the **Container image name**, e.g. `europe-west1-docker.pkg.dev/YOUR_PROJECT_ID/docker/karaplan:master`.
Expand All @@ -21,21 +28,8 @@ In the side menu, go to **Cloud Run**:
* Select **Allow unauthenticated invocations**.
* Expand additional settings at the bottom.
* In the **Container** tab, set **Memory** to `1 GiB`.
* In the **Variables and secrets** tab, add the following **Environment variables** (replace `toComplete` with appropriate values):

| Name | Value |
| ---- | ----- |
| SPRING_DATASOURCE_USERNAME | karaplan |
| SPRING_DATASOURCE_PASSWORD | toComplete |
| SPRING_DATASOURCE_URL | jdbc:mysql:///karaplan?useSSL=false&socketFactory=com.google.cloud.sql.mysql.SocketFactory&cloudSqlInstance=toComplete |
| SPRING_PROFILES_ACTIVE | gcp |
| SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTID | toComplete |
| SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTSECRET | toComplete |
| SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_FACEBOOK_CLIENTID | toComplete |
| SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_FACEBOOK_CLIENTSECRET | toComplete |
| SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTID | toComplete |
| SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTSECRET | toComplete |

* In the **Variables and secrets** tab, add a `SPRING_PROFILES_ACTIVE` **Environment variable** with value `gcp`.
* In the **Security** tab, select the previously created `karaplan` **Service Account**.
* Click **Create**.

If you have a custom domain name:
Expand All @@ -55,21 +49,13 @@ Use the following commands in [Cloud Shell](https://cloud.google.com/shell/) or
PROJECT_ID=$(gcloud config get-value project)
REGION=$(gcloud config get-value compute/region)

# Create environment variables (replace 'toComplete' with appropriate values)
ENV_VARS="\
SPRING_DATASOURCE_USERNAME=karaplan,\
SPRING_DATASOURCE_PASSWORD=toComplete,\
SPRING_DATASOURCE_URL=jdbc:mysql:///karaplan?useSSL=false&socketFactory=com.google.cloud.sql.mysql.SocketFactory&cloudSqlInstance=$PROJECT_ID:$REGION:toComplete,\
SPRING_PROFILES_ACTIVE=gcp,\
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTID=toComplete,\
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTSECRET=toComplete,\
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_FACEBOOK_CLIENTID=toComplete,\
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_FACEBOOK_CLIENTSECRET=toComplete,\
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTID=toComplete,\
SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTSECRET=toComplete
# Create Service Account and grant permissions
gcloud iam service-accounts create karaplan
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:karaplan@$PROJECT_ID.iam.gserviceaccount.com" --role=roles/secretmanager.secretAccessor
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:karaplan@$PROJECT_ID.iam.gserviceaccount.com" --role=roles/cloudsql.client

# Deploy Cloud Run service
gcloud run deploy karaplan --image $REGION-docker.pkg.dev/$PROJECT_ID/docker/karaplan:master --cpu=1 --memory=1Gi --min-instances=0 --max-instances=5 --allow-unauthenticated --region=$REGION --set-env-vars="$ENV_VARS"
gcloud run deploy karaplan --image $REGION-docker.pkg.dev/$PROJECT_ID/docker/karaplan:master --cpu=1 --memory=1Gi --min-instances=0 --max-instances=5 --allow-unauthenticated --region=$REGION --service-account=karaplan@$PROJECT_ID.iam.gserviceaccount.com --set-env-vars="SPRING_PROFILES_ACTIVE=gcp"

If you have a custom domain name:

Expand Down
Binary file modified docs/deployment/gcp/cloudrun/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 23 additions & 37 deletions docs/deployment/gcp/cloudrun/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,14 @@ resource "google_cloud_run_service" "karaplan-service" {
template {
metadata {
annotations = {
"autoscaling.knative.dev/minScale" = var.min_instances_count
"autoscaling.knative.dev/maxScale" = var.max_instances_count
"run.googleapis.com/client-name" = "terraform"
"autoscaling.knative.dev/minScale" = var.min_instances_count
"autoscaling.knative.dev/maxScale" = var.max_instances_count
"run.googleapis.com/client-name" = "terraform"
"run.googleapis.com/startup-cpu-boost" = "true"
}
}
spec {
service_account_name = google_service_account.karaplan-sa.email
containers {
image = "${var.region}-docker.pkg.dev/${var.project_id}/docker/karaplan:master"
resources {
Expand All @@ -49,47 +51,31 @@ resource "google_cloud_run_service" "karaplan-service" {
value = "gcp"
}
env {
name = "SPRING_DATASOURCE_USERNAME"
value = var.db_username
}
env {
name = "SPRING_DATASOURCE_PASSWORD"
value = var.db_password
}
env {
name = "SPRING_DATASOURCE_URL"
value = "jdbc:mysql:///${var.db_name}?useSSL=false&socketFactory=com.google.cloud.sql.mysql.SocketFactory&cloudSqlInstance=${var.db_instance}"
}
env {
name = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTID"
value = var.google_oauth_clientid
}
env {
name = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GOOGLE_CLIENTSECRET"
value = var.google_oauth_clientsecret
}
env {
name = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_FACEBOOK_CLIENTID"
value = var.facebook_oauth_clientid
}
env {
name = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_FACEBOOK_CLIENTSECRET"
value = var.facebook_oauth_clientsecret
}
env {
name = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTID"
value = var.github_oauth_clientid
}
env {
name = "SPRING_SECURITY_OAUTH2_CLIENT_REGISTRATION_GITHUB_CLIENTSECRET"
value = var.github_oauth_clientsecret
name = "SECRET_PREFIX"
value = var.name
}
}
}
}
autogenerate_revision_name = true
}

// Service account
resource "google_service_account" "karaplan-sa" {
project = var.project_id
account_id = var.name
}
resource "google_project_iam_member" "karaplan-sa-secret-accessor" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.karaplan-sa.email}"
}
resource "google_project_iam_member" "karaplan-sa-sql-client" {
project = var.project_id
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.karaplan-sa.email}"
}

// Public access
resource "google_cloud_run_service_iam_member" "karaplan-service-iam-member" {
service = google_cloud_run_service.karaplan-service.name
Expand Down
30 changes: 0 additions & 30 deletions docs/deployment/gcp/cloudrun/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,3 @@ variable "max_instances_count" {
default = 5
description = "Maximum number of instances to create"
}
variable "db_instance" {
description = "Database instance (project_id:region:instance_name)"
}
variable "db_name" {
description = "Database name"
}
variable "db_username" {
description = "Database user name"
}
variable "db_password" {
description = "Database user password"
}
variable "google_oauth_clientid" {
description = "Google OAuth 2.0 client ID"
}
variable "google_oauth_clientsecret" {
description = "Google OAuth 2.0 client secret"
}
variable "facebook_oauth_clientid" {
description = "Facebook OAuth 2.0 client ID"
}
variable "facebook_oauth_clientsecret" {
description = "Facebook OAuth 2.0 client secret"
}
variable "github_oauth_clientid" {
description = "GitHub OAuth 2.0 client ID"
}
variable "github_oauth_clientsecret" {
description = "GitHub OAuth 2.0 client secret"
}
70 changes: 63 additions & 7 deletions docs/deployment/gcp/gae/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,77 @@ This example uses [App Engine](https://cloud.google.com/appengine/) to run the a

## Prerequisites

Before starting, follow the [SQL](../sql) guide to create the database.
Before starting, follow the [SQL](../sql) and [Secret Manager](../secret-manager) guides to create the database and configuration.

## Configure the application
## Using Cloud Console

Copy the `src/main/appengine/files/application.example.yml` as `application.yml` in the same directory. Open it with your preferred editor and replace `toComplete` with appropriate values. Refer to the deployment [README](../../README.md) file for information about configuring identity providers.
Go to [Cloud Console](https://console.cloud.google.com) and make sure the appropriate project is selected in the header menu.

## Deploy the application
In the side menu, go to **IAM & Admin > Service Accounts**:
* Click **Create Service Account**.
* Set `karaplan` as the Service Account **name** and **ID**.
* Click **Create and continue**.
* Select the following **Roles**:
* Secret Manager Secret Accessor
* Cloud SQL Client
* Click **Done**.

In the side menu, go to **App Engine**:
* Click **Create Application**.
* Select your preferred **Region** (e.g. `europe-west`).
* Select the previously created `karaplan` **Service Account**.

If you have a custom domain name:
* From the **Settings** menu, go to the **Custom Domains** tab.
* Click **Add a custom domain**.
* Select your **verified domain** and click **Continue**.
* Enter the **fully-qualified domain name** to use.
* Click **Save mappings**.
* Add the **CNAME record** to your domain as instructed.

Finally, follow the instructions in the *Deploy the application* section below.

## Using Cloud Shell / SDK

Use the following commands in [Cloud Shell](https://cloud.google.com/shell/) or anywhere the [Cloud SDK](https://cloud.google.com/sdk/) is installed:

# Set variables, adjust them as needed
REGION="europe-west1"
PROJECT_ID=$(gcloud config get-value project)
REGION="europe-west"

# Create Service Account and grant permissions
gcloud iam service-accounts create karaplan
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:karaplan@$PROJECT_ID.iam.gserviceaccount.com" --role=roles/secretmanager.secretAccessor
gcloud projects add-iam-policy-binding $PROJECT_ID --member="serviceAccount:karaplan@$PROJECT_ID.iam.gserviceaccount.com" --role=roles/cloudsql.client

# Create app in region (warning: can't be changed later!)
gcloud app create --region=$REGION
gcloud app create --region=$REGION --service-account=karaplan@$PROJECT_ID.iam.gserviceaccount.com

# If the app already exists, update the Service Account if necessary
gcloud app update --service-account=karaplan@$PROJECT_ID.iam.gserviceaccount.com

If you have a custom domain name:

DOMAIN=your.custom.domain

# Create domain mapping
gcloud app domain-mappings create $DOMAIN --certificate-management=AUTOMATIC

# Add the CNAME record to your domain as instructed.

Finally, follow the instructions in the *Deploy the application* section below.

## Using Terraform

This directory contains a [Terraform](https://terraform.io) module to provision some of the resources automatically. See the `main.tf`, `variables.tf` files for more information.

Please refer to the [Terraform Cloud Run Deployment](../../terraform/gae) guide for a full example.

Finally, follow the instructions in the *Deploy the application* section below.

## Deploy the application

Use the following commands in [Cloud Shell](https://cloud.google.com/shell/) or anywhere the [Cloud SDK](https://cloud.google.com/sdk/) is installed:

# Get app source code if necessary
git clone https://github.com/fcrespel/karaplan.git
Expand All @@ -27,4 +83,4 @@ Use the following commands in [Cloud Shell](https://cloud.google.com/shell/) or
# Build and deploy app with Maven
./mvnw -Dfrontend-build -Dappengine-build -DskipTests package appengine:deploy

After completion, the application should be available at `https://<project-id>.appspot.com`
After completion, the application should be available at `https://<project-id>.ew.r.appspot.com`
44 changes: 44 additions & 0 deletions docs/deployment/gcp/gae/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// DNS zone
data "google_dns_managed_zone" "karaplan-dns-zone" {
count = var.dns_zone != "" ? 1 : 0
name = var.dns_zone
project = var.dns_project_id
}

// DNS record
resource "google_dns_record_set" "karaplan-dns-record" {
count = var.dns_zone != "" ? 1 : 0
name = "${var.dns_name_prefix}.${data.google_dns_managed_zone.karaplan-dns-zone[0].dns_name}"
project = data.google_dns_managed_zone.karaplan-dns-zone[0].project
managed_zone = data.google_dns_managed_zone.karaplan-dns-zone[0].name
type = "CNAME"
ttl = 300
rrdatas = ["ghs.googlehosted.com."]
}

// Domain name mapping
resource "google_app_engine_domain_mapping" "karaplan-domain-mapping" {
count = var.dns_zone != "" ? 1 : 0
project = var.project_id
domain_name = replace(google_dns_record_set.karaplan-dns-record[0].name, "/\\.$/", "")

ssl_settings {
ssl_management_type = "AUTOMATIC"
}
}

// Service account
resource "google_service_account" "karaplan-sa" {
project = var.project_id
account_id = var.name
}
resource "google_project_iam_member" "karaplan-sa-secret-accessor" {
project = var.project_id
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.karaplan-sa.email}"
}
resource "google_project_iam_member" "karaplan-sa-sql-client" {
project = var.project_id
role = "roles/cloudsql.client"
member = "serviceAccount:${google_service_account.karaplan-sa.email}"
}
22 changes: 22 additions & 0 deletions docs/deployment/gcp/gae/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
variable "name" {
default = "karaplan"
description = "Name to use in all resources of this module"
}
variable "project_id" {
description = "GCP project ID"
}
variable "region" {
description = "GCP region"
}
variable "dns_project_id" {
default = ""
description = "Cloud DNS project ID"
}
variable "dns_zone" {
default = ""
description = "Cloud DNS zone name"
}
variable "dns_name_prefix" {
default = "karaplan"
description = "DNS name prefix"
}
8 changes: 8 additions & 0 deletions docs/deployment/gcp/gae/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.10"
}
}
}
Loading

0 comments on commit 44fe2e4

Please sign in to comment.