From 7df2b1075ed8115374f623aec6386317625d48c6 Mon Sep 17 00:00:00 2001 From: Jordan Ramos Date: Thu, 18 Dec 2025 18:12:35 -0700 Subject: [PATCH] docs(tinyauth): document .env file solution for "User not found" error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Issue #5: "User not found" error resolved with .env file approach - Update Configuration section to show .env as RECOMMENDED method - Document $$ escaping requirement for bcrypt hashes in .env files - Update credential management, troubleshooting, and backup sections - Update status to "User authentication working with .env configuration" The .env file approach eliminates YAML/shell parsing issues with special characters in bcrypt hashes and represents Docker Compose best practice. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- services/tinyauth/README.md | 158 ++++++++++++++++++++++++++++-------- 1 file changed, 125 insertions(+), 33 deletions(-) diff --git a/services/tinyauth/README.md b/services/tinyauth/README.md index 77ecc75..c94c50b 100644 --- a/services/tinyauth/README.md +++ b/services/tinyauth/README.md @@ -70,6 +70,16 @@ TinyAuth is a lightweight, self-hosted authentication service providing Single S ### Docker Compose +**✅ RECOMMENDED APPROACH**: Use `.env` file for credential storage + +This method eliminates YAML/shell parsing issues with special characters in bcrypt hashes and represents Docker Compose best practice for credential management. + +**File**: `/home/jramos/homelab/services/tinyauth/.env` + +```bash +USERS=jramos:$$2y$$05$$CNW/Anbac0mD./ajAepRm.aUvpeAFtOWVrqSxge5wEKZK3yD1.tT. +``` + **File**: `/home/jramos/homelab/services/tinyauth/docker-compose.yml` ```yaml @@ -82,14 +92,23 @@ services: - "8000:3000" # External:Internal (TinyAuth runs on port 3000 internally) environment: - APP_URL=https://tinyauth.apophisnetworking.net - - USERS='jramos:$2b$05$...' # Bcrypt-hashed password (MUST be single-quoted) + - USERS=${USERS} # References .env file variable ``` **Critical Configuration Notes**: - **APP_URL**: MUST use the domain name, not an IP address (IP addresses trigger validation errors) - **Port Mapping**: TinyAuth listens on port 3000 internally, exposed as 8000 externally -- **USERS Format**: `'username:bcrypt_hash'` - Single quotes prevent shell interpretation of special characters +- **USERS Format**: `username:bcrypt_hash` stored in `.env` file - **Bcrypt Hash**: Generate with `htpasswd -nbB username password`, then extract hash portion +- **Double Dollar Signs**: In `.env` files, use `$$` to escape dollar signs in bcrypt hashes (e.g., `$$2y$$05$$...`) +- **.env File Security**: Set permissions with `chmod 600 .env` to restrict access + +**Why .env File is Recommended**: +- ✅ Prevents YAML/shell parsing issues with special characters in bcrypt hashes +- ✅ Cleaner separation of secrets from configuration +- ✅ Easier to manage multiple users (just edit one variable) +- ✅ Avoids quoting complexity in docker-compose.yml +- ✅ Standard practice for Docker Compose credential management ### Nginx Proxy Manager Configuration @@ -224,20 +243,20 @@ docker ps | grep tinyauth **Root Cause**: - TinyAuth v4 requires **bcrypt-hashed passwords**, not plaintext -- Initial configuration used `USERS=jramos:Nbkx4md007` (plaintext) +- Initial configuration used plaintext password storage - TinyAuth compares bcrypt hash of input against stored hash - plaintext storage fails **Solution**: 1. Generate bcrypt hash: ```bash -htpasswd -nbB jramos Nbkx4md007 +htpasswd -nbB jramos YourPassword # Output: jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789... ``` -2. Update docker-compose.yml with **single-quoted hash**: -```yaml -- USERS='jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...' +2. Store hash in `.env` file with `$$` escaping: +```bash +USERS=jramos:$$2y$$05$$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789... ``` 3. Restart container: @@ -247,22 +266,79 @@ docker-compose down docker-compose up -d ``` -**Why Single Quotes Matter**: -- `$` has special meaning in shell/YAML double-quoted strings -- Single quotes prevent variable expansion and preserve the literal bcrypt hash -- Without quotes, the hash will be corrupted during environment variable parsing +**Why Bcrypt Hash is Required**: +- Security: Bcrypt is computationally expensive, resists brute force attacks +- Industry Standard: Modern password storage best practice +- One-way Hash: Even if .env is compromised, passwords cannot be reversed **Validation**: ```bash -# Check environment variable is set correctly +# Check environment variable is set correctly inside container docker exec tinyauth env | grep USERS -# Should show: USERS='jramos:$2b$05$...' +# Should show: USERS=jramos:$2y$05$... (single $ inside container) # Test authentication -curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx +curl -u jramos:YourPassword http://192.168.2.10:8000/api/auth/nginx # Should return HTTP 200 on success ``` +### Issue #5: "User not found" Error - Resolved with .env File Approach + +**Symptoms**: +- Login page loaded correctly +- Valid credentials entered but TinyAuth returned "User not found" +- Logs showed: `WRN internal/service/auth_service.go:130 > Local user not found username=jramos` +- docker-compose.yml had USERS environment variable configured with bcrypt hash + +**Root Cause**: +- YAML/shell parsing of bcrypt hashes with special characters (`$`) was inconsistent +- Even with single quotes in docker-compose.yml, the hash could be corrupted during environment variable expansion +- Different YAML parsers handle quoted strings with `$` symbols differently +- The quoted string approach created subtle parsing issues that prevented TinyAuth from recognizing the user + +**Solution**: +1. Create `.env` file in `/home/jramos/homelab/services/tinyauth/`: + ```bash + USERS=jramos:$$2y$$05$$CNW/Anbac0mD./ajAepRm.aUvpeAFtOWVrqSxge5wEKZK3yD1.tT. + ``` + +2. Update docker-compose.yml to reference the variable: + ```yaml + environment: + - USERS=${USERS} + ``` + +3. Restart container: + ```bash + cd /home/jramos/homelab/services/tinyauth + docker-compose down + docker-compose up -d + ``` + +**Why This Works**: +- `.env` files use different escaping rules than YAML +- `$$` in `.env` files escapes to a single `$` in the environment variable +- Docker Compose reads .env files automatically and substitutes `${USERS}` with the file content +- Eliminates YAML parser ambiguity with special characters +- The `.env` approach is Docker Compose's intended method for managing credentials + +**Validation**: +```bash +# Verify .env file exists and has correct format +cat /home/jramos/homelab/services/tinyauth/.env +# Should show: USERS=jramos:$$2y$$05$$... + +# Verify environment variable is correct inside container +docker exec tinyauth env | grep USERS +# Should show: USERS=jramos:$2y$05$... (single $ inside container) + +# Test authentication +curl -u jramos:YourPassword http://192.168.2.10:8000/api/auth/nginx +# Should return HTTP 200 +``` + +**✅ This is now the RECOMMENDED configuration method** - see Configuration section above. + ## Access & Credentials ### Login URL @@ -276,22 +352,26 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx ```bash htpasswd -nbB newuser password123 ``` -2. Update docker-compose.yml USERS variable (comma-separated for multiple users): - ```yaml - - USERS='jramos:$2b$05$...,alice:$2b$05$...,bob:$2b$05$...' +2. Update `.env` file with USERS variable (comma-separated for multiple users): + ```bash + USERS=jramos:$$2y$$05$$...,alice:$$2y$$05$$...,bob:$$2y$$05$$... ``` + **Remember**: Use `$$` (double dollar signs) to escape `$` in .env files + 3. Restart container: ```bash + cd /home/jramos/homelab/services/tinyauth docker-compose down && docker-compose up -d ``` **Changing Passwords**: 1. Generate new bcrypt hash with new password -2. Replace the hash in docker-compose.yml +2. Replace the hash in `.env` file (remember to use `$$` for escaping) 3. Restart container -**Security Note**: Credentials are stored in docker-compose.yml. For production use, consider: -- Environment variable injection from secrets management +**Security Note**: Credentials are stored in `.env` file. For production use, consider: +- Set file permissions: `chmod 600 .env` +- Environment variable injection from secrets management (Docker Secrets, Vault) - Integration with LDAP/Active Directory - Migration to more robust SSO (Authelia, Keycloak) @@ -327,7 +407,10 @@ docker-compose restart ### Backup ```bash -# Backup docker-compose.yml (contains credentials) +# Backup .env file (contains credentials) - CRITICAL +cp .env .env.backup-$(date +%Y%m%d) + +# Backup docker-compose.yml cp docker-compose.yml docker-compose.yml.backup-$(date +%Y%m%d) ``` @@ -337,6 +420,7 @@ cp docker-compose.yml docker-compose.yml.backup-$(date +%Y%m%d) docker pull ghcr.io/steveiliop56/tinyauth:v4 # Recreate container with new image +cd /home/jramos/homelab/services/tinyauth docker-compose down docker-compose pull docker-compose up -d @@ -357,21 +441,28 @@ docker logs nginx-proxy-manager | grep tinyauth curl -I https://tinyauth.apophisnetworking.net ``` -### Symptoms: "Invalid password" error +### Symptoms: "Invalid password" or "User not found" error **Check**: -1. USERS environment variable uses bcrypt hash: `docker exec tinyauth env | grep USERS` -2. Hash is single-quoted in docker-compose.yml -3. Password hasn't changed since hash generation -4. Account isn't locked (wait 5 minutes after 5 failed attempts) +1. `.env` file exists in same directory as docker-compose.yml +2. USERS environment variable uses bcrypt hash with `$$` escaping in .env: `cat .env` +3. Hash is correctly loaded inside container: `docker exec tinyauth env | grep USERS` +4. Password hasn't changed since hash generation +5. Account isn't locked (wait 5 minutes after 5 failed attempts) **Commands**: ```bash -# Verify hash format +# Verify .env file exists and has correct format +cat /home/jramos/homelab/services/tinyauth/.env +# Should show: USERS=jramos:$$2y$$05$$... + +# Verify hash format inside container (single $, not double) docker exec tinyauth env | grep USERS +# Should show: USERS=jramos:$2y$05$... (single $ inside container) # Test authentication directly -curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx +curl -u jramos:YourPassword http://192.168.2.10:8000/api/auth/nginx +# Should return HTTP 200 on success ``` ### Symptoms: "IP addresses not allowed" @@ -424,8 +515,8 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx ✅ No database dependencies (reduces vulnerability vectors) ### Weaknesses & Mitigations -⚠️ **Credentials in docker-compose.yml**: Ensure file permissions restrict read access - - Mitigation: `chmod 600 docker-compose.yml` +⚠️ **Credentials in .env file**: Ensure file permissions restrict read access + - Mitigation: `chmod 600 .env` - Future: Migrate to secrets management (Docker Secrets, Vault) ⚠️ **No MFA**: Single-factor authentication only @@ -443,6 +534,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx ### Recommended Hardening 1. **File Permissions**: ```bash + chmod 600 /home/jramos/homelab/services/tinyauth/.env chmod 600 /home/jramos/homelab/services/tinyauth/docker-compose.yml ``` @@ -456,7 +548,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx 4. **Log Monitoring**: - Configure alerts for repeated authentication failures - - Forward logs to Loki (CT 101 - monitoring stack) + - Forward logs to Loki (VM 101 - monitoring stack) ## Future Enhancements @@ -468,7 +560,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx ### Medium-Term - [ ] Extend authentication to Proxmox web UI (if supported by TinyAuth) -- [ ] Implement automated backup of docker-compose.yml to PBS +- [ ] Implement automated backup of .env to Proxmox Backup Server - [ ] Explore TinyAuth API for programmatic user management ### Long-Term @@ -489,4 +581,4 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx **Maintained by**: Homelab Infrastructure Team **Last Updated**: 2025-12-18 -**Status**: ✅ Operational - Protecting NetBox with SSO authentication +**Status**: ✅ Operational - User authentication working with .env configuration