diff --git a/docs/changelog.d/feature-gandi-docs.doc.md b/docs/changelog.d/feature-gandi-docs.doc.md new file mode 100644 index 0000000..cf58c52 --- /dev/null +++ b/docs/changelog.d/feature-gandi-docs.doc.md @@ -0,0 +1 @@ +Add Gandi DNS reference card and operations how-to, rewrite homepage intro for wider audience. diff --git a/docs/how-to/gandi-operations.md b/docs/how-to/gandi-operations.md new file mode 100644 index 0000000..3845f86 --- /dev/null +++ b/docs/how-to/gandi-operations.md @@ -0,0 +1,88 @@ +--- +title: gandi-operations +tags: + - how-to + - dns + - pulumi +--- + +# Gandi Operations + +How to manage DNS records and cycle the Gandi API token. + +## Prerequisites + +- Pulumi CLI installed (`brew install pulumi`) +- Access to 1Password blumeops vault (for PAT) +- On the tailnet (Pulumi resolves indri's IP via MagicDNS) + +## Preview and Apply DNS Changes + +```bash +# Preview changes (always do this first) +mise run dns-preview + +# Apply changes +mise run dns-up +``` + +Both tasks fetch the Gandi PAT from 1Password automatically. + +To run Pulumi directly: + +```bash +export GANDI_PERSONAL_ACCESS_TOKEN=$(op item get mco6ka3dc3rmw7zkg2dhia5d2m --field pat --reveal --vault vg6xf6vvfmoh5hqjjhlhbeoaie) +cd pulumi/gandi +pulumi preview +pulumi up --yes +``` + +## Cycle the Gandi PAT + +The Gandi Personal Access Token has a maximum lifetime of 90 days. Currently set to 30 days as a security compromise, though shorter may be appropriate given infrequent use. + +### 1. Create a new PAT + +Go to the [Gandi admin console](https://admin.gandi.net/organizations/1db8d76a-f729-11ed-b8d1-00163e94b645/account/pat) and create a new token: + +- **Name:** `blumeops-pulumi` (or similar) +- **Expiration:** 30 days (max 90; shorter is fine if you run this rarely) +- **Required permission:** Manage domain name technical configurations +- **Also enable:** See and renew domain names + +Copy the new PAT to your clipboard. + +### 2. Update 1Password + +With the new PAT on your clipboard: + +```bash +op item edit mco6ka3dc3rmw7zkg2dhia5d2m pat="$(pbpaste)" --vault vg6xf6vvfmoh5hqjjhlhbeoaie +``` + +### 3. Delete the old PAT + +Return to the Gandi admin console and delete the previous token. + +### 4. Verify + +```bash +mise run dns-preview +``` + +A successful preview confirms the new PAT is working. + +## Break-Glass Override + +If MagicDNS is unavailable and Pulumi can't resolve indri's IP, set the target IP manually: + +```bash +export BLUMEOPS_REVERSE_PROXY_IP=100.98.163.89 +mise run dns-up +``` + +## Related + +- [[gandi]] - DNS configuration reference +- [[caddy]] - Reverse proxy (also uses a Gandi token for TLS) +- [[update-tailscale-acls]] - Similar Pulumi workflow for Tailscale diff --git a/docs/how-to/how-to.md b/docs/how-to/how-to.md index e4582c4..1ac4d7d 100644 --- a/docs/how-to/how-to.md +++ b/docs/how-to/how-to.md @@ -20,6 +20,7 @@ Task-oriented instructions for common BlumeOps operations. These guides assume y | Guide | Description | |-------|-------------| | [[update-tailscale-acls]] | Update Tailscale access control policies | +| [[gandi-operations]] | Manage DNS records and cycle the Gandi API token | | [[use-pypi-proxy]] | Configure pip and publish packages to devpi | ## Documentation diff --git a/docs/index.md b/docs/index.md index 3fa7a3d..8d556fd 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,11 +1,39 @@ --- title: blumeops-documentation +aliases: [] +id: index +tags: [] --- -Welcome to the BlumeOps documentation. +Welcome to the BlumeOps (aka "Blue Mops") documentation. Here you will find +hopefully everything you'll need to understand and operate my personal digital +infrastructure. **New here?** Start with [[exploring-the-docs]] to find your way around. +## What is BlumeOps? + +BlumeOps is my personal homelab infrastructure managed entirely through code. +Everything lives in a single git repository, from service configs to deployment +automation. Even the [[forgejo]] instance that hosts this repo is defined +within it, making BlumeOps fully self-hosting. It's a digital life raft I built +for myself as I went, and you can see it all from within your editor of choice. +(I recommend vim.) + +These services run on my home [[hosts|infrastructure]], primarily an m1 mac +mini named [[indri]] and a Synology NAS called [[sifaka]]. The infrastructure +is networked via [[tailscale]], with the domain `eblu.me` hosted via [[gandi]] +with [[caddy]] providing a reverse proxy to resolve tailnet devices. + +The goal of BlumeOps is threefold: + +1. To provide a rich array of useful personal services in order to manage my + own digital life. +2. To exercise my skills as a software engineer specializing in + Platforms/DevOps/SRE. +3. To act as a portfolio piece for talking about building hosted software + platforms. + ## Sections - [[tutorials|Tutorials]] - Learning-oriented guides for getting started diff --git a/docs/reference/infrastructure/gandi.md b/docs/reference/infrastructure/gandi.md new file mode 100644 index 0000000..877819d --- /dev/null +++ b/docs/reference/infrastructure/gandi.md @@ -0,0 +1,67 @@ +--- +title: gandi +tags: + - infrastructure + - networking + - dns +--- + +# Gandi + +DNS hosting provider for the `eblu.me` domain, managed via Pulumi IaC. + +## Quick Reference + +| Property | Value | +|----------|-------| +| **Domain** | `eblu.me` | +| **Provider** | Gandi LiveDNS | +| **IaC** | `pulumi/gandi/` | +| **Stack** | `eblu-me` | + +## What It Does + +Gandi hosts the DNS records that make `*.ops.eblu.me` resolve to [[indri]]'s Tailscale IP (100.98.163.89). Since Tailscale IPs are not publicly routable, this gives services real DNS names while keeping them private to the tailnet. + +The target IP is resolved dynamically from `indri.tail8d86e.ts.net` at deploy time, so if indri's Tailscale IP changes, re-running the deployment is sufficient. + +## DNS Records + +| Record | Type | Value | TTL | +|--------|------|-------|-----| +| `*.ops.eblu.me` | A | indri's Tailscale IP | 300s | +| `ops.eblu.me` | A | indri's Tailscale IP | 300s | + +Both records point to [[indri]], which runs [[caddy]] as the reverse proxy for all services. See [[routing]] for the full service URL map. + +## Pulumi Configuration + +The Pulumi program lives in `pulumi/gandi/`: + +- `__main__.py` - Creates the two A records via `pulumiverse_gandi` +- `Pulumi.eblu-me.yaml` - Stack config (domain, subdomain) + +Stack config values: + +| Key | Value | +|-----|-------| +| `blumeops-dns:domain` | `eblu.me` | +| `blumeops-dns:subdomain` | `ops` | + +A break-glass override is available via the `BLUMEOPS_REVERSE_PROXY_IP` environment variable, which bypasses dynamic IP resolution. + +## TLS Integration + +[[caddy]] uses Gandi's API separately (via `GANDI_BEARER_TOKEN`) for ACME DNS-01 challenges to obtain a wildcard Let's Encrypt certificate for `*.ops.eblu.me`. This is a different credential from the Pulumi PAT. + +## Authentication + +Gandi requires a Personal Access Token (PAT) for API access. PATs have a maximum lifetime of 90 days (currently set to 30). See [[gandi-operations]] for deployment and PAT cycling instructions. + +## Related + +- [[gandi-operations]] - PAT cycling and deployment how-to +- [[routing]] - Service URLs and routing architecture +- [[caddy]] - Reverse proxy using Gandi for TLS +- [[tailscale]] - Tailnet networking +- [[indri]] - Server hosting Caddy (DNS target) diff --git a/docs/reference/infrastructure/routing.md b/docs/reference/infrastructure/routing.md index fb45449..3bbf870 100644 --- a/docs/reference/infrastructure/routing.md +++ b/docs/reference/infrastructure/routing.md @@ -61,5 +61,6 @@ DNS points to indri's Tailscale IP (100.98.163.89). TLS via Let's Encrypt (ACME ## Related +- [[gandi]] - DNS hosting for `eblu.me` - [[tailscale]] - ACL configuration - [[indri]] - Where services run diff --git a/docs/reference/reference.md b/docs/reference/reference.md index 49ac915..34f0978 100644 --- a/docs/reference/reference.md +++ b/docs/reference/reference.md @@ -44,6 +44,7 @@ Host inventory and network configuration. - [[indri]] - Primary server - [[gilbert]] - Development workstation - [[tailscale]] - ACLs, groups, tags +- [[gandi]] - DNS hosting for `eblu.me` - [[routing|Routing]] - DNS domains, port mappings ## Kubernetes diff --git a/docs/reference/services/caddy.md b/docs/reference/services/caddy.md index 7430ddf..e7f8e00 100644 --- a/docs/reference/services/caddy.md +++ b/docs/reference/services/caddy.md @@ -92,6 +92,7 @@ The build includes the `github.com/caddy-dns/gandi` plugin for ACME DNS-01 chall ## Related +- [[gandi]] - DNS hosting and ACME DNS-01 provider - [[routing]] - Service routing architecture - [[forgejo]] - Git forge (proxied by Caddy) - [[zot]] - Container registry (proxied by Caddy) diff --git a/pulumi/gandi/README.md b/pulumi/gandi/README.md index 5a2a442..d8d30d9 100644 --- a/pulumi/gandi/README.md +++ b/pulumi/gandi/README.md @@ -37,7 +37,7 @@ This project requires a Gandi Personal Access Token (PAT) with LiveDNS permissio 2. Create a new PAT: - Name: `blumeops-pulumi` (or similar) - - Expiration: 30 days (maximum) + - Expiration: 30 days (maximum is 90; shorter is fine if used rarely) - Permissions required: - **Manage domain name technical configurations** (required for DNS records) - See and renew domain names