agentic-team-templates 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +280 -0
- package/bin/cli.js +5 -0
- package/package.json +47 -0
- package/src/index.js +521 -0
- package/templates/_shared/code-quality.md +162 -0
- package/templates/_shared/communication.md +114 -0
- package/templates/_shared/core-principles.md +62 -0
- package/templates/_shared/git-workflow.md +165 -0
- package/templates/_shared/security-fundamentals.md +173 -0
- package/templates/blockchain/.cursorrules/defi-patterns.md +520 -0
- package/templates/blockchain/.cursorrules/gas-optimization.md +339 -0
- package/templates/blockchain/.cursorrules/overview.md +130 -0
- package/templates/blockchain/.cursorrules/security.md +318 -0
- package/templates/blockchain/.cursorrules/smart-contracts.md +364 -0
- package/templates/blockchain/.cursorrules/testing.md +415 -0
- package/templates/blockchain/.cursorrules/web3-integration.md +538 -0
- package/templates/blockchain/CLAUDE.md +389 -0
- package/templates/cli-tools/.cursorrules/architecture.md +412 -0
- package/templates/cli-tools/.cursorrules/arguments.md +406 -0
- package/templates/cli-tools/.cursorrules/distribution.md +546 -0
- package/templates/cli-tools/.cursorrules/error-handling.md +455 -0
- package/templates/cli-tools/.cursorrules/overview.md +136 -0
- package/templates/cli-tools/.cursorrules/testing.md +537 -0
- package/templates/cli-tools/.cursorrules/user-experience.md +545 -0
- package/templates/cli-tools/CLAUDE.md +356 -0
- package/templates/data-engineering/.cursorrules/data-modeling.md +367 -0
- package/templates/data-engineering/.cursorrules/data-quality.md +455 -0
- package/templates/data-engineering/.cursorrules/overview.md +85 -0
- package/templates/data-engineering/.cursorrules/performance.md +339 -0
- package/templates/data-engineering/.cursorrules/pipeline-design.md +280 -0
- package/templates/data-engineering/.cursorrules/security.md +460 -0
- package/templates/data-engineering/.cursorrules/testing.md +452 -0
- package/templates/data-engineering/CLAUDE.md +974 -0
- package/templates/devops-sre/.cursorrules/capacity-planning.md +653 -0
- package/templates/devops-sre/.cursorrules/change-management.md +584 -0
- package/templates/devops-sre/.cursorrules/chaos-engineering.md +651 -0
- package/templates/devops-sre/.cursorrules/disaster-recovery.md +641 -0
- package/templates/devops-sre/.cursorrules/incident-management.md +565 -0
- package/templates/devops-sre/.cursorrules/observability.md +714 -0
- package/templates/devops-sre/.cursorrules/overview.md +230 -0
- package/templates/devops-sre/.cursorrules/postmortems.md +588 -0
- package/templates/devops-sre/.cursorrules/runbooks.md +760 -0
- package/templates/devops-sre/.cursorrules/slo-sli.md +617 -0
- package/templates/devops-sre/.cursorrules/toil-reduction.md +567 -0
- package/templates/devops-sre/CLAUDE.md +1007 -0
- package/templates/documentation/.cursorrules/adr.md +277 -0
- package/templates/documentation/.cursorrules/api-documentation.md +411 -0
- package/templates/documentation/.cursorrules/code-comments.md +253 -0
- package/templates/documentation/.cursorrules/maintenance.md +260 -0
- package/templates/documentation/.cursorrules/overview.md +82 -0
- package/templates/documentation/.cursorrules/readme-standards.md +306 -0
- package/templates/documentation/CLAUDE.md +120 -0
- package/templates/fullstack/.cursorrules/api-contracts.md +331 -0
- package/templates/fullstack/.cursorrules/architecture.md +298 -0
- package/templates/fullstack/.cursorrules/overview.md +109 -0
- package/templates/fullstack/.cursorrules/shared-types.md +348 -0
- package/templates/fullstack/.cursorrules/testing.md +386 -0
- package/templates/fullstack/CLAUDE.md +349 -0
- package/templates/ml-ai/.cursorrules/data-engineering.md +483 -0
- package/templates/ml-ai/.cursorrules/deployment.md +601 -0
- package/templates/ml-ai/.cursorrules/model-development.md +538 -0
- package/templates/ml-ai/.cursorrules/monitoring.md +658 -0
- package/templates/ml-ai/.cursorrules/overview.md +131 -0
- package/templates/ml-ai/.cursorrules/security.md +637 -0
- package/templates/ml-ai/.cursorrules/testing.md +678 -0
- package/templates/ml-ai/CLAUDE.md +1136 -0
- package/templates/mobile/.cursorrules/navigation.md +246 -0
- package/templates/mobile/.cursorrules/offline-first.md +302 -0
- package/templates/mobile/.cursorrules/overview.md +71 -0
- package/templates/mobile/.cursorrules/performance.md +345 -0
- package/templates/mobile/.cursorrules/testing.md +339 -0
- package/templates/mobile/CLAUDE.md +233 -0
- package/templates/platform-engineering/.cursorrules/ci-cd.md +778 -0
- package/templates/platform-engineering/.cursorrules/developer-experience.md +632 -0
- package/templates/platform-engineering/.cursorrules/infrastructure-as-code.md +600 -0
- package/templates/platform-engineering/.cursorrules/kubernetes.md +710 -0
- package/templates/platform-engineering/.cursorrules/observability.md +747 -0
- package/templates/platform-engineering/.cursorrules/overview.md +215 -0
- package/templates/platform-engineering/.cursorrules/security.md +855 -0
- package/templates/platform-engineering/.cursorrules/testing.md +878 -0
- package/templates/platform-engineering/CLAUDE.md +850 -0
- package/templates/utility-agent/.cursorrules/action-control.md +284 -0
- package/templates/utility-agent/.cursorrules/context-management.md +186 -0
- package/templates/utility-agent/.cursorrules/hallucination-prevention.md +253 -0
- package/templates/utility-agent/.cursorrules/overview.md +78 -0
- package/templates/utility-agent/.cursorrules/token-optimization.md +369 -0
- package/templates/utility-agent/CLAUDE.md +513 -0
- package/templates/web-backend/.cursorrules/api-design.md +255 -0
- package/templates/web-backend/.cursorrules/authentication.md +309 -0
- package/templates/web-backend/.cursorrules/database-patterns.md +298 -0
- package/templates/web-backend/.cursorrules/error-handling.md +366 -0
- package/templates/web-backend/.cursorrules/overview.md +69 -0
- package/templates/web-backend/.cursorrules/security.md +358 -0
- package/templates/web-backend/.cursorrules/testing.md +395 -0
- package/templates/web-backend/CLAUDE.md +366 -0
- package/templates/web-frontend/.cursorrules/accessibility.md +296 -0
- package/templates/web-frontend/.cursorrules/component-patterns.md +204 -0
- package/templates/web-frontend/.cursorrules/overview.md +72 -0
- package/templates/web-frontend/.cursorrules/performance.md +325 -0
- package/templates/web-frontend/.cursorrules/state-management.md +227 -0
- package/templates/web-frontend/.cursorrules/styling.md +271 -0
- package/templates/web-frontend/.cursorrules/testing.md +311 -0
- package/templates/web-frontend/CLAUDE.md +399 -0
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
# Infrastructure as Code
|
|
2
|
+
|
|
3
|
+
Guidelines for writing maintainable, secure, and scalable infrastructure code.
|
|
4
|
+
|
|
5
|
+
## Core Principles
|
|
6
|
+
|
|
7
|
+
1. **Declarative Over Imperative** - Describe desired state, not steps
|
|
8
|
+
2. **Idempotent Operations** - Running twice produces same result
|
|
9
|
+
3. **Version Everything** - IaC, modules, providers, dependencies
|
|
10
|
+
4. **Test Infrastructure** - Validate before applying
|
|
11
|
+
|
|
12
|
+
## Terraform Best Practices
|
|
13
|
+
|
|
14
|
+
### File Organization
|
|
15
|
+
|
|
16
|
+
```hcl
|
|
17
|
+
# main.tf - Primary resources
|
|
18
|
+
# variables.tf - Input variables with descriptions
|
|
19
|
+
# outputs.tf - Output values
|
|
20
|
+
# versions.tf - Provider and Terraform version constraints
|
|
21
|
+
# locals.tf - Local values and computed expressions
|
|
22
|
+
# data.tf - Data sources
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Version Constraints
|
|
26
|
+
|
|
27
|
+
```hcl
|
|
28
|
+
# versions.tf
|
|
29
|
+
terraform {
|
|
30
|
+
required_version = ">= 1.5.0, < 2.0.0"
|
|
31
|
+
|
|
32
|
+
required_providers {
|
|
33
|
+
aws = {
|
|
34
|
+
source = "hashicorp/aws"
|
|
35
|
+
version = "~> 5.0"
|
|
36
|
+
}
|
|
37
|
+
kubernetes = {
|
|
38
|
+
source = "hashicorp/kubernetes"
|
|
39
|
+
version = "~> 2.23"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Variable Definitions
|
|
46
|
+
|
|
47
|
+
```hcl
|
|
48
|
+
# variables.tf
|
|
49
|
+
variable "environment" {
|
|
50
|
+
description = "Deployment environment (dev, staging, production)"
|
|
51
|
+
type = string
|
|
52
|
+
|
|
53
|
+
validation {
|
|
54
|
+
condition = contains(["dev", "staging", "production"], var.environment)
|
|
55
|
+
error_message = "Environment must be dev, staging, or production."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
variable "vpc_cidr" {
|
|
60
|
+
description = "CIDR block for VPC"
|
|
61
|
+
type = string
|
|
62
|
+
default = "10.0.0.0/16"
|
|
63
|
+
|
|
64
|
+
validation {
|
|
65
|
+
condition = can(cidrnetmask(var.vpc_cidr))
|
|
66
|
+
error_message = "Must be a valid CIDR block."
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
variable "tags" {
|
|
71
|
+
description = "Common tags applied to all resources"
|
|
72
|
+
type = map(string)
|
|
73
|
+
default = {}
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Local Values
|
|
78
|
+
|
|
79
|
+
```hcl
|
|
80
|
+
# locals.tf
|
|
81
|
+
locals {
|
|
82
|
+
# Compute common values once
|
|
83
|
+
name_prefix = "${var.project}-${var.environment}"
|
|
84
|
+
|
|
85
|
+
# Merge default tags with provided tags
|
|
86
|
+
common_tags = merge(
|
|
87
|
+
{
|
|
88
|
+
Environment = var.environment
|
|
89
|
+
Project = var.project
|
|
90
|
+
ManagedBy = "terraform"
|
|
91
|
+
Team = var.team
|
|
92
|
+
},
|
|
93
|
+
var.tags
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Conditional logic
|
|
97
|
+
is_production = var.environment == "production"
|
|
98
|
+
|
|
99
|
+
# Complex transformations
|
|
100
|
+
subnet_cidrs = {
|
|
101
|
+
for idx, az in data.aws_availability_zones.available.names :
|
|
102
|
+
az => cidrsubnet(var.vpc_cidr, 8, idx)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Resource Naming
|
|
108
|
+
|
|
109
|
+
```hcl
|
|
110
|
+
# Consistent, meaningful names
|
|
111
|
+
resource "aws_vpc" "main" {
|
|
112
|
+
cidr_block = var.vpc_cidr
|
|
113
|
+
enable_dns_hostnames = true
|
|
114
|
+
enable_dns_support = true
|
|
115
|
+
|
|
116
|
+
tags = merge(local.common_tags, {
|
|
117
|
+
Name = "${local.name_prefix}-vpc"
|
|
118
|
+
})
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
resource "aws_subnet" "private" {
|
|
122
|
+
for_each = local.subnet_cidrs
|
|
123
|
+
|
|
124
|
+
vpc_id = aws_vpc.main.id
|
|
125
|
+
cidr_block = each.value
|
|
126
|
+
availability_zone = each.key
|
|
127
|
+
|
|
128
|
+
tags = merge(local.common_tags, {
|
|
129
|
+
Name = "${local.name_prefix}-private-${each.key}"
|
|
130
|
+
Type = "private"
|
|
131
|
+
})
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Module Design
|
|
136
|
+
|
|
137
|
+
### Module Structure
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
modules/
|
|
141
|
+
└── eks-cluster/
|
|
142
|
+
├── main.tf # Primary resources
|
|
143
|
+
├── variables.tf # Input variables
|
|
144
|
+
├── outputs.tf # Output values
|
|
145
|
+
├── versions.tf # Version constraints
|
|
146
|
+
├── iam.tf # IAM resources
|
|
147
|
+
├── security.tf # Security groups
|
|
148
|
+
├── README.md # Documentation
|
|
149
|
+
└── examples/
|
|
150
|
+
└── basic/
|
|
151
|
+
└── main.tf # Usage example
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Module Interface
|
|
155
|
+
|
|
156
|
+
```hcl
|
|
157
|
+
# modules/eks-cluster/variables.tf
|
|
158
|
+
|
|
159
|
+
# Required variables - no defaults
|
|
160
|
+
variable "cluster_name" {
|
|
161
|
+
description = "Name of the EKS cluster"
|
|
162
|
+
type = string
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
variable "vpc_id" {
|
|
166
|
+
description = "VPC ID where cluster will be created"
|
|
167
|
+
type = string
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
variable "subnet_ids" {
|
|
171
|
+
description = "Subnet IDs for EKS cluster"
|
|
172
|
+
type = list(string)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
# Optional variables - sensible defaults
|
|
176
|
+
variable "kubernetes_version" {
|
|
177
|
+
description = "Kubernetes version"
|
|
178
|
+
type = string
|
|
179
|
+
default = "1.28"
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
variable "enable_private_endpoint" {
|
|
183
|
+
description = "Enable private API endpoint"
|
|
184
|
+
type = bool
|
|
185
|
+
default = true
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
variable "node_groups" {
|
|
189
|
+
description = "Node group configurations"
|
|
190
|
+
type = map(object({
|
|
191
|
+
instance_types = list(string)
|
|
192
|
+
min_size = number
|
|
193
|
+
max_size = number
|
|
194
|
+
desired_size = number
|
|
195
|
+
disk_size = optional(number, 50)
|
|
196
|
+
labels = optional(map(string), {})
|
|
197
|
+
taints = optional(list(object({
|
|
198
|
+
key = string
|
|
199
|
+
value = string
|
|
200
|
+
effect = string
|
|
201
|
+
})), [])
|
|
202
|
+
}))
|
|
203
|
+
default = {}
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Module Outputs
|
|
208
|
+
|
|
209
|
+
```hcl
|
|
210
|
+
# modules/eks-cluster/outputs.tf
|
|
211
|
+
|
|
212
|
+
output "cluster_id" {
|
|
213
|
+
description = "EKS cluster ID"
|
|
214
|
+
value = aws_eks_cluster.main.id
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
output "cluster_endpoint" {
|
|
218
|
+
description = "EKS cluster API endpoint"
|
|
219
|
+
value = aws_eks_cluster.main.endpoint
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
output "cluster_certificate_authority_data" {
|
|
223
|
+
description = "Base64 encoded certificate data"
|
|
224
|
+
value = aws_eks_cluster.main.certificate_authority[0].data
|
|
225
|
+
sensitive = true
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
output "cluster_security_group_id" {
|
|
229
|
+
description = "Security group ID attached to the cluster"
|
|
230
|
+
value = aws_eks_cluster.main.vpc_config[0].cluster_security_group_id
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
output "oidc_provider_arn" {
|
|
234
|
+
description = "OIDC provider ARN for IRSA"
|
|
235
|
+
value = aws_iam_openid_connect_provider.eks.arn
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## State Management
|
|
240
|
+
|
|
241
|
+
### Remote Backend Configuration
|
|
242
|
+
|
|
243
|
+
```hcl
|
|
244
|
+
# backend.tf
|
|
245
|
+
terraform {
|
|
246
|
+
backend "s3" {
|
|
247
|
+
bucket = "company-terraform-state"
|
|
248
|
+
key = "infrastructure/production/terraform.tfstate"
|
|
249
|
+
region = "us-east-1"
|
|
250
|
+
encrypt = true
|
|
251
|
+
dynamodb_table = "terraform-locks"
|
|
252
|
+
|
|
253
|
+
# Assume role for cross-account access
|
|
254
|
+
role_arn = "arn:aws:iam::123456789012:role/TerraformStateAccess"
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### State Isolation Strategy
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
# One state file per environment per component
|
|
263
|
+
terraform-state/
|
|
264
|
+
├── networking/
|
|
265
|
+
│ ├── dev/terraform.tfstate
|
|
266
|
+
│ ├── staging/terraform.tfstate
|
|
267
|
+
│ └── production/terraform.tfstate
|
|
268
|
+
├── eks/
|
|
269
|
+
│ ├── dev/terraform.tfstate
|
|
270
|
+
│ ├── staging/terraform.tfstate
|
|
271
|
+
│ └── production/terraform.tfstate
|
|
272
|
+
└── databases/
|
|
273
|
+
├── dev/terraform.tfstate
|
|
274
|
+
├── staging/terraform.tfstate
|
|
275
|
+
└── production/terraform.tfstate
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### Cross-State References
|
|
279
|
+
|
|
280
|
+
```hcl
|
|
281
|
+
# Reference outputs from another state
|
|
282
|
+
data "terraform_remote_state" "networking" {
|
|
283
|
+
backend = "s3"
|
|
284
|
+
config = {
|
|
285
|
+
bucket = "company-terraform-state"
|
|
286
|
+
key = "networking/${var.environment}/terraform.tfstate"
|
|
287
|
+
region = "us-east-1"
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
# Use the referenced values
|
|
292
|
+
resource "aws_eks_cluster" "main" {
|
|
293
|
+
name = local.cluster_name
|
|
294
|
+
role_arn = aws_iam_role.cluster.arn
|
|
295
|
+
|
|
296
|
+
vpc_config {
|
|
297
|
+
subnet_ids = data.terraform_remote_state.networking.outputs.private_subnet_ids
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
## Security Practices
|
|
303
|
+
|
|
304
|
+
### Sensitive Data Handling
|
|
305
|
+
|
|
306
|
+
```hcl
|
|
307
|
+
# Mark sensitive outputs
|
|
308
|
+
output "database_password" {
|
|
309
|
+
description = "RDS master password"
|
|
310
|
+
value = aws_db_instance.main.password
|
|
311
|
+
sensitive = true
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
# Use secrets manager for credentials
|
|
315
|
+
data "aws_secretsmanager_secret_version" "db_credentials" {
|
|
316
|
+
secret_id = "production/database/master"
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
locals {
|
|
320
|
+
db_credentials = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
resource "aws_db_instance" "main" {
|
|
324
|
+
username = local.db_credentials.username
|
|
325
|
+
password = local.db_credentials.password
|
|
326
|
+
# ...
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Least Privilege IAM
|
|
331
|
+
|
|
332
|
+
```hcl
|
|
333
|
+
# Specific, minimal permissions
|
|
334
|
+
data "aws_iam_policy_document" "eks_cluster" {
|
|
335
|
+
statement {
|
|
336
|
+
sid = "EKSClusterPolicy"
|
|
337
|
+
effect = "Allow"
|
|
338
|
+
actions = [
|
|
339
|
+
"eks:DescribeCluster",
|
|
340
|
+
"eks:ListClusters",
|
|
341
|
+
]
|
|
342
|
+
resources = [aws_eks_cluster.main.arn]
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
statement {
|
|
346
|
+
sid = "CloudWatchLogs"
|
|
347
|
+
effect = "Allow"
|
|
348
|
+
actions = [
|
|
349
|
+
"logs:CreateLogGroup",
|
|
350
|
+
"logs:CreateLogStream",
|
|
351
|
+
"logs:PutLogEvents",
|
|
352
|
+
]
|
|
353
|
+
resources = ["arn:aws:logs:*:*:log-group:/aws/eks/${var.cluster_name}/*"]
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
## Testing Infrastructure
|
|
359
|
+
|
|
360
|
+
### Validation
|
|
361
|
+
|
|
362
|
+
```hcl
|
|
363
|
+
# terraform validate - syntax and consistency
|
|
364
|
+
# terraform plan - preview changes
|
|
365
|
+
# terraform fmt -check - formatting compliance
|
|
366
|
+
|
|
367
|
+
# Custom validation rules
|
|
368
|
+
variable "instance_type" {
|
|
369
|
+
type = string
|
|
370
|
+
|
|
371
|
+
validation {
|
|
372
|
+
condition = can(regex("^(t3|m5|c5)\\.", var.instance_type))
|
|
373
|
+
error_message = "Only t3, m5, or c5 instance families allowed."
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### Pre-commit Hooks
|
|
379
|
+
|
|
380
|
+
```yaml
|
|
381
|
+
# .pre-commit-config.yaml
|
|
382
|
+
repos:
|
|
383
|
+
- repo: https://github.com/antonbabenko/pre-commit-terraform
|
|
384
|
+
rev: v1.83.5
|
|
385
|
+
hooks:
|
|
386
|
+
- id: terraform_fmt
|
|
387
|
+
- id: terraform_validate
|
|
388
|
+
- id: terraform_docs
|
|
389
|
+
- id: terraform_tflint
|
|
390
|
+
- id: terraform_tfsec
|
|
391
|
+
|
|
392
|
+
- repo: https://github.com/bridgecrewio/checkov
|
|
393
|
+
rev: 2.4.0
|
|
394
|
+
hooks:
|
|
395
|
+
- id: checkov
|
|
396
|
+
args: [--framework, terraform]
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Integration Tests (Terratest)
|
|
400
|
+
|
|
401
|
+
```go
|
|
402
|
+
// test/eks_test.go
|
|
403
|
+
package test
|
|
404
|
+
|
|
405
|
+
import (
|
|
406
|
+
"testing"
|
|
407
|
+
"github.com/gruntwork-io/terratest/modules/terraform"
|
|
408
|
+
"github.com/stretchr/testify/assert"
|
|
409
|
+
)
|
|
410
|
+
|
|
411
|
+
func TestEksCluster(t *testing.T) {
|
|
412
|
+
t.Parallel()
|
|
413
|
+
|
|
414
|
+
terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{
|
|
415
|
+
TerraformDir: "../modules/eks-cluster",
|
|
416
|
+
Vars: map[string]interface{}{
|
|
417
|
+
"cluster_name": "test-cluster",
|
|
418
|
+
"environment": "test",
|
|
419
|
+
},
|
|
420
|
+
})
|
|
421
|
+
|
|
422
|
+
defer terraform.Destroy(t, terraformOptions)
|
|
423
|
+
terraform.InitAndApply(t, terraformOptions)
|
|
424
|
+
|
|
425
|
+
clusterEndpoint := terraform.Output(t, terraformOptions, "cluster_endpoint")
|
|
426
|
+
assert.Contains(t, clusterEndpoint, "eks.amazonaws.com")
|
|
427
|
+
}
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
## CI/CD Integration
|
|
431
|
+
|
|
432
|
+
### Plan and Apply Pipeline
|
|
433
|
+
|
|
434
|
+
```yaml
|
|
435
|
+
# .github/workflows/terraform.yml
|
|
436
|
+
name: Terraform
|
|
437
|
+
|
|
438
|
+
on:
|
|
439
|
+
pull_request:
|
|
440
|
+
paths:
|
|
441
|
+
- 'terraform/**'
|
|
442
|
+
push:
|
|
443
|
+
branches: [main]
|
|
444
|
+
paths:
|
|
445
|
+
- 'terraform/**'
|
|
446
|
+
|
|
447
|
+
jobs:
|
|
448
|
+
validate:
|
|
449
|
+
runs-on: ubuntu-latest
|
|
450
|
+
steps:
|
|
451
|
+
- uses: actions/checkout@v4
|
|
452
|
+
- uses: hashicorp/setup-terraform@v3
|
|
453
|
+
|
|
454
|
+
- name: Terraform Format
|
|
455
|
+
run: terraform fmt -check -recursive
|
|
456
|
+
|
|
457
|
+
- name: Terraform Validate
|
|
458
|
+
run: |
|
|
459
|
+
terraform init -backend=false
|
|
460
|
+
terraform validate
|
|
461
|
+
|
|
462
|
+
- name: TFLint
|
|
463
|
+
uses: terraform-linters/setup-tflint@v4
|
|
464
|
+
|
|
465
|
+
- name: Run TFLint
|
|
466
|
+
run: tflint --recursive
|
|
467
|
+
|
|
468
|
+
plan:
|
|
469
|
+
needs: validate
|
|
470
|
+
runs-on: ubuntu-latest
|
|
471
|
+
strategy:
|
|
472
|
+
matrix:
|
|
473
|
+
environment: [dev, staging, production]
|
|
474
|
+
steps:
|
|
475
|
+
- uses: actions/checkout@v4
|
|
476
|
+
- uses: hashicorp/setup-terraform@v3
|
|
477
|
+
|
|
478
|
+
- name: Terraform Plan
|
|
479
|
+
run: |
|
|
480
|
+
cd environments/${{ matrix.environment }}
|
|
481
|
+
terraform init
|
|
482
|
+
terraform plan -out=plan.tfplan
|
|
483
|
+
|
|
484
|
+
- name: Upload Plan
|
|
485
|
+
uses: actions/upload-artifact@v3
|
|
486
|
+
with:
|
|
487
|
+
name: plan-${{ matrix.environment }}
|
|
488
|
+
path: environments/${{ matrix.environment }}/plan.tfplan
|
|
489
|
+
|
|
490
|
+
apply:
|
|
491
|
+
needs: plan
|
|
492
|
+
if: github.ref == 'refs/heads/main'
|
|
493
|
+
runs-on: ubuntu-latest
|
|
494
|
+
environment: production
|
|
495
|
+
steps:
|
|
496
|
+
- uses: actions/checkout@v4
|
|
497
|
+
- uses: hashicorp/setup-terraform@v3
|
|
498
|
+
|
|
499
|
+
- name: Download Plan
|
|
500
|
+
uses: actions/download-artifact@v3
|
|
501
|
+
with:
|
|
502
|
+
name: plan-production
|
|
503
|
+
|
|
504
|
+
- name: Terraform Apply
|
|
505
|
+
run: |
|
|
506
|
+
cd environments/production
|
|
507
|
+
terraform init
|
|
508
|
+
terraform apply -auto-approve plan.tfplan
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## Common Pitfalls
|
|
512
|
+
|
|
513
|
+
### 1. Hardcoded Values
|
|
514
|
+
|
|
515
|
+
```hcl
|
|
516
|
+
# Bad
|
|
517
|
+
resource "aws_instance" "app" {
|
|
518
|
+
ami = "ami-12345678"
|
|
519
|
+
instance_type = "t3.medium"
|
|
520
|
+
subnet_id = "subnet-abcdef"
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
# Good
|
|
524
|
+
data "aws_ami" "amazon_linux" {
|
|
525
|
+
most_recent = true
|
|
526
|
+
owners = ["amazon"]
|
|
527
|
+
|
|
528
|
+
filter {
|
|
529
|
+
name = "name"
|
|
530
|
+
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
resource "aws_instance" "app" {
|
|
535
|
+
ami = data.aws_ami.amazon_linux.id
|
|
536
|
+
instance_type = var.instance_type
|
|
537
|
+
subnet_id = var.subnet_id
|
|
538
|
+
}
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
### 2. Missing Dependencies
|
|
542
|
+
|
|
543
|
+
```hcl
|
|
544
|
+
# Bad - implicit dependency may cause race condition
|
|
545
|
+
resource "aws_instance" "app" {
|
|
546
|
+
ami = data.aws_ami.app.id
|
|
547
|
+
instance_type = "t3.medium"
|
|
548
|
+
|
|
549
|
+
user_data = "echo ${aws_s3_bucket.config.bucket}"
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
# Good - explicit dependency
|
|
553
|
+
resource "aws_instance" "app" {
|
|
554
|
+
ami = data.aws_ami.app.id
|
|
555
|
+
instance_type = "t3.medium"
|
|
556
|
+
|
|
557
|
+
user_data = "echo ${aws_s3_bucket.config.bucket}"
|
|
558
|
+
|
|
559
|
+
depends_on = [aws_s3_bucket.config]
|
|
560
|
+
}
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### 3. Ignoring Drift
|
|
564
|
+
|
|
565
|
+
```yaml
|
|
566
|
+
# Set up scheduled drift detection
|
|
567
|
+
name: Drift Detection
|
|
568
|
+
on:
|
|
569
|
+
schedule:
|
|
570
|
+
- cron: '0 */4 * * *'
|
|
571
|
+
|
|
572
|
+
jobs:
|
|
573
|
+
detect-drift:
|
|
574
|
+
runs-on: ubuntu-latest
|
|
575
|
+
steps:
|
|
576
|
+
- name: Terraform Plan
|
|
577
|
+
run: |
|
|
578
|
+
terraform plan -detailed-exitcode
|
|
579
|
+
continue-on-error: true
|
|
580
|
+
id: plan
|
|
581
|
+
|
|
582
|
+
- name: Alert on Drift
|
|
583
|
+
if: steps.plan.outputs.exitcode == 2
|
|
584
|
+
run: |
|
|
585
|
+
# Send alert to Slack
|
|
586
|
+
curl -X POST $SLACK_WEBHOOK -d '{"text":"Drift detected!"}'
|
|
587
|
+
```
|
|
588
|
+
|
|
589
|
+
### 4. Monolithic State
|
|
590
|
+
|
|
591
|
+
```hcl
|
|
592
|
+
# Bad - everything in one state
|
|
593
|
+
# All resources in a single terraform apply
|
|
594
|
+
|
|
595
|
+
# Good - logical separation
|
|
596
|
+
# networking/ - VPCs, subnets, routing
|
|
597
|
+
# compute/ - EKS clusters, node groups
|
|
598
|
+
# data/ - RDS, ElastiCache
|
|
599
|
+
# security/ - IAM, KMS
|
|
600
|
+
```
|