- ovpmon-helper: new publish-crl command (validated copy of pki/crl.pem to /etc/openvpn/crl.pem, root:root 644); crl-verify allowlisted only for that path; CRL is refreshed on service start/restart. - Profiler: publish after gen-crl (init/revoke) and on server/configure; generator renders the published path when running unprivileged. - doas rule for publish-crl; docs and helper copy updated. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
53 lines
2.4 KiB
Python
53 lines
2.4 KiB
Python
import os
|
|
import logging
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.orm import Session
|
|
from database import get_db
|
|
from utils.auth import verify_token
|
|
from services import generator, process, config
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(dependencies=[Depends(verify_token)])
|
|
|
|
@router.post("/server/configure")
|
|
def configure_server(db: Session = Depends(get_db)):
|
|
try:
|
|
# Generate to a temporary location or standard location
|
|
# As per plan, we behave like srvconf
|
|
output_path = "/etc/openvpn/server.conf"
|
|
|
|
# Unprivileged service: render to the staging dir, the root helper validates and installs it
|
|
if not process.is_container() and os.geteuid() != 0:
|
|
staged = os.path.join(os.getenv("OVPMON_STAGING_DIR", "/var/lib/ovpmon/staging"), "server.conf")
|
|
os.makedirs(os.path.dirname(staged), exist_ok=True)
|
|
generator.generate_server_config(db, output_path=staged)
|
|
ok, msg = process.install_config()
|
|
if not ok:
|
|
raise HTTPException(status_code=400, detail=f"Configuration rejected: {msg}")
|
|
ok, msg = process.publish_crl()
|
|
if not ok:
|
|
if config.get_system_settings(db).crl_verify:
|
|
raise HTTPException(status_code=500, detail=f"Configuration installed, but CRL publishing failed: {msg}")
|
|
logger.warning(f"[SERVER] CRL not published (crl_verify is off): {msg}")
|
|
return {"message": "Server configuration generated", "path": output_path}
|
|
|
|
# Ensure we can write to /etc/openvpn
|
|
if not os.path.exists(os.path.dirname(output_path)) or not os.access(os.path.dirname(output_path), os.W_OK):
|
|
# For local dev or non-root host, use staging
|
|
output_path = "staging/server.conf"
|
|
os.makedirs("staging", exist_ok=True)
|
|
logger.info(f"[SERVER] /etc/openvpn not writable, using staging path: {output_path}")
|
|
else:
|
|
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
|
|
|
|
content = generator.generate_server_config(db, output_path=output_path)
|
|
return {"message": "Server configuration generated", "path": output_path}
|
|
except HTTPException:
|
|
raise
|
|
except ValueError as e:
|
|
raise HTTPException(status_code=400, detail=str(e))
|
|
except Exception as e:
|
|
raise HTTPException(status_code=500, detail=str(e))
|