From 5538d54fb4ee6a23cc1c393c3290c5336d3403a9 Mon Sep 17 00:00:00 2001 From: Hunter Halloran Date: Fri, 30 Jan 2026 12:59:04 -0500 Subject: [PATCH] fix: Move ragenix to externally managed, and ask for env file references --- .gitmodules | 2 +- ATHENIX_INTEGRATION.md | 305 +++++++++++++++++++++++++++++++++++++ NIX_FLAKE_MIGRATION.md | 2 +- SECRETS_QUICK_REFERENCE.md | 213 ++++++++++++++++++++++++++ SECRETS_REFACTORING.md | 146 ++++++++++++++++++ default.nix | 79 +++++++--- usda-vision | 2 +- 7 files changed, 728 insertions(+), 21 deletions(-) create mode 100644 ATHENIX_INTEGRATION.md create mode 100644 SECRETS_QUICK_REFERENCE.md create mode 100644 SECRETS_REFACTORING.md diff --git a/.gitmodules b/.gitmodules index f5d85cd..80bebc6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "usda-vision"] path = usda-vision - url = git@github.com:salirezav/usda-vision.git + url = git@factory.uga.edu:MODEL/usda-vision.git diff --git a/ATHENIX_INTEGRATION.md b/ATHENIX_INTEGRATION.md new file mode 100644 index 0000000..ce08c9f --- /dev/null +++ b/ATHENIX_INTEGRATION.md @@ -0,0 +1,305 @@ +# Integrating usda-dash-config with athenix + +This guide shows how to properly integrate the usda-vision flake and usda-dash-config module into your athenix infrastructure. + +## Architecture + +``` +athenix/ (main flake) + ├── flake.nix + │ └── inputs.usda-vision (flake input) + └── nixos-systems/ + └── inventory.nix + └── imports usda-dash-config/default.nix (external module) + └── receives usda-vision packages as parameter +``` + +## Step 1: Add usda-vision as a flake input in athenix + +In your `~/athenix/flake.nix`, add usda-vision as an input: + +```nix +{ + description = "Athenix infrastructure"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + # Add usda-vision flake + usda-vision = { + url = "path:/path/to/usda-dash-config/usda-vision"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + # Your other inputs... + }; + + outputs = { self, nixpkgs, usda-vision, ... }: { + # Your outputs... + }; +} +``` + +## Step 2: Make packages available to NixOS modules + +In your athenix flake outputs, ensure the usda-vision packages are available to your NixOS configurations. There are two approaches: + +### Approach A: Using specialArgs (Recommended) + +```nix +outputs = { self, nixpkgs, usda-vision, ... }: { + nixosConfigurations.usda-dash = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + specialArgs = { + # Pass usda-vision packages to all modules + usda-vision-packages = usda-vision.packages.x86_64-linux; + }; + + modules = [ + # Your modules... + ]; + }; +} +``` + +### Approach B: Using _module.args + +```nix +outputs = { self, nixpkgs, usda-vision, ... }: { + nixosConfigurations.usda-dash = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + modules = [ + # Make packages available as module args + { + _module.args = { + usda-vision-packages = usda-vision.packages.x86_64-linux; + }; + } + + # Your other modules... + ]; + }; +} +``` + +## Step 3: Configure secrets with ragenix in athenix + +Secrets are managed by ragenix in the athenix flake, not in this flake. Configure your secrets in athenix: + +```nix +# In your athenix flake or secrets configuration +{ + age.secrets.usda-vision-env = { + file = ./secrets/usda-vision/env.age; # Encrypted with ragenix in athenix + mode = "0644"; + owner = "root"; + group = "root"; + }; + + age.secrets.usda-vision-azure-env = { + file = ./secrets/usda-vision/azure-env.age; # Encrypted with ragenix in athenix + mode = "0644"; + owner = "root"; + group = "root"; + }; +} +``` + +## Step 4: Import usda-dash-config in inventory.nix + +In your `nixos-systems/inventory.nix` (or wherever you import external modules): + +```nix +{ config, usda-vision-packages, ... }: + +{ + imports = [ + # Import the usda-dash-config module, passing packages and secret paths + (import /path/to/usda-dash-config/default.nix { + inherit usda-vision-packages; + envFile = config.age.secrets.usda-vision-env.path; + azureEnvFile = config.age.secrets.usda-vision-azure-env.path; + }) + + # Your other imports... + ]; +} +``` + +Or if using nix-lxc devices pattern: + +```nix +{ config, usda-vision-packages, ... }: + +{ + nix-lxc = { + devices = { + "usda-dash" = + let + usda-dash-config = builtins.fetchGit { + url = "https://git.factory.uga.edu/MODEL/usda-dash-config.git"; + rev = "commit-hash"; + submodules = true; + }; + in + import "${usda-dash-config}/default.nix" { + inherit usda-vision-packages; + envFile = config.age.secrets.usda-vision-env.path; + azureEnvFile = config.age.secrets.usda-vision-azure-env.path; + }; + }; + }; +} +``` + +## Complete Example + +Here's a complete example of how it all fits together: + +### ~/athenix/flake.nix + +```nix +{ + description = "Athenix infrastructure"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + usda-vision = { + url = "path:/home/engr-ugaif/usda-dash-config/usda-vision"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + + agenix.url = "github:ryantm/agenix"; + }; + + outputs = { self, nixpkgs, usda-vision, agenix, ... }: { + nixosConfigurations = { + usda-dash = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + + specialArgs = { + usda-vision-packages = usda-vision.packages.x86_64-linux; + }; + + modules = [ + agenix.nixosModules.default + ./nixos-systems/inventory.nix + ]; + }; + }; + }; +} +``` + +### ~/athenix/nixos-systems/inventory.nix + +```nix +{ config, pkgs, usda-vision-packages, ... }: + +{ + imports = [ + # Import usda-dash-config, passing the packages and secret file paths + (import /home/engr-ugaif/usda-dash-config/default.nix { + inherit usda-vision-packages; + envFile = config.age.secrets.usda-vision-env.path; + azureEnvFile = config.age.secrets.usda-vision-azure-env.path; + }) + ]; + + # Configure secrets (managed by ragenix in athenix) + age.secrets.usda-vision-env = { + file = ./secrets/usda-vision/env.age; # Store encrypted secrets in athenix + mode = "0644"; + }; + + age.secrets.usda-vision-azure-env = { + file = ./secrets/usda-vision/azure-env.age; # Azure OAuth config + mode = "0644"; + }; + + # The usda-dash services are now configured and will use the ragenix-managed secrets +} +``` + +## Local Development vs Production + +### Local Development (in usda-vision/) + +```bash +cd /path/to/usda-dash-config/usda-vision +nix develop # Uses the local flake +``` + +### Production Build (from athenix) + +```bash +cd ~/athenix +nixos-rebuild switch --flake .#usda-dash +``` + +The usda-vision packages are built by athenix and passed to the usda-dash-config module. + +## Troubleshooting + +### "usda-vision-packages is null" + +The packages aren't being passed correctly. Check: +- `usda-vision` is in your athenix flake inputs +- `specialArgs` or `_module.args` includes `usda-vision-packages` +- The import in inventory.nix uses `inherit usda-vision-packages;` + +### "attribute 'camera-sdk' missing" + +The usda-vision flake hasn't been built. Try: +```bash +nix flake update # Update the flake lock +nix build /path/to/usda-dash-config/usda-vision#camera-sdk # Test build +``` + +### Fallback behavior + +If `usda-vision-packages` is not provided, the module falls back to building locally with `callPackage`. This works for standalone testing but isn't recommended for production. + +## Benefits of This Approach + +1. ✅ **Pure builds**: No `--impure` needed +2. ✅ **Centralized secrets**: Secrets managed by ragenix in athenix, not in usda-vision flake +3. ✅ **Centralized packages**: usda-vision is built once by athenix +4. ✅ **Version control**: Lock file in athenix controls versions +5. ✅ **Clean separation**: + - usda-vision flake: package definitions only + - athenix: secrets management and deployment + - usda-dash-config: NixOS module configuration +6. ✅ **Flexible secrets**: Can easily pass different secret files per environment (dev/staging/prod) + +## Managing Secrets in Athenix + +To create and manage secrets in athenix: + +```bash +# In athenix directory +cd ~/athenix + +# Create the secrets directory +mkdir -p secrets/usda-vision + +# Create/edit the main environment file secret +ragenix -e secrets/usda-vision/env.age + +# Create/edit the Azure environment file secret +ragenix -e secrets/usda-vision/azure-env.age +``` + +The content of `env.age` should match the format of `.env.example`: +```bash +VITE_SUPABASE_URL=http://127.0.0.1:54321 +VITE_SUPABASE_ANON_KEY=your-key-here +# ... etc +``` + - usda-vision = flake (build system) + - usda-dash-config = module (configuration) + - athenix = orchestrator (infrastructure) +5. ✅ **Reusable**: Other athenix machines can use the same packages diff --git a/NIX_FLAKE_MIGRATION.md b/NIX_FLAKE_MIGRATION.md index 2a30e68..a8037be 100644 --- a/NIX_FLAKE_MIGRATION.md +++ b/NIX_FLAKE_MIGRATION.md @@ -1,4 +1,4 @@ -# Nix Flake Migration Summary +t pu# Nix Flake Migration Summary ## What Changed diff --git a/SECRETS_QUICK_REFERENCE.md b/SECRETS_QUICK_REFERENCE.md new file mode 100644 index 0000000..612792a --- /dev/null +++ b/SECRETS_QUICK_REFERENCE.md @@ -0,0 +1,213 @@ +# Quick Reference: Secrets Management in Athenix + +## For Infrastructure Maintainers (Athenix) + +### Initial Setup + +```bash +# 1. Ensure ragenix/agenix is configured in athenix +cd ~/athenix + +# 2. Create secrets directory +mkdir -p secrets/usda-vision + +# 3. Create the main environment secrets file +ragenix -e secrets/usda-vision/env.age +``` + +**Content template for env.age:** +```bash +# Supabase Configuration +VITE_SUPABASE_URL=http://127.0.0.1:54321 +VITE_SUPABASE_ANON_KEY=your-anon-key-here + +# Vision API Configuration +VITE_VISION_API_URL=http://exp-dash:8000 +VITE_ENABLE_VIDEO_MODULE=true +VITE_VIDEO_REMOTE_URL=http://exp-dash:3001/assets/remoteEntry.js +VITE_MEDIA_API_URL=http://exp-dash:8090 + +# Vision System Module +VITE_ENABLE_VISION_SYSTEM_MODULE=true +VITE_VISION_SYSTEM_REMOTE_URL=http://exp-dash:3002/assets/remoteEntry.js + +# Enable scheduling module +VITE_ENABLE_SCHEDULING_MODULE=true +``` + +### Optional: Azure OAuth Configuration + +```bash +# Create Azure OAuth secrets file +ragenix -e secrets/usda-vision/azure-env.age +``` + +**Content template for azure-env.age:** +```bash +AZURE_CLIENT_ID=your-client-id +AZURE_CLIENT_SECRET=your-client-secret +AZURE_TENANT_ID=your-tenant-id +AZURE_REDIRECT_URI=http://your-domain/auth/callback +``` + +### Configure in NixOS + +Add to your athenix configuration (e.g., `nixos-systems/inventory.nix`): + +```nix +{ config, usda-vision-packages, ... }: + +{ + # Configure ragenix secrets + age.secrets.usda-vision-env = { + file = ./secrets/usda-vision/env.age; + mode = "0644"; + owner = "root"; + group = "root"; + }; + + age.secrets.usda-vision-azure-env = { + file = ./secrets/usda-vision/azure-env.age; + mode = "0644"; + owner = "root"; + group = "root"; + }; + + # Import usda-dash-config module with secret paths + imports = [ + (import /path/to/usda-dash-config/default.nix { + inherit usda-vision-packages; + envFile = config.age.secrets.usda-vision-env.path; + azureEnvFile = config.age.secrets.usda-vision-azure-env.path; + }) + ]; +} +``` + +### Deploy + +```bash +cd ~/athenix +nixos-rebuild switch --flake .#usda-dash +``` + +## For Application Developers (usda-vision) + +### Local Development + +```bash +cd usda-vision + +# Enter development environment +nix develop + +# Create local .env for development +cp .env.example .env +nano .env # Edit with your local configuration + +# Start services +docker-compose up +``` + +### Important Notes + +- **DO NOT** commit `.env` files to the repository +- **DO NOT** manage secrets in the usda-vision flake +- All production secrets should be managed in athenix using ragenix +- The `.env.example` files are safe to commit (they contain demo values) + +## Checking Deployed Secrets + +On the deployed system: + +```bash +# Check if secrets are properly deployed +ls -la /var/lib/usda-vision/.env* + +# View the active configuration (be careful with sensitive data!) +sudo cat /var/lib/usda-vision/.env + +# Check systemd service status +systemctl status usda-vision +``` + +## Troubleshooting + +### Service fails to start with "ConditionPathExists not met" + +The `envFile` wasn't properly passed or the ragenix secret isn't configured. + +**Solution:** +1. Verify age.secrets.usda-vision-env is configured in athenix +2. Check that envFile parameter is passed to the module +3. Rebuild with `nixos-rebuild switch` + +### .env file is empty or has wrong content + +The ragenix secret might not have the right content. + +**Solution:** +```bash +cd ~/athenix +ragenix -e secrets/usda-vision/env.age +# Verify/update the content +nixos-rebuild switch --flake .#usda-dash +``` + +### Want to use different secrets for different environments + +Pass different secret files: + +```nix +# For production +envFile = config.age.secrets.usda-vision-env-prod.path; + +# For staging +envFile = config.age.secrets.usda-vision-env-staging.path; + +# For development +envFile = config.age.secrets.usda-vision-env-dev.path; +``` + +## Architecture Summary + +``` +┌─────────────────────────────────────────────────┐ +│ athenix (Infrastructure) │ +│ │ +│ ┌─────────────────────────────────┐ │ +│ │ ragenix secret management │ │ +│ │ • env.age │ │ +│ │ • azure-env.age │ │ +│ │ │ │ +│ │ Decrypted at deploy time → │ │ +│ │ /run/agenix/usda-vision-env │ │ +│ └─────────────────────────────────┘ │ +│ ↓ │ +│ ┌─────────────────────────────────┐ │ +│ │ NixOS Configuration │ │ +│ │ imports usda-dash-config with: │ │ +│ │ • usda-vision-packages │ │ +│ │ • envFile path │ │ +│ │ • azureEnvFile path │ │ +│ └─────────────────────────────────┘ │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ usda-dash-config (NixOS Module) │ +│ │ +│ Copies secrets to: │ +│ /var/lib/usda-vision/.env │ +│ /var/lib/usda-vision/.env.azure │ +│ │ +│ Starts systemd service: usda-vision │ +└─────────────────────────────────────────────────┘ + ↓ +┌─────────────────────────────────────────────────┐ +│ usda-vision (Application Flake) │ +│ │ +│ • Package definitions only │ +│ • No secret management │ +│ • Development shell with tools │ +└─────────────────────────────────────────────────┘ +``` diff --git a/SECRETS_REFACTORING.md b/SECRETS_REFACTORING.md new file mode 100644 index 0000000..6323184 --- /dev/null +++ b/SECRETS_REFACTORING.md @@ -0,0 +1,146 @@ +# Secrets Management Refactoring + +## Summary of Changes + +This refactoring moves secrets management from the usda-vision flake to athenix (the parent infrastructure flake), following the principle that secrets should be managed centrally at the infrastructure level, not in application flakes. + +## What Changed + +### 1. Removed ragenix from usda-vision flake + +**Before:** usda-vision/flake.nix included ragenix as an input and provided tools for local secret management. + +**After:** usda-vision/flake.nix is now purely for package definitions. Ragenix is removed from inputs. + +**Files modified:** +- [usda-vision/flake.nix](usda-vision/flake.nix) + +### 2. Updated default.nix to accept secret file paths + +**Before:** The module used hardcoded paths and copied .env.example files. + +**After:** The module accepts `envFile` and `azureEnvFile` parameters pointing to ragenix-managed secrets from athenix. + +**Files modified:** +- [default.nix](default.nix) + +**New parameters:** +```nix +{ usda-vision-packages ? null +, envFile ? null # NEW: Path to ragenix-managed .env +, azureEnvFile ? null # NEW: Path to ragenix-managed .env.azure +, ... +} +``` + +### 3. Removed hardcoded .env path transformations + +**Before:** package.nix used sed to rewrite env_file paths in docker-compose.yml + +**After:** Paths are not rewritten; secrets are copied to the working directory by the systemd service + +**Files modified:** +- [usda-vision/package.nix](usda-vision/package.nix) + +### 4. Updated integration documentation + +**Files modified:** +- [ATHENIX_INTEGRATION.md](ATHENIX_INTEGRATION.md) + +## How to Use in Athenix + +### Step 1: Create secrets in athenix + +```bash +cd ~/athenix +mkdir -p secrets/usda-vision + +# Edit the main environment file +ragenix -e secrets/usda-vision/env.age + +# Edit the Azure OAuth configuration +ragenix -e secrets/usda-vision/azure-env.age +``` + +### Step 2: Configure age secrets in athenix + +```nix +# In athenix flake or NixOS configuration +{ + age.secrets.usda-vision-env = { + file = ./secrets/usda-vision/env.age; + mode = "0644"; + owner = "root"; + group = "root"; + }; + + age.secrets.usda-vision-azure-env = { + file = ./secrets/usda-vision/azure-env.age; + mode = "0644"; + owner = "root"; + group = "root"; + }; +} +``` + +### Step 3: Pass secret paths to usda-dash-config module + +```nix +# In inventory.nix or wherever you import usda-dash-config +{ config, usda-vision-packages, ... }: + +{ + imports = [ + (import /path/to/usda-dash-config/default.nix { + inherit usda-vision-packages; + envFile = config.age.secrets.usda-vision-env.path; + azureEnvFile = config.age.secrets.usda-vision-azure-env.path; + }) + ]; +} +``` + +## Benefits + +1. **Centralized secret management**: All infrastructure secrets are managed in athenix using ragenix +2. **No hardcoded transformations**: The derivation doesn't modify env file paths +3. **Flexible deployment**: Different secrets can be passed for dev/staging/prod environments +4. **Pure builds**: No need for `--impure` flag since secrets aren't built into the derivation +5. **Security**: Secrets are encrypted at rest in athenix and only decrypted on the target system +6. **Clean separation of concerns**: + - usda-vision flake: Package definitions only + - athenix: Infrastructure and secrets management + - usda-dash-config: NixOS module configuration + +## Migration for Existing Deployments + +If you have existing deployments using the old approach: + +1. Create the secret files in athenix as shown above +2. Copy the content from your existing `.env` files into the ragenix-managed secrets +3. Update your inventory.nix to pass the secret file paths +4. Rebuild with `nixos-rebuild switch` +5. Verify the secrets are correctly copied to `/var/lib/usda-vision/.env` + +## Fallback Behavior + +If `envFile` is not provided (e.g., for local testing), the module will: +1. Print a warning +2. Copy `.env.example` to `/var/lib/usda-vision/.env` +3. Remind you to configure secrets in athenix + +This allows the module to work standalone for development, but production deployments should always provide proper secrets. + +## Local Development + +For local development in the usda-vision directory, you can still use: + +```bash +cd usda-vision +nix develop +cp .env.example .env +# Edit .env with your local configuration +docker-compose up +``` + +The flake.nix still provides a development shell with all necessary tools, but ragenix should be installed from athenix if needed for secret management. diff --git a/default.nix b/default.nix index a53a951..9a0fa94 100644 --- a/default.nix +++ b/default.nix @@ -1,4 +1,8 @@ -{ inputs, ... }: +{ usda-vision-packages ? null +, envFile ? null +, azureEnvFile ? null +, ... +}: # ============================================================================ # USDA Dashboard External System Module @@ -21,6 +25,25 @@ # - Unprivileged: no (or privileged: yes) # Edit the container config in Proxmox: /etc/pve/lxc/.conf # Add: features: nesting=1,keyctl=1 +# +# USAGE FROM ATHENIX: +# +# 1. Add usda-vision as a flake input in athenix/flake.nix: +# +# inputs.usda-vision = { +# url = "path:/path/to/usda-dash-config/usda-vision"; +# inputs.nixpkgs.follows = "nixpkgs"; +# }; +# +# 2. In inventory.nix, pass the usda-vision packages and ragenix-managed secrets: +# +# imports = [ +# (import /path/to/usda-dash-config/default.nix { +# usda-vision-packages = inputs.usda-vision.packages.${system}; +# envFile = config.age.secrets.usda-vision-env.path; +# azureEnvFile = config.age.secrets.usda-vision-azure-env.path; +# }) +# ]; { config, @@ -30,12 +53,17 @@ }: let - # Import the usda-vision flake - usda-vision-flake = (builtins.getFlake (toString ./usda-vision)).packages.${pkgs.system}; - - # Get packages from the flake - camera-sdk = usda-vision-flake.camera-sdk; - usda-vision-app = usda-vision-flake.usda-vision; + # Get packages from the parameter passed by athenix + # Fallback to local callPackage if not provided (for standalone testing) + camera-sdk = + if usda-vision-packages != null + then usda-vision-packages.camera-sdk + else pkgs.callPackage ./usda-vision/camera-sdk.nix {}; + + usda-vision-app = + if usda-vision-packages != null + then usda-vision-packages.usda-vision + else pkgs.callPackage ./usda-vision/package.nix {}; in { @@ -157,10 +185,9 @@ in wants = [ "network-online.target" ]; wantedBy = [ "multi-user.target" ]; - # Only start if .env file exists and is not empty - unitConfig = { - ConditionPathExists = "/var/lib/usda-vision/.env"; - ConditionPathIsReadWrite = "/var/lib/usda-vision/.env"; + # Only start if .env file exists (will be managed by ragenix) + unitConfig = lib.mkIf (envFile != null) { + ConditionPathExists = envFile; }; preStart = '' @@ -170,18 +197,34 @@ in --checksum \ --exclude='node_modules' \ --exclude='.env' \ + --exclude='.env.azure' \ --exclude='__pycache__' \ --exclude='.venv' \ ${usda-vision-app}/opt/usda-vision/ /var/lib/usda-vision/ - # Ensure .env file exists with defaults if empty - if [ ! -s /var/lib/usda-vision/.env ]; then - if [ -f ${usda-vision-app}/opt/usda-vision/.env.example ]; then - echo "Copying .env.example to /var/lib/usda-vision/.env" - cp ${usda-vision-app}/opt/usda-vision/.env.example /var/lib/usda-vision/.env - echo "Please edit /var/lib/usda-vision/.env with your configuration" + # Copy ragenix-managed secrets to working directory + ${lib.optionalString (envFile != null) '' + echo "Copying environment file from ragenix-managed secret..." + cp ${envFile} /var/lib/usda-vision/.env + chmod 644 /var/lib/usda-vision/.env + ''} + + ${lib.optionalString (azureEnvFile != null) '' + echo "Copying Azure environment file from ragenix-managed secret..." + cp ${azureEnvFile} /var/lib/usda-vision/.env.azure + chmod 644 /var/lib/usda-vision/.env.azure + ''} + + # Fallback: use example file if no secrets provided + ${lib.optionalString (envFile == null) '' + if [ ! -s /var/lib/usda-vision/.env ]; then + if [ -f ${usda-vision-app}/opt/usda-vision/.env.example ]; then + echo "WARNING: No ragenix-managed secrets provided, using .env.example" + echo "Please configure secrets in athenix using ragenix" + cp ${usda-vision-app}/opt/usda-vision/.env.example /var/lib/usda-vision/.env + fi fi - fi + ''} ''; serviceConfig = { diff --git a/usda-vision b/usda-vision index 3434082..20a01c8 160000 --- a/usda-vision +++ b/usda-vision @@ -1 +1 @@ -Subproject commit 3434082584afb95e0b3467f1c383753f9bde2522 +Subproject commit 20a01c89afd8e54fba2f345fb9d72eec1cbafda4