Install Harness Delegate on Google Kubernetes Engine (GKE) with Workload Identity
Workload Identity allows a Kubernetes Service Account (KSA) in your Google Kubernetes Engine (GKE) cluster to act as a Google Identity and Access Management (IAM) Service Account. Pods that use the configured KSA automatically authenticate as the IAM service account when accessing Google Cloud APIs.
This topic explains how to enable Workload Identity on GKE and deploy a Harness Delegate onto Workload Identity-enabled GKE. To demonstrate this, the examples in this topic use Terraform pipelines to deploy GKE and Harness Delegate, and it also builds a simple CI pipeline to push an image to Google Artifact Registry (GAR) without using Google Cloud Platform (GCP) connectors or configuring secrets.
Using a Workload Identity-enabled Harness Delegate can help simplify and secure your pipelines. With this setup, pipelines can use any Google API services by configuring the GSA with the correct roles and permissions, and you no longer need to store or update the Google API credentials in Harness. For example, after deploying a Workload Identity-enabled delegate, you can also do keyless signing of your container images using Google Application Credentials using cosign.
Prerequisites
To use GKE with Workload Identity, you need a Google Cloud account with a Service Account with the following roles:
Kubernetes Engine Admin
to create a GKE cluster.Compute Network Admin
to create the virtual private cloud (VPC) networks.Service Account Admin
andService Account User
roles or the specificService Account
roles used to create, update, or delete a Service Account:- iam.serviceAccounts.actAs
- iam.serviceAccounts.get
- iam.serviceAccounts.create
- iam.serviceAccounts.delete
- iam.serviceAccounts.update
- iam.serviceAccounts.get
- iam.serviceAccounts.getIamPolicy
- iam.serviceAccounts.setIamPolicy
To follow along with the examples in this topic, you need the following tools:
The examples in this topic use Terraform pipelines to deploy GKE and Harness Delegate. If you want to follow along, clone the sources locally:
git clone https://github.com/harness-apps/workload-identity-gke-demo.git && cd "$(basename "$_" .git)"
export DEMO_HOME="$PWD"
Configure Google Cloud
-
When working with Google Cloud, the following environment variables help set the Google Cloud context, like Service Account Key file, project, and so on. You can use direnv or set these variables on your shell:
export GOOGLE_APPLICATION_CREDENTIALS="the google cloud service account key json file to use"
export CLOUDSDK_ACTIVE_CONFIG_NAME="the google cloud cli profile to use"
export GOOGLE_CLOUD_PROJECT="the google cloud project to use"
export KUBECONFIG="$DEMO_HOME/.kube/config"For more information about gcloud cli configurations, go to the Google Cloud SDK documentation.
-
You might need to override some Terraform variables that you don't want to check in to VCS. Add them to a file called
.local.tfvars
and set the following environment variable to be picked up by Terraform runs:export TFVARS_FILE=.local.tfvars
Check the Inputs section for all possible Terraform variables that are configurable.
Example .local.tfvars
project_id = "my-awesome-gcp-project"
region = "asia-south1"
cluster_name = "wi-demos"
kubernetes_version = "1.24."
harness_account_id = "REPLACE WITH YOUR HARNESS ACCOUNT ID"
harness_delegate_token = "REPLACE WITH YOUR HARNESS DELEGATE TOKEN"
harness_delegate_name = "wi-demos-delegate"
harness_delegate_namespace = "harness-delegate-ng"
harness_manager_endpoint = "https://app.harness.io/gratis"
-
Use Terraform to create a GKE cluster with
WorkloadIdentity
enabled for its nodes.task init
-
Use Terraform apply to create a GKE Cluster.
task create_cluster
Deploy the Harness Delegate
Deploy a Harness Delegate onto the GKE cluster.
-
To be able to successfully deploy a Harness Delegate, update the following values in the
.local.tfvars
file,harness_account_id
: Set this to your Harness Account ID, which you can find on your Account Overview page in Harness or in any Harness app URL.harness_delegate_token
: This is a Harness Delegate token.harness_delegate_name
: Defaults toharness-delegate
.harness_delegate_namespace
: Defaults toharness-delegate-ng
.harness_manager_endpoint
: Use the Harness Cluster Hosting Account from your Account Overview page to find the matching endpoint URL for this value. For example, the endpoint URL forprod-2
ishttps://app.harness.io/gratis
. For more information, go to Install delegate.
-
To deploy the Harness Delegate, run
task deploy_harness_delegate
, and then wait while the delegate connects.You can check delegate status on the Delegates page in the Harness Platform.
For Kubernetes delegates, you can also use
kubectl get pods -n harness-delegate-ng
. For running delegates, the output is something like:NAME READY STATUS RESTARTS AGE
your-delegate name 1/1 Running 0 2m23sAs part of deploying the Harness Delegate, the task also performs these additional tasks:
- Creates a Google Service Account (GSA)
harness-delegate
. - Adds an IAM binding policy to the
harness-delegate
service account (SA), with the roleroles/iam.workloadIdentityUser
and a member "serviceAccount:$GOOGLE_CLOUD_PROJECT.svc.id.goog[\default/harness-builder]". - Adds a
harness-delegate
SA with the roleroles/artifactregistry.createOnPushRepoAdmin
, enabling it to push images to GAR. - Creates a KSA
harness-builder
annotated withiam.gke.io/gcp-service-account
toharness-delegate
, allowing it to impersonate the GSA thereby enabling it to push the built application image to GAR.
- Creates a Google Service Account (GSA)
Test it with a CI pipeline
Having deployed the Harness Delegate, you can use a CI pipeline to test the setup by building and pushing a sample Go app to GAR.
This demo pipeline does the following:
- Builds a Go application. You can build any application, but Go is used as an example here.
- Packages the application build artifact as a container image.
- Pushes the image to GAR.
- Caches the build artifacts and dependencies (Go modules) onto GCS to make the build process faster in the future.
Import the template
The demo repository used for this topic has a build stage template that you can use to create the demo pipeline.
- In your Harness account, go to Account Overview, select Organizations, and then select the default organization.
- From the Organization overview page, select Templates.
- Select New Template, and then select the Import From Git option.
- Populate the Import Template From Git fields as follows:
- Name:
ko_gar_build_push
- Version Label:
1
- Git Connector: Select or create a GitHub connector
- Repository: Use the public demo repo or your personal fork of the demo repo,
harness-apps/workload-identity-gke-demo
- Git Branch:
main
- YAML Path:
.harness/ko_gar_build_push_1.yaml
- Name:
- Select Import
Create the pipeline
- Go to the CI module (Builds), select Pipeline, and select Create Pipeline.
- Select Add Stage, and then select Use template.
- Select the
ko_gar_build_push
template you imported, and then select Use template. - Enter a Stage Name, select or create a codebase connector, and set the Repository Name to the public demo repo or your personal fork of the demo repo,
harness-apps/workload-identity-gke-demo
. - Select Set Up Stage, and then populate the Template Inputs:
- Kubernetes Cluster: Select or create a Kubernetes cluster connector.
- Namespace:
default
- Service Account Name:
harness-builder
(Theharness-builder
KSA is mapped to Google IAM Service Account (GSA)harness-delegate
to inherit the GCP roles, using Workload Identity in this case to push the images to Google Artifact Registry (GAR).) - Environment Variable for Download Binaries step: Set the
REGISTRY_LIST
value as the path to your GAR registry list. - Environment Variable for Build and Push step: Set the
KO_DOCKER_REPO
value to the GAR repo where you want to push the image, such asREGION-docker.pkg.dev/YOUR_USERNAME/YOUR_REPO
- Save and run the pipeline to build and push the image to GAR. You can check the build logs to see where the image was pushed.
Clean up resources
To clean up all the Google Cloud resources that were created as part of this demo, you can run the following task:
task destroy