# PRD: Layer 35 - Storage (S3 Assets Bucket)

**Scope:** Deployment account. S3 bucket for Wiki.js assets and workload access via IRSA/pod identity.

**Dependencies:** PRD_00-cross-cutting, PRD_00-bootstrap, PRD_10-network (optional for VPC endpoints), PRD_20-eks (OIDC for IRSA).

## 1. Purpose and Execution Order

| ID | Requirement |
| ---- | ------------- |
| R-S35-001 | This layer SHALL provision the mandatory S3 bucket for Wiki.js assets and the IAM role (IRSA) for Wiki.js workload access. |
| R-S35-002 | The layer SHALL run after EKS (for OIDC/IRSA) and before or in parallel with platform and app-wikijs. |
| R-S35-003 | Outputs SHALL be published to Parameter Store: bucket name, bucket ARN, KMS key ARN, and Wiki.js IRSA role ARN. |

## 2. KMS Key

| ID | Requirement |
| ---- | ------------- |
| R-S35-101 | A dedicated KMS key SHALL be created for the S3 assets bucket encryption. |
| R-S35-102 | The KMS key SHALL be used for SSE-KMS default encryption on the bucket and SHALL be usable by the Wiki.js IRSA role for encrypt/decrypt and GenerateDataKey. |

## 3. S3 Bucket

| ID | Requirement |
| ---- | ------------- |
| R-S35-201 | An S3 bucket SHALL be created for Wiki.js assets. |
| R-S35-202 | The bucket SHALL have SSE-KMS as default encryption using the layer's KMS key. |
| R-S35-203 | The bucket SHALL have versioning enabled. |
| R-S35-204 | The bucket SHALL have a bucket public access block applied (block all public access). |
| R-S35-205 | Lifecycle rules SHALL be parameterized and SHALL include at least: noncurrent version expiration, abort incomplete multipart uploads; optional transitions MAY be included. |
| R-S35-206 | Bucket policy SHALL deny non-TLS requests (e.g. aws:SecureTransport = false). |
| R-S35-207 | Bucket policy SHALL deny unencrypted puts (e.g. require SSE-KMS or equivalent). |

## 4. IRSA / Pod Identity for Wiki.js

| ID | Requirement |
| ---- | ------------- |
| R-S35-301 | An IAM role SHALL be created for the Wiki.js workload, assumable via IRSA (or pod identity) using the EKS cluster OIDC provider (read from Parameter Store). |
| R-S35-302 | The role SHALL have least-privilege permissions: `s3:ListBucket` on the assets bucket. |
| R-S35-303 | The role SHALL have object CRUD permissions on the bucket prefix used by Wiki.js (e.g. `bucket/prefix/*`). |
| R-S35-304 | The role SHALL have KMS permissions (encrypt, decrypt, GenerateDataKey) on the bucket's KMS key. |
| R-S35-305 | The role SHALL NOT have broader S3 or KMS access than required for the Wiki.js assets bucket and prefix. |

## 5. Parameter Store Outputs

| ID | Requirement |
| ---- | ------------- |
| R-S35-401 | The layer SHALL publish to Parameter Store under `wikijs/<region>/<env>/35-storage-s3-assets/`: bucket name, bucket ARN, KMS key ARN, and Wiki.js IRSA role ARN. |
| R-S35-402 | Outputs SHALL be consumable by layer 50 (app-wikijs) to configure Wiki.js Helm values (bucket, prefix, region) and to bind the Wiki.js service account to the IRSA role. |
| R-S35-403 | The layer SHALL publish only under its own prefix. |

## 6. Destroy Behavior

| ID | Requirement |
| ---- | ------------- |
| R-S35-501 | On `terraform destroy`, the layer SHALL remove the IAM role, bucket policy, bucket, and KMS key (in an order that respects dependencies) after the application layer (50) has been destroyed. |
| R-S35-502 | The layer SHALL delete its own Parameter Store prefix after successful destroy. |
| R-S35-503 | A provision workflow and a destroy workflow SHALL exist; destroy SHALL run after 50-app-wikijs and before 30-data-rds. |

## 7. Implementation Notes

- **Terraform:** Root module at `terraform/35-storage-s3-assets/` (main.tf, variables.tf, outputs.tf, providers.tf, backend.hcl.example, terraform.tfvars, README.md). Uses `terraform-aws-modules/s3-bucket/aws` (~> 4.0) for the bucket; KMS key and IRSA role are created with provider resources.
- **Workflows:** `tf-35-storage-s3-assets-provision.yaml` and `tf-35-storage-s3-assets-destroy.yaml` (extension `.yaml`), calling `_terraform-layer.yaml`.
- **Parameter Store (published):** `bucket_name`, `bucket_arn`, `kms_key_arn`, `wikijs_irsa_role_arn`, `bucket_prefix` under `wikijs/<region>/<env>/35-storage-s3-assets/`.
- **Reads from:** `wikijs/<region>/<env>/20-eks/` (`oidc_issuer_url`, `oidc_provider_arn`, `cluster_name`).
