Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enabled workload identity access for kms and gcs #113

Merged
merged 18 commits into from
Jun 13, 2024
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ No resources.
| <a name="input_allowed_inbound_cidrs"></a> [allowed\_inbound\_cidrs](#input\_allowed\_inbound\_cidrs) | Which IPv4 addresses/ranges to allow access. This must be explicitly provided, and by default is set to ["*"] | `list(string)` | <pre>[<br> "*"<br>]</pre> | no |
| <a name="input_bucket_name"></a> [bucket\_name](#input\_bucket\_name) | Use an existing bucket. | `string` | `""` | no |
| <a name="input_create_redis"></a> [create\_redis](#input\_create\_redis) | Boolean indicating whether to provision an redis instance (true) or not (false). | `bool` | `false` | no |
| <a name="input_create_workload_identity"></a> [create\_workload\_identity](#input\_create\_workload\_identity) | Flag to indicate whether to create a workload identity for the service account. | `bool` | `true` | no |
| <a name="input_database_machine_type"></a> [database\_machine\_type](#input\_database\_machine\_type) | Specifies the machine type to be allocated for the database | `string` | `"db-n1-standard-2"` | no |
| <a name="input_database_sort_buffer_size"></a> [database\_sort\_buffer\_size](#input\_database\_sort\_buffer\_size) | Specifies the sort\_buffer\_size value to set for the database | `number` | `67108864` | no |
| <a name="input_database_version"></a> [database\_version](#input\_database\_version) | Version for MySQL | `string` | `"MYSQL_8_0_31"` | no |
Expand All @@ -119,13 +120,15 @@ No resources.
| <a name="input_redis_tier"></a> [redis\_tier](#input\_redis\_tier) | Specifies the tier for this Redis instance | `string` | `"STANDARD_HA"` | no |
| <a name="input_resource_limits"></a> [resource\_limits](#input\_resource\_limits) | Specifies the resource limits for the wandb deployment | `map(string)` | <pre>{<br> "cpu": null,<br> "memory": null<br>}</pre> | no |
| <a name="input_resource_requests"></a> [resource\_requests](#input\_resource\_requests) | Specifies the resource requests for the wandb deployment | `map(string)` | <pre>{<br> "cpu": "2000m",<br> "memory": "2G"<br>}</pre> | no |
| <a name="input_service_account_name"></a> [service\_account\_name](#input\_service\_account\_name) | n/a | `string` | `"workload-identity-sa"` | no |
| <a name="input_size"></a> [size](#input\_size) | Deployment size for the instance | `string` | `null` | no |
| <a name="input_ssl"></a> [ssl](#input\_ssl) | Enable SSL certificate | `bool` | `true` | no |
| <a name="input_subdomain"></a> [subdomain](#input\_subdomain) | Subdomain for accessing the Weights & Biases UI. Default creates record at Route53 Route. | `string` | `null` | no |
| <a name="input_subnetwork"></a> [subnetwork](#input\_subnetwork) | Pre-existing subnetwork self link | `string` | `null` | no |
| <a name="input_use_internal_queue"></a> [use\_internal\_queue](#input\_use\_internal\_queue) | Uses an internal redis queue instead of using google pubsub. | `bool` | `false` | no |
| <a name="input_wandb_image"></a> [wandb\_image](#input\_wandb\_image) | Docker repository of to pull the wandb image from. | `string` | `"wandb/local"` | no |
| <a name="input_wandb_version"></a> [wandb\_version](#input\_wandb\_version) | The version of Weights & Biases local to deploy. | `string` | `"latest"` | no |
| <a name="input_workload_account_id"></a> [workload\_account\_id](#input\_workload\_account\_id) | n/a | `string` | `"workload-identity"` | no |

## Outputs

Expand All @@ -147,6 +150,7 @@ No resources.
| <a name="output_fqdn"></a> [fqdn](#output\_fqdn) | The FQDN to the W&B application |
| <a name="output_gke_node_count"></a> [gke\_node\_count](#output\_gke\_node\_count) | n/a |
| <a name="output_gke_node_instance_type"></a> [gke\_node\_instance\_type](#output\_gke\_node\_instance\_type) | n/a |
| <a name="output_sa_account_email"></a> [sa\_account\_email](#output\_sa\_account\_email) | This output provides the email address of the service account created for workload identity, if workload identity is enabled. Otherwise, it returns null |
| <a name="output_service_account"></a> [service\_account](#output\_service\_account) | Weights & Biases service account used to manage resources. |
| <a name="output_standardized_size"></a> [standardized\_size](#output\_standardized\_size) | n/a |
| <a name="output_url"></a> [url](#output\_url) | The URL to the W&B application |
Expand Down
33 changes: 20 additions & 13 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ locals {
}

module "service_accounts" {
source = "./modules/service_accounts"
namespace = var.namespace
bucket_name = var.bucket_name
depends_on = [module.project_factory_project_services]
source = "./modules/service_accounts"
namespace = var.namespace
bucket_name = var.bucket_name
account_id = var.workload_account_id
service_account_name = var.service_account_name
workload_identity = var.create_workload_identity
depends_on = [module.project_factory_project_services]
}

module "kms" {
Expand Down Expand Up @@ -78,14 +81,15 @@ locals {
}

module "app_gke" {
source = "./modules/app_gke"
namespace = var.namespace
machine_type = coalesce(try(local.deployment_size[var.size].node_instance, null), var.gke_machine_type)
node_count = coalesce(try(local.deployment_size[var.size].node_count, null), var.gke_node_count)
network = local.network
subnetwork = local.subnetwork
service_account = module.service_accounts.service_account
depends_on = [module.project_factory_project_services]
source = "./modules/app_gke"
namespace = var.namespace
machine_type = coalesce(try(local.deployment_size[var.size].node_instance, null), var.gke_machine_type)
node_count = coalesce(try(local.deployment_size[var.size].node_count, null), var.gke_node_count)
network = local.network
subnetwork = local.subnetwork
service_account = module.service_accounts.service_account
workload_identity = var.create_workload_identity
depends_on = [module.project_factory_project_services]
}

module "app_lb" {
Expand Down Expand Up @@ -148,7 +152,10 @@ module "gke_app" {
database_connection_string = module.database.connection_string
redis_connection_string = local.redis_connection_string
redis_ca_cert = local.redis_certificate

service_account_name = var.service_account_name
service_account_annotations = var.create_workload_identity ? {
"iam.gke.io/gcp-service-account": module.service_accounts.sa_account_email
} : {}
oidc_client_id = var.oidc_client_id
oidc_issuer = var.oidc_issuer
oidc_auth_method = var.oidc_auth_method
Expand Down
15 changes: 14 additions & 1 deletion modules/app_gke/main.tf
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
data "google_client_config" "current" {}

locals {
project_id = data.google_client_config.current.project
}

resource "google_container_cluster" "default" {
name = "${var.namespace}-cluster"

network = var.network.self_link
subnetwork = var.subnetwork.self_link
networking_mode = "VPC_NATIVE"

enable_intranode_visibility = true

# Conditionally enable workload identity
dynamic "workload_identity_config" {
for_each = var.workload_identity == true ? [1] : []
content {
workload_pool = "${local.project_id}.svc.id.goog"
}
}

binary_authorization {
evaluation_mode = "PROJECT_SINGLETON_POLICY_ENFORCE"
}
Expand Down
5 changes: 5 additions & 0 deletions modules/app_gke/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,9 @@ variable "machine_type" {

variable "node_count" {
type = number
}

variable "workload_identity" {
description = "Flag to indicate whether to enable workload identity for the service account."
type = bool
}
28 changes: 27 additions & 1 deletion modules/service_accounts/main.tf
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
data "google_client_config" "current" {}

data "google_project" "project" {}
resource "random_id" "main" {
# 30 bytes ensures that enough characters are generated to satisfy the service account ID requirements, regardless of
# the prefix.
Expand Down Expand Up @@ -60,3 +60,29 @@ resource "google_project_iam_member" "secretmanager_admin" {
member = local.sa_member
role = "roles/secretmanager.admin"
}

resource "google_service_account" "workload-identity-user-sa" {
count = var.workload_identity == true ? 1 : 0
account_id = var.account_id
display_name = "Service Account For Workload Identity"
}

resource "google_project_iam_member" "storage-role" {
count = var.workload_identity == true ? 1 : 0
project = local.project_id
role = "roles/storage.admin"
member = "serviceAccount:${google_service_account.workload-identity-user-sa[count.index].email}"
}

resource "google_project_iam_member" "kms-role" {
count = var.workload_identity == true ? 1 : 0
project = local.project_id
role = "roles/cloudkms.admin"
member = "serviceAccount:${google_service_account.workload-identity-user-sa[count.index].email}"
}
resource "google_project_iam_member" "workload_identity-role" {
count = var.workload_identity == true ? 1 : 0
project = local.project_id
role = "roles/iam.workloadIdentityUser"
member = "serviceAccount:${local.project_id}.svc.id.goog[default/${var.service_account_name}]"
}
4 changes: 4 additions & 0 deletions modules/service_accounts/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ output "service_account" {
value = google_service_account.main

description = "The service account."
}

output "sa_account_email" {
value = var.workload_identity == true ? google_service_account.workload-identity-user-sa[0].email : null
}
14 changes: 14 additions & 0 deletions modules/service_accounts/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,18 @@ variable "bucket_name" {
type = string
description = "Existing bucket the service account will access"
default = ""
}
variable "account_id" {
description = "The ID of the Google Cloud Platform (GCP) account."
type = string
}

variable "service_account_name" {
description = "The name of the service account."
type = string
}

variable "workload_identity" {
description = "Flag to indicate whether to enable workload identity for the service account."
type = bool
}
6 changes: 4 additions & 2 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,7 @@ output "database_instance_type" {
value = coalesce(try(local.deployment_size[var.size].db, null), var.database_machine_type)
}



output "sa_account_email" {
description = "This output provides the email address of the service account created for workload identity, if workload identity is enabled. Otherwise, it returns null"
value = var.create_workload_identity == true ? module.service_accounts.sa_account_email : null
}
19 changes: 19 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,22 @@ variable "size" {
type = string
default = null
}


variable "create_workload_identity" {
description = "Flag to indicate whether to create a workload identity for the service account."
type = bool
default = true
}

variable "workload_account_id" {
type = string
default = "workload-identity"
}

variable "service_account_name" {
type = string
default = "workload-identity-sa"
}