Hi mt1990,
Taking on a brownfield Terraform adoption for 25+ resource groups is a massive undertaking, but you are definitely on the right track by using aztfexport with the --hcl-only flag first.
Adding to Marcin's excellent advice, here are a few structural and security strategies you can use to make this process smoother and safer:
1. Reassurances on Copilot Security (E5 Environment) You mentioned being cautious about feeding your infrastructure data to Microsoft 365 Copilot. Since you are on an E5 license, it is important to know that Microsoft 365 Copilot comes with Enterprise Data Protection (EDP). This means your prompts and the infrastructure data you paste are kept entirely within your Microsoft 365 tenant boundary. Your data is not retained, and it is not used to train any underlying foundation models.
However, as Marcin pointed out, M365 Copilot is optimized for documents and emails. For refactoring HCL at scale, you should ideally use GitHub Copilot within VS Code. If your company has GitHub Copilot Business or Enterprise, it offers similar enterprise-grade data protection, meaning your codebase remains confidential.
2. The "Module" Approach over Flat Files Separating resources into compute.tf, networking.tf, etc., is a good start, but doing this across 25+ resource groups in a flat directory will still become a maintenance nightmare.
Recommendation: Group your state files by Lifecycle Environment (e.g., Prod, QA, Dev) or by Application/Workload, not just by Resource Group.
Consider turning your repeated setups into Terraform Modules. Use Copilot to scan your exported HCL, identify repeating patterns (like standard VM setups or VNet configurations), and extract them into reusable modules.
3. Leverage Terraform 1.5+ Import Blocks Since you want to reach a zero-change terraform plan, make heavy use of the new declarative import {} blocks introduced in Terraform 1.5. Instead of running state import commands manually in the CLI, you can define your imports directly in your .tf files. You can actually ask Copilot (even securely through the Edge browser logged in with your Entra ID) to generate these import {} blocks for you by feeding it a list of your Azure Resource IDs.
4. Handle "Side-Effect" Resources
When running your first terraform plan, expect to see drift on resources that Azure creates automatically (like default NSG rules, OS disks attached to VMs, or automatically generated storage accounts for boot diagnostics). Use lifecycle { ignore_changes = [tags, specific_attributes] } generously during this initial phase to achieve that clean plan, and then slowly remove them as you bring those attributes under Terraform's strict control.
Good luck with the refactoring! Taking it one logical workload at a time is the safest way forward.