Skip to content

Commit

Permalink
feat: Support GCP impersonation (#94)
Browse files Browse the repository at this point in the history
Introduce new parameter `streamnative_org_id` which is required to grant
permissions of GCP project for impersonation
  • Loading branch information
ciiiii authored Jul 27, 2024
1 parent b99a234 commit 97cfe1c
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 20 deletions.
7 changes: 5 additions & 2 deletions modules/gcp/vendor-access/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ provider "google" {
}
module "sn_managed_cloud" {
source = "github.com/streamnative/terraform-managed-cloud//modules/gcp/vendor-access?ref=v3.7.0"
source = "github.com/streamnative/terraform-managed-cloud//modules/gcp/vendor-access?ref=v3.15.0"
project = "<YOUR_PROJECT>"
streamnative_org_id = "<YOUR_ORG_ID>"
}
```

Expand Down Expand Up @@ -523,7 +524,8 @@ No modules.
|------|-------------|------|---------|:--------:|
| <a name="input_extra_google_services"></a> [extra\_google\_services](#input\_extra\_google\_services) | Extra google API services need to be enabled. | `list(string)` | `[]` | no |
| <a name="input_project"></a> [project](#input\_project) | The project id of the target project | `string` | n/a | yes |
| <a name="input_roles"></a> [roles](#input\_roles) | The role list will be associated with StreamNative GSA. | `list(string)` | <pre>[<br> "roles/editor",<br> "roles/compute.admin",<br> "roles/compute.loadBalancerAdmin",<br> "roles/compute.networkAdmin",<br> "roles/container.admin",<br> "roles/dns.admin",<br> "roles/storage.admin",<br> "roles/iam.serviceAccountAdmin",<br> "roles/iam.workloadIdentityPoolAdmin",<br> "roles/resourcemanager.projectIamAdmin"<br>]</pre> | no |
| <a name="input_roles"></a> [roles](#input\_roles) | The role list will be associated with StreamNative GSA. | `list(string)` | <pre>[<br> "roles/editor",<br> "roles/cloudkms.admin",<br> "roles/compute.admin",<br> "roles/compute.loadBalancerAdmin",<br> "roles/compute.networkAdmin",<br> "roles/container.admin",<br> "roles/dns.admin",<br> "roles/storage.admin",<br> "roles/iam.serviceAccountAdmin",<br> "roles/iam.workloadIdentityPoolAdmin",<br> "roles/resourcemanager.projectIamAdmin"<br>]</pre> | no |
| <a name="input_streamnative_org_id"></a> [streamnative\_org\_id](#input\_streamnative\_org\_id) | Your Organization ID within StreamNative Cloud, used as name of impersonation GSA in your project. This will be the organization ID in the StreamNative console, e.g. "o-xhopj". | `string` | `""` | no |
| <a name="input_streamnative_support_access_gsa"></a> [streamnative\_support\_access\_gsa](#input\_streamnative\_support\_access\_gsa) | The GSA will be used by StreamnNative support team. | `list(string)` | <pre>[<br> "[email protected]"<br>]</pre> | no |
| <a name="input_streamnative_vendor_access_gsa"></a> [streamnative\_vendor\_access\_gsa](#input\_streamnative\_vendor\_access\_gsa) | The GSA will be used by StreamnNative cloud. | `list(string)` | <pre>[<br> "[email protected]",<br> "[email protected]"<br>]</pre> | no |
Expand All @@ -533,3 +535,4 @@ No modules.
|------|-------------|
| <a name="output_google_services"></a> [google\_services](#output\_google\_services) | Enabled google services. |
| <a name="output_iam_bindings"></a> [iam\_bindings](#output\_iam\_bindings) | Configured iam policies. |
| <a name="output_impersonation_iam_bindings"></a> [impersonation\_iam\_bindings](#output\_impersonation\_iam\_bindings) | Configured iam policies for impersonation. |
10 changes: 10 additions & 0 deletions modules/gcp/vendor-access/common.tf
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ variable "streamnative_vendor_access_gsa" {
description = "The GSA will be used by StreamnNative cloud."
}

variable "streamnative_org_id" {
default = ""
type = string
description = "Your Organization ID within StreamNative Cloud, used as name of impersonation GSA in your project. This will be the organization ID in the StreamNative console, e.g. \"o-xhopj\"."
validation {
condition = length(var.streamnative_org_id) <= 18
error_message = "The organization ID must not exceed 18 characters. If you reach this limit, please contact StreamNative support."
}
}

variable "streamnative_support_access_gsa" {
default = ["[email protected]"]
type = list(string)
Expand Down
3 changes: 2 additions & 1 deletion modules/gcp/vendor-access/docs/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ provider "google" {
}

module "sn_managed_cloud" {
source = "github.com/streamnative/terraform-managed-cloud//modules/gcp/vendor-access?ref=v3.7.0"
source = "github.com/streamnative/terraform-managed-cloud//modules/gcp/vendor-access?ref=v3.15.0"
project = "<YOUR_PROJECT>"
streamnative_org_id = "<YOUR_ORG_ID>"
}
88 changes: 71 additions & 17 deletions modules/gcp/vendor-access/main.tf
Original file line number Diff line number Diff line change
@@ -1,13 +1,4 @@
locals {
streamnative_gsa = concat(var.streamnative_vendor_access_gsa, var.streamnative_support_access_gsa)
iam_bindings = flatten([
for role in var.roles : [
for gsa in local.streamnative_gsa : {
role : role,
member : format("serviceAccount:%s", gsa),
}
]
])
google_services = concat([
"autoscaling.googleapis.com",
"cloudresourcemanager.googleapis.com",
Expand All @@ -31,23 +22,86 @@ resource "google_project_service" "gcp_apis" {
service = local.google_services[count.index]
}

locals {
is_impersonation_enabled = var.streamnative_org_id != ""
streamnative_gsa = concat(var.streamnative_vendor_access_gsa, var.streamnative_support_access_gsa)
}

# Grant permissions directly to the StreamNative Cloud service account
locals {
iam_bindings = local.is_impersonation_enabled ? [] : flatten([
for role in var.roles : [
for gsa in local.streamnative_gsa : {
role : role,
member : format("serviceAccount:%s", gsa),
}
]
])
}

resource "google_project_iam_member" "sn_access" {
for_each = {
for index, binding in local.iam_bindings :
index => binding
}
count = length(local.iam_bindings)
project = var.project
role = each.value.role
member = each.value.member
role = local.iam_bindings[count.index].role
member = local.iam_bindings[count.index].member
depends_on = [google_project_service.gcp_apis]
}

# Grant permissions to the project service account that will be impersonated by StreamNative Cloud service account
locals {
streamnative_bootstrap_gsa_name = format("snbootstrap-%s", var.streamnative_org_id)
streamnative_bootstrap_roles = local.is_impersonation_enabled ? var.roles : []
impersonation_roles = [
"roles/iam.serviceAccountUser",
"roles/iam.serviceAccountAdmin",
"roles/iam.serviceAccountTokenCreator",
]
impersonation_iam_bindings = local.is_impersonation_enabled ? flatten([
for role in local.impersonation_roles : [
for gsa in local.streamnative_gsa : {
role : role,
member : format("serviceAccount:%s", gsa),
}
]
]) : []

}
resource "google_service_account" "sn_bootstrap" {
count = local.is_impersonation_enabled ? 1 : 0
account_id = local.streamnative_bootstrap_gsa_name
project = var.project
display_name = "StreamNative Bootstrap GSA that will be impersonated by StreamNative Cloud Control Plane."
depends_on = [google_project_service.gcp_apis]
}

resource "google_project_iam_member" "sn_bootstrap" {
count = length(local.streamnative_bootstrap_roles)
project = var.project
role = local.streamnative_bootstrap_roles[count.index]
member = format("serviceAccount:%s", google_service_account.sn_bootstrap[0].email)
depends_on = [google_service_account.sn_bootstrap]
}

resource "google_service_account_iam_member" "sn_bootstrap_impersonation" {
count = length(local.impersonation_iam_bindings)
service_account_id = google_service_account.sn_bootstrap[0].id
role = local.impersonation_iam_bindings[count.index].role
member = local.impersonation_iam_bindings[count.index].member
depends_on = [google_service_account.sn_bootstrap]
}


output "google_services" {
value = local.google_services
value = local.google_services
description = "Enabled google services."
}

output "iam_bindings" {
value = local.iam_bindings
value = local.iam_bindings
description = "Configured iam policies."
}

output "impersonation_iam_bindings" {
value = local.impersonation_iam_bindings
description = "Configured iam policies for impersonation."
}

0 comments on commit 97cfe1c

Please sign in to comment.