272ed647cf
- Updated host_vars for dev-02 to include login history settings and modified code server authentication. - Adjusted opencode server configurations and reduced resource allocation. - Introduced a new playbook for configuring nginx reverse proxy with TLS and OAuth2. - Enhanced linux_dev_station role defaults and tasks, including package updates and service configurations. - Removed unnecessary credential assertions in linux_dev_station tasks. - Created nginx_proxy role with tasks for certbot, nginx installation, and oauth2-proxy setup. - Added templates for nginx and oauth2-proxy configurations. - Updated terraform configuration to reflect new DNS records for ide and agent services. - Documented changes and configurations in linux_dev_station.md for clarity and future reference.
103 lines
5.4 KiB
Markdown
103 lines
5.4 KiB
Markdown
# Linux Dev Station - dev-02.lab.alexpires.me
|
|
|
|
## Overview
|
|
Provisioned `dev-02.lab.alexpires.me` (Fedora, `10.19.4.210`) as a remote dev station mirroring the macOS setup. Includes code-server, opencode, and dev toolchain management. Exposed via nginx reverse proxy with TLS termination and OAuth2/OIDC SSO (Gitea as IdP).
|
|
|
|
## Role: `linux_dev_station`
|
|
- **Location:** `ansible/roles/linux_dev_station/`
|
|
- **Scope:** Fedora only (`ansible_facts['distribution'] == "Fedora"`)
|
|
- **Package manager:** dnf for system packages; tool-managed (uv, rustup, fnm) for dev toolchains
|
|
- **Excludes:** podman/container runtime management
|
|
|
|
### Components
|
|
- **SSH hardening:** Public key auth, password auth disabled, root login disabled
|
|
- **Users:** `devstation` user with sudo, zsh shell, and required groups
|
|
- **Zsh:** Oh My Zsh with agnoster theme, plugins, custom env vars, and zshrc management
|
|
- **Tooling:**
|
|
- `uv` - Python package manager
|
|
- `rustup` - Rust toolchain
|
|
- `fnm` + `node` - Node.js version manager
|
|
- `code-server` - VS Code remote on `127.0.0.1:3000`
|
|
- `opencode` - AI coding assistant (HTTP server on `127.0.0.1:4096`)
|
|
- **Firewall:** firewalld with `fw_allowed_ports` (22, 443)
|
|
- **Systemd services:** code-server, opencode
|
|
|
|
### Opencode Details
|
|
- **Repo:** `anomalyco/opencode` (not `opencode-ai`)
|
|
- **Version:** `1.17.18`
|
|
- **Binary:** `opencode-linux-x64.tar.gz`
|
|
- **Mode:** HTTP server (`serve`), binds to `127.0.0.1`
|
|
- **Install strategy:** Versioned directories (`~/.local/lib/tool-vX.Y.Z`) + symlinks for idempotent upgrades
|
|
|
|
### Oh My Zsh Plugins (Linux)
|
|
git, fzf, common-aliases, sudo, tmux, extract, colored-man-pages, history-substring-search, kubectl, microk8s, docker, docker-compose, ansible, aws, golang, dnf, bgnotify
|
|
|
|
## macOS Role Updates
|
|
- **Location:** `ansible/roles/macos_dev_station/`
|
|
- Synced Oh My Zsh fixes: sourcing, theme, plugins, extra env vars
|
|
- **Oh My Zsh Plugins (macOS):** git, fzf, common-aliases, sudo, tmux, extract, colored-man-pages, history-substring-search, kubectl, docker, docker-compose, ansible, aws, golang, brew, bgnotify
|
|
|
|
## TLS + OAuth2/OIDC SSO (`nginx_proxy` role)
|
|
- **Location:** `ansible/roles/nginx_proxy/` — standalone, generic role not tied to `linux_dev_station`
|
|
- **Playbook:** `ansible/playbook_nginx_proxy.yml` targets `[nginx]` group
|
|
- **Architecture:** nginx (:443, TLS) → oauth2-proxy (:4180, session mgmt) → backends (127.0.0.1 only)
|
|
- **Certificate:** SAN cert for `ide.lab.alexpires.me` + `agent.lab.alexpires.me` via certbot DNS-01 (cloudns plugin), auto-renewal cron
|
|
- **SSO cookie:** Scoped to `.lab.alexpires.me`
|
|
- **IdP:** Gitea (`code.alexpires.me`), OAuth2 app `lab-services` (confidential client, scopes: `openid`, `profile`, `email`)
|
|
- **oauth2-proxy:** v7.15.3, config format: `oidc_issuer_url`, `http_address`, `upstreams` array, `cookie_domains` array, `proxy_websockets = true`, `reverse_proxy = true`
|
|
- **Services exposed:**
|
|
- `https://ide.lab.alexpires.me` → code-server (127.0.0.1:3000)
|
|
- `https://agent.lab.alexpires.me` → opencode (127.0.0.1:4096)
|
|
- **Nginx fixes applied:** `types_hash_bucket_size 64;`, ssl_ciphers single line, http2 separate directive, SAN cert shared via first site directory, POST auth_request body fix (`proxy_set_header Content-Length "";`), proxy_buffer_size for oauth2 callback
|
|
|
|
### Defaults
|
|
- `nginx_proxy_oauth2_proxy_version: "7.15.3"`
|
|
- `nginx_proxy_cloudns_nameserver: "109.201.133.111"`
|
|
- `nginx_proxy_sites` — list of site configs with server_name, upstream, websocket toggle
|
|
|
|
### Secrets
|
|
- `OAUTH2_PROXY_COOKIE_SECRET` — 32-byte random, stored in vault
|
|
- `OAUTH2_PROXY_CLIENT_ID` / `OAUTH2_PROXY_CLIENT_SECRET` — from Gitea OAuth2 app
|
|
- `CLOUDNS_AUTH_ID` / `CLOUDNS_PASSWORD` — DNS credentials for certbot
|
|
|
|
## Infrastructure Changes
|
|
- **DNS:**
|
|
- Added A record for `dev-02.lab.alexpires.me` (`10.19.4.210`)
|
|
- Added A records for `ide` and `agent` → `10.19.4.210` (in `terraform/apps/dev-01/config.tf`)
|
|
- **Inventory:** Added `[nginx]` group with `dev-02.lab.alexpires.me`; dev-02 removed from `[certbot]` group
|
|
- **Host vars:** `ansible/host_vars/dev-02.lab.alexpires.me.yml` with `nginx_proxy_sites`, `bind_to_localhost: true`, firewall rules (22, 443), OAuth2 credentials via `lookup('env', ...)`
|
|
- **dev-01 cleanup:** Removed `opencode`/`vscode` CNAME records and `proxy_services` entries (no longer proxying to dev-02)
|
|
|
|
## Service Bindings
|
|
| Service | Binding |
|
|
|---------|---------|
|
|
| code-server | `127.0.0.1:3000` |
|
|
| opencode | `127.0.0.1:4096` |
|
|
| oauth2-proxy | `127.0.0.1:4180` |
|
|
| nginx | `0.0.0.0:443` |
|
|
|
|
## Firewall
|
|
| Port | Access |
|
|
|------|--------|
|
|
| 22 | `10.19.4.0/24` + VPN (`10.5.5.5/32`) |
|
|
| 443 | `10.19.4.0/24` + VPN (`10.5.5.5/32`) |
|
|
| 3000/4096 | Closed (nginx handles all external access) |
|
|
|
|
## SELinux
|
|
- http_port_t extended to include 4180 (oauth2-proxy)
|
|
- httpd_can_network_connect enabled
|
|
- `/etc/letsencrypt` context set to `httpd_cert_t`
|
|
|
|
## Known Issues & Workarounds
|
|
- **ssh-agent systemd:** Removed due to SELinux blocking transitions; managed via `.zshrc` startup instead
|
|
- **ACL issue:** `allow_world_readable_tmpfiles = True` required in `ansible.cfg` for macOS→Fedora `become_user` compatibility
|
|
|
|
## Required Credentials
|
|
- `GITEA_APP_TOKEN`
|
|
- `OPEN_WEBUI_API_KEY`
|
|
- `CLOUDNS_AUTH_ID` / `CLOUDNS_PASSWORD` (for certbot DNS-01)
|
|
- `OAUTH2_PROXY_COOKIE_SECRET` / `CLIENT_ID` / `CLIENT_SECRET` (for nginx_proxy role)
|
|
|
|
## Ansible.cfg Fix
|
|
Added `allow_world_readable_tmpfiles = True` under `[defaults]` to fix `become_user` failures on Fedora when running from macOS.
|