Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .cursor/rules/markdown.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
description: Markdown and markdownlint (MD060) conventions for this repo.
globs:
- "**/*.md"
alwaysApply: false
---

# Markdown

Repo **`.markdownlint.yaml`** disables **MD013** (line length); do not re-wrap markdown to an arbitrary column limit unless the user asks.

## Root `README.md` — terraform-docs (do not edit)

The block between **`<!-- BEGIN_TF_DOCS -->`** and **`<!-- END_TF_DOCS -->`** is **generated by terraform-docs**. **Never** edit, reformat, or fix lint inside those markers.

- To change inputs/outputs/docs in that section: edit `variables.tf`, `outputs.tf`, or other Terraform in the root module, then regenerate (e.g. `terraform-docs markdown table --output-file README.md --output-mode inject .` from the repo root, per your local workflow).
- **Do not remove** the `<!-- markdownlint-disable MD060 -->` / `<!-- markdownlint-enable MD060 -->` pair that wraps that block (they sit **outside** the BEGIN/END markers). They suppress MD060 for terraform-docs’ default table separators.

## MD060 — table column style (`compact`)

For **hand-written** markdown (outside the generated README block), markdownlint **MD060** uses **compact** style:

1. **Every cell** has one space after the opening `|` and one space before the closing `|`.
2. **Separator rows** use `| --- | --- |`, not `|---------|---------|`.

**Correct:**

```markdown
| Column A | Column B |
| --- | --- |
| foo | bar |
```

**Wrong (triggers MD060):**

```markdown
| Column A | Column B |
|----------|----------|
| foo | bar |
```

Apply this pattern to **all** manually authored tables in `*.md` (example READMEs, module docs, etc.).
92 changes: 92 additions & 0 deletions .cursor/rules/project-conventions.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
description: Project-wide conventions for terraform-aws-eks-basic. Always apply when working in this repo.
globs:
alwaysApply: true
---

# Project Conventions

## Repo overview

This is a Terraform module (`terraform-aws-eks-basic`) for creating EKS clusters.

- Root module: the reusable module itself (do not treat as an example)
- `examples/`: standalone Terraform configurations that call the root module for testing/reference
- `modules/argocd-codeconnections/`: optional submodule for GitHub CodeConnections + IAM
- Related GitOps repo: `/home/johna/workspace/k8sforge/kube-infra` (Argo CD manifests)

## Terraform workflow

Always run Terraform commands from within the example directory, not the root:
```bash
cd examples/auto-mode
terraform init
terraform plan
terraform apply
```

## Examples

The three primary full-featured examples are:
- `examples/auto-mode` — EKS Auto Mode (primary example; used for personal testing)
- `examples/fargate` — Pure Fargate
- `examples/basic` — Classic EC2 managed node groups

These all share the same variable/output structure for consistency.

Minimal example (`examples/minimal`) is BYO VPC, no capabilities, ~30 lines.

### Example conventions
- No `kubernetes` or `helm` provider blocks unless the example actually uses them
- Variables always include `endpoint_public_access`, `public_access_cidrs`, `private_access_cidrs`, `argocd_idc_instance_arn`, `argocd_rbac_role_mappings`, `argocd_vpce_ids`, `access_entries`, `tags`
- Outputs always include `aws_region`, `cluster_name`, `cluster_endpoint`, `oidc_provider_arn`, and any Argo CD CodeConnections outputs when applicable
- Comments use `# ── Section Title ──────` header style with closing `# ──` line

## Argo CD capability

- Requires AWS IAM Identity Center (`argocd_idc_instance_arn`)
- Use `merge({ack={}, kro={}}, var.argocd_idc_instance_arn != null ? { argocd = {...} } : {})` pattern
- Always include `network_access = { vpce_ids = var.argocd_vpce_ids }` even when empty
- Always include `rbac_role_mapping = var.argocd_rbac_role_mappings`

### CodeConnections

- Always use `modules/argocd-codeconnections` submodule — do not wire inline
- `argocd_capability_role_name = module.eks.cluster_capability_role_names["argocd"]`
- Connection `name` should follow pattern `"github-${var.cluster_name}"`
- Always expose `argocd_connection_ids`, `argocd_codeconnections_iam_role_name`, `argocd_codeconnections_iam_policy_name` as outputs
- After apply, go to AWS Console → CodeConnections to complete OAuth; connections start in PENDING state
- Argo CD Application repoURLs must use the UUID from `connection_ids` output — other UUIDs cause AccessDeniedException

## Known bugs

### Argo CD UI public ↔ private switching

**Symptom:** Changing `argocd_vpce_ids` between empty and a VPCE ID does not apply in-place.

**Workaround:**
1. Remove `argocd` from `capabilities` block
2. Run `terraform apply` (destroys the Argo CD capability)
3. Re-add `argocd` with the correct `argocd_vpce_ids`
4. Run `terraform apply` again

This applies only to the Argo CD UI endpoint — not the Kubernetes API endpoint access.

## Pod Identity vs IRSA

