Skip to content

Commit 6232f9d

Browse files
tspascoalCopilotGeekTrainer
authored
Enhance Copilot instructions module by adding a step to Generate Instructions with Copilot (#134)
* Enhance Copilot instructions module by adding a step to Generate Instructions with copilot Add two IaC examples from copilot-awesome so users can see more elaborate instruction files Added a reference to copilot-awesome repo --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Christopher Harrison <[email protected]>
1 parent 9161838 commit 6232f9d

File tree

3 files changed

+340
-0
lines changed

3 files changed

+340
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
description: 'Infrastructure as Code with Bicep'
3+
applyTo: '**/*.bicep'
4+
---
5+
6+
## Naming Conventions
7+
8+
- When writing Bicep code, use lowerCamelCase for all names (variables, parameters, resources)
9+
- Use resource type descriptive symbolic names (e.g., 'storageAccount' not 'storageAccountName')
10+
- Avoid using 'name' in a symbolic name as it represents the resource, not the resource's name
11+
- Avoid distinguishing variables and parameters by the use of suffixes
12+
13+
## Structure and Declaration
14+
15+
- Always declare parameters at the top of files with @description decorators
16+
- Use latest stable API versions for all resources
17+
- Use descriptive @description decorators for all parameters
18+
- Specify minimum and maximum character length for naming parameters
19+
20+
## Parameters
21+
22+
- Set default values that are safe for test environments (use low-cost pricing tiers)
23+
- Use @allowed decorator sparingly to avoid blocking valid deployments
24+
- Use parameters for settings that change between deployments
25+
26+
## Variables
27+
28+
- Variables automatically infer type from the resolved value
29+
- Use variables to contain complex expressions instead of embedding them directly in resource properties
30+
31+
## Resource References
32+
33+
- Use symbolic names for resource references instead of reference() or resourceId() functions
34+
- Create resource dependencies through symbolic names (resourceA.id) not explicit dependsOn
35+
- For accessing properties from other resources, use the 'existing' keyword instead of passing values through outputs
36+
37+
## Resource Names
38+
39+
- Use template expressions with uniqueString() to create meaningful and unique resource names
40+
- Add prefixes to uniqueString() results since some resources don't allow names starting with numbers
41+
42+
## Child Resources
43+
44+
- Avoid excessive nesting of child resources
45+
- Use parent property or nesting instead of constructing resource names for child resources
46+
47+
## Security
48+
49+
- Never include secrets or keys in outputs
50+
- Use resource properties directly in outputs (e.g., storageAccount.properties.primaryEndpoints)
51+
52+
## Documentation
53+
54+
- Include helpful // comments within your Bicep files to improve readability
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
---
2+
description: 'Create or modify solutions built using Terraform on Azure.'
3+
applyTo: '**/*.terraform, **/*.tf, **/*.tfvars, **/*.tflint.hcl, **/*.tfstate, **/*.tf.json, **/*.tfvars.json'
4+
---
5+
6+
# Azure Terraform Best Practices
7+
8+
## Integration and Self-Containment
9+
10+
This instruction set extends the universal DevOps Core Principles and Taming Copilot directives for Azure/Terraform scenarios. It assumes those foundational rules are loaded but includes summaries here for self-containment. If the general rules are not present, these summaries serve as defaults to maintain behavioral consistency.
11+
12+
### Incorporated DevOps Core Principles (CALMS Framework)
13+
14+
- **Culture**: Foster collaborative, blameless culture with shared responsibility and continuous learning.
15+
- **Automation**: Automate everything possible across the software delivery lifecycle to reduce manual effort and errors.
16+
- **Lean**: Eliminate waste, maximize flow, and deliver value continuously by reducing batch sizes and bottlenecks.
17+
- **Measurement**: Measure everything relevant (e.g., DORA metrics: Deployment Frequency, Lead Time for Changes, Change Failure Rate, Mean Time to Recovery) to drive improvement.
18+
- **Sharing**: Promote knowledge sharing, collaboration, and transparency across teams.
19+
20+
### Incorporated Taming Copilot Directives (Behavioral Hierarchy)
21+
22+
- **Primacy of User Directives**: Direct user commands take highest priority.
23+
- **Factual Verification**: Prioritize tools for current, factual answers over internal knowledge.
24+
- **Adherence to Philosophy**: Follow minimalist, surgical approaches—code on request only, minimal necessary changes, direct and concise responses.
25+
- **Tool Usage**: Use tools purposefully; declare intent before action; prefer parallel calls when possible.
26+
27+
These summaries ensure the mode functions independently while aligning with the broader chat mode context. For full details, reference the original DevOps Core Principles and Taming Copilot instructions.
28+
29+
## Chat Mode Integration
30+
31+
When operating in chat mode with these instructions loaded:
32+
33+
- Treat this as a self-contained extension that incorporates summarized general rules for independent operation.
34+
- Prioritize user directives over automated actions, especially for terraform commands beyond validate.
35+
- Use implicit dependencies where possible and confirm before any terraform plan or apply operations.
36+
- Maintain minimalist responses and surgical code changes, aligning with the incorporated Taming philosophy.
37+
- **Planning Files Awareness**: Always check for planning files in the `.terraform-planning-files/` folder (if present). Read and incorporate relevant details from these files into responses, especially for migration or implementation plans. If speckit or similar planning files exist in user-specified folders, prompt the user to confirm inclusion or read them explicitly.
38+
39+
## 1. Overview
40+
41+
These instructions provide Azure-specific guidance for solutions created Terraform, including how to incorporate and use Azure Verified Modules.
42+
43+
For general Terraform conventions, see [terraform.instructions.md](terraform.instructions.md).
44+
45+
For development of modules, especially Azure Verified Modules, see [azure-verified-modules-terraform.instructions.md](azure-verified-modules-terraform.instructions.md).
46+
47+
## 2. Anti-Patterns to Avoid
48+
49+
**Configuration:**
50+
51+
- MUST NOT hardcode values that should be parameterized
52+
- SHOULD NOT use `terraform import` as a regular workflow pattern
53+
- SHOULD avoid complex conditional logic that makes code hard to understand
54+
- MUST NOT use `local-exec` provisioners unless absolutely necessary
55+
56+
**Security:**
57+
58+
- MUST NEVER store secrets in Terraform files or state
59+
- MUST avoid overly permissive IAM roles or network rules
60+
- MUST NOT disable security features for convenience
61+
- MUST NOT use default passwords or keys
62+
63+
**Operational:**
64+
65+
- MUST NOT apply Terraform changes directly to production without testing
66+
- MUST avoid making manual changes to Terraform-managed resources
67+
- MUST NOT ignore Terraform state file corruption or inconsistencies
68+
- MUST NOT run Terraform from local machines for production
69+
- MUST only use a Terraform state file (`**/*.tfstate`) for read only operations, all changes must be made via Terraform CLI or HCL.
70+
- MUST only use the contents of `**/.terraform/**` (fetched modules and providers) for read only operations.
71+
72+
These build on the incorporated Taming Copilot directives for secure, operational practices.
73+
74+
---
75+
76+
## 3. Organize Code Cleanly
77+
78+
Structure Terraform configurations with logical file separation:
79+
80+
- Use `main.tf` for resources
81+
- Use `variables.tf` for inputs
82+
- Use `outputs.tf` for outputs
83+
- Use `terraform.tf` for provider configurations
84+
- Use `locals.tf` to abstract complex expressions and for better readability
85+
- Follow consistent naming conventions and formatting (`terraform fmt`)
86+
- If the main.tf or variables.tf files grow too large, split them into multiple files by resource type or function (e.g., `main.networking.tf`, `main.storage.tf` - move equivalent variables to `variables.networking.tf`, etc.)
87+
88+
Use `snake_casing` for variables and module names.
89+
90+
## 4. Use Azure Verified Modules (AVM)
91+
92+
Any significant resource should use an AVM if available. AVMs are designed to be aligned to the Well Architected Framework, are supported and maintained by Microsoft helping reduce the amount of code to be maintained. Information about how to discover these is available in [Azure Verified Modules for Terraform](azure-verified-modules-terraform.instructions.md).
93+
94+
If an Azure Verified Module is not available for the resource, suggest creating one "in the style of" AVM in order to align to existing work and provide an opportunity to contribute upstream to the community.
95+
96+
An exception to this instruction is if the user has been directed to use an internal private registry, or explicitly states they do not wish to use Azure Verified Modules.
97+
98+
This aligns with the incorporated DevOps Automation principle by leveraging pre-validated, community-maintained modules.
99+
100+
## 5. Variable and Code Style Standards
101+
102+
Follow AVM-aligned coding standards in solution code to maintain consistency:
103+
104+
- **Variable naming**: Use snake_case for all variable names (per TFNFR4 and TFNFR16). Be descriptive and consistent with naming conventions.
105+
- **Variable definitions**: All variables must have explicit type declarations (per TFNFR18) and comprehensive descriptions (per TFNFR17). Avoid nullable defaults for collection values (per TFNFR20) unless there's a specific need.
106+
- **Sensitive variables**: Mark sensitive variables appropriately and avoid setting `sensitive = false` explicitly (per TFNFR22). Handle sensitive default values correctly (per TFNFR23).
107+
- **Dynamic blocks**: Use dynamic blocks for optional nested objects where appropriate (per TFNFR12), and leverage `coalesce` or `try` functions for default values (per TFNFR13).
108+
- **Code organization**: Consider using `locals.tf` specifically for local values (per TFNFR31) and ensure precise typing for locals (per TFNFR33).
109+
110+
## 6. Secrets
111+
112+
The best secret is one that does not need to be stored. e.g. use Managed Identities rather than passwords or keys.
113+
114+
Use `ephemeral` secrets with write-only parameters when supported (Terraform v1.11+) to avoid storing secrets in state files. Consult module documentation for availability.
115+
116+
Where secrets are required, store in Key Vault unless directed to use a different service.
117+
118+
Never write secrets to local filesystems or commit to git.
119+
120+
Mark sensitive values appropriately, isolate them from other attributes, and avoid outputting sensitive data unless absolutely necessary. Follow TFNFR19, TFNFR22, and TFNFR23.
121+
122+
## 7. Outputs
123+
124+
- **Avoid unnecessary outputs**, only use these to expose information needed by other configurations.
125+
- Use `sensitive = true` for outputs containing secrets
126+
- Provide clear descriptions for all outputs
127+
128+
```hcl
129+
output "resource_group_name" {
130+
description = "Name of the created resource group"
131+
value = azurerm_resource_group.example.name
132+
}
133+
134+
output "virtual_network_id" {
135+
description = "ID of the virtual network"
136+
value = azurerm_virtual_network.example.id
137+
}
138+
```
139+
140+
## 8. Local Values Usage
141+
142+
- Use locals for computed values and complex expressions
143+
- Improve readability by extracting repeated expressions
144+
- Combine related values into structured locals
145+
146+
```hcl
147+
locals {
148+
common_tags = {
149+
Environment = var.environment
150+
Project = var.project_name
151+
Owner = var.owner
152+
CreatedBy = "terraform"
153+
}
154+
155+
resource_name_prefix = "${var.project_name}-${var.environment}"
156+
location_short = substr(var.location, 0, 3)
157+
}
158+
```
159+
160+
## 9. Follow recommended Terraform practices
161+
162+
- **Redundant depends_on Detection**: Search and remove `depends_on` where the dependent resource is already referenced implicitly in the same resource block. Retain `depends_on` only where it is explicitly required. Never depend on module outputs.
163+
164+
- **Iteration**: Use `count` for 0-1 resources, `for_each` for multiple resources. Prefer maps for stable resource addresses. Align with TFNFR7.
165+
166+
- **Data sources**: Acceptable in root modules but avoid in reusable modules. Prefer explicit module parameters over data source lookups.
167+
168+
- **Parameterization**: Use strongly typed variables with explicit `type` declarations (TFNFR18), comprehensive descriptions (TFNFR17), and non-nullable defaults (TFNFR20). Leverage AVM-exposed variables.
169+
170+
- **Versioning**: Target latest stable Terraform and Azure provider versions. Specify versions in code and keep updated (TFFR3).
171+
172+
## 10. Folder Structure
173+
174+
Use a consistent folder structure for Terraform configurations.
175+
176+
Use tfvars to modify environmental differences. In general, aim to keep environments similar whilst cost optimising for non-production environments.
177+
178+
Antipattern - branch per environment, repository per environment, folder per environment - or similar layouts that make it hard to test the root folder logic between environments.
179+
180+
Be aware of tools such as Terragrunt which may influence this design.
181+
182+
A **suggested** structure is:
183+
184+
```text
185+
my-azure-app/
186+
├── infra/ # Terraform root module (AZD compatible)
187+
│ ├── main.tf # Core resources
188+
│ ├── variables.tf # Input variables
189+
│ ├── outputs.tf # Outputs
190+
│ ├── terraform.tf # Provider configuration
191+
│ ├── locals.tf # Local values
192+
│ └── environments/ # Environment-specific configurations
193+
│ ├── dev.tfvars # Development environment
194+
│ ├── test.tfvars # Test environment
195+
│ └── prod.tfvars # Production environment
196+
├── .github/workflows/ # CI/CD pipelines (if using github)
197+
├── .azdo/ # CI/CD pipelines (suggested if using Azure DevOps)
198+
└── README.md # Documentation
199+
```
200+
201+
Never change the folder structure without direct agreement with the user.
202+
203+
Follow AVM specifications TFNFR1, TFNFR2, TFNFR3, and TFNFR4 for consistent file naming and structure.
204+
205+
## Azure-Specific Best Practices
206+
207+
### Resource Naming and Tagging
208+
209+
- Follow [Azure naming conventions](https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/azure-best-practices/resource-naming)
210+
- Use consistent region naming and variables for multi-region deployments
211+
- Implement consistent tagging.
212+
213+
### Resource Group Strategy
214+
215+
- Use existing resource groups when specified
216+
- Create new resource groups only when necessary and with confirmation
217+
- Use descriptive names indicating purpose and environment
218+
219+
### Networking Considerations
220+
221+
- Validate existing VNet/subnet IDs before creating new network resources (for example, is this solution being deployed into an existing hub & spoke landing zone)
222+
- Use NSGs and ASGs appropriately
223+
- Implement private endpoints for PaaS services when required, use resource firewall restrictions to restrict public access otherwise. Comment exceptions where public endpoints are required.
224+
225+
### Security and Compliance
226+
227+
- Use Managed Identities instead of service principals
228+
- Implement Key Vault with appropriate RBAC.
229+
- Enable diagnostic settings for audit trails
230+
- Follow principle of least privilege
231+
232+
## Cost Management
233+
234+
- Confirm budget approval for expensive resources
235+
- Use environment-appropriate sizing (dev vs prod)
236+
- Ask for cost constraints if not specified
237+
238+
## State Management
239+
240+
- Use remote backend (Azure Storage) with state locking
241+
- Never commit state files to source control
242+
- Enable encryption at rest and in transit
243+
244+
## Validation
245+
246+
- Do an inventory of existing resources and offer to remove unused resource blocks.
247+
- Run `terraform validate` to check syntax
248+
- Ask before running `terraform plan`. Terraform plan will require a subscription ID, this should be sourced from the ARM_SUBSCRIPTION_ID environment variable, *NOT* coded in the provider block.
249+
- Test configurations in non-production environments first
250+
- Ensure idempotency (multiple applies produce same result)
251+
252+
## Fallback Behavior
253+
254+
If general rules are not loaded, default to: minimalist code generation, explicit consent for any terraform commands beyond validate, and adherence to CALMS principles in all suggestions.

content/1-hour/3-copilot-instructions.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,37 @@ Whenever you make a call to Copilot chat, the references dialog indicates all fi
9696
> [!NOTE]
9797
> The exact code generated will vary, but the new Python suggestion should now utilize type hints.
9898
99+
## Make the instructions even better
100+
101+
While we intentionally included a starter Copilot instructions file to illustrate how powerful they are, even with minimal content, you can leverage Copilot itself to either generate comprehensive instructions or improve existing ones.
102+
103+
### Using Copilot to generate instructions
104+
105+
1. Open Copilot Chat
106+
2. Select the `+` icon towards the top of Copilot chat to begin a new chat.
107+
3. Click on the `Cog` icon at the top of the Chat window and select `Generate Instructions` from the menu.
108+
4. Copilot will analyze the repository and generate a comprehensive instructions file based on the project structure, technologies, and patterns.
109+
5. Review the generated instructions. In a real-world scenario, you would customize them with items specific to your enterprise or team requirements (such as internal coding standards, security policies, or organizational best practices). For this lab, you can use the generated instructions as-is.
110+
111+
> [!TIP]
112+
> The [github/awesome-copilot][awesome-copilot] repository contains a curated collection of example Copilot instructions files (as well as other resources like prompts, modes, etc.) from various projects and technologies. You can use these as inspiration or starting points for your own instructions.
113+
114+
### Beyond copilot-instructions.md: Specialized instructions
115+
116+
While `copilot-instructions.md` is included in every Copilot Chat interaction, you can also add more specialized instructions in the `.github/instructions` folder. These files can be:
117+
118+
- **Automatically applied** based on file patterns (using the `applyTo` frontmatter property). For example, you can ensure all React files (*.tsx and *.jsx) have the same instructions.
119+
- **Included on demand** by adding context to the chat. This is useful for specific types of tasks, like creating a new API endpoint which might require tests and updates to a data abstraction layer.
120+
121+
For example, this repository includes:
122+
123+
- **bicep-code-best-practices.instructions.md** - Automatically applies when working with `*.bicep` files to ensure consistent Infrastructure as Code practices for Azure Bicep
124+
- **terraform-azure.instructions.md** - Automatically applies when working with Terraform files (`*.tf`, `*.tfvars`, etc.) to follow best practices when deploying to Azure
125+
126+
Take some seconds to examine those files, they have been sourced from [github/awesome-copilot][awesome-copilot].
127+
128+
This approach keeps your main instructions file concise while providing deep, specialized guidance when needed. It's particularly useful for polyglot projects or teams working with multiple technologies and deployment targets.
129+
99130
## Summary and next steps
100131
101132
Copilot instructions improves the quality of suggestions, and ensures better alignment with the desired practices you have in place. With the groundwork in place, let's [add new functionality to our website][walkthrough-next]!
@@ -109,6 +140,7 @@ Copilot instructions improves the quality of suggestions, and ensures better ali
109140
|:-----------------------------------|------------------------------------------:|
110141
111142
[arrow-functions]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
143+
[awesome-copilot]: https://github.com/github/awesome-copilot
112144
[custom-instructions]: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot
113145
[type-hints]: https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html
114146
[walkthrough-previous]: ./2-explore-project.md

0 commit comments

Comments
 (0)