feat(hardening): build scoped Grant writers per service
This commit is contained in:
@@ -1,11 +1,11 @@
|
|||||||
"""AIOS V2 运维操作 Provenance Gate 与生产 Writer 工厂。"""
|
"""AIOS V2 运维操作 Provenance Gate 与服务级 Scoped Writer 工厂。"""
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from dataclasses import asdict, dataclass
|
from dataclasses import asdict, dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Mapping, Protocol
|
from typing import Any, Mapping, Protocol, Sequence
|
||||||
|
|
||||||
from .provenance import (
|
from .provenance import (
|
||||||
Ed25519PublicKeyVerifier,
|
Ed25519PublicKeyVerifier,
|
||||||
@@ -17,12 +17,8 @@ from .provenance import (
|
|||||||
SQLiteProvenanceStore,
|
SQLiteProvenanceStore,
|
||||||
digest_payload,
|
digest_payload,
|
||||||
)
|
)
|
||||||
from .provenance_grants import (
|
from .provenance_grants import GrantAuthorization, GrantVerifier, SQLiteGrantStore
|
||||||
GrantAuthorization,
|
from .provenance_scoped import ScopedLeastPrivilegeProvenanceWriter
|
||||||
GrantVerifier,
|
|
||||||
LeastPrivilegeProvenanceWriter,
|
|
||||||
SQLiteGrantStore,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AuthorizationWriter(Protocol):
|
class AuthorizationWriter(Protocol):
|
||||||
@@ -67,7 +63,7 @@ class OperationReceipt:
|
|||||||
|
|
||||||
|
|
||||||
class ProvenanceOperationGate:
|
class ProvenanceOperationGate:
|
||||||
"""部署、回滚和审计操作的统一授权入口。"""
|
"""部署、回滚、审计和运行操作的统一授权入口。"""
|
||||||
|
|
||||||
def __init__(self, writer: AuthorizationWriter) -> None:
|
def __init__(self, writer: AuthorizationWriter) -> None:
|
||||||
self.writer = writer
|
self.writer = writer
|
||||||
@@ -151,33 +147,45 @@ _GRANT_ENV_BY_PATH: Mapping[str, str] = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def grant_ids_from_environment() -> dict[str, str]:
|
def grant_ids_from_environment(
|
||||||
values = {
|
*,
|
||||||
path: os.getenv(variable, "").strip()
|
required_paths: Sequence[str] | None = None,
|
||||||
for path, variable in _GRANT_ENV_BY_PATH.items()
|
) -> dict[str, str]:
|
||||||
}
|
paths = tuple(
|
||||||
configured = {path: value for path, value in values.items() if value}
|
sorted(
|
||||||
if configured and len(configured) != len(values):
|
{
|
||||||
missing = [
|
ExecutionPath(path).value
|
||||||
variable
|
for path in (required_paths or tuple(item.value for item in ExecutionPath))
|
||||||
for path, variable in _GRANT_ENV_BY_PATH.items()
|
}
|
||||||
if not values[path]
|
|
||||||
]
|
|
||||||
raise RuntimeError(
|
|
||||||
f"partial least-privilege Provenance Grant configuration; missing {missing}"
|
|
||||||
)
|
)
|
||||||
return configured
|
)
|
||||||
|
values = {
|
||||||
|
path: os.getenv(_GRANT_ENV_BY_PATH[path], "").strip()
|
||||||
|
for path in paths
|
||||||
|
}
|
||||||
|
missing = [
|
||||||
|
_GRANT_ENV_BY_PATH[path]
|
||||||
|
for path, value in values.items()
|
||||||
|
if not value
|
||||||
|
]
|
||||||
|
if missing:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"missing scoped Provenance Grant configuration: {missing}"
|
||||||
|
)
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
def build_provenance_writer_from_env(
|
def build_provenance_writer_from_env(
|
||||||
*,
|
*,
|
||||||
state_dir: str | Path | None = None,
|
state_dir: str | Path | None = None,
|
||||||
required: bool | None = None,
|
required: bool | None = None,
|
||||||
|
required_paths: Sequence[str] | None = None,
|
||||||
|
writer_id: str = "aios-v2-scoped-grant-writer",
|
||||||
) -> AuthorizationWriter | None:
|
) -> AuthorizationWriter | None:
|
||||||
"""从环境构建验证 Writer。
|
"""从环境构建服务级最小权限 Writer。
|
||||||
|
|
||||||
生产强制模式必须配置七个独立子 Grant。旧全权限 Writer 只允许在显式关闭
|
生产强制模式必须显式声明当前进程需要的路径;仅加载这些路径对应的 Grant。
|
||||||
强制模式的候选/测试环境中使用。
|
旧全权限 Writer 只允许在显式关闭强制模式的候选/测试环境中使用。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
require_value = (
|
require_value = (
|
||||||
@@ -195,8 +203,6 @@ def build_provenance_writer_from_env(
|
|||||||
receipt_root = os.getenv(
|
receipt_root = os.getenv(
|
||||||
"AIOS_PROVENANCE_RECEIPT_DIR", str(base / "provenance-receipts")
|
"AIOS_PROVENANCE_RECEIPT_DIR", str(base / "provenance-receipts")
|
||||||
).strip()
|
).strip()
|
||||||
grant_ids = grant_ids_from_environment()
|
|
||||||
|
|
||||||
configured = bool(public_key_file and key_id)
|
configured = bool(public_key_file and key_id)
|
||||||
if not configured:
|
if not configured:
|
||||||
if require_value:
|
if require_value:
|
||||||
@@ -207,22 +213,33 @@ def build_provenance_writer_from_env(
|
|||||||
|
|
||||||
verifier = Ed25519PublicKeyVerifier.from_file(public_key_file, key_id=key_id)
|
verifier = Ed25519PublicKeyVerifier.from_file(public_key_file, key_id=key_id)
|
||||||
parent_store = SQLiteProvenanceStore(store_file)
|
parent_store = SQLiteProvenanceStore(store_file)
|
||||||
if grant_ids:
|
normalized_paths = tuple(
|
||||||
|
sorted(
|
||||||
|
{
|
||||||
|
ExecutionPath(path).value
|
||||||
|
for path in (required_paths or ())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if require_value:
|
||||||
|
if not normalized_paths:
|
||||||
|
raise RuntimeError(
|
||||||
|
"production Run Provenance requires explicit service scope"
|
||||||
|
)
|
||||||
|
grant_ids = grant_ids_from_environment(required_paths=normalized_paths)
|
||||||
grant_store = SQLiteGrantStore(store_file)
|
grant_store = SQLiteGrantStore(store_file)
|
||||||
trusted_grants = GrantVerifier(
|
trusted_grants = GrantVerifier(
|
||||||
parent_store,
|
parent_store,
|
||||||
grant_store,
|
grant_store,
|
||||||
{key_id: verifier},
|
{key_id: verifier},
|
||||||
)
|
)
|
||||||
return LeastPrivilegeProvenanceWriter(
|
return ScopedLeastPrivilegeProvenanceWriter(
|
||||||
trusted_grants,
|
trusted_grants,
|
||||||
receipt_root,
|
receipt_root,
|
||||||
grant_ids,
|
grant_ids,
|
||||||
)
|
required_paths=normalized_paths,
|
||||||
|
writer_id=writer_id,
|
||||||
if require_value:
|
|
||||||
raise RuntimeError(
|
|
||||||
"production Run Provenance requires seven independent Grant IDs; full-rights provenance is prohibited"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
legacy = ProvenanceVerifier(parent_store, {key_id: verifier})
|
legacy = ProvenanceVerifier(parent_store, {key_id: verifier})
|
||||||
|
|||||||
Reference in New Issue
Block a user