| Context | Use |
| --- | --- |
| Auto Mode | Pod Identity (`"pod_identity"`) — agent is built in |
| EC2 nodes | Pod Identity (`"pod_identity"`) — requires `eks-pod-identity-agent` addon |
| Fargate | IRSA (`"irsa"`) — Pod Identity agent cannot run on Fargate |

## kube-infra repo

GitOps manifests live at `/home/johna/workspace/k8sforge/kube-infra`.
Argo CD Application `repoURL` must use the CodeConnections UUID from Terraform output `argocd_connection_ids`.
Bootstrap secret commands are documented in `bootstrap/README.md` in that repo.

## Markdown

- **`README.md` terraform-docs block:** Do **not** edit anything between `<!-- BEGIN_TF_DOCS -->` and `<!-- END_TF_DOCS -->` — it is auto-generated. Regenerate with terraform-docs after changing root-module Terraform. Do **not** remove the `markdownlint-disable MD060` / `markdownlint-enable MD060` HTML comments that wrap that block (they live outside the markers).
- **All other `*.md`:** Use **compact** tables for markdownlint **MD060** (`| --- | --- |` separators). **MD013** (line length) is off repo-wide. See `.markdownlint.yaml` and `.cursor/rules/markdown.mdc`.
82 changes: 82 additions & 0 deletions .cursor/rules/terraform-eks.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
description: Terraform coding conventions for terraform-aws-eks-basic. Apply to all .tf files.
globs:
- "**/*.tf"
alwaysApply: false
---

# Terraform EKS Module Conventions

## Variable standards

- Use `default = null` for optional string variables that gate a feature (e.g. `argocd_idc_instance_arn`)
- Use `default = []` for optional list variables (e.g. `argocd_vpce_ids`)
- Required variables have no `default`
- Boolean feature flags default to `false` (e.g. `enable_ebs_csi_driver = false`)
- Identity type variables always default to `"irsa"` (e.g. `ebs_csi_driver_identity_type`)
- Always group related variables with a `# ── Section Title ──` comment

## IAM role references

- Always use role **names** (not ARNs) when referencing capability roles for inline policies
- Use `module.eks.cluster_capability_role_names["argocd"]` not `cluster_capability_role_arns`
- The `argocd-codeconnections` submodule expects `argocd_capability_role_name` (string), not ARN

## Comment style for optional feature blocks

Use this style for all optional blocks in examples — makes it easy to scan what to enable:

```hcl
# ── Feature Name ────────────────────────────────────────────────────────────
# Short explanation of when/why to enable this.
# Mutually exclusive with: X
# NOT applicable on: Y
# ────────────────────────────────────────────────────────────────────────────
enable_feature = true
```

Do not add comments that just repeat what the code does — only explain non-obvious intent, trade-offs, or constraints.

## Auto Mode specifics

- Set `addons = {}` — built-ins cover CoreDNS, vpc-cni, kube-proxy, Pod Identity Agent
- Set `enable_automode = true` and `automode_node_pools = ["system", "general-purpose"]`
- Do NOT set `eks_managed_node_groups` (mutually exclusive)
- Use private subnets only for `subnet_ids` on Auto Mode

## Fargate specifics

- Pass `concat(module.vpc.public_subnet_ids, module.vpc.private_subnet_ids)` to `subnet_ids`
- Always include a `kube-system` Fargate profile so CoreDNS can schedule
- Set `computeType = "fargate"` in the CoreDNS addon `configuration_values`
- Only vpc-cni and coredns addons needed (no kube-proxy, no Pod Identity Agent)
- Secrets Manager and EBS CSI must use `"irsa"` identity type — Pod Identity not supported on Fargate
- EBS CSI is not applicable on Fargate — remove it entirely

## Capabilities block pattern

Always use `merge()` with a conditional for Argo CD:

```hcl
capabilities = merge(
{ ack = {}, kro = {} },
var.argocd_idc_instance_arn != null ? { argocd = { ... } } : {}
)
```

Always include `network_access = { vpce_ids = var.argocd_vpce_ids }` in the Argo CD block.

## Module source paths

- Examples reference the root module as `../../`
- Examples reference the CodeConnections submodule as `../../modules/argocd-codeconnections`

## Provider blocks in examples

Only declare providers that the example actually uses:
- `aws` — always
- `tls` — always (used by root module for OIDC certificate)
- `kubernetes` — only if the example creates Kubernetes resources directly
- `helm` — only if the example deploys Helm charts directly

Do not add `kubernetes` or `helm` providers just because the root module exists — the root module handles them internally when needed.
9 changes: 9 additions & 0 deletions .markdownlint.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# markdownlint: https://github.com/DavidAnson/markdownlint
# MD060 (table-column-style): "compact" for hand-written tables (| --- | separators).
# Root README disables MD060 between markdownlint-disable/enable comments wrapping
# the terraform-docs output (<!-- BEGIN_TF_DOCS --> … <!-- END_TF_DOCS -->).
default: true
# MD013 (line-length): disabled — long lines are common in README tables and terraform-docs output.
MD013: false
MD060:
style: "compact"
Loading