Skip to content

Uninstall

Admin guide

Greenlight runs entirely in your own cloud, so you remove it there, as a cloud owner — never from the dashboard. Settings → Danger zone says the same and removes nothing. Shift cannot uninstall Greenlight for you: it has no access to your cloud.

Uninstalling is a by-hand sequence, run once. Your databases, storage, DNS zone, and cluster carry delete protection so that no automatic update can ever destroy them (Upgrades). Uninstalling is the one time you lift that protection, on purpose.

  1. Keep what you need. Export the audit log, and snapshot or back up any database or storage you may want later, using your cloud’s own tools. Once the step that deletes them has run, they cannot be recovered.

  2. Delete your apps in Greenlight first. Use each app’s lifecycle menu (Kill switch & restore). That removes the identities, images, secrets, and DNS records each app was given, the way the platform expects, so fewer leftovers need finding by hand.

  3. Stop automatic updates, so no scheduled update runs halfway through the teardown:

    Terminal window
    kubectl -n greenlight-updater patch cronjob greenlight-updater -p '{"spec":{"suspend":true}}'
  4. Remove the DNS delegation for your Greenlight host (for example greenlight.example.com) at whoever hosts your parent domain. Greenlight never had access to that record. Until it is gone, public resolvers keep answering for the host after the zone itself is deleted.

Installed from the Azure portal (Marketplace)

Section titled “Installed from the Azure portal (Marketplace)”

Delete the managed application in the Azure portal. Azure removes its managed resource group, and everything Greenlight created, with it. If the delete is refused, contact Shift support before trying anything else: the managed resource group’s deny assignment stops you changing it directly.

Everything Greenlight creates sits in the one resource group you installed into, so deleting that group removes the install. Delete locks guard the cluster, both PostgreSQL servers, the storage account, and the Key Vault, so remove those first.

  1. Remove the delete locks in the install’s resource group:

    Terminal window
    az lock list --resource-group <resource-group> --output table
    az lock delete --ids $(az lock list --resource-group <resource-group> --query '[].id' --output tsv)
  2. Delete the resource group. This removes the cluster (and the node resource group Azure manages for it), the databases, storage, Key Vault, DNS zone, network, and identities:

    Terminal window
    az group delete --name <resource-group>
  3. Purge the Key Vault, if you want its name back. A deleted vault stays recoverable for 90 days and holds its name for that time. Greenlight’s vault does not use purge protection, so you can purge it straight away:

    Terminal window
    az keyvault list-deleted --query "[].{name:name, location:properties.location}" --output table
    az keyvault purge --name <vault-name> --location <region>

Delete the project. This is the simplest complete removal. It also takes the Terraform state bucket (greenlight-tfstate-<project>), which nothing else uses once the install is gone:

Terminal window
gcloud projects delete <project>

Google keeps a deleted project recoverable for 30 days before removing it for good. Billing for its resources stops when the delete is requested.

Destroy only what Greenlight created, with the Terraform files from the release package you last installed or updated with. Run the steps in order. Each one clears something that would otherwise stop the destroy.

  1. Remove the cluster workloads while the cluster still exists, so the load balancers and firewall rules they own are deleted cleanly:

    Terminal window
    helm uninstall greenlight -n greenlight-system
    helm uninstall traefik -n traefik
  2. Empty the Cloud DNS zone of every record except NS and SOA. Greenlight writes the host’s A records and the certificate’s _acme-challenge TXT records itself, and Google refuses to delete a zone that still has them.

  3. Delete the Cloud SQL instances directly (gcloud sql instances delete <instance>) instead of letting Terraform drop their database users first. The users own objects inside the database, so dropping them fails.

  4. Delete what Greenlight created while running, which Terraform does not track: the Secret Manager secrets that hold integration credentials, app secrets, the Slack webhook URL, and Greenlight’s own signing and encryption keys, and the service account made for each app. List them, check each list, then delete what it shows. The secret filter leaves out the four greenlight-cloudsql-* secrets, which the destroy in step 6 removes:

    Terminal window
    gcloud secrets list --project <project> --filter="name ~ /secrets/(integrations|apps|notifications|greenlight)- AND NOT name ~ /secrets/greenlight-cloudsql-" --format="value(name)"
    gcloud iam service-accounts list --project <project> --filter="displayName:'Greenlight app'" --format="value(email)"

    Delete each secret with gcloud secrets delete <name> --project <project> and each account with gcloud iam service-accounts delete <email> --project <project>.

  5. Lift the delete protection on a copy of the package’s deployment/gcp/ directory. In every .tf file, change prevent_destroy = true to false. Never edit the package you install from.

  6. Destroy from that copy against the install’s state:

    Terminal window
    terraform init -backend-config="bucket=greenlight-tfstate-<project>" -backend-config="prefix=install"
    terraform destroy \
    -var "projectId=<project>" -var "region=<region>" -var "controlPlaneHost=<host>" \
    -var "sourceRegistryUrl=" -var "sourceRegistryUsername=" -var "sourceRegistryPassword="

    If it stops, fix the cause and run it again:

    • A resource you already deleted is still in the state (for example a Cloud SQL user after step 3): terraform state rm <address>, then rerun.
    • The private services connection says producer services are still using it: wait a few minutes after Cloud SQL is gone and rerun. If it persists, delete the VPC peering named servicenetworking-googleapis-com, then rerun.
    • The network cannot be deleted because firewall rules use it: delete the leftover k8s-… rules GKE created on that network (gcloud compute firewall-rules list --filter="network:<network>"), then rerun.
  7. Decide the state bucket. Keep gs://greenlight-tfstate-<project> as the record of what was destroyed, or delete it, including every object version.

