Files
org-stack/README.md
Stefano Manfredi 2866bff217 first commit
2025-12-01 14:58:40 +00:00

466 lines
18 KiB
Markdown

# Organization Stack
A self-hosted collaboration and authentication platform featuring Single Sign-On (SSO), Two-Factor Authentication (2FA), centralized user management, Git hosting, and wiki collaboration.
## Overview
This project provides a complete, production-ready stack for small to medium organizations seeking self-hosted alternatives to cloud services. All components communicate through modern authentication standards (LDAP, OIDC, Forward-Auth) providing seamless single sign-on across all services.
### Components
- **[lldap](https://github.com/lldap/lldap)** - Lightweight LDAP directory for centralized user and group management
- **[Authelia](https://www.authelia.com/)** - SSO authentication server with 2FA/TOTP support, OIDC provider, and forward-auth endpoint
- **[Gitea](https://gitea.io/)** - Self-hosted Git service with web UI (authenticated via OIDC)
- **[JSPWiki](https://jspwiki.apache.org/)** - Collaborative wiki platform (authenticated via Forward-Auth)
- **Registration Service** - User self-provisioning with admin approval (FastAPI + SQLite)
- **[Caddy](https://caddyserver.com/)** - Reverse proxy with automatic HTTPS via Let's Encrypt
### Key Features
- **Single Sign-On (SSO)** - One set of credentials for all services
- **Two-Factor Authentication** - TOTP (Google Authenticator, Authy, etc.) support
- **Automatic HTTPS** - Let's Encrypt certificates managed by Caddy
- **File-Based Secrets** - Secure secret management following Docker best practices
- **One-Command Deployment** - Automated setup script handles everything
- **Zero Manual Configuration** - Template-based config generation from `.env`
## Quick Start
### Prerequisites
- **Remote Server**: Linux server with Docker and Docker Compose v2 installed
- **Local Machine**: SSH access to remote server, rsync installed
- **Domain**: Domain name with DNS pointing to your server (or `/etc/hosts` for testing)
### Installation
> **Note**: For production deployments with multiple administrators, see [MULTI_ADMIN_SETUP.md](MULTI_ADMIN_SETUP.md) for system-wide installation with proper permissions.
1. **Clone the repository**
```bash
git clone https://github.com/yourorg/org-stack.git
cd org-stack
```
2. **Configure environment**
```bash
cp .env.example .env
nano .env # Edit BASE_DOMAIN, REMOTE_USER, REMOTE_HOST
```
Required changes in `.env`:
- `BASE_DOMAIN=example.com` → your actual domain
- `REMOTE_USER=user` → your SSH username (or `deploy` for multi-admin)
- `REMOTE_HOST=example.com` → your server hostname/IP
- `REMOTE_PATH=/opt/org-stack` → optional, for system-wide installation
3. **Deploy**
```bash
./deploy.sh
```
The deploy script will:
- Generate all required secrets automatically
- Create configuration files from templates
- Sync files to your remote server via rsync
- Start all Docker containers
4. **Access services**
- **lldap**: https://ldap.yourdomain.com (create users here first)
- **Authelia**: https://auth.yourdomain.com
- **Gitea**: https://git.yourdomain.com
- **Wiki**: https://wiki.yourdomain.com
- **Registration**: https://register.yourdomain.com (public user registration)
### First-Time Setup
After deployment, complete these steps:
1. **Create users in lldap**
- Access https://ldap.yourdomain.com
- Login with admin credentials (shown by deploy.sh)
- Create user accounts and assign to `lldap_admin` group for admin privileges
2. **Setup Gitea**
- Access https://git.yourdomain.com
- Complete the installation wizard (use defaults)
- Go to Site Admin → Authentication Sources → Add Authentication Source
- Type: `OAuth2`
- Authentication Name: `authelia` ⚠️ **IMPORTANT: Must be lowercase!**
- Provider: `OpenID Connect`
- Client ID: `gitea`
- Client Secret: (shown by deploy.sh)
- OpenID Connect Auto Discovery URL: `http://authelia:9091/.well-known/openid-configuration`
- Logout and test "Sign in with OpenID Connect"
3. **Test the wiki**
- Access https://wiki.yourdomain.com
- You'll be redirected to Authelia for login
- After authentication, you'll have admin access if you're in the `lldap_admin` group
4. **Enable user self-registration (optional)**
- Users can submit registration requests at https://register.yourdomain.com
- Admins review requests at https://register.yourdomain.com/admin (requires Authelia login)
- Admin dashboard shows:
- **Pending requests**: Approve or reject with optional reason
- **Audit log**: Historical record of all approval/rejection decisions
- When approved:
- User is automatically created in lldap with random password
- User receives email with credentials (if SMTP configured in .env)
- Request is moved to audit log
- **User management**: After approval, manage users directly in lldap (single source of truth)
## Architecture
```
┌─────────────────────────────────────────────────────────────────────┐
│ Internet / Users │
└──────────────────────────────┬──────────────────────────────────────┘
┌─────────▼──────────┐
│ Caddy (HTTPS) │ ← Automatic Let's Encrypt
│ Reverse Proxy │
└──────────┬─────────┘
┌───────────────────┼───────────────────┐
│ │ │
┌───────▼────────┐ ┌──────▼────────┐ ┌──────▼────────┐
│ Gitea (Git) │ │ JSPWiki (Wiki)│ │ lldap (Admin)│
│ via OIDC ────┼──┤ via Fwd-Auth ─┼──┤ via Fwd-Auth ─┼──┐
└────────────────┘ └───────────────┘ └───────────────┘ │
┌────────────────────────────────────┘
┌────────▼─────────┐
│ Authelia │ ← SSO/2FA/OIDC/Forward-Auth
│ (Auth Server) │
└────────┬─────────┘
┌────────▼─────────┐
│ lldap │ ← User Database (LDAP)
└──────────────────┘
```
### Authentication Flow
**OIDC Flow (Gitea)**:
1. User accesses Gitea → redirected to Authelia
2. Authelia validates credentials against lldap via LDAP
3. Authelia enforces 2FA (TOTP)
4. Authelia issues OIDC tokens
5. User redirected back to Gitea, logged in
**Forward-Auth Flow (Wiki, lldap)**:
1. User accesses Wiki → Caddy forwards auth request to Authelia
2. Authelia validates session (or prompts login + 2FA)
3. Authelia returns `Remote-User` header
4. Caddy forwards request to Wiki with authenticated user header
5. Wiki trusts the `Remote-User` header (container authentication)
For detailed architecture documentation, see [ARCHITECTURE.md](./ARCHITECTURE.md).
## Configuration
All configuration is managed through a single `.env` file. The deployment script generates service-specific configs from templates.
### Key Configuration Options
```bash
# Domain Configuration
BASE_DOMAIN=example.com # Your domain
GITEA_SUBDOMAIN=git # Creates git.example.com
WIKI_SUBDOMAIN=wiki # Creates wiki.example.com
AUTH_SUBDOMAIN=auth # Creates auth.example.com
LLDAP_SUBDOMAIN=ldap # Creates ldap.example.com
# TLS Mode
USE_SELF_SIGNED_CERTS=false # false=Let's Encrypt, true=self-signed
# Authentication
REQUIRE_2FA=true # Require TOTP for all services
# Advanced
SESSION_EXPIRATION=1h # How long sessions last
MAX_RETRIES=3 # Failed login attempts before ban
```
See `.env.example` for complete documentation of all options.
### SMTP Email Notifications
To enable email notifications for password resets, 2FA codes, and registration approvals:
1. Edit `.env` and configure SMTP settings:
```bash
SMTP_ENABLED=true
SMTP_HOST="smtp.gmail.com"
SMTP_PORT=587
SMTP_USER="your-email@gmail.com"
SMTP_PASSWORD='your-app-password' # Use quotes for special characters
SMTP_FROM="noreply@yourdomain.com"
```
2. Deploy changes:
```bash
./deploy.sh
```
See [SMTP_SETUP.md](SMTP_SETUP.md) for detailed configuration examples and troubleshooting.
## Management
The `manage.sh` script provides common operations:
```bash
# View logs
./manage.sh logs # All services
./manage.sh logs authelia # Specific service
# Restart services
./manage.sh restart
# Update to latest images
./manage.sh update
# Backup data volumes
./manage.sh backup
# Restore from backup
./manage.sh restore backup-YYYYMMDD-HHMMSS.tar.gz
# Complete reset (DESTRUCTIVE - deletes all data)
./manage.sh reset
# Check service status
./manage.sh status
```
## Security Features
### Secrets Management
All secrets are stored as individual files (not environment variables) following Docker security best practices:
- Mounted read-only to containers
- Not visible in `docker inspect` or process listings
- Individual file permissions (600)
- Never committed to git (secrets/ in .gitignore)
### Authentication Layers
1. **Centralized User Database**: Single source of truth in lldap
2. **SSO Authentication**: Authelia validates all login attempts
3. **Two-Factor Authentication**: TOTP enforcement for all services
4. **Session Management**: Configurable expiration and inactivity timeouts
5. **Rate Limiting**: Brute-force protection with automatic bans
### Network Security
**Hardened Configuration:**
- **Zero Direct Access**: No service ports exposed except through Caddy
- **Exposed Ports**: Only 80/443 (HTTP/HTTPS) and 2222 (Git SSH)
- **Internal Communication**: All services use Docker network hostnames
- **Authentication Required**: Every service requires Authelia login (except public registration form)
- **TLS Termination**: Caddy handles all HTTPS with automatic certificate management
- **Network Isolation**: Services isolated on internal Docker bridge network
**Port Summary:**
- `80/443` → Caddy (reverse proxy) → All web services
- `2222` → Gitea SSH (for Git operations only)
- All other services accessible ONLY via Caddy with Authelia authentication
## Protocols & Technologies
This project demonstrates integration of several authentication protocols:
### LDAP (Lightweight Directory Access Protocol)
- **Implementation**: lldap
- **RFC**: [RFC 4511](https://tools.ietf.org/html/rfc4511)
- **Used for**: Centralized user/group storage, credential verification
- **Resources**:
- [lldap GitHub](https://github.com/lldap/lldap)
- [LDAP Wikipedia](https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol)
### OIDC (OpenID Connect)
- **Implementation**: Authelia (provider), Gitea (client)
- **Spec**: [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html)
- **Used for**: Gitea SSO authentication
- **Resources**:
- [OpenID Connect Explained](https://connect2id.com/learn/openid-connect)
- [Authelia OIDC Docs](https://www.authelia.com/integration/openid-connect/introduction/)
### Forward-Auth
- **Implementation**: Authelia (endpoint), Caddy (proxy)
- **Used for**: Wiki and lldap authentication via trusted headers
- **How it works**: Proxy delegates authentication to external service before forwarding requests
- **Resources**:
- [Authelia Forward-Auth Docs](https://www.authelia.com/integration/proxies/fowarded-headers/)
- [Caddy forward_auth Directive](https://caddyserver.com/docs/caddyfile/directives/forward_auth)
### TOTP (Time-Based One-Time Password)
- **Implementation**: Authelia, compatible with Google Authenticator/Authy
- **RFC**: [RFC 6238](https://tools.ietf.org/html/rfc6238)
- **Used for**: Two-factor authentication
- **Resources**:
- [TOTP Wikipedia](https://en.wikipedia.org/wiki/Time-based_One-Time_Password)
- [Authelia 2FA Docs](https://www.authelia.com/overview/authentication/one-time-password/)
## Troubleshooting
### Check notifications (2FA codes, password resets)
```bash
ssh user@server 'cd ~/org-stack && docker compose exec authelia cat /data/notification.txt'
```
Or use the manage script:
```bash
./manage.sh logs authelia | grep -A 20 "one-time code"
```
### Gitea OIDC not working
**Error: "invalid_request" or "redirect_uri does not match"**
- **Cause**: Authentication source name is case-sensitive
- **Solution**: Name must be exactly `authelia` (lowercase) in Gitea admin panel
- **Why**: Gitea uses the name in redirect URI: `/user/oauth2/{name}/callback`
**Other common issues:**
1. Verify OIDC configuration uses internal URL:
- Auto Discovery URL: `http://authelia:9091/.well-known/openid-configuration` (NOT https://)
2. Check Authelia logs: `./manage.sh logs authelia`
3. Verify client secret matches what deploy.sh showed
### Services showing 502 errors
1. Check if all containers are running: `./manage.sh status`
2. Check Authelia logs: `./manage.sh logs authelia`
3. Verify secrets are mounted: `ssh user@server 'ls -la ~/org-stack/secrets/authelia'`
### 2FA not working
1. Verify `REQUIRE_2FA=true` in `.env`
2. Redeploy: `./deploy.sh`
3. Check Authelia configuration: `cat authelia/configuration.yml | grep policy`
### Let's Encrypt certificate failures
1. Verify DNS points to your server: `dig yourdomain.com`
2. Verify ports 80 and 443 are accessible externally
3. Check Caddy logs: `./manage.sh logs caddy`
4. If testing, use self-signed: `USE_SELF_SIGNED_CERTS=true` in `.env`
## Backup & Recovery
### Backup
```bash
./manage.sh backup
```
Creates timestamped tarball of all Docker volumes in `backups/` directory.
### Restore
```bash
./manage.sh restore backups/backup-YYYYMMDD-HHMMSS.tar.gz
```
### What's Backed Up
- lldap database (all users and groups)
- Authelia data (sessions, 2FA registrations)
- Gitea data (all repositories)
- JSPWiki data (all wiki pages)
- Caddy data (TLS certificates)
**Note**: The `secrets/` directory is NOT backed up by design. Back it up separately and securely.
## Development
### Testing Changes Locally
```bash
# Use self-signed certs to avoid Let's Encrypt rate limits
echo "USE_SELF_SIGNED_CERTS=true" >> .env
# For local testing without DNS, add to /etc/hosts:
echo "127.0.0.1 git.example.com wiki.example.com auth.example.com ldap.example.com" | sudo tee -a /etc/hosts
# Deploy
./deploy.sh
```
### Project Structure
```
org-stack/
├── .env.example # Configuration template
├── deploy.sh # Automated deployment script
├── manage.sh # Management utilities
├── compose.yml # Docker Compose service definitions
├── Caddyfile.*.template # Caddy templates (prod/test)
├── authelia/
│ └── configuration.yml.template # Authelia config template
├── jspwiki/
│ ├── Dockerfile # Custom JSPWiki image
│ ├── RemoteUserFilter.java # Servlet filter for SSO
│ ├── ldap-sync.sh # LDAP user synchronization
│ ├── configure-web-xml.sh # web.xml modification for container auth
│ └── entrypoint.sh # Container startup script
├── jspwiki-custom.properties # JSPWiki config (container auth)
├── jspwiki.policy # JSPWiki security policy
└── secrets/ # Auto-generated secrets (gitignored)
├── lldap/
│ ├── JWT_SECRET
│ └── LDAP_USER_PASS
└── authelia/
├── JWT_SECRET
├── SESSION_SECRET
├── STORAGE_ENCRYPTION_KEY
├── OIDC_HMAC_SECRET
└── OIDC_PRIVATE_KEY
```
## Production Recommendations
### Network Security
1. **Firewall Rules**:
```bash
# Allow only necessary ports
ufw allow 80/tcp # HTTP (redirects to HTTPS)
ufw allow 443/tcp # HTTPS
ufw allow 2222/tcp # Git SSH (optional, only if using Git SSH)
ufw allow 22/tcp # SSH for server management
ufw enable
```
2. **Port Verification**: Only 80, 443, and 2222 should be accessible externally
3. **DNS Configuration**: Ensure A records point to your server for all subdomains
### Operational Security
4. **Backups**: Schedule regular backups with `./manage.sh backup`
5. **Monitoring**: Set up monitoring for container health and authentication failures
6. **Updates**: Regularly update with `./manage.sh update`
7. **Secrets Rotation**: Periodically regenerate secrets and redeploy
8. **SMTP**: Configure real email notifier in `.env` (replace file-based logging)
### Performance
9. **Database**: Consider PostgreSQL instead of SQLite for Gitea in high-traffic scenarios
10. **Rate Limiting**: Configure Caddy rate limiting for public endpoints
## Contributing
Contributions welcome! Please:
1. Fork the repository
2. Create a feature branch
3. Submit a pull request with clear description
## License
MIT License - see LICENSE file for details
## Acknowledgments
- **lldap**: Nitnelave and contributors
- **Authelia**: Authelia team
- **Gitea**: Gitea maintainers
- **JSPWiki**: Apache JSPWiki project
- **Caddy**: Caddy team
This project demonstrates integration of these excellent open-source tools into a cohesive authentication platform.
## Support
- **Issues**: [GitHub Issues](https://github.com/yourorg/org-stack/issues)
- **Discussions**: [GitHub Discussions](https://github.com/yourorg/org-stack/discussions)
- **Authelia Support**: [Authelia Discord](https://discord.authelia.com)
- **lldap Support**: [lldap Discussions](https://github.com/lldap/lldap/discussions)