Skip to content

Commit

Permalink
fix: WI conditionally invoke data source if using external GSA (#974)
Browse files Browse the repository at this point in the history
* fix: conditionally invoke datasource for custom gsa

* add an example for custom gsa

* refactor tests

* fmt
  • Loading branch information
bharathkkb committed Aug 14, 2021
1 parent a861a2d commit b208d5c
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 33 deletions.
8 changes: 6 additions & 2 deletions examples/workload_identity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,12 @@ Read more about [workload identity in the docs](https://cloud.google.com/kuberne
| ca\_certificate | n/a |
| client\_token | n/a |
| cluster\_name | Cluster name |
| k8s\_service\_account\_email | K8S GCP service account. |
| k8s\_service\_account\_name | K8S GCP service name |
| default\_wi\_email | GCP service account. |
| default\_wi\_ksa\_name | K8S SA name |
| existing\_gsa\_email | GCP service account. |
| existing\_gsa\_name | K8S SA name |
| existing\_ksa\_email | GCP service account. |
| existing\_ksa\_name | K8S SA name |
| kubernetes\_endpoint | n/a |
| location | Cluster location (zones) |
| project\_id | Project id where GKE cluster is created. |
Expand Down
16 changes: 15 additions & 1 deletion examples/workload_identity/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ module "workload_identity" {
use_existing_k8s_sa = false
}


# example with existing KSA
resource "kubernetes_service_account" "test" {
metadata {
Expand All @@ -83,3 +82,18 @@ module "workload_identity_existing_ksa" {
use_existing_k8s_sa = true
k8s_sa_name = kubernetes_service_account.test.metadata.0.name
}

# example with existing GSA
resource "google_service_account" "custom" {
account_id = "custom-gsa"
project = var.project_id
}

module "workload_identity_existing_gsa" {
source = "../../modules/workload-identity"
project_id = var.project_id
name = google_service_account.custom.account_id
use_existing_gcp_sa = true
# wait till custom GSA is created to force module data source read during apply
depends_on = [google_service_account.custom]
}
33 changes: 28 additions & 5 deletions examples/workload_identity/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,35 @@ output "cluster_name" {
value = module.gke.name
}

output "k8s_service_account_email" {
description = "K8S GCP service account."
# Default instantiation of WI module
output "default_wi_email" {
description = "GCP service account."
value = module.workload_identity.gcp_service_account_email
}

output "k8s_service_account_name" {
description = "K8S GCP service name"
value = module.workload_identity.gcp_service_account_name
output "default_wi_ksa_name" {
description = "K8S SA name"
value = module.workload_identity.k8s_service_account_name
}

# Existing KSA instantiation of WI module
output "existing_ksa_email" {
description = "GCP service account."
value = module.workload_identity_existing_ksa.gcp_service_account_email
}

output "existing_ksa_name" {
description = "K8S SA name"
value = module.workload_identity_existing_ksa.k8s_service_account_name
}

# Existing GSA instantiation of WI module
output "existing_gsa_email" {
description = "GCP service account."
value = google_service_account.custom.email
}

output "existing_gsa_name" {
description = "K8S SA name"
value = module.workload_identity_existing_gsa.k8s_service_account_name
}
9 changes: 5 additions & 4 deletions modules/workload-identity/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ locals {
# GCP service account ids must be < 30 chars matching regex ^[a-z](?:[-a-z0-9]{4,28}[a-z0-9])$
# KSAs do not have this naming restriction.
gcp_given_name = var.gcp_sa_name != null ? var.gcp_sa_name : substr(var.name, 0, 30)
gcp_sa_email = data.google_service_account.cluster_service_account.email
gcp_sa_email = var.use_existing_gcp_sa ? data.google_service_account.cluster_service_account[0].email : google_service_account.cluster_service_account[0].email
gcp_sa_fqn = "serviceAccount:${local.gcp_sa_email}"

# This will cause Terraform to block returning outputs until the service account is created
Expand All @@ -30,8 +30,9 @@ locals {
}

data "google_service_account" "cluster_service_account" {
# This will cause Terraform to block looking up details until the service account is created
account_id = var.use_existing_gcp_sa ? local.gcp_given_name : google_service_account.cluster_service_account[0].account_id
count = var.use_existing_gcp_sa ? 1 : 0

account_id = var.name
project = var.project_id
}

Expand Down Expand Up @@ -72,7 +73,7 @@ module "annotate-sa" {
}

resource "google_service_account_iam_member" "main" {
service_account_id = data.google_service_account.cluster_service_account.name
service_account_id = var.use_existing_gcp_sa ? data.google_service_account.cluster_service_account[0].name : google_service_account.cluster_service_account[0].name
role = "roles/iam.workloadIdentityUser"
member = local.k8s_sa_gcp_derived_name
}
Expand Down
34 changes: 29 additions & 5 deletions test/fixtures/workload_identity/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,36 @@ output "cluster_name" {
value = module.example.cluster_name
}

output "k8s_service_account_email" {
description = "K8S GCP service account."
value = module.example.k8s_service_account_email
# Default instantiation of WI module
output "default_wi_email" {
description = "GCP service account."
value = module.example.default_wi_email
}

output "k8s_service_account_name" {
output "default_wi_ksa_name" {
description = "K8S GCP service account name."
value = module.example.k8s_service_account_name
value = module.example.default_wi_ksa_name
}

# Existing KSA instantiation of WI module
output "existing_ksa_email" {
description = "GCP service account."
value = module.example.existing_ksa_email
}

output "existing_ksa_name" {
description = "K8S GCP service name"
value = module.example.existing_ksa_name
}

# Existing GSA instantiation of WI module
output "existing_gsa_email" {
description = "GCP service account."
value = module.example.existing_gsa_email
}

output "existing_gsa_name" {
description = "K8S GCP service name"
value = module.example.existing_gsa_name
}

32 changes: 18 additions & 14 deletions test/integration/workload_identity/controls/gcloud.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
project_id = attribute('project_id')
location = attribute('location')
cluster_name = attribute('cluster_name')
k8s_service_account_email = attribute('k8s_service_account_email')
k8s_service_account_name = attribute('k8s_service_account_name')
wi_gsa_to_k8s_sa = {
attribute('default_wi_email') => attribute('default_wi_ksa_name'),
attribute('existing_ksa_email') => attribute('existing_ksa_name'),
attribute('existing_gsa_email') => attribute('existing_gsa_name')
}

control "gcloud" do
title "Google Compute Engine GKE configuration"
Expand Down Expand Up @@ -57,20 +60,21 @@
end
end
end
wi_gsa_to_k8s_sa.each do |gsa_email,ksa_name|
describe command("gcloud iam service-accounts get-iam-policy #{gsa_email} --format=json") do
its(:exit_status) { should eq 0 }
its(:stderr) { should eq '' }

describe command("gcloud iam service-accounts get-iam-policy #{k8s_service_account_email} --format=json") do
its(:exit_status) { should eq 0 }
its(:stderr) { should eq '' }

let!(:iam) do
if subject.exit_status == 0
JSON.parse(subject.stdout)
else
{}
let!(:iam) do
if subject.exit_status == 0
JSON.parse(subject.stdout)
else
{}
end
end
it "has expected workload identity user roles" do
expect(iam['bindings'][0]).to include("members" => ["serviceAccount:#{project_id}.svc.id.goog[default/#{ksa_name}]"], "role" => "roles/iam.workloadIdentityUser")
end
end
it "has expected workload identity user roles" do
expect(iam['bindings'][0]).to include("members" => [k8s_service_account_name], "role" => "roles/iam.workloadIdentityUser")
end
end
end
16 changes: 14 additions & 2 deletions test/integration/workload_identity/inspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,21 @@ attributes:
- name: project_id
required: true
type: string
- name: k8s_service_account_email
- name: default_wi_email
required: true
type: string
- name: k8s_service_account_name
- name: default_wi_ksa_name
required: true
type: string
- name: existing_ksa_email
required: true
type: string
- name: existing_ksa_name
required: true
type: string
- name: existing_gsa_email
required: true
type: string
- name: existing_gsa_name
required: true
type: string

0 comments on commit b208d5c

Please sign in to comment.