-
Notifications
You must be signed in to change notification settings - Fork 0
Configuration Errors
- Introduction
- Environment Variable Configuration
- Secret Key Management
- RP Entity Configuration
- TLS Certificate Issues
- MDS Metadata Configuration
- Cloud Deployment Configuration
- Debugging Configuration Loading
- Common Misconfigurations
- Troubleshooting Guide
The Post-Quantum WebAuthn Platform relies on a sophisticated configuration system that manages environment variables, secret keys, RP entity settings, and TLS certificates. Configuration errors can prevent the platform from starting correctly or compromise security. This document covers common configuration issues, their symptoms, and resolution strategies.
The platform uses several critical environment variables for operation:
| Variable | Purpose | Default Value | Validation Required |
|---|---|---|---|
FIDO_SERVER_SECRET_KEY |
Flask session secret | Generated randomly | Must be securely stored |
FIDO_SERVER_SECRET_KEY_FILE |
Path to secret key file | None | File must be readable |
FIDO_SERVER_RP_ID |
Relying Party Identifier | Request host | Must be valid domain |
FIDO_SERVER_RP_NAME |
Relying Party Name | "Demo server" | Human-readable name |
FIDO_SERVER_SESSION_METADATA_RECOVER |
Session recovery flag | None | Boolean values |
The configuration system follows a specific priority order for resolving environment variables:
flowchart TD
A["Environment Variable Check"] --> B{"Variable Set?"}
B --> |Yes| C["Use Environment Value"]
B --> |No| D["Check Alternative Path"]
D --> E{"Alternative Path Set?"}
E --> |Yes| F["Attempt File Read"]
E --> |No| G["Use Default Value"]
F --> H{"File Read Successful?"}
H --> |Yes| I["Use File Content"]
H --> |No| J["Log Warning & Continue"]
C --> K["Configuration Complete"]
I --> K
G --> K
J --> K
Diagram sources
- server/server/config.py
Section sources
- server/server/config.py
The platform implements a robust secret key management system that handles multiple storage mechanisms:
- Environment Variable: Direct string value
- File-based Storage: Secure file containing key bytes
- Automatic Generation: Random 32-byte key generation
- Persistent Storage: Automatic key persistence to disk
sequenceDiagram
participant App as Application
participant Config as Config Module
participant Env as Environment
participant FS as File System
participant Gen as Key Generator
App->>Config : _resolve_secret_key()
Config->>Env : os.environ.get("FIDO_SERVER_SECRET_KEY")
Env-->>Config : secret_key_value
alt secret_key_value exists
Config->>Config : Encode UTF-8
else secret_key_value missing
Config->>Env : os.environ.get("FIDO_SERVER_SECRET_KEY_FILE")
Env-->>Config : file_path
alt file_path exists
Config->>FS : Open file_path
FS-->>Config : file_content
alt file_content valid
Config->>Config : Use file_content
else file_content invalid
Config->>Config : Log warning & continue
end
else file_path missing
Config->>Gen : os.urandom(32)
Gen-->>Config : random_bytes
Config->>FS : Store to default_path
FS-->>Config : Success/Failure
end
end
Config-->>App : Final secret key bytes
Diagram sources
- server/server/config.py
Symptoms: Flask session errors, CSRF validation failures
Cause: No secret key configured in any storage mechanism
Solution: Set FIDO_SERVER_SECRET_KEY or FIDO_SERVER_SECRET_KEY_FILE
Symptoms: "Unable to read secret key file" warnings in logs Cause: Insufficient file permissions or non-existent file Solution: Verify file existence and permissions
Symptoms: Application fails to start with key-related errors Cause: Truncated or corrupted key files Solution: Delete corrupted files and let system regenerate
Section sources
- server/server/config.py
The platform implements intelligent RP ID resolution with multiple fallback mechanisms:
flowchart TD
A["determine_rp_id()"] --> B{"Explicit ID Provided?"}
B --> |Yes| C["Return Explicit ID"]
B --> |No| D{"Configured RP_ID?"}
D --> |Yes| E["Return Configured ID"]
D --> |No| F{"Request Context Available?"}
F --> |Yes| G["Extract Host from Request"]
F --> |No| H["Return 'localhost'"]
G --> I{"Host is Localhost?"}
I --> |Yes| J["Return 'localhost'"]
I --> |No| K["Return Host"]
C --> L["Build RP Entity"]
E --> L
J --> L
K --> L
H --> L
Diagram sources
- server/server/config.py
| Issue | Symptom | Cause | Solution |
|---|---|---|---|
| Invalid RP ID | Authentication failures | Malformed domain name | Use valid domain format |
| Missing RP Name | Default "Demo server" | Unset FIDO_SERVER_RP_NAME
|
Set appropriate name |
| Host Resolution Failure | RP ID defaults to localhost | No request context | Ensure proper host header |
| Case Sensitivity | RP ID mismatches | Different hostname casing | Normalize to lowercase |
The build_rp_entity() function creates the relying party entity with proper validation:
classDiagram
class PublicKeyCredentialRpEntity {
+string name
+string id
+validate_rp_id() bool
+normalize_host() string
}
class ConfigModule {
+build_rp_entity() PublicKeyCredentialRpEntity
+determine_rp_id() string
+create_fido_server() Fido2Server
}
class FlaskRequest {
+string host
+has_request_context() bool
}
ConfigModule --> PublicKeyCredentialRpEntity : creates
ConfigModule --> FlaskRequest : uses
PublicKeyCredentialRpEntity --> ConfigModule : validated by
Diagram sources
- server/server/config.py
Section sources
- server/server/config.py
The platform supports multiple methods for configuring trusted certificate authorities:
flowchart TD
A["Parse Trusted CA Subjects"] --> B["Split by Delimiters"]
B --> C["Normalize Components"]
C --> D{"Empty Components?"}
D --> |Yes| E["Remove Empty"]
D --> |No| F["Validate Subjects"]
E --> F
F --> G{"Valid Subjects?"}
G --> |Yes| H["Store in Config"]
G --> |No| I["Return None"]
H --> J["Trusted CA Subjects Ready"]
I --> J
Diagram sources
- server/server/config.py
The platform supports SHA-256 fingerprint validation for certificate trust:
| Requirement | Value | Purpose |
|---|---|---|
| Minimum Length | 40 hexadecimal characters | Prevent trivial matches |
| Format | Uppercase hex | Consistent comparison |
| Validation | SHA-256 hash | Cryptographic verification |
The platform includes built-in trust anchors for metadata downloads:
graph TB
subgraph "Built-in Trust Anchors"
A["ISRG Root X1<br/>SHA-256: 29:19:FF:..."]
B["DigiCert Global Root G2<br/>SHA-256: 40:3D:..."]
C["Baltimore CyberTrust Root<br/>SHA-256: 7D:28:..."]
end
subgraph "Additional Trust Anchors"
D["Custom CA Certificates"]
E["Environment-Specific CAs"]
end
A --> F["TLS Verification Chain"]
B --> F
C --> F
D --> F
E --> F
Diagram sources
- server/server/config.py
Symptoms: Metadata download timeouts, SSL certificate errors Cause: Outdated or missing trust anchors Solution: Update trust anchor configuration or network connectivity
Symptoms: Certificate verification failures Cause: Incorrect CA certificate format or expired certificates Solution: Verify certificate format and expiration dates
Section sources
- server/server/config.py
The platform uses the FIDO Alliance Metadata Service (MDS) for authenticator information:
| Constant | Value | Purpose |
|---|---|---|
MDS_METADATA_URL |
https://mds3.fidoalliance.org/ |
Primary MDS endpoint |
MDS_METADATA_FILENAME |
blob.jwt |
Metadata blob filename |
MDS_METADATA_PATH |
static/blob.jwt |
Local metadata path |
MDS_METADATA_VERIFIED_PATH |
static/fido-mds3.verified.json |
Verified metadata path |
sequenceDiagram
participant App as Application
participant Startup as Startup Module
participant Metadata as Metadata Module
participant Network as Network Layer
participant Cache as Cache System
App->>Startup : warm_up_dependencies()
Startup->>Metadata : ensure_metadata_bootstrapped()
Metadata->>Network : download_metadata_blob()
Network-->>Metadata : JWT blob or cached data
alt New metadata available
Metadata->>Metadata : Verify signature
Metadata->>Cache : Store verified metadata
Cache-->>Metadata : Success
else Cached metadata valid
Metadata->>Metadata : Load from cache
end
Metadata-->>Startup : Metadata ready
Startup-->>App : Dependencies warmed
Diagram sources
- server/server/startup.py
- server/server/metadata.py
The platform implements cryptographic verification of metadata sources:
flowchart TD
A["Metadata Download"] --> B["Verify Signature"]
B --> C{"Signature Valid?"}
C --> |Yes| D["Mark as Trusted"]
C --> |No| E["Mark as Untrusted"]
D --> F["Store in Base Metadata"]
E --> G["Use Fallback"]
F --> H["Ready for Use"]
G --> H
Diagram sources
- server/server/metadata.py
Section sources
- server/server/config.py
- server/server/metadata.py
The Render deployment configuration defines basic service settings:
| Setting | Value | Purpose |
|---|---|---|
| Type | web |
Web service type |
| Runtime | docker |
Containerized deployment |
| Plan | free |
Free tier deployment |
| Auto Deploy | true |
Automatic deployments |
| Dockerfile | ./Dockerfile |
Container definition |
The Cloud Build pipeline automates deployment to Google Cloud Run:
| Parameter | Value | Impact |
|---|---|---|
| CPU | 0.5 |
Resource allocation |
| Memory | 512Mi |
Memory allocation |
| Port | 8080 |
Container port |
| Min Instances | 0 |
Auto-scaling minimum |
| Max Instances | 3 |
Auto-scaling maximum |
The Docker container exposes several environment variables:
| Variable | Purpose | Default |
|---|---|---|
PORT |
Container port | 8000 |
LD_LIBRARY_PATH |
Library paths | /opt/liboqs/lib:/usr/local/lib |
PYTHONPATH |
Python module path | /app |
Section sources
- render.yaml
- cloudbuild.yaml
- Dockerfile
The platform implements comprehensive logging for configuration debugging:
graph TB
subgraph "Logging Sources"
A["config.py - Secret Key Operations"]
B["startup.py - Dependency Checks"]
C["metadata.py - Metadata Downloads"]
D["app.py - Application Startup"]
end
subgraph "Log Levels"
E["INFO - Startup Messages"]
F["WARNING - Configuration Warnings"]
G["DEBUG - Detailed Operations"]
H["ERROR - Critical Failures"]
end
A --> F
B --> E
C --> G
D --> E
Diagram sources
- server/server/config.py
- server/server/startup.py
To debug environment variable issues, use these commands:
# Check all FIDO_SERVER variables
env | grep FIDO_SERVER
# Verify secret key file permissions
ls -la $FIDO_SERVER_SECRET_KEY_FILE
# Test RP ID resolution
python -c "from server.server.config import determine_rp_id; print(determine_rp_id())"# Configuration validation script
from server.server.config import app, determine_rp_id, build_rp_entity
print("=== Configuration Validation ===")
print(f"Secret Key: {'Set' if app.secret_key else 'Not Set'}")
print(f"RP ID: {app.config.get('FIDO_SERVER_RP_ID')}")
print(f"RP Name: {app.config.get('FIDO_SERVER_RP_NAME')}")
print(f"Session Recovery: {app.config.get('SESSION_METADATA_RECOVER_ON_START')}")
# Test RP entity creation
try:
rp = build_rp_entity()
print(f"RP Entity: {rp.id} - {rp.name}")
except Exception as e:
print(f"RP Entity Error: {e}")
# Test RP ID resolution
try:
rp_id = determine_rp_id()
print(f"Resolved RP ID: {rp_id}")
except Exception as e:
print(f"RP ID Resolution Error: {e}")Section sources
- server/server/config.py
- server/server/startup.py
Problem: RP ID contains invalid characters or malformed domains
Example: http://example.com instead of example.com
Solution: Remove protocol prefixes and ensure valid domain format
Problem: Secret key contains special characters or improper encoding Example: Non-UTF-8 characters in secret key Solution: Use base64-encoded secrets or ensure proper UTF-8 encoding
Problem: Custom CA certificates not properly configured Example: Incorrect subject DN format Solution: Use proper RFC 2253 DN format for subjects
Problem: Incorrect service type or runtime specification
Example: Using python runtime instead of docker
Solution: Verify Render platform requirements
Problem: Incorrect image tagging or deployment parameters Example: Using wrong project ID or region Solution: Validate Cloud Build configuration against project settings
Problem: Missing essential environment variables in container Example: PORT not set or LD_LIBRARY_PATH incorrect Solution: Review Dockerfile environment variable declarations
Problem: RP ID resolves to localhost in production Example: Missing Host header or proxy configuration Solution: Configure proper reverse proxy or set explicit RP_ID
Problem: Session data lost on restart Example: Missing SESSION_METADATA_RECOVER flag Solution: Set appropriate recovery flag for deployment environment
Section sources
- server/server/config.py
- render.yaml
- cloudbuild.yaml
-
Environment Variables
-
FIDO_SERVER_SECRET_KEYorFIDO_SERVER_SECRET_KEY_FILEset -
FIDO_SERVER_RP_IDproperly configured -
FIDO_SERVER_RP_NAMEset appropriately
-
-
File Permissions
- Secret key file readable by application user
- Metadata directories writable
- Log directories accessible
-
Network Connectivity
- MDS metadata endpoint reachable
- Custom CA certificates accessible
- Reverse proxy configured correctly
-
Application Logs
# Check application startup logs docker logs <container_id> # Monitor real-time logs docker logs -f <container_id>
-
Configuration Validation
# Test configuration loading python -c "from server.server.config import app; print(app.config)" # Verify secret key generation python -c "from server.server.config import _resolve_secret_key; print(len(_resolve_secret_key()))"
-
RP Entity Testing
# Test RP ID resolution curl -H "Host: example.com" http://localhost:5000/_health # Verify RP entity construction python -c "from server.server.config import build_rp_entity; rp = build_rp_entity(); print(rp.id, rp.name)"
Error Pattern: "Unable to read secret key file" warnings Diagnosis: Check file existence, permissions, and encoding Resolution: Fix file permissions or regenerate secret key
Error Pattern: RP ID resolves to localhost unexpectedly Diagnosis: Verify request context and host header Resolution: Configure reverse proxy or set explicit RP_ID
Error Pattern: MDS metadata download timeouts Diagnosis: Check network connectivity and firewall rules Resolution: Update trust anchors or configure proxy settings
The platform implements several caching mechanisms:
- Metadata Cache: Local storage of verified metadata
- Session Metadata: Persistent session state
- Secret Key Cache: Temporary storage of generated keys
# Configuration health check script
import logging
from server.server.config import app, determine_rp_id, build_rp_entity
def check_configuration_health():
"""Perform comprehensive configuration health check."""
logger = logging.getLogger(__name__)
# Check secret key
if not app.secret_key:
logger.error("Secret key not configured")
return False
# Check RP configuration
try:
rp_id = determine_rp_id()
if rp_id == "localhost":
logger.warning("RP ID resolves to localhost")
except Exception as e:
logger.error(f"RP ID resolution failed: {e}")
return False
# Check metadata availability
try:
from server.server.metadata import ensure_metadata_bootstrapped
ensure_metadata_bootstrapped()
except Exception as e:
logger.error(f"Metadata bootstrap failed: {e}")
return False
logger.info("Configuration health check passed")
return True
if __name__ == "__main__":
check_configuration_health()Section sources
- server/server/startup.py
- server/server/config.py