Greenlight expects its own AWS account. The databases, buckets, DNS zone, EKS cluster, and the GitHub App secrets carry delete protection, so a plain terraform destroy is refused until you lift it.

  1. Remove the cluster workloads, then wait for the ingress load balancer to go before removing the controller that deletes it. On a private install that publishes through PrivateLink, first rerun ./install.sh --private-link-consumers none: AWS will not delete a load balancer an endpoint service still publishes, and that run rejects the connected endpoints and removes the service.

    Terminal window
    helm uninstall greenlight -n greenlight-system
    helm uninstall traefik -n traefik

    Continue once the Network Load Balancer tagged elbv2.k8s.aws/cluster=<cluster-name> is gone and, on a public install, the ingress Elastic IP shows no association. Then:

    Terminal window
    helm uninstall cert-manager -n cert-manager
    helm uninstall aws-load-balancer-controller -n kube-system
    helm uninstall cluster-autoscaler -n kube-system
  2. Empty the Route 53 zone for your host of every record set except NS and SOA. Check that the zone’s name is exactly your host before you delete anything.

  3. Delete what Greenlight created while running, which Terraform does not track: IAM roles under the /gl-app/ path, gl-app-* ECR repositories, and Secrets Manager secrets under greenlight/, integrations/, apps/, and notifications/.

  4. Lift the delete protection on a copy of the package’s deployment/aws/ directory. In every .tf file, change prevent_destroy = true to false. Never edit the package you install from.

  5. Destroy from that copy against the install’s state:

    Terminal window
    terraform init -backend-config="bucket=greenlight-tfstate-<account-id>" \
    -backend-config="key=install/terraform.tfstate" -backend-config="region=<region>"
    terraform plan -destroy \
    -var "region=<region>" -var "controlPlaneHost=<host>" \
    -var "sourceRegistryUrl=" -var "sourceRegistryUsername=" -var "sourceRegistryPassword="
    terraform destroy \
    -var "region=<region>" -var "controlPlaneHost=<host>" \
    -var "sourceRegistryUrl=" -var "sourceRegistryUsername=" -var "sourceRegistryPassword="

    Read the plan first: it should contain only deletions. The databases take longest, so run the destroy where a dropped session cannot interrupt it; a partial failure is safe to rerun. The databases are deleted without a final snapshot, every bucket is emptied with all its versions, and secrets are deleted without a recovery window.

  6. Decide the state bucket. Keep greenlight-tfstate-<account-id> as the record of what was destroyed, or delete every object version and the lock file, then the bucket.

Whichever cloud you used, a few things live elsewhere:

  • The DNS delegation at your parent domain, if you have not already removed it.
  • The GitHub App. Uninstall it from your GitHub organization, and archive or delete the app and plugin marketplace repositories it managed, if you no longer want them.
  • The sign-in client you registered with your identity provider for Greenlight.
  • Your Shift subscription. Tell Shift the install is gone, so the subscription can be closed and the install stops appearing as one that has missed its reports.