@c0x12c/ai-toolkit 1.15.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/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +12 -0
- package/README.md +439 -0
- package/VERSION +1 -0
- package/agents/design-critic.md +127 -0
- package/agents/idea-killer.md +72 -0
- package/agents/infrastructure-expert.md +49 -0
- package/agents/micronaut-backend-expert.md +45 -0
- package/agents/phase-reviewer.md +150 -0
- package/agents/research-planner.md +70 -0
- package/agents/solution-architect-cto.md +49 -0
- package/agents/sre-architect.md +49 -0
- package/agents/team-coordinator.md +111 -0
- package/bin/cli.js +780 -0
- package/claude-md/00-header.md +39 -0
- package/claude-md/01-core.md +105 -0
- package/claude-md/05-database.md +20 -0
- package/claude-md/11-backend-micronaut.md +19 -0
- package/claude-md/20-frontend-react.md +44 -0
- package/claude-md/25-ux-design.md +56 -0
- package/claude-md/30-infrastructure.md +24 -0
- package/claude-md/30-project-mgmt.md +119 -0
- package/claude-md/40-product.md +39 -0
- package/claude-md/50-ops.md +34 -0
- package/claude-md/60-research.md +27 -0
- package/claude-md/90-footer.md +21 -0
- package/commands/spartan/brainstorm.md +134 -0
- package/commands/spartan/brownfield.md +157 -0
- package/commands/spartan/build.md +435 -0
- package/commands/spartan/careful.md +94 -0
- package/commands/spartan/commit-message.md +112 -0
- package/commands/spartan/content.md +17 -0
- package/commands/spartan/context-save.md +161 -0
- package/commands/spartan/contribute.md +140 -0
- package/commands/spartan/daily.md +42 -0
- package/commands/spartan/debug.md +308 -0
- package/commands/spartan/deep-dive.md +55 -0
- package/commands/spartan/deploy.md +207 -0
- package/commands/spartan/e2e.md +264 -0
- package/commands/spartan/env-setup.md +166 -0
- package/commands/spartan/epic.md +199 -0
- package/commands/spartan/fe-review.md +181 -0
- package/commands/spartan/figma-to-code.md +260 -0
- package/commands/spartan/forensics.md +46 -0
- package/commands/spartan/freeze.md +84 -0
- package/commands/spartan/fundraise.md +53 -0
- package/commands/spartan/gate-review.md +229 -0
- package/commands/spartan/gsd-upgrade.md +376 -0
- package/commands/spartan/guard.md +42 -0
- package/commands/spartan/init-project.md +178 -0
- package/commands/spartan/init-rules.md +298 -0
- package/commands/spartan/interview.md +154 -0
- package/commands/spartan/kickoff.md +73 -0
- package/commands/spartan/kotlin-service.md +109 -0
- package/commands/spartan/lean-canvas.md +222 -0
- package/commands/spartan/lint-rules.md +122 -0
- package/commands/spartan/map-codebase.md +124 -0
- package/commands/spartan/migration.md +82 -0
- package/commands/spartan/next-app.md +317 -0
- package/commands/spartan/next-feature.md +212 -0
- package/commands/spartan/onboard.md +326 -0
- package/commands/spartan/outreach.md +16 -0
- package/commands/spartan/phase.md +142 -0
- package/commands/spartan/pitch.md +18 -0
- package/commands/spartan/plan.md +210 -0
- package/commands/spartan/pr-ready.md +202 -0
- package/commands/spartan/project.md +106 -0
- package/commands/spartan/qa.md +222 -0
- package/commands/spartan/research.md +254 -0
- package/commands/spartan/review.md +132 -0
- package/commands/spartan/scan-rules.md +173 -0
- package/commands/spartan/sessions.md +143 -0
- package/commands/spartan/spec.md +131 -0
- package/commands/spartan/startup.md +257 -0
- package/commands/spartan/team.md +570 -0
- package/commands/spartan/teardown.md +161 -0
- package/commands/spartan/testcontainer.md +97 -0
- package/commands/spartan/tf-cost.md +123 -0
- package/commands/spartan/tf-deploy.md +116 -0
- package/commands/spartan/tf-drift.md +100 -0
- package/commands/spartan/tf-import.md +107 -0
- package/commands/spartan/tf-module.md +121 -0
- package/commands/spartan/tf-plan.md +100 -0
- package/commands/spartan/tf-review.md +106 -0
- package/commands/spartan/tf-scaffold.md +109 -0
- package/commands/spartan/tf-security.md +147 -0
- package/commands/spartan/think.md +221 -0
- package/commands/spartan/unfreeze.md +13 -0
- package/commands/spartan/update.md +134 -0
- package/commands/spartan/ux.md +1233 -0
- package/commands/spartan/validate.md +193 -0
- package/commands/spartan/web-to-prd.md +706 -0
- package/commands/spartan/workstreams.md +109 -0
- package/commands/spartan/write.md +16 -0
- package/commands/spartan.md +386 -0
- package/frameworks/00-framework-comparison-guide.md +317 -0
- package/frameworks/01-lean-canvas.md +196 -0
- package/frameworks/02-design-sprint.md +304 -0
- package/frameworks/03-foundation-sprint.md +337 -0
- package/frameworks/04-business-model-canvas.md +391 -0
- package/frameworks/05-customer-development.md +426 -0
- package/frameworks/06-jobs-to-be-done.md +358 -0
- package/frameworks/07-mom-test.md +392 -0
- package/frameworks/08-value-proposition-canvas.md +488 -0
- package/frameworks/09-javelin-board.md +428 -0
- package/frameworks/10-build-measure-learn.md +467 -0
- package/frameworks/11-mvp-approaches.md +533 -0
- package/frameworks/think-before-build.md +593 -0
- package/lib/assembler.js +197 -0
- package/lib/assembler.test.js +159 -0
- package/lib/detector.js +166 -0
- package/lib/detector.test.js +221 -0
- package/lib/packs.js +16 -0
- package/lib/resolver.js +272 -0
- package/lib/resolver.test.js +298 -0
- package/lib/worktree.sh +104 -0
- package/package.json +50 -0
- package/packs/backend-micronaut.yaml +35 -0
- package/packs/backend-nodejs.yaml +15 -0
- package/packs/backend-python.yaml +15 -0
- package/packs/core.yaml +37 -0
- package/packs/database.yaml +21 -0
- package/packs/frontend-react.yaml +24 -0
- package/packs/infrastructure.yaml +40 -0
- package/packs/ops.yaml +16 -0
- package/packs/packs.compiled.json +371 -0
- package/packs/product.yaml +22 -0
- package/packs/project-mgmt.yaml +24 -0
- package/packs/research.yaml +39 -0
- package/packs/shared-backend.yaml +14 -0
- package/packs/ux-design.yaml +21 -0
- package/rules/backend-micronaut/API_DESIGN.md +313 -0
- package/rules/backend-micronaut/BATCH_PROCESSING.md +92 -0
- package/rules/backend-micronaut/CONTROLLERS.md +388 -0
- package/rules/backend-micronaut/KOTLIN.md +414 -0
- package/rules/backend-micronaut/RETROFIT_PLACEMENT.md +290 -0
- package/rules/backend-micronaut/SERVICES_AND_BEANS.md +325 -0
- package/rules/core/NAMING_CONVENTIONS.md +208 -0
- package/rules/core/SKILL_AUTHORING.md +174 -0
- package/rules/core/TIMEZONE.md +316 -0
- package/rules/database/ORM_AND_REPO.md +289 -0
- package/rules/database/SCHEMA.md +146 -0
- package/rules/database/TRANSACTIONS.md +311 -0
- package/rules/frontend-react/FRONTEND.md +344 -0
- package/rules/infrastructure/MODULES.md +260 -0
- package/rules/infrastructure/NAMING.md +196 -0
- package/rules/infrastructure/PROVIDERS.md +309 -0
- package/rules/infrastructure/SECURITY.md +310 -0
- package/rules/infrastructure/STATE_AND_BACKEND.md +237 -0
- package/rules/infrastructure/STRUCTURE.md +234 -0
- package/rules/infrastructure/VARIABLES.md +285 -0
- package/rules/shared-backend/ARCHITECTURE.md +46 -0
- package/rules/ux-design/DESIGN_PROCESS.md +176 -0
- package/skills/api-endpoint-creator/SKILL.md +455 -0
- package/skills/api-endpoint-creator/error-handling-guide.md +244 -0
- package/skills/api-endpoint-creator/examples.md +522 -0
- package/skills/api-endpoint-creator/testing-patterns.md +302 -0
- package/skills/article-writing/SKILL.md +109 -0
- package/skills/article-writing/examples.md +59 -0
- package/skills/backend-api-design/SKILL.md +84 -0
- package/skills/backend-api-design/code-patterns.md +138 -0
- package/skills/brainstorm/SKILL.md +95 -0
- package/skills/browser-qa/SKILL.md +87 -0
- package/skills/browser-qa/playwright-snippets.md +110 -0
- package/skills/ci-cd-patterns/SKILL.md +108 -0
- package/skills/ci-cd-patterns/workflows.md +149 -0
- package/skills/competitive-teardown/SKILL.md +93 -0
- package/skills/competitive-teardown/example-analysis.md +50 -0
- package/skills/content-engine/SKILL.md +131 -0
- package/skills/content-engine/examples.md +72 -0
- package/skills/database-patterns/SKILL.md +72 -0
- package/skills/database-patterns/code-templates.md +114 -0
- package/skills/database-table-creator/SKILL.md +141 -0
- package/skills/database-table-creator/examples.md +552 -0
- package/skills/database-table-creator/kotlin-templates.md +400 -0
- package/skills/database-table-creator/migration-template.sql +68 -0
- package/skills/database-table-creator/validation-checklist.md +337 -0
- package/skills/deep-research/SKILL.md +80 -0
- package/skills/design-intelligence/SKILL.md +268 -0
- package/skills/design-workflow/SKILL.md +127 -0
- package/skills/design-workflow/checklists.md +45 -0
- package/skills/idea-validation/SKILL.md +129 -0
- package/skills/idea-validation/example-report.md +50 -0
- package/skills/investor-materials/SKILL.md +122 -0
- package/skills/investor-materials/example-outline.md +70 -0
- package/skills/investor-outreach/SKILL.md +112 -0
- package/skills/investor-outreach/examples.md +76 -0
- package/skills/kotlin-best-practices/SKILL.md +58 -0
- package/skills/kotlin-best-practices/code-patterns.md +132 -0
- package/skills/market-research/SKILL.md +99 -0
- package/skills/security-checklist/SKILL.md +65 -0
- package/skills/security-checklist/audit-reference.md +95 -0
- package/skills/service-debugging/SKILL.md +116 -0
- package/skills/service-debugging/common-issues.md +65 -0
- package/skills/startup-pipeline/SKILL.md +152 -0
- package/skills/terraform-best-practices/SKILL.md +244 -0
- package/skills/terraform-module-creator/SKILL.md +284 -0
- package/skills/terraform-review/SKILL.md +222 -0
- package/skills/terraform-security-audit/SKILL.md +280 -0
- package/skills/terraform-service-scaffold/SKILL.md +574 -0
- package/skills/testing-strategies/SKILL.md +116 -0
- package/skills/testing-strategies/examples.md +103 -0
- package/skills/testing-strategies/integration-test-setup.md +71 -0
- package/skills/ui-ux-pro-max/SKILL.md +238 -0
- package/skills/ui-ux-pro-max/data/charts.csv +26 -0
- package/skills/ui-ux-pro-max/data/colors.csv +97 -0
- package/skills/ui-ux-pro-max/data/icons.csv +101 -0
- package/skills/ui-ux-pro-max/data/landing.csv +31 -0
- package/skills/ui-ux-pro-max/data/products.csv +97 -0
- package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
- package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
- package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
- package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
- package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
- package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
- package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
- package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
- package/skills/ui-ux-pro-max/data/styles.csv +68 -0
- package/skills/ui-ux-pro-max/data/typography.csv +58 -0
- package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
- package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
- package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
- package/skills/ui-ux-pro-max/python-setup.md +146 -0
- package/skills/ui-ux-pro-max/scripts/core.py +253 -0
- package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
- package/skills/ui-ux-pro-max/scripts/search.py +114 -0
- package/skills/web-to-prd/SKILL.md +478 -0
- package/templates/build-config.yaml +44 -0
- package/templates/commands-config.yaml +55 -0
- package/templates/competitor-analysis.md +60 -0
- package/templates/content/AGENT_TEMPLATE.md +47 -0
- package/templates/content/COMMAND_TEMPLATE.md +27 -0
- package/templates/content/RULE_TEMPLATE.md +40 -0
- package/templates/content/SKILL_TEMPLATE.md +41 -0
- package/templates/design-config.md +105 -0
- package/templates/design-doc.md +207 -0
- package/templates/epic.md +100 -0
- package/templates/feature-spec.md +181 -0
- package/templates/idea-canvas.md +47 -0
- package/templates/implementation-plan.md +159 -0
- package/templates/prd-template.md +86 -0
- package/templates/preamble.md +89 -0
- package/templates/project-readme.md +35 -0
- package/templates/quality-gates.md +230 -0
- package/templates/spartan-config.yaml +164 -0
- package/templates/user-interview.md +69 -0
- package/templates/validation-checklist.md +108 -0
- package/templates/workflow-backend-micronaut.md +409 -0
- package/templates/workflow-frontend-react.md +233 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.tf"
|
|
4
|
+
- "**/*.hcl"
|
|
5
|
+
- "**/*.tfvars"
|
|
6
|
+
---
|
|
7
|
+
# Security Patterns and Requirements
|
|
8
|
+
|
|
9
|
+
> Full guide: use `/spartan:tf-security` command
|
|
10
|
+
|
|
11
|
+
## Authentication
|
|
12
|
+
|
|
13
|
+
### OIDC for CI/CD
|
|
14
|
+
|
|
15
|
+
GitHub Actions authenticate to AWS via OIDC -- temporary STS credentials, no static keys.
|
|
16
|
+
|
|
17
|
+
```hcl
|
|
18
|
+
# bootstrap/oidc.tf
|
|
19
|
+
module "github_oidc" {
|
|
20
|
+
source = "c0x12c/github-oidc/aws"
|
|
21
|
+
version = "~> 0.2.0"
|
|
22
|
+
|
|
23
|
+
github_organization = var.github_organization
|
|
24
|
+
repositories = var.github_repositories
|
|
25
|
+
|
|
26
|
+
# OIDC is case-sensitive -- org name must match exactly
|
|
27
|
+
# "MyOrg" != "myorg"
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### WRONG -- Static AWS credentials in CI/CD
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
# .github/workflows/deploy.yml
|
|
35
|
+
env:
|
|
36
|
+
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
37
|
+
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### CORRECT -- OIDC authentication
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
# .github/workflows/deploy.yml
|
|
44
|
+
permissions:
|
|
45
|
+
id-token: write
|
|
46
|
+
contents: read
|
|
47
|
+
|
|
48
|
+
steps:
|
|
49
|
+
- uses: aws-actions/configure-aws-credentials@v4
|
|
50
|
+
with:
|
|
51
|
+
role-to-assume: ${{ vars.AWS_ROLE_ARN }}
|
|
52
|
+
aws-region: us-west-2
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### GitHub App Authentication
|
|
56
|
+
|
|
57
|
+
Use GitHub App auth for the Terraform GitHub provider. Never use PATs.
|
|
58
|
+
|
|
59
|
+
### WRONG -- Personal Access Token
|
|
60
|
+
|
|
61
|
+
```hcl
|
|
62
|
+
provider "github" {
|
|
63
|
+
token = var.github_token # PAT -- tied to individual, security risk
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### CORRECT -- GitHub App auth with owner
|
|
68
|
+
|
|
69
|
+
```hcl
|
|
70
|
+
provider "github" {
|
|
71
|
+
owner = module.config_github.organization # REQUIRED with App auth
|
|
72
|
+
app_auth {
|
|
73
|
+
id = module.config_github.app_id
|
|
74
|
+
pem_file = module.config_github.pem_file
|
|
75
|
+
installation_id = module.config_github.app_installation_id
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### IRSA for Pods
|
|
81
|
+
|
|
82
|
+
Pods access AWS via IAM Roles for Service Accounts (IRSA). Never attach IAM roles to nodes.
|
|
83
|
+
|
|
84
|
+
```hcl
|
|
85
|
+
# modules/{service}/eks.tf
|
|
86
|
+
module "irsa" {
|
|
87
|
+
source = "c0x12c/eks-irsa/aws"
|
|
88
|
+
version = "~> 0.3.0"
|
|
89
|
+
|
|
90
|
+
service_account_name = var.service_name
|
|
91
|
+
namespace = var.service_name
|
|
92
|
+
oidc_provider_arn = var.eks_oidc_provider_arn
|
|
93
|
+
|
|
94
|
+
policy_arns = [
|
|
95
|
+
aws_iam_policy.s3_access.arn,
|
|
96
|
+
aws_iam_policy.sqs_access.arn,
|
|
97
|
+
]
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Secrets Management
|
|
104
|
+
|
|
105
|
+
### git-secret-protector
|
|
106
|
+
|
|
107
|
+
Secrets are encrypted in git using [git-secret-protector](https://github.com/nicovince/git-secret-protector) smudge/clean filters. The encrypted file IS committed — not gitignored. It auto-decrypts on checkout when the key is available.
|
|
108
|
+
|
|
109
|
+
#### Setup
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# 1. Install
|
|
113
|
+
pip install git-secret-protector
|
|
114
|
+
|
|
115
|
+
# 2. Initialize per-environment filters
|
|
116
|
+
git-secret-protector init --filter secrets-dev
|
|
117
|
+
git-secret-protector init --filter secrets-prod
|
|
118
|
+
|
|
119
|
+
# 3. Configure .gitattributes — one rule per environment
|
|
120
|
+
cat >> .gitattributes <<'EOF'
|
|
121
|
+
live/envs/dev/secrets.tfvars filter=secrets-dev
|
|
122
|
+
live/envs/prod/secrets.tfvars filter=secrets-prod
|
|
123
|
+
EOF
|
|
124
|
+
|
|
125
|
+
# 4. Store encryption keys
|
|
126
|
+
# Local: keys are cached in .git_secret_protector/cache/ (gitignored)
|
|
127
|
+
# CI/CD: store as GitHub repository secrets (GIT_SECRET_PROTECTOR_KEY_DEV, etc.)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
#### CI/CD Integration
|
|
131
|
+
|
|
132
|
+
```yaml
|
|
133
|
+
# Decrypt before terraform plan/apply
|
|
134
|
+
- name: Decrypt secrets
|
|
135
|
+
run: |
|
|
136
|
+
pip install git-secret-protector
|
|
137
|
+
git-secret-protector reveal --filter secrets-${{ env.ENVIRONMENT }}
|
|
138
|
+
env:
|
|
139
|
+
GIT_SECRET_PROTECTOR_KEY: ${{ secrets.GIT_SECRET_PROTECTOR_KEY_DEV }}
|
|
140
|
+
|
|
141
|
+
# Then pass both var files to terraform
|
|
142
|
+
- name: Plan
|
|
143
|
+
run: |
|
|
144
|
+
terraform plan \
|
|
145
|
+
-var-file=envs/${{ env.ENVIRONMENT }}/terraform.tfvars \
|
|
146
|
+
-var-file=envs/${{ env.ENVIRONMENT }}/secrets.tfvars
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
#### Key Rules
|
|
150
|
+
|
|
151
|
+
- `secrets.tfvars` — encrypted in git, decrypted during CI/CD. Contains DB passwords, API keys, tokens.
|
|
152
|
+
- `terraform.tfvars` — public, version-controlled, non-sensitive values.
|
|
153
|
+
- Use separate filters per environment (`secrets-dev`, `secrets-prod`) — different keys.
|
|
154
|
+
- NEVER store encryption keys in the repo. Use GitHub secrets or AWS SSM.
|
|
155
|
+
- `.git_secret_protector/cache/` must be in `.gitignore`.
|
|
156
|
+
|
|
157
|
+
#### WRONG — Secrets in .gitignore
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# .gitignore
|
|
161
|
+
secrets.tfvars # File NOT in git = lost on new clone, no audit trail
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### CORRECT — Secrets encrypted in git
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
# .gitattributes
|
|
168
|
+
live/envs/dev/secrets.tfvars filter=secrets-dev
|
|
169
|
+
live/envs/prod/secrets.tfvars filter=secrets-prod
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Sensitive Variables
|
|
173
|
+
|
|
174
|
+
Mark all credential variables and outputs with `sensitive = true`.
|
|
175
|
+
|
|
176
|
+
### WRONG -- Credentials without sensitive flag
|
|
177
|
+
|
|
178
|
+
```hcl
|
|
179
|
+
variable "database_password" {
|
|
180
|
+
type = string
|
|
181
|
+
# Missing sensitive = true -- shows in plan output
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
output "rds_password" {
|
|
185
|
+
value = module.rds.password
|
|
186
|
+
# Missing sensitive = true -- visible in state output
|
|
187
|
+
}
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### CORRECT -- Sensitive flag on credentials
|
|
191
|
+
|
|
192
|
+
```hcl
|
|
193
|
+
variable "database_password" {
|
|
194
|
+
type = string
|
|
195
|
+
sensitive = true
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
output "rds_password" {
|
|
199
|
+
value = module.rds.password
|
|
200
|
+
sensitive = true
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## Network Security
|
|
207
|
+
|
|
208
|
+
### WRONG -- Public subnet for data stores
|
|
209
|
+
|
|
210
|
+
```hcl
|
|
211
|
+
module "rds" {
|
|
212
|
+
source = "c0x12c/rds/aws"
|
|
213
|
+
version = "~> 0.6.6"
|
|
214
|
+
subnet_ids = var.public_subnet_ids # Data stores in public subnet
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
### WRONG -- Open security group
|
|
219
|
+
|
|
220
|
+
```hcl
|
|
221
|
+
resource "aws_security_group_rule" "redis" {
|
|
222
|
+
type = "ingress"
|
|
223
|
+
from_port = 6379
|
|
224
|
+
to_port = 6379
|
|
225
|
+
protocol = "tcp"
|
|
226
|
+
cidr_blocks = ["0.0.0.0/0"] # Open to the world
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### CORRECT -- Private subnets with VPC CIDR scoping
|
|
231
|
+
|
|
232
|
+
```hcl
|
|
233
|
+
module "rds" {
|
|
234
|
+
source = "c0x12c/rds/aws"
|
|
235
|
+
version = "~> 0.6.6"
|
|
236
|
+
subnet_ids = var.private_subnet_ids # Private subnets only
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
resource "aws_security_group_rule" "redis" {
|
|
240
|
+
type = "ingress"
|
|
241
|
+
from_port = 6379
|
|
242
|
+
to_port = 6379
|
|
243
|
+
protocol = "tcp"
|
|
244
|
+
cidr_blocks = [var.vpc_cidr_block] # VPC CIDR only
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
### WRONG -- Wildcard IAM policies
|
|
249
|
+
|
|
250
|
+
```hcl
|
|
251
|
+
resource "aws_iam_policy" "s3_access" {
|
|
252
|
+
policy = jsonencode({
|
|
253
|
+
Statement = [{
|
|
254
|
+
Effect = "Allow"
|
|
255
|
+
Action = "s3:*"
|
|
256
|
+
Resource = "*"
|
|
257
|
+
}]
|
|
258
|
+
})
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
### CORRECT -- Scoped IAM policies
|
|
263
|
+
|
|
264
|
+
```hcl
|
|
265
|
+
resource "aws_iam_policy" "s3_access" {
|
|
266
|
+
policy = jsonencode({
|
|
267
|
+
Statement = [{
|
|
268
|
+
Effect = "Allow"
|
|
269
|
+
Action = [
|
|
270
|
+
"s3:GetObject",
|
|
271
|
+
"s3:PutObject",
|
|
272
|
+
"s3:DeleteObject",
|
|
273
|
+
]
|
|
274
|
+
Resource = [
|
|
275
|
+
"${aws_s3_bucket.assets.arn}/*",
|
|
276
|
+
]
|
|
277
|
+
}]
|
|
278
|
+
})
|
|
279
|
+
}
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Resource Security Requirements
|
|
285
|
+
|
|
286
|
+
| Resource | Requirements |
|
|
287
|
+
|----------|-------------|
|
|
288
|
+
| RDS | Private subnet, encrypted storage, auto-generated password, backup enabled |
|
|
289
|
+
| Redis | Transit encryption enabled, private subnet, VPC CIDR security group |
|
|
290
|
+
| S3 | Block public access, versioning, SSE (AES256), granular IAM policy |
|
|
291
|
+
| EKS | Access entries (not aws-auth ConfigMap), SSO roles, IRSA |
|
|
292
|
+
| ECS | Private subnet, task role with least privilege, execution role scoped |
|
|
293
|
+
| SQS | Encryption at rest, IAM policy scoped to service |
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Quick Reference
|
|
298
|
+
|
|
299
|
+
| Aspect | Rule |
|
|
300
|
+
|--------|------|
|
|
301
|
+
| CI/CD auth | OIDC (temporary STS credentials), never static keys |
|
|
302
|
+
| GitHub provider | App auth with `owner` field, never PATs |
|
|
303
|
+
| Pod AWS access | IRSA, never node-level IAM roles |
|
|
304
|
+
| Secrets in git | git-secret-protector with `.gitattributes` filters |
|
|
305
|
+
| Sensitive vars | `sensitive = true` on all credentials |
|
|
306
|
+
| Data stores | Private subnets only, never public |
|
|
307
|
+
| Security groups | VPC CIDR scoped, never `0.0.0.0/0` |
|
|
308
|
+
| IAM policies | Least privilege, specific actions and resources |
|
|
309
|
+
| S3 | Block public access, versioning, SSE |
|
|
310
|
+
| Encryption | At rest and in transit for all data stores |
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
---
|
|
2
|
+
paths:
|
|
3
|
+
- "**/*.tf"
|
|
4
|
+
- "**/*.hcl"
|
|
5
|
+
- "**/*.tfvars"
|
|
6
|
+
---
|
|
7
|
+
# State Management
|
|
8
|
+
|
|
9
|
+
> Full guide: use `/spartan:tf-plan` or `/spartan:tf-deploy` commands
|
|
10
|
+
|
|
11
|
+
## S3 Backend Configuration
|
|
12
|
+
|
|
13
|
+
All Terraform state uses S3 with encryption and lock files enabled.
|
|
14
|
+
|
|
15
|
+
```hcl
|
|
16
|
+
# terraform.tf
|
|
17
|
+
terraform {
|
|
18
|
+
backend "s3" {
|
|
19
|
+
bucket = "{project}-{region_short}-tf-{env}"
|
|
20
|
+
key = "live-{env}.tfstate"
|
|
21
|
+
region = "us-west-2"
|
|
22
|
+
encrypt = true
|
|
23
|
+
use_lockfile = true
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Backend Config Files
|
|
31
|
+
|
|
32
|
+
Use partial backend configuration with `envs/{env}/state.config` files. Initialize with `-backend-config`:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
terraform init -backend-config=envs/dev/state.config
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### state.config format
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
# envs/dev/state.config
|
|
42
|
+
bucket = "{project}-uswest2-tf-dev"
|
|
43
|
+
key = "live-dev.tfstate"
|
|
44
|
+
region = "us-west-2"
|
|
45
|
+
use_lockfile = true
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
# envs/prod/state.config
|
|
50
|
+
bucket = "{project}-uswest2-tf-prod"
|
|
51
|
+
key = "live-prod.tfstate"
|
|
52
|
+
region = "us-west-2"
|
|
53
|
+
use_lockfile = true
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Service-namespaced keys
|
|
57
|
+
|
|
58
|
+
For service-level Terraform, namespace the state key by service:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
# {service}-repo/terraform/envs/dev/state.config
|
|
62
|
+
bucket = "{project}-uswest2-tf-dev"
|
|
63
|
+
key = "{service}/live-dev.tfstate"
|
|
64
|
+
region = "us-west-2"
|
|
65
|
+
use_lockfile = true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## State Isolation
|
|
71
|
+
|
|
72
|
+
Every environment gets its own state file. Never share state across environments.
|
|
73
|
+
|
|
74
|
+
### WRONG -- Single state for all environments
|
|
75
|
+
|
|
76
|
+
```hcl
|
|
77
|
+
terraform {
|
|
78
|
+
backend "s3" {
|
|
79
|
+
bucket = "{project}-tf"
|
|
80
|
+
key = "infrastructure.tfstate" # One file for everything
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### CORRECT -- Per-environment state isolation
|
|
86
|
+
|
|
87
|
+
```hcl
|
|
88
|
+
# Dev state: {project}-uswest2-tf-dev/live-dev.tfstate
|
|
89
|
+
# Prod state: {project}-uswest2-tf-prod/live-prod.tfstate
|
|
90
|
+
# Service state: {project}-uswest2-tf-dev/{service}/live-dev.tfstate
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Remote State References
|
|
96
|
+
|
|
97
|
+
Services read platform infrastructure outputs via `terraform_remote_state`.
|
|
98
|
+
|
|
99
|
+
```hcl
|
|
100
|
+
# data.tf
|
|
101
|
+
data "terraform_remote_state" "infra" {
|
|
102
|
+
backend = "s3"
|
|
103
|
+
config = {
|
|
104
|
+
bucket = var.infra_state_bucket
|
|
105
|
+
key = var.infra_state_key
|
|
106
|
+
region = var.aws_region
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Extract remote state values into flat locals (see VARIABLES rule):
|
|
112
|
+
|
|
113
|
+
```hcl
|
|
114
|
+
# locals.tf
|
|
115
|
+
locals {
|
|
116
|
+
vpc_id = data.terraform_remote_state.infra.outputs.vpc_id
|
|
117
|
+
private_subnet_ids = data.terraform_remote_state.infra.outputs.private_subnet_ids
|
|
118
|
+
eks_cluster_name = data.terraform_remote_state.infra.outputs.eks_cluster_name
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Bootstrap to Live Dependency Chain
|
|
125
|
+
|
|
126
|
+
Bootstrap creates foundational resources. Live reads them via remote state.
|
|
127
|
+
|
|
128
|
+
```hcl
|
|
129
|
+
# bootstrap/outputs.tf
|
|
130
|
+
output "state_bucket_arn" {
|
|
131
|
+
value = aws_s3_bucket.tf_state.arn
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
output "route53_zone_id" {
|
|
135
|
+
value = aws_route53_zone.main.zone_id
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# live/data.tf
|
|
139
|
+
data "terraform_remote_state" "bootstrap" {
|
|
140
|
+
backend = "s3"
|
|
141
|
+
config = {
|
|
142
|
+
bucket = var.state_bucket
|
|
143
|
+
key = "bootstrap.tfstate"
|
|
144
|
+
region = var.aws_region
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## State Movement
|
|
152
|
+
|
|
153
|
+
Use `terraform state mv` for index changes (e.g., when refactoring resources).
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# Moving a resource from index to named key
|
|
157
|
+
terraform state mv 'module.rds.random_password.password[0]' \
|
|
158
|
+
'module.rds.random_password.password["main"]'
|
|
159
|
+
|
|
160
|
+
# Moving a resource between modules
|
|
161
|
+
terraform state mv 'module.old.aws_ecr_repository.repo' \
|
|
162
|
+
'module.new.aws_ecr_repository.repo'
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Always run `terraform plan` after state moves to verify no changes.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Anti-Patterns
|
|
170
|
+
|
|
171
|
+
### WRONG -- Local backend for shared infrastructure
|
|
172
|
+
|
|
173
|
+
```hcl
|
|
174
|
+
terraform {
|
|
175
|
+
backend "local" {
|
|
176
|
+
path = "terraform.tfstate" # Only on your machine
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### WRONG -- No encryption on state backend
|
|
182
|
+
|
|
183
|
+
```hcl
|
|
184
|
+
terraform {
|
|
185
|
+
backend "s3" {
|
|
186
|
+
bucket = "{project}-tf-dev"
|
|
187
|
+
key = "live-dev.tfstate"
|
|
188
|
+
region = "us-west-2"
|
|
189
|
+
# Missing encrypt = true -- state contains secrets in plaintext
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### WRONG -- No lock files
|
|
195
|
+
|
|
196
|
+
```hcl
|
|
197
|
+
terraform {
|
|
198
|
+
backend "s3" {
|
|
199
|
+
bucket = "{project}-tf-dev"
|
|
200
|
+
key = "live-dev.tfstate"
|
|
201
|
+
region = "us-west-2"
|
|
202
|
+
encrypt = true
|
|
203
|
+
# Missing use_lockfile = true -- concurrent access risk
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### CORRECT -- Full backend configuration
|
|
209
|
+
|
|
210
|
+
```hcl
|
|
211
|
+
terraform {
|
|
212
|
+
backend "s3" {
|
|
213
|
+
bucket = "{project}-uswest2-tf-dev"
|
|
214
|
+
key = "live-dev.tfstate"
|
|
215
|
+
region = "us-west-2"
|
|
216
|
+
encrypt = true
|
|
217
|
+
use_lockfile = true
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Quick Reference
|
|
225
|
+
|
|
226
|
+
| Aspect | Rule |
|
|
227
|
+
|--------|------|
|
|
228
|
+
| Backend | S3 with `encrypt = true` and `use_lockfile = true` |
|
|
229
|
+
| State bucket naming | `{project}-{region_short}-tf-{env}` |
|
|
230
|
+
| State key (platform) | `live-{env}.tfstate` |
|
|
231
|
+
| State key (service) | `{service}/live-{env}.tfstate` |
|
|
232
|
+
| Bootstrap state key | `bootstrap.tfstate` |
|
|
233
|
+
| Env config | `envs/{env}/state.config` with partial backend config |
|
|
234
|
+
| Init command | `terraform init -backend-config=envs/{env}/state.config` |
|
|
235
|
+
| Isolation | One state file per environment, never shared |
|
|
236
|
+
| Remote state | `terraform_remote_state` to read other layers |
|
|
237
|
+
| State moves | `terraform state mv` + verify with `terraform plan` |
|