https://github.com/idvoretskyi/akamai-dev-box
OpenTofu configuration for a development box on Akamai Cloud
https://github.com/idvoretskyi/akamai-dev-box
Last synced: 27 days ago
JSON representation
OpenTofu configuration for a development box on Akamai Cloud
- Host: GitHub
- URL: https://github.com/idvoretskyi/akamai-dev-box
- Owner: idvoretskyi
- License: mit
- Created: 2026-04-09T17:47:12.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-10T19:14:55.000Z (28 days ago)
- Last Synced: 2026-05-10T21:19:47.739Z (28 days ago)
- Language: HCL
- Size: 36.1 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# akamai-dev-box
[](LICENSE)
[](https://github.com/idvoretskyi/akamai-dev-box/actions/workflows/validate.yml)
[](https://github.com/idvoretskyi/akamai-dev-box/actions/workflows/trivy.yml)
Pure OpenTofu configuration that spins up a remote Ubuntu 26.04 dev box on
[Akamai Cloud](https://www.linode.com/) (formerly Linode), preloaded with k3s,
container tooling, CNCF CLIs, common language toolchains, and AI coding agents
(Claude Code + OpenCode). Intended to be used as a remote brain for
agentic-coding sessions and CNCF demo work, reached over SSH and/or
[vscode.dev tunnel](https://code.visualstudio.com/docs/remote/tunnels).
## What's installed
| Layer | Tools |
| ------------------ | -------------------------------------------------------------- |
| OS | Ubuntu 25.10 (26.04 not yet available on Akamai; update `image` once it appears) |
| Container runtimes | Docker CE (+ buildx, compose), containerd (via k3s) |
| Kubernetes | k3s single-node (Traefik + ServiceLB disabled by default) |
| Kube CLIs | kubectl, helm, k9s, stern, cilium-cli, flux, argocd, yq |
| Languages | Go, Node LTS (via fnm), Python (via uv), Rust (rustup) |
| AI agents | Claude Code (`@anthropic-ai/claude-code`), OpenCode |
| Editor | VSCode `code` CLI + tunnel (`https://vscode.dev/tunnel/`) |
| Base utilities | git, tmux, jq, ripgrep, fd, bat, neovim, htop |
All toggles are exposed as variables — disable any layer you don't want.
## Architecture
```
laptop ── SSH ─────────────┐
├── Akamai VM ── k3s (single node)
laptop ── VSCode tunnel ───┘ ── Docker
(outbound HTTPS only,
no inbound web ports required)
```
## Prerequisites
- [OpenTofu](https://opentofu.org/) >= 1.6
- An [Akamai API token](https://cloud.linode.com/profile/tokens) with read/write
on Linodes and Firewalls (set `LINODE_TOKEN`)
- An Ed25519 SSH public key
- (Optional) `linode-cli` configured locally — its region/type/image are
inherited automatically
- A GitHub account for the one-time VSCode tunnel device-code login
## Configuration sourcing
`region`, `instance_type`, and `image` are sourced from `~/.config/linode-cli`
by default (the `default-user`'s section). Set them explicitly in
`terraform.tfvars` (or via `-var`) to override. If the file is absent,
built-in fallbacks apply (`us-east`, `g6-standard-4`, `linode/ubuntu26.04`).
Precedence: `terraform.tfvars` / `-var` → `~/.config/linode-cli` → fallback.
## Quick start
```sh
# 1. Configure
export LINODE_TOKEN="your-token-here"
cp tofu/terraform.tfvars.example tofu/terraform.tfvars
$EDITOR tofu/terraform.tfvars # at minimum: authorized_keys + root_pass
# 2. Deploy
tofu -chdir=tofu init
tofu -chdir=tofu apply
# 3. Wait for cloud-init to finish (5–10 min)
eval "$(tofu -chdir=tofu output -raw wait_ready_command)"
# 4. One-time VSCode tunnel setup (interactive GitHub device-code login)
eval "$(tofu -chdir=tofu output -raw vscode_tunnel_setup_command)"
# 5. Open the tunnel
tofu -chdir=tofu output -raw vscode_tunnel_url
```
## Common operations
All helpers live as outputs whose value is a ready-to-run shell command.
| What | Command |
| ----------------------------- | ------------------------------------------------------------------------ |
| Show all outputs | `tofu -chdir=tofu output` |
| SSH as the non-root user | `eval "$(tofu -chdir=tofu output -raw ssh_command_user)"` |
| Tail cloud-init log | `eval "$(tofu -chdir=tofu output -raw first_boot_log_command)"` |
| Wait for cloud-init ready | `eval "$(tofu -chdir=tofu output -raw wait_ready_command)"` |
| Fetch kubeconfig locally | `eval "$(tofu -chdir=tofu output -raw kubeconfig_fetch_command)"` |
| k3s nodes + pods over SSH | `eval "$(tofu -chdir=tofu output -raw k3s_status_command)"` |
| VSCode tunnel setup (one-off) | `eval "$(tofu -chdir=tofu output -raw vscode_tunnel_setup_command)"` |
| Open the tunnel URL | `open "$(tofu -chdir=tofu output -raw vscode_tunnel_url)"` |
| Plan changes | `tofu -chdir=tofu plan` |
| Format + validate | `tofu -chdir=tofu fmt -recursive && tofu -chdir=tofu validate` |
| Tear it all down | `tofu -chdir=tofu destroy` |
After running the kubeconfig fetch, use the cluster locally with:
```sh
export KUBECONFIG="$PWD/kubeconfig.devbox"
kubectl get nodes
```
## Variables
Only the most relevant are listed; see `tofu/variables.tf` for the full list
with descriptions and validation rules.
| Name | Default | Notes |
| -------------------------- | ------------------------------------ | ------------------------------------------------------ |
| `region` | from `linode-cli`, else `us-east` | |
| `instance_type` | from `linode-cli`, else `g6-standard-4` | 4 vCPU / 8 GB recommended minimum for k3s + agents |
| `image` | from `linode-cli`, else `linode/ubuntu25.10` | Ubuntu 26.04 not yet in Akamai catalog |
| `instance_label` | `dev-box` | |
| `hostname` | (instance label) | |
| `timezone` | `UTC` | |
| `username` | `devuser` | Non-root user created by cloud-init |
| `authorized_keys` | `[]` | Required for SSH access |
| `root_pass` | (required) | API requires it; SSH key auth is used in practice |
| `create_firewall` | `true` | |
| `allowed_ssh_cidrs_ipv4/6` | open | Restrict to your own IPs in production |
| `expose_web` | `false` | Open inbound 80/443 |
| `expose_k3s_api` | `false` | Open inbound 6443; requires CIDR allow-lists |
| `install_docker` | `true` | |
| `install_k3s` | `true` | |
| `k3s_disable_components` | `["traefik","servicelb"]` | |
| `install_languages` | `["go","node","python","rust"]` | |
| `install_claude_code` | `true` | |
| `install_opencode` | `true` | |
| `install_vscode_tunnel` | `true` | Manual `code tunnel` login on first boot |
| `vscode_tunnel_name` | (hostname) | |
## Security notes
- **No inbound web ports by default.** SSH (22) is the only port open out of
the box. VSCode access uses Microsoft's outbound tunnel, so neither 80/443
nor 6443 need to be exposed for the editor or for kubectl (use the
`kubeconfig_fetch_command` output instead).
- **Restrict SSH** to your own networks via `allowed_ssh_cidrs_ipv4/6`.
- **Root login disabled** after cloud-init runs.
- **API token** lives only in `LINODE_TOKEN`. Scope it to Linodes RW +
Firewalls RW.
- **State files** (`terraform.tfstate*`) are gitignored. Don't commit them.
- **Root password** is required by the Linode API but unused for login.
Generate one with `openssl rand -base64 32`.
## Cost (rough, USD/month, varies by region)
| Plan | vCPU / RAM / Disk | ~/mo |
| --------------- | ----------------- | ----- |
| g6-standard-2 | 2 / 4 GB / 80 GB | $24 |
| g6-standard-4 | 4 / 8 GB / 160 GB | $48 (default) |
| g6-standard-6 | 4 / 16 GB / 320 GB | $96 |
| g6-dedicated-8 | 8 / 16 GB / 640 GB | $218 |
Add ~$2/mo per plan if `backups_enabled = true`. Egress overages apply for
heavy demo traffic.
## Project layout
```
.
├── .github/
│ ├── dependabot.yml
│ ├── settings.yml
│ └── workflows/
│ ├── validate.yml # tofu fmt + validate, shellcheck, actionlint
│ └── trivy.yml # IaC + secrets scan
├── LICENSE
├── README.md
└── tofu/
├── cloud-init/
│ ├── main.yaml.tpl # cloud-config template
│ └── scripts/
│ ├── 10-base.sh
│ ├── 20-docker.sh
│ ├── 30-k3s.sh
│ ├── 40-kube-tools.sh
│ ├── 50-langs.sh
│ ├── 60-agents.sh
│ └── 70-vscode-tunnel.sh
├── scripts/
│ └── read-linode-cli.sh # local linode-cli config reader
├── main.tf
├── outputs.tf
├── provider.tf
├── terraform.tfvars.example
├── variables.tf
└── versions.tf
```
## Tear down
```sh
tofu -chdir=tofu destroy
```
Verify in the Linode console that no orphaned resources remain.
## Contributing
PRs welcome. Before opening one:
```sh
tofu -chdir=tofu fmt -recursive
tofu -chdir=tofu init -backend=false
tofu -chdir=tofu validate
```
## License
[MIT](LICENSE).