Great set of questions—let’s break this down using clear systems thinking and practical engineering management advice, ensuring you’re set up for robust, reliable automation.
You can use the schedule trigger in GitHub Actions to run your workflows at specific times. You’ll need two workflows:
- One for
terraform applyat 8 a.m. - One for
terraform destroyat 5 p.m.
Example schedule YAML:
# .github/workflows/terraform-apply.yml
name: Terraform Apply Bastion
on:
schedule:
- cron: '0 8 * * *' # 8 a.m. UTC
jobs:
apply:
runs-on: ubuntu-latest
steps:
# Setup Terraform, Azure login, etc.
- run: terraform apply -target=azurerm_bastion_host.example -auto-approve# .github/workflows/terraform-destroy.yml
name: Terraform Destroy Bastion
on:
schedule:
- cron: '0 17 * * *' # 5 p.m. UTC
jobs:
destroy:
runs-on: ubuntu-latest
steps:
# Setup Terraform, Azure login, etc.
- run: terraform destroy -target=azurerm_bastion_host.example -auto-approveterraform apply -target=xyz.resource_block_namewill create only the specified resource (and any dependencies).terraform destroy -target=xyz.resource_block_namewill destroy only the specified resource (and any dependents).- Caution: Relying on
-targetis not recommended as a long-term or complex workflow (Terraform docs). It’s okay for simple, isolated resources, but can cause state or dependency issues in larger setups.
- Yes: When you destroy a resource and then re-apply it, Azure will create a new resource with a new resource ID. Any manual configurations, connections, or data in the old resource are lost.
- Terraform state: After destroy, the resource is removed from the state file. When you apply again, Terraform sees it as “missing” and creates a new one.
- If other resources depend on the bastion host, destroying it could break those resources.
- Solution: Use explicit dependencies in Terraform or isolate the resource in its own state file (
terraform workspaceor splitting into separate modules/states).
- Solution: Use explicit dependencies in Terraform or isolate the resource in its own state file (
- Targeting can lead to inconsistent states if dependencies aren’t managed.
- Solution: Regularly review and validate your state (
terraform plan) and consider full applies/destroys for more complex scenarios.
- Solution: Regularly review and validate your state (
- Storing secrets in GitHub Actions is sensitive.
- Solution: Use GitHub Secrets for credentials; rotate and audit regularly.
- If someone needs the resource outside of scheduled hours, automation will destroy it.
- Solution: Communicate schedule clearly, and provide an override or manual trigger workflow.
- Transparency: Make these schedules and the rationale visible to your team. Document in your repo and in team channels.
- Feedback: Encourage feedback if the schedule causes workflow pain—be open to adjusting.
- System Health: Monitor runs and set up notifications for failures. Don’t assume “no news is good news.”
Make sure your workflow logs into Azure:
- name: Azure Login
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}| Action | Command | Result |
|---|---|---|
| Scheduled Apply | terraform apply -target=azurerm_bastion_host.xyz | (Re)creates bastion host |
| Scheduled Destroy | terraform destroy -target=azurerm_bastion_host.xyz | Destroys bastion host |
| Resource ID | New resource ID generated each apply/destroy cycle | Old resource/data is lost |
This approach is fine for isolated, stateless resources. For anything more, it’s better to treat infrastructure as cattle, not pets—avoid manual changes and always keep your state and config in sync. Proactively communicate, listen to feedback, and iterate on the schedule and process as your team’s needs evolve. That’s how you build trust and deliver the best work together.