# Architecture - Wiki.js on AWS EKS Auto Mode

## 1. Scope

This repository deploys a production-grade Wiki.js stack on AWS using:

- Terraform (layered root modules, isolated state per layer)
- GitHub Actions (OIDC to AWS, workflow_dispatch, per-layer provision/destroy)
- Argo CD (GitOps delivery of Kubernetes workloads)
- Amazon EKS Auto Mode (cluster + managed capabilities)
- Amazon RDS PostgreSQL (external database for Wiki.js)
- Amazon S3 (mandatory Wiki.js assets storage, SSE-KMS)
- AWS Systems Manager Parameter Store (inter-layer contract for non-secret values)
- AWS Secrets Manager (all secrets; no secrets in code, logs, or Terraform state)

## 2. Design drivers and invariants

### 2.1 Layering model (non-negotiable)

- Each `terraform/<layer>/` directory is a standalone Terraform root module with its own backend key.
- No `terraform_remote_state` usage across layers.
- Inter-layer value exchange is only via SSM Parameter Store, using a strict prefix contract.
- Terraform state locking uses S3 native lockfile (`use_lockfile = true`).
- Every layer has a provision workflow and a destroy workflow.

### 2.2 Secrets model (non-negotiable)

- Sensitive values are stored only in AWS Secrets Manager.
- Terraform and workflows reference secrets by ARN only.
- Kubernetes consumes secrets through the Secrets Store CSI Driver + AWS provider (SecretProviderClass).
- No long-lived credentials in the cluster; workloads assume IAM roles via IRSA/pod identity.

### 2.3 Wiki.js deployment constraints (practical)

- Wiki.js is deployed behind HTTPS on a dedicated hostname (FQDN). Avoid deploying under a URL sub-path.
- Wiki.js uses an external PostgreSQL database (RDS).
- Wiki.js uses S3 as the mandatory assets backend; access is via IRSA with least privilege.

## 3. Environments and naming

- Environments are modeled as Terraform workspaces named `<region>-<env>` (example: `eu-west-1-dev`).
- Parameter Store prefix pattern:

  `/<prefix>/<region>/<env>/<layer-id>-<layer-name>/<key>`

- Resource naming convention:

  `${prefix}-${region}-<name>-${env}`

## 4. Deployment topology (layers)

### 4.1 Layer responsibilities

| Layer | Scope | Responsibility | Writes to Parameter Store |
| ------: | ------- | ---------------- | --------------------------- |
| 00-bootstrap | deployment acct | Terraform state bucket (SSE-KMS + versioning + BPA), KMS keys, Parameter Store "contract" base keys | Yes |
| 01-dns-main | domain acct (via assume) | Create only a DNS IAM role in the domain account, trusted by deployment role | Yes |
| 10-network | deployment acct | VPC, subnets (public/private/db), security groups, VPC endpoints, routing | Yes |
| 20-eks | deployment acct | EKS Auto Mode cluster, OIDC/IRSA foundations | Yes |
| 30-data-rds | deployment acct | RDS PostgreSQL (private subnets, SG restricted) + managed master password | Yes |
| 35-storage-s3-assets | deployment acct | S3 assets bucket (SSE-KMS, versioning, BPA, lifecycle) + Wiki.js IRSA role | Yes |
| 40-platform | deployment acct | Namespaces, Secrets Store CSI, storage driver, baseline logging | Yes |
| 45-argocd | deployment acct | Argo CD install (internal by default; optional external UI) | Yes |
| 50-app-wikijs | deployment acct + domain acct (via assume) | Argo CD Application for Wiki.js, ALB ingress + TLS, Route 53 A(alias) record | Yes |

### 4.2 Terraform layer dependency diagram

![Terraform layer dependency diagram](diagrams/terraform-layer-dependency.svg)

## 5. Runtime architecture (data plane)

### 5.1 Request and data flows

![Request and data flows](diagrams/request-data-flows.svg)

### 5.2 Network placement

- ALB in public subnets.
- EKS workloads in private subnets.
- RDS in database subnets.
- Security groups enforce:
  - ALB inbound 443
  - App inbound from ALB SG only
  - RDS inbound 5432 from workload SG only
- VPC endpoints reduce dependency on NAT for AWS APIs (S3 gateway and interface endpoints such as ECR, STS, Secrets Manager, SSM, CloudWatch Logs).

## 6. Control plane architecture (delivery and operations)

### 6.1 GitOps and IaC delivery flow

![GitOps and IaC delivery flow](diagrams/gitops-delivery-flow.svg)

### 6.2 Cross-account DNS model

The domain and hosted zone can be in a separate "domain account". Layer 01 creates a DNS role in the domain account. Layer 50 assumes that DNS role (while running as the deployment role) to create the Route 53 record.

![Cross-account DNS model](diagrams/cross-account-dns.svg)

## 7. Secrets, identities, and permissions

### 7.1 Identity layers

- GitHub Actions uses OIDC to assume `deployment_account_role_arn` (no static AWS keys).
- EKS workloads use IRSA/pod identity:
  - Wiki.js service account is bound to the IRSA role created in layer 35.
  - That role has least privilege to the S3 bucket prefix and KMS key.

### 7.2 Secrets consumption pattern

1. RDS layer uses managed master password - AWS creates a Secrets Manager secret for the master credential.
2. Platform layer installs Secrets Store CSI + AWS provider.
3. App layer defines SecretProviderClass entries that sync required Secrets Manager ARNs into Kubernetes secrets.
4. Wiki.js reads DB credentials and app secret from those Kubernetes secrets.

## 8. Operational notes

### 8.1 Two-apply reality for layer 50

The ALB is created by the Kubernetes Ingress controller (EKS Auto Mode capability) after Argo CD syncs the Ingress. Layer 50 may require a second Terraform apply to:

- discover the ALB attributes (DNS name and hosted zone ID)
- publish them into Parameter Store
- create/update the Route 53 alias record deterministically

### 8.2 Backups and data retention

- RDS automated backups are enabled; deletion protection may block destroy until explicitly disabled.
- S3 versioning is enabled; lifecycle rules control retention and cost.

### 8.3 Observability baseline

- EKS control plane logging and Fluent Bit -> CloudWatch Logs provide baseline operational visibility.
- Extend with metrics/tracing if required; keep secrets model and network constraints consistent with this architecture.

## 9. Parameter Store contract (reference)

Top-level prefix:

`/<prefix>/<region>/<env>/`

Example (not exhaustive):

- `00-bootstrap/` - `tfstate_bucket`, `tfstate_kms_key_arn`, `hosted_zone_id`, `acm_cert_arn`, `wikijs_fqdn`
- `01-dns-main/` - `dns_role_arn`
- `10-network/` - `vpc_id`, subnet IDs (JSON), SG IDs
- `20-eks/` - `cluster_name`, `oidc_issuer_url`, `oidc_provider_arn`, `cluster_endpoint`
- `30-data-rds/` - `endpoint`, `port`, `db_name`, `secret_arn`
- `35-storage-s3-assets/` - `bucket_name`, `kms_key_arn`, `wikijs_irsa_role_arn`, `bucket_prefix`
- `45-argocd/` - `argocd_server_url`, `argocd_admin_credentials_secret_arn`
- `50-app-wikijs/` - `alb_dns_name`, `alb_hosted_zone_id`, `application_url`
