Offload certificate key generation to worker threads
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
"""Key generation, detail, rename/delete and export."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
@@ -18,6 +17,7 @@ from ..models import Certificate, Key, Request
|
||||
from ..openapi import error_response, json_response, schema_ref
|
||||
from ..service import (
|
||||
ValidationError,
|
||||
generate_key as generate_private_key,
|
||||
parse_key_generation,
|
||||
parse_uuid,
|
||||
save_key,
|
||||
@@ -30,9 +30,6 @@ from ..service import (
|
||||
if TYPE_CHECKING:
|
||||
from ..mixin import Kca
|
||||
|
||||
# Key generation is CPU-bound; this bounds concurrent RSA/DSA jobs.
|
||||
_keygen_semaphore = asyncio.Semaphore(2)
|
||||
|
||||
|
||||
async def _vault(kca: "Kca", ctx: HttpContext, vault_id: str):
|
||||
user = await authenticated_user(kca.oidc, ctx)
|
||||
@@ -85,13 +82,11 @@ def register(app: KayaApp, kca: "Kca") -> None:
|
||||
await send_error(ctx, 400, str(exc))
|
||||
return
|
||||
try:
|
||||
async with _keygen_semaphore:
|
||||
generated = await asyncio.to_thread(
|
||||
key_core.generate_key,
|
||||
params["key_type"],
|
||||
params["size"],
|
||||
params["curve"],
|
||||
)
|
||||
generated = await generate_private_key(
|
||||
params["key_type"],
|
||||
params["size"],
|
||||
params["curve"],
|
||||
)
|
||||
key = await save_key(
|
||||
vault,
|
||||
generated,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
"""Certificate signing requests: list, create, detail, export and transforms."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
from datetime import datetime, timezone
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
@@ -21,6 +20,7 @@ from ..models import Key, Request, Template
|
||||
from ..openapi import error_response, json_response, schema_ref
|
||||
from ..service import (
|
||||
ValidationError,
|
||||
generate_key,
|
||||
parse_extensions,
|
||||
parse_subject,
|
||||
parse_uuid,
|
||||
@@ -36,8 +36,6 @@ from ..service import (
|
||||
if TYPE_CHECKING:
|
||||
from ..mixin import Kca
|
||||
|
||||
_keygen_semaphore = asyncio.Semaphore(2)
|
||||
|
||||
|
||||
async def _vault(kca: "Kca", ctx: HttpContext, vault_id: str):
|
||||
user = await authenticated_user(kca.oidc, ctx)
|
||||
@@ -98,13 +96,11 @@ def register(app: KayaApp, kca: "Kca") -> None:
|
||||
key_obj = await load_private_key(key_model)
|
||||
elif isinstance(body.get("new_key"), dict):
|
||||
new_key = body["new_key"]
|
||||
async with _keygen_semaphore:
|
||||
generated = await asyncio.to_thread(
|
||||
key_core.generate_key,
|
||||
str(new_key.get("key_type") or "rsa"),
|
||||
int(new_key.get("size") or key_core.DEFAULT_KEY_SIZE),
|
||||
new_key.get("curve"),
|
||||
)
|
||||
generated = await generate_key(
|
||||
str(new_key.get("key_type") or "rsa"),
|
||||
int(new_key.get("size") or key_core.DEFAULT_KEY_SIZE),
|
||||
new_key.get("curve"),
|
||||
)
|
||||
key_model = await save_key(
|
||||
vault,
|
||||
generated,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Business logic: validation, persistence, serialization and CA operations."""
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import hashlib
|
||||
import secrets
|
||||
from datetime import datetime, timedelta, timezone
|
||||
@@ -471,6 +472,20 @@ async def serialize_vault_detail(vault: Vault) -> Dict[str, Any]:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Key generation is CPU-bound; bound concurrent jobs across all routes.
|
||||
_keygen_semaphore = asyncio.Semaphore(2)
|
||||
|
||||
|
||||
async def generate_key(
|
||||
key_type: str,
|
||||
size: int = key_core.DEFAULT_KEY_SIZE,
|
||||
curve: Optional[str] = None,
|
||||
) -> key_core.PrivateKey:
|
||||
"""Generate a private key without blocking the event loop."""
|
||||
async with _keygen_semaphore:
|
||||
return await asyncio.to_thread(key_core.generate_key, key_type, size, curve)
|
||||
|
||||
|
||||
def parse_key_generation(payload: Mapping[str, Any]) -> Dict[str, Any]:
|
||||
key_type = str(payload.get("key_type") or payload.get("type") or "rsa").lower()
|
||||
if key_type not in key_core.KEY_TYPES:
|
||||
@@ -708,7 +723,7 @@ async def issue_certificate(
|
||||
key_obj = await load_private_key(key_model)
|
||||
elif new_key_payload:
|
||||
try:
|
||||
generated = key_core.generate_key(
|
||||
generated = await generate_key(
|
||||
str(new_key_payload.get("key_type") or "rsa"),
|
||||
int(new_key_payload.get("size") or key_core.DEFAULT_KEY_SIZE),
|
||||
new_key_payload.get("curve"),
|
||||
@@ -873,13 +888,13 @@ async def preview_certificate(vault: Vault, payload: Mapping[str, Any]) -> Dict[
|
||||
else:
|
||||
new_key = payload.get("new_key")
|
||||
if isinstance(new_key, Mapping):
|
||||
generated = key_core.generate_key(
|
||||
generated = await generate_key(
|
||||
str(new_key.get("key_type") or "ec"),
|
||||
int(new_key.get("size") or 2048),
|
||||
new_key.get("curve") or "secp256r1",
|
||||
)
|
||||
else:
|
||||
generated = key_core.generate_key("ec", curve="secp256r1")
|
||||
generated = await generate_key("ec", curve="secp256r1")
|
||||
public_key = generated.public_key()
|
||||
|
||||
extensions_spec = parse_extensions(payload.get("extensions"))
|
||||
@@ -1446,6 +1461,7 @@ __all__ = [
|
||||
"find_key",
|
||||
"find_request",
|
||||
"generate_crl",
|
||||
"generate_key",
|
||||
"import_parsed_items",
|
||||
"iso",
|
||||
"issue_certificate",
|
||||
|
||||
Reference in New Issue
Block a user