Skip to content

Architecture Decision Log

This document captures all architectural decisions organized by category.

Decision Choice Rationale
Language TypeScript (latest) Type safety, modern JS features
Runtime BunJS Fast, all-in-one (runtime, package manager, test runner)
Testing Bun test + MSW Native Bun support, HTTP mocking
Build Bun bundler + tsc Fast bundling + type checking
CLI Framework Commander.js Mature, widely used
Tool Management Mise Consistent tool versions across team
Decision Choice Rationale
Encryption Algorithm AES-256-GCM Industry standard, authenticated
Key Derivation PBKDF2 (Web Crypto) NIST-standard KDF
KDF Iterations 600,000 OWASP recommended minimum
Passphrase Source Env var / file / flag Flexible for CI/CD
Encrypted Fields Sensitive only Performance, readability
Field Detection Name patterns + Secret<T> Automatic + explicit
SSH Keys Public only Private keys not managed by Kyku
Resource Status Notes
Vpc ✅ Included With region and AZ distribution
Subnet ✅ Included First-class, public/private
Vm ✅ Included With AZ distribution
SecurityGroup ✅ Included With SG-to-SG references
LoadBalancer ✅ Included With AZ spanning
Database ✅ Included PostgreSQL, MySQL, MariaDB
Identity ✅ Included IAM users, service accounts
Role ✅ Included With hierarchical permissions
Storage (S3/Cloud Storage) ❌ Deferred Post-MVP
K8s Cluster ❌ Deferred Post-MVP
K8s Deployment ❌ Deferred Post-MVP
Decision Choice Rationale
Region Format Abstract + override Portable, flexible
Abstract Regions us-east, eu-central, etc. User-friendly
AZ Distribution Automatic (default) High availability
Subnet Model First-class resources Explicit control when needed
Subnet Types Public + private Security best practice
DB Placement Always private subnets Security
Decision Choice Rationale
State Format JSON Human-readable, debuggable
State Location .kyku/state.<env>.json Per-environment
Encryption Field-level Selective, performant
Locking File-based (future) Prevent concurrent applies
Decision Choice Rationale
Commands plan, apply, output Core workflow
Plan Output Human-readable text Easy review
Apply Confirmation Interactive prompt Prevent accidents
Auto-approve --auto-approve flag CI/CD support
Secrets in Output Redacted by default Security
Exit Codes Standard (0=success, 1=error) Shell scripting
Feature AWS GCP Hetzner
VPC/Network ✅ Full ✅ Full ✅ Full
Subnet ✅ Per-AZ ✅ Regional ✅ Simple
VM ✅ Full ✅ Full ✅ Full
Security Group ✅ Native ✅ Firewall Rules ✅ Firewall
Load Balancer ✅ ALB/NLB ✅ Cloud LB ✅ LB
Database ✅ RDS ✅ Cloud SQL
Identity/User ✅ IAM User ✅ Service Account
Role ✅ IAM Role ✅ Custom Role

Decision: Build universal infrastructure provisioning tool Scope: AWS, GCP, Hetzner | Resources: VM, DB, LB, VPC, Security Groups, IAM

Decision: TypeScript + BunJS + Mise Rationale: Modern, fast, type-safe

Decision: SG-to-SG references in rules Rationale: Natural security model for infrastructure

Decision: IAM auth primary, password legacy Rationale: Security best practice

Decision: Abstract regions, first-class subnets Rationale: Portability across providers, explicit control when needed

Decision: AES-256-GCM + Argon2id → Superseded by 2024-05-13 (PBKDF2)

Decision: Post-MVP Rationale: Focus on infrastructure primitives first

Decision: Hybrid — OIDC automatic in CI, standard credential chains locally Rationale: CI platforms provide OIDC tokens natively; local dev uses SDK defaults

Decision: AssumeRoleWithWebIdentity via STS, inject temp creds into env vars Config: KYKU_AWS_ROLE_ARN, KYKU_AWS_ROLE_SESSION_NAME

Decision: Workload Identity Federation + service account impersonation Config: KYKU_GCP_WORKLOAD_PROVIDER, KYKU_GCP_SERVICE_ACCOUNT, KYKU_GCP_PROJECT_ID

Decision: No OIDC support, continue with HCLOUD_TOKEN Rationale: Hetzner Cloud API does not support OIDC federation

2024-05-13: Encryption — PBKDF2 over Argon2id

Section titled “2024-05-13: Encryption — PBKDF2 over Argon2id”

Decision: Use Web Crypto PBKDF2 (600,000 iterations, SHA-256) Rationale: Bun.password.hash() returns formatted hash strings, not raw key bytes. PBKDF2 is the correct tool for deriving AES-256-GCM keys.

Decision: Output values persisted to state file after resource creation. Cross-resource output references create implicit dependency edges.

Decision: Timestamped state backup before every apply execution. Rationale: Safety net for failed applies.

Decision: VPC includes IGW, NAT Gateways (per AZ), route tables (public + private). Rationale: VPCs without IGW/NAT are non-functional. Auto-generating avoids requiring users to understand AWS networking primitives.

Decision: Separate instance type mapping (db.t3.* vs t3.*). Rationale: Cloud managed databases use different naming conventions than compute.

Decision: @google-cloud/compute and @google-cloud/iam (modular packages). Rationale: Smaller install, proper ESM support. Monolithic googleapis has CJS/ESM issues.

Decision: EC2 instances automatically get IAM instance profiles for SGs with associated IAM roles. Rationale: Database IAM auth requires instance profiles.

Decision: Resources are classes with constructors, not plain interfaces. Rationale: Auto-generated UUIDs, outputs proxy, natural user API (new Vpc({...})).

Decision: resource.outputs.<key> returns OutputValue placeholder. Template literals stringify to ${output:<id>:<key>}. Engine resolves during apply.

Decision: Handlers referenced by handlerId string via global CustomResourceRegistry. Rationale: Functions cannot be serialized to JSON state. Registry allows state to survive plan/apply runs.

Decision: Auto-created subnets injected as full Subnet resources with deterministic IDs. Rationale: Users need to reference auto-subnets. First-class resources make them visible in graph and state.

Decision: CLI provider factory uses dynamic import(). Rationale: Avoids bundling all provider SDKs. Reduces CLI startup time.

Decision: kyku destroy operates on state file, not config. Rationale: Resources removed from config would otherwise be orphaned.

Decision: Target Groups for health checks (ELB v2 API). Rationale: ConfigureHealthCheckCommand does not exist in ELB v2 SDK.