If icon
TerraformCLI icon
Sleep icon
GCloudCLI icon
Set icon
AnsibleCLI icon

Deploy an Active Directory Domain Controller on Google Cloud

End-to-end AD domain controller lifecycle on GCP with Kestra. Terraform provisions Windows Server, a startup script promotes the DC, and Ansible configures DNS.

Categories
Infrastructure

Stand up a complete Active Directory domain controller on Google Cloud from a single flow. Terraform creates the firewall rules and a Windows Server instance whose startup script installs AD DS and DNS and promotes the forest; gcloud generates admin credentials; the connection details land in the KV store for downstream flows (VM domain joins, DNS registration); and Ansible connects over WinRM to set a durable admin password and create the reverse DNS lookup zone. The same flow handles teardown via the action input, reusing the same Terraform state.

How it works

  1. The createOrDelete task (io.kestra.plugin.core.flow.If) branches on the action input.
  2. On create, createADController (io.kestra.plugin.terraform.cli.TerraformCLI) applies an inlined main.tf that creates an RDP/AD firewall rule scoped to your public IP and the internal subnet, plus a windows-2022 instance with a static internal IP. The rendered setup-dc.ps1 is attached as windows-startup-script-ps1: it enables WinRM, opens NTP (Kerberos needs sub-5-minute drift), installs AD-Domain-Services and DNS, and idempotently runs Install-ADDSForest. State is stored in a GCS backend with the VM name as prefix.
  3. waitForStartupBootConfig (io.kestra.plugin.core.flow.Sleep, PT10M) waits for promotion and reboot.
  4. resetPassword (io.kestra.plugin.gcp.cli.GCloudCLI) runs gcloud compute reset-windows-password and captures credentials.json.
  5. createADConfigMap (io.kestra.plugin.core.kv.Set) publishes dcConfig (IPs, domain, username, subnet CIDR) to the KV store for sibling flows.
  6. enableReverseLookupZone (io.kestra.plugin.ansible.cli.AnsibleCLI) builds a WinRM inventory from the generated credentials, sets the admin password to your managed secret with ansible.windows.win_user, and creates the in-addr.arpa reverse zone with ansible.windows.win_shell.
  7. On delete, deleteADController destroys everything from the same state and flips the VM asset to state: deleted.

What you get

  • A one-shot, idempotent AD forest deployment including DNS and NTP configuration.
  • Generated Windows credentials replaced by a secret-managed password immediately.
  • A dcConfig KV record that downstream flows use for domain joins and DNS records.
  • Full lifecycle in one flow: create and destroy share state and configuration.
  • The DC tracked as a governed VM asset in the Kestra Assets catalog.

Who it's for

  • Infrastructure teams running Windows AD workloads on GCP.
  • Platform engineers building lab, demo, or dev environments with real domain services.
  • IT operations automating hybrid identity foundations.

Why orchestrate this with Kestra

This deployment spans four toolchains: Terraform, GCP startup scripts, gcloud, and Ansible over WinRM. Kestra sequences them with real dependencies, passes artifacts between steps (Terraform outputs into gcloud, gcloud credentials into the Ansible inventory), keeps the domain password in a secrets backend rather than in scripts, and publishes the DC's connection details to the KV store so the rest of your automation can consume them declaratively.

Prerequisites

  • A GCP project with Compute Engine enabled and a service account allowed to manage instances and firewall rules.
  • A GCS bucket for Terraform state (replace my-terraform-state-bucket).
  • Kestra Enterprise Edition for the Assets tracking (remove the assets blocks to run on OSS).

Secrets

  • GCP_SERVICE_ACCOUNT_JSON: JSON key used by Terraform and gcloud.
  • AD_ADMIN_PASSWORD: the durable domain administrator password set during promotion and via Ansible.

Quick start

  1. Add the secrets above to your Kestra namespace.
  2. Set billingAccount, network, subnet, subnetCIDR, and your public IP in remoteUserIpAddress.
  3. Replace the state bucket in both backend.tf blocks.
  4. Execute with action: create; RDP to the external IP once complete.
  5. Run again with action: delete to tear everything down.

How to extend

  • Chain a Linux VM provisioning flow that reads kv('dcConfig') to join machines to the domain.
  • Add a Pause approval gate before the delete branch.
  • Restrict the firewall further or switch WinRM to HTTPS (5986) with proper certificates for production.
  • Register forward DNS records for new VMs with another AnsibleCLI task against the DC.

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.