mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-12-15 00:35:47 -07:00
ENGINE: Fixed Certificates Rotating at every Reboot
This commit is contained in:
35
Borealis.ps1
35
Borealis.ps1
@@ -189,26 +189,43 @@ function Ensure-EngineTlsMaterial {
|
|||||||
[string]$CertificateRoot
|
[string]$CertificateRoot
|
||||||
)
|
)
|
||||||
|
|
||||||
if (-not (Test-Path $CertificateRoot)) {
|
$effectiveRoot = $null
|
||||||
New-Item -Path $CertificateRoot -ItemType Directory -Force | Out-Null
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Test-Path $PythonPath) {
|
if (Test-Path $PythonPath) {
|
||||||
$code = @'
|
$code = @'
|
||||||
from Data.Engine.services.crypto import certificates
|
from Data.Engine.security import certificates
|
||||||
certificates.ensure_certificate()
|
certificates.ensure_certificate()
|
||||||
|
print(certificates.engine_certificates_root())
|
||||||
'@
|
'@
|
||||||
try {
|
try {
|
||||||
& $PythonPath -c $code | Out-Null
|
$output = & $PythonPath -c $code
|
||||||
|
if ($output) {
|
||||||
|
$raw = $output | Select-Object -Last 1
|
||||||
|
if ($raw) {
|
||||||
|
$effectiveRoot = ([string]$raw).Trim()
|
||||||
|
}
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
Write-Host "Failed to pre-generate Engine TLS certificates: $($_.Exception.Message)" -ForegroundColor Yellow
|
Write-Host "Failed to pre-generate Engine TLS certificates: $($_.Exception.Message)" -ForegroundColor Yellow
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$env:BOREALIS_CERT_DIR = $CertificateRoot
|
if (-not $effectiveRoot -and $CertificateRoot) {
|
||||||
$env:BOREALIS_TLS_CERT = Join-Path $CertificateRoot 'borealis-server-cert.pem'
|
$effectiveRoot = $CertificateRoot
|
||||||
$env:BOREALIS_TLS_KEY = Join-Path $CertificateRoot 'borealis-server-key.pem'
|
}
|
||||||
$env:BOREALIS_TLS_BUNDLE = Join-Path $CertificateRoot 'borealis-server-bundle.pem'
|
|
||||||
|
if (-not $effectiveRoot) {
|
||||||
|
$effectiveRoot = Join-Path $scriptDir 'Engine\Certificates'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $effectiveRoot)) {
|
||||||
|
New-Item -Path $effectiveRoot -ItemType Directory -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
$env:BOREALIS_CERT_DIR = $effectiveRoot
|
||||||
|
$env:BOREALIS_TLS_CERT = Join-Path $effectiveRoot 'borealis-server-cert.pem'
|
||||||
|
$env:BOREALIS_TLS_KEY = Join-Path $effectiveRoot 'borealis-server-key.pem'
|
||||||
|
$env:BOREALIS_TLS_BUNDLE = Join-Path $effectiveRoot 'borealis-server-bundle.pem'
|
||||||
}
|
}
|
||||||
|
|
||||||
function Ensure-EngineWebInterface {
|
function Ensure-EngineWebInterface {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ from cryptography.hazmat.primitives.asymmetric import ed25519
|
|||||||
from ..security.certificates import project_root_path
|
from ..security.certificates import project_root_path
|
||||||
|
|
||||||
_TOKEN_ENV_ROOT = "BOREALIS_ENGINE_AUTH_TOKEN_ROOT"
|
_TOKEN_ENV_ROOT = "BOREALIS_ENGINE_AUTH_TOKEN_ROOT"
|
||||||
_LEGACY_SERVER_ROOT_ENV = "BOREALIS_SERVER_ROOT"
|
|
||||||
_KEY_FILENAME = "borealis-jwt-ed25519.key"
|
_KEY_FILENAME = "borealis-jwt-ed25519.key"
|
||||||
|
|
||||||
|
|
||||||
@@ -59,16 +58,6 @@ def _token_root() -> Path:
|
|||||||
return root
|
return root
|
||||||
|
|
||||||
|
|
||||||
def _legacy_key_paths() -> Dict[str, Path]:
|
|
||||||
project_root = project_root_path()
|
|
||||||
server_root = _env_path(_LEGACY_SERVER_ROOT_ENV) or (project_root / "Server" / "Borealis")
|
|
||||||
candidates = {
|
|
||||||
"auth_keys": server_root / "auth_keys" / _KEY_FILENAME,
|
|
||||||
"keys": server_root / "keys" / _KEY_FILENAME,
|
|
||||||
}
|
|
||||||
return candidates
|
|
||||||
|
|
||||||
|
|
||||||
def _tighten_permissions(path: Path) -> None:
|
def _tighten_permissions(path: Path) -> None:
|
||||||
try:
|
try:
|
||||||
if os.name != "nt":
|
if os.name != "nt":
|
||||||
@@ -159,7 +148,6 @@ def load_service() -> JWTService:
|
|||||||
|
|
||||||
def _load_or_create_private_key() -> ed25519.Ed25519PrivateKey:
|
def _load_or_create_private_key() -> ed25519.Ed25519PrivateKey:
|
||||||
_KEY_DIR.mkdir(parents=True, exist_ok=True)
|
_KEY_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
_migrate_legacy_key_if_present()
|
|
||||||
|
|
||||||
if _KEY_FILE.exists():
|
if _KEY_FILE.exists():
|
||||||
with _KEY_FILE.open("rb") as fh:
|
with _KEY_FILE.open("rb") as fh:
|
||||||
@@ -177,30 +165,4 @@ def _load_or_create_private_key() -> ed25519.Ed25519PrivateKey:
|
|||||||
return private_key
|
return private_key
|
||||||
|
|
||||||
|
|
||||||
def _migrate_legacy_key_if_present() -> None:
|
|
||||||
if _KEY_FILE.exists():
|
|
||||||
return
|
|
||||||
|
|
||||||
legacy_paths = _legacy_key_paths()
|
|
||||||
for legacy_file in legacy_paths.values():
|
|
||||||
if not legacy_file.exists():
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
legacy_bytes = legacy_file.read_bytes()
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
_KEY_FILE.write_bytes(legacy_bytes)
|
|
||||||
_tighten_permissions(_KEY_FILE)
|
|
||||||
except Exception:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
legacy_file.unlink()
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
break
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["JWTService", "load_service"]
|
__all__ = ["JWTService", "load_service"]
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ environment variables prefixed with ``BOREALIS_``, and finally built-in
|
|||||||
defaults that mirror the legacy server runtime. Key environment variables are
|
defaults that mirror the legacy server runtime. Key environment variables are
|
||||||
|
|
||||||
``BOREALIS_DATABASE_PATH`` path to the SQLite database file. Defaults to
|
``BOREALIS_DATABASE_PATH`` path to the SQLite database file. Defaults to
|
||||||
``<ProjectRoot>/database.db``.
|
the Engine runtime copy under ``<ProjectRoot>/Engine/Data/Engine/database.db``.
|
||||||
``BOREALIS_CORS_ORIGINS`` comma separated list of allowed origins for CORS.
|
``BOREALIS_CORS_ORIGINS`` comma separated list of allowed origins for CORS.
|
||||||
``BOREALIS_SECRET`` Flask session secret key.
|
``BOREALIS_SECRET`` Flask session secret key.
|
||||||
``BOREALIS_COOKIE_*`` Session cookie policies (``SAMESITE``, ``SECURE``,
|
``BOREALIS_COOKIE_*`` Session cookie policies (``SAMESITE``, ``SECURE``,
|
||||||
@@ -72,7 +72,7 @@ def _discover_project_root() -> Path:
|
|||||||
|
|
||||||
|
|
||||||
PROJECT_ROOT = _discover_project_root()
|
PROJECT_ROOT = _discover_project_root()
|
||||||
DEFAULT_DATABASE_PATH = PROJECT_ROOT / "database.db"
|
DEFAULT_DATABASE_PATH = PROJECT_ROOT / "Engine" / "Data" / "Engine" / "database.db"
|
||||||
LOG_ROOT = PROJECT_ROOT / "Engine" / "Logs"
|
LOG_ROOT = PROJECT_ROOT / "Engine" / "Logs"
|
||||||
LOG_FILE_PATH = LOG_ROOT / "engine.log"
|
LOG_FILE_PATH = LOG_ROOT / "engine.log"
|
||||||
ERROR_LOG_FILE_PATH = LOG_ROOT / "error.log"
|
ERROR_LOG_FILE_PATH = LOG_ROOT / "error.log"
|
||||||
|
|||||||
@@ -266,7 +266,11 @@ def _server_certificate_needs_regeneration(
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
san = certificate.extensions.get_extension_for_class(x509.SubjectAlternativeName).value # type: ignore[attr-defined]
|
san = certificate.extensions.get_extension_for_class(x509.SubjectAlternativeName).value # type: ignore[attr-defined]
|
||||||
names = {entry.value for entry in san.get_values_for_type(x509.DNSName)}
|
raw_names = san.get_values_for_type(x509.DNSName)
|
||||||
|
names = {
|
||||||
|
entry if isinstance(entry, str) else getattr(entry, "value", str(entry))
|
||||||
|
for entry in raw_names
|
||||||
|
}
|
||||||
except Exception:
|
except Exception:
|
||||||
names = set()
|
names = set()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user