Least Privilege Deploys with GKE

When deploying applications I try to separate the components by the frequency that they change. Low frequency items like kube clusters, ingress, databases etc will be handled by the infra pipeline and high frequency items like the app will be handled by the app pipeline.

In the app pipeline I want to use a credential with least privilege to perform the deployment.

The setup:

  • Application on Google cloud (GCP)
  • Deployed on Google Kubernetes Engine (GKE)
  • Deployed via Github Actions

The simple (but less than ideal) way to do this is to set up github actions to use a gcp service account with the gcp permission of container.admin or container.clusterAdmin. However, assuming the deploy action only needs to edit an apps/v1/deployment, this would give the service account far too many permissions.

Here is a simple way to setup a gcp service account with minimum/least privilege to deploy applications.


resource "google_service_account" "github-deployer" {
  account_id   = "github-deployer"
  display_name = "github-deployer"
}

resource "google_project_iam_member" "kube_connector" {
  project = var.project_id
  role    = "roles/container.clusterViewer"
  member  = "serviceAccount:${google_service_account.github-deployer.email}"
}

This roles/container.clusterViewer only provides the ability to connect to the cluster not to do anything in that cluster. Authentication, not authorization.

Then you extend that with a kubernetes RBAC configuration:

The role:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: app
  name: deployer
rules:
- apiGroups: [""] # "" indicates the core API group
  resources: ["pods"]
  verbs: ["get", "watch", "list"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "watch", "list", "update", "delete", "create", "patch"]

The roleBinding:

kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: deployer
  namespace: app
subjects:
# IAM service account
- kind: User
  name: github-deployer@my-simple-test-project-derp.iam.gserviceaccount.com
roleRef:
  kind: Role
  name: deployer
  apiGroup: rbac.authorization.k8s.io

With this in place, the google service account can edit pods and deployments, but can’t even see let alone edit secrets, ingress, services, or other resources in the app or other namespaces.

Effectively creating a least privilege ci/cd setup for use in github actions or any other system.

References: