Auth configuration in docker
This commit is contained in:
@@ -24,3 +24,8 @@ _ReSharper*/
|
|||||||
DataBackup/
|
DataBackup/
|
||||||
*.db
|
*.db
|
||||||
/.claude/*
|
/.claude/*
|
||||||
|
|
||||||
|
# Production secrets and configuration
|
||||||
|
auth-secrets.json
|
||||||
|
docker-compose.yml
|
||||||
|
docker-compose.override.yml
|
||||||
|
|||||||
+279
@@ -0,0 +1,279 @@
|
|||||||
|
# Docker Deployment Guide
|
||||||
|
|
||||||
|
## Authentication Configuration for Production
|
||||||
|
|
||||||
|
The application supports two methods for configuring authentication credentials in Docker:
|
||||||
|
|
||||||
|
### Option 1: Volume-Mounted JSON File (Recommended)
|
||||||
|
|
||||||
|
This approach allows you to edit credentials without rebuilding the container.
|
||||||
|
|
||||||
|
**Steps:**
|
||||||
|
|
||||||
|
1. **Generate Password Hashes** (on your development machine):
|
||||||
|
```bash
|
||||||
|
# Run the app locally and navigate to:
|
||||||
|
https://localhost:<port>/dev/hash-password?password=YourPassword
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Create `auth-secrets.json`** on your Docker host:
|
||||||
|
```bash
|
||||||
|
cp auth-secrets.example.json auth-secrets.json
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Edit `auth-secrets.json`** and replace the placeholder hashes:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Authentication": {
|
||||||
|
"Users": [
|
||||||
|
{
|
||||||
|
"Email": "admin@example.com",
|
||||||
|
"PasswordHash": "$2a$11$actual.hash.here",
|
||||||
|
"Role": "Administrator",
|
||||||
|
"DisplayName": "Administrator"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Mount the file in Docker Compose**:
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- ./auth-secrets.json:/app/secrets/auth-secrets.json:ro
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Update credentials**: Simply edit `auth-secrets.json` on the host and restart the container:
|
||||||
|
```bash
|
||||||
|
docker-compose restart webapp
|
||||||
|
```
|
||||||
|
|
||||||
|
**Security Note**: Set proper file permissions on the host:
|
||||||
|
```bash
|
||||||
|
chmod 600 auth-secrets.json
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Option 2: Environment Variables
|
||||||
|
|
||||||
|
This approach is useful for container orchestration platforms (Kubernetes, Docker Swarm, etc.).
|
||||||
|
|
||||||
|
**Docker Compose Example**:
|
||||||
|
```yaml
|
||||||
|
environment:
|
||||||
|
- TSA_Authentication__Users__0__Email=admin@example.com
|
||||||
|
- TSA_Authentication__Users__0__PasswordHash=$2a$11$hash...
|
||||||
|
- TSA_Authentication__Users__0__Role=Administrator
|
||||||
|
- TSA_Authentication__Users__0__DisplayName=Administrator
|
||||||
|
- TSA_Authentication__Users__1__Email=advisor@example.com
|
||||||
|
- TSA_Authentication__Users__1__PasswordHash=$2a$11$hash...
|
||||||
|
- TSA_Authentication__Users__1__Role=Advisor
|
||||||
|
- TSA_Authentication__Users__1__DisplayName=Chapter Advisor
|
||||||
|
```
|
||||||
|
|
||||||
|
**Docker Run Example**:
|
||||||
|
```bash
|
||||||
|
docker run -d \
|
||||||
|
-p 8080:8080 \
|
||||||
|
-e ASPNETCORE_ENVIRONMENT=Production \
|
||||||
|
-e TSA_Authentication__Users__0__Email=admin@example.com \
|
||||||
|
-e TSA_Authentication__Users__0__PasswordHash='$2a$11$hash...' \
|
||||||
|
-e TSA_Authentication__Users__0__Role=Administrator \
|
||||||
|
-e TSA_Authentication__Users__0__DisplayName=Administrator \
|
||||||
|
tsa-chapter-organizer:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
**Kubernetes Secret Example**:
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: tsa-auth-secrets
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
TSA_Authentication__Users__0__Email: "admin@example.com"
|
||||||
|
TSA_Authentication__Users__0__PasswordHash: "$2a$11$hash..."
|
||||||
|
TSA_Authentication__Users__0__Role: "Administrator"
|
||||||
|
TSA_Authentication__Users__0__DisplayName: "Administrator"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Building and Running
|
||||||
|
|
||||||
|
### Build the Docker Image
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd WebApp
|
||||||
|
docker build -t tsa-chapter-organizer:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run with Docker Compose
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Copy and customize the example
|
||||||
|
cp docker-compose.example.yml docker-compose.yml
|
||||||
|
|
||||||
|
# Edit auth-secrets.json with your credentials
|
||||||
|
cp auth-secrets.example.json auth-secrets.json
|
||||||
|
# (Edit the file and replace hashes)
|
||||||
|
|
||||||
|
# Start the container
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# View logs
|
||||||
|
docker-compose logs -f webapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Access the Application
|
||||||
|
|
||||||
|
- HTTP: `http://localhost:8080`
|
||||||
|
- HTTPS: `https://localhost:8081` (if configured)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Managing Users
|
||||||
|
|
||||||
|
### Adding a New User
|
||||||
|
|
||||||
|
**With Volume-Mounted File:**
|
||||||
|
1. Edit `auth-secrets.json` on the host
|
||||||
|
2. Add new user entry to the `Users` array
|
||||||
|
3. Restart the container: `docker-compose restart webapp`
|
||||||
|
|
||||||
|
**With Environment Variables:**
|
||||||
|
1. Add new environment variables (increment the index number)
|
||||||
|
2. Recreate the container: `docker-compose up -d`
|
||||||
|
|
||||||
|
### Changing a Password
|
||||||
|
|
||||||
|
1. Generate new hash using the dev endpoint (on local dev machine)
|
||||||
|
2. Update the `PasswordHash` value in your configuration
|
||||||
|
3. Restart/recreate the container
|
||||||
|
|
||||||
|
### Removing a User
|
||||||
|
|
||||||
|
1. Remove the user entry from your configuration
|
||||||
|
2. Restart/recreate the container
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
1. **File Permissions**:
|
||||||
|
```bash
|
||||||
|
chmod 600 auth-secrets.json
|
||||||
|
chown root:root auth-secrets.json
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Never Commit Secrets**: Add to `.gitignore`:
|
||||||
|
```
|
||||||
|
auth-secrets.json
|
||||||
|
docker-compose.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Use HTTPS in Production**: Configure SSL/TLS certificates
|
||||||
|
|
||||||
|
4. **Backup Credentials**: Store encrypted backups of `auth-secrets.json`
|
||||||
|
|
||||||
|
5. **Password Rotation**: Periodically regenerate password hashes
|
||||||
|
|
||||||
|
6. **Monitor Access**: Review application logs for failed login attempts:
|
||||||
|
```bash
|
||||||
|
docker-compose logs webapp | grep "Failed login"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container Won't Start
|
||||||
|
|
||||||
|
Check logs:
|
||||||
|
```bash
|
||||||
|
docker-compose logs webapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### Can't Login
|
||||||
|
|
||||||
|
1. Verify `auth-secrets.json` is properly mounted:
|
||||||
|
```bash
|
||||||
|
docker exec tsa-app ls -la /app/secrets/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Check if the file is being loaded:
|
||||||
|
```bash
|
||||||
|
docker-compose logs webapp | grep "secrets"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Verify JSON syntax:
|
||||||
|
```bash
|
||||||
|
cat auth-secrets.json | jq .
|
||||||
|
```
|
||||||
|
|
||||||
|
### Forgot Admin Password
|
||||||
|
|
||||||
|
1. Generate a new password hash locally
|
||||||
|
2. Update `auth-secrets.json` on the host
|
||||||
|
3. Restart the container
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Example: Complete Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. Generate password hashes locally
|
||||||
|
# Navigate to: https://localhost:5001/dev/hash-password?password=MySecurePass123
|
||||||
|
|
||||||
|
# 2. Create secrets file
|
||||||
|
cat > auth-secrets.json <<EOF
|
||||||
|
{
|
||||||
|
"Authentication": {
|
||||||
|
"Users": [
|
||||||
|
{
|
||||||
|
"Email": "admin@myschool.edu",
|
||||||
|
"PasswordHash": "$2a$11$paste_hash_here",
|
||||||
|
"Role": "Administrator",
|
||||||
|
"DisplayName": "TSA Admin"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# 3. Set permissions
|
||||||
|
chmod 600 auth-secrets.json
|
||||||
|
|
||||||
|
# 4. Create docker-compose.yml
|
||||||
|
cp docker-compose.example.yml docker-compose.yml
|
||||||
|
|
||||||
|
# 5. Start the application
|
||||||
|
docker-compose up -d
|
||||||
|
|
||||||
|
# 6. Check it's running
|
||||||
|
docker-compose ps
|
||||||
|
curl http://localhost:8080
|
||||||
|
|
||||||
|
# 7. Login
|
||||||
|
# Navigate to http://localhost:8080/login
|
||||||
|
# Use: admin@myschool.edu / MySecurePass123
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Production Deployment Checklist
|
||||||
|
|
||||||
|
- [ ] Generated secure password hashes
|
||||||
|
- [ ] Created `auth-secrets.json` with production credentials
|
||||||
|
- [ ] Set file permissions to 600
|
||||||
|
- [ ] Configured HTTPS/SSL certificates
|
||||||
|
- [ ] Updated `ASPNETCORE_URLS` for production domain
|
||||||
|
- [ ] Configured volume for database persistence
|
||||||
|
- [ ] Removed development endpoints (already done in code)
|
||||||
|
- [ ] Set up log monitoring
|
||||||
|
- [ ] Configured automatic backups
|
||||||
|
- [ ] Tested login with all user roles
|
||||||
|
- [ ] Tested rate limiting (5 failed attempts)
|
||||||
|
- [ ] Documented admin password securely
|
||||||
|
- [ ] Added `auth-secrets.json` to `.gitignore`
|
||||||
@@ -7,6 +7,20 @@ using WebApp.Components;
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Configure authentication secrets for production (Docker, etc.)
|
||||||
|
if (builder.Environment.IsProduction())
|
||||||
|
{
|
||||||
|
// Option 1: Load from volume-mounted secrets file
|
||||||
|
var secretsPath = "/app/secrets/auth-secrets.json";
|
||||||
|
if (File.Exists(secretsPath))
|
||||||
|
{
|
||||||
|
builder.Configuration.AddJsonFile(secretsPath, optional: false, reloadOnChange: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Option 2: Environment variables with prefix
|
||||||
|
builder.Configuration.AddEnvironmentVariables(prefix: "TSA_");
|
||||||
|
}
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddControllersWithViews();
|
builder.Services.AddControllersWithViews();
|
||||||
builder.Services.AddRazorComponents()
|
builder.Services.AddRazorComponents()
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"Authentication": {
|
||||||
|
"Users": [
|
||||||
|
{
|
||||||
|
"Email": "admin@example.com",
|
||||||
|
"PasswordHash": "$2a$11$REPLACE_WITH_ACTUAL_HASH",
|
||||||
|
"Role": "Administrator",
|
||||||
|
"DisplayName": "Administrator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Email": "advisor@example.com",
|
||||||
|
"PasswordHash": "$2a$11$REPLACE_WITH_ACTUAL_HASH",
|
||||||
|
"Role": "Advisor",
|
||||||
|
"DisplayName": "Chapter Advisor"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
webapp:
|
||||||
|
image: tsa-chapter-organizer:latest
|
||||||
|
container_name: tsa-app
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
- "8081:8081"
|
||||||
|
environment:
|
||||||
|
- ASPNETCORE_ENVIRONMENT=Production
|
||||||
|
- ASPNETCORE_URLS=https://+:8081;http://+:8080
|
||||||
|
- ASPNETCORE_HTTPS_PORT=8081
|
||||||
|
|
||||||
|
# Option 2: Environment Variables approach (uncomment to use)
|
||||||
|
# - TSA_Authentication__Users__0__Email=admin@example.com
|
||||||
|
# - TSA_Authentication__Users__0__PasswordHash=$2a$11$...
|
||||||
|
# - TSA_Authentication__Users__0__Role=Administrator
|
||||||
|
# - TSA_Authentication__Users__0__DisplayName=Administrator
|
||||||
|
# - TSA_Authentication__Users__1__Email=advisor@example.com
|
||||||
|
# - TSA_Authentication__Users__1__PasswordHash=$2a$11$...
|
||||||
|
# - TSA_Authentication__Users__1__Role=Advisor
|
||||||
|
# - TSA_Authentication__Users__1__DisplayName=Chapter Advisor
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
# Option 1: Volume-mounted secrets file (recommended for easy editing)
|
||||||
|
- ./auth-secrets.json:/app/secrets/auth-secrets.json:ro
|
||||||
|
|
||||||
|
# Database persistence
|
||||||
|
- ./data:/app/data
|
||||||
|
|
||||||
|
# HTTPS certificate (if needed)
|
||||||
|
# - ./certs:/https:ro
|
||||||
|
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# Uncomment if using HTTPS with certificate
|
||||||
|
# environment:
|
||||||
|
# - ASPNETCORE_Kestrel__Certificates__Default__Password=your-cert-password
|
||||||
|
# - ASPNETCORE_Kestrel__Certificates__Default__Path=/https/aspnetapp.pfx
|
||||||
Reference in New Issue
Block a user