环境配置管理与敏感信息保护

『宝藏代码胶囊开张啦!』—— 我的 CodeCapsule 来咯!✨写代码不再头疼!我的新站点 CodeCapsule 主打一个 “白菜价”+“量身定制”!无论是卡脖子的毕设/课设/文献复现,需要灵光一现的算法改进,还是想给项目加个“外挂”,这里都有便宜又好用的代码方案等你发现!低成本,高适配,助你轻松通关!速来围观 👉 CodeCapsule官网

环境配置管理与敏感信息保护

引言

在现代软件开发中,环境配置管理和敏感信息保护是确保系统安全性和可维护性的关键环节。随着云原生和微服务架构的普及,应用环境的复杂性和动态性显著增加,如何在多环境(开发、测试、生产)中安全地管理配置和敏感数据成为了每个开发团队必须面对的重要课题。

根据2023年数据泄露调查报告显示,配置错误导致的数据泄露占比达到23%,而敏感信息暴露问题更是安全漏洞的主要来源之一。本文将深入探讨环境配置管理的完整生命周期和敏感信息保护的最佳实践,并提供可落地的Python实现方案。

1. 环境配置管理基础

1.1 环境配置的重要性

环境配置管理是系统部署和运行的基础,它决定了应用程序在不同环境中的行为差异。良好的配置管理能够:

  • 提高部署效率:自动化配置减少人工干预
  • 降低错误率:统一配置减少人为失误
  • 增强可移植性:应用在不同环境间无缝迁移
  • 简化故障排查:清晰的配置逻辑便于问题定位

1.2 配置的分类与层级

环境配置体系
运行时配置
构建时配置
部署时配置
环境变量
命令行参数
动态配置服务
构建参数
依赖版本
资源文件
基础设施配置
网络配置
服务发现

1.3 配置管理的演化历程

配置管理经历了多个阶段的演进:

  1. 硬编码阶段:配置直接写在代码中
  2. 配置文件阶段:使用独立的配置文件
  3. 环境变量阶段:基于环境变量注入配置
  4. 配置中心阶段:集中式配置管理服务
  5. 声明式配置阶段:基础设施即代码(IaC)

2. 敏感信息保护基础

2.1 敏感信息的定义与分类

敏感信息是指任何如果被未经授权访问、使用、披露、修改或破坏,可能会对个人、组织或系统造成损害的信息。按照信息类型可以分为:

类别示例保护等级
认证凭证密码、API密钥、令牌极高
加密密钥对称密钥、非对称私钥极高
个人信息身份证号、手机号、地址
财务信息银行卡号、交易记录
系统配置数据库连接字符串、服务端点
业务数据订单信息、用户偏好

2.2 敏感信息泄露的风险模型

敏感信息泄露的风险可以用以下公式表示:

Risk = Likelihood × Impact \text{Risk} = \text{Likelihood} \times \text{Impact} Risk=Likelihood×Impact

其中:

  • Likelihood \text{Likelihood} Likelihood:泄露发生的概率
  • Impact \text{Impact} Impact:泄露造成的损失

对于不同类型的敏感信息,其风险值计算可以进一步细化:

Risk t o t a l = ∑ i = 1 n w i ⋅ ( Exposure i × Criticality i ) \text{Risk}_{total} = \sum_{i=1}^{n} w_i \cdot (\text{Exposure}_i \times \text{Criticality}_i) Risktotal=i=1nwi(Exposurei×Criticalityi)

这里:

  • w i w_i wi:信息类型权重
  • Exposure i \text{Exposure}_i Exposurei:暴露程度
  • Criticality i \text{Criticality}_i Criticalityi:信息关键性

2.3 敏感信息生命周期管理

定期更新
加密存储
按需解密
安全传输
安全擦除
创建
存储
加密
密钥管理
访问控制
使用
传输
TLS加密
认证授权
轮换
销毁

3. 环境配置管理架构

3.1 配置管理架构设计

一个完整的配置管理系统应该包含以下组件:

  1. 配置源:配置文件、环境变量、数据库、配置中心等
  2. 配置解析器:解析不同格式的配置
  3. 配置验证器:验证配置的完整性和正确性
  4. 配置加密器:处理敏感配置的加解密
  5. 配置分发器:将配置分发到各个服务实例

3.2 多环境配置策略

不同的环境需要不同的配置策略:

环境配置策略敏感信息处理访问控制
本地开发本地配置文件,包含模拟值模拟数据,无真实密钥宽松
持续集成从安全存储读取,使用临时凭证短期有效凭证中等
测试环境近似生产配置,使用测试数据测试专用凭证严格
预生产与生产几乎一致,但数据隔离生产级保护严格
生产环境完全隔离,最小权限原则最高级别保护最严格

3.3 配置版本控制策略

配置应该像代码一样进行版本控制,但敏感配置需要特殊处理:

  1. 版本化:所有配置变更都有版本记录
  2. 分支策略:不同环境使用不同分支
  3. 回滚机制:快速回退到已知良好状态
  4. 审计跟踪:谁在什么时候修改了什么

4. 敏感信息保护技术

4.1 加密算法选择

根据不同的使用场景选择合适的加密算法:

场景推荐算法密钥长度特点
配置文件加密AES-GCM256位认证加密,防篡改
API密钥存储Argon2id变长抗暴力破解,内存困难
数据库字段AES-CBC + HMAC256位兼容性好,需要IV
传输加密TLS 1.3取决于证书端到端加密
密码哈希bcrypt变长自适应成本因子

4.2 密钥管理架构

密钥管理是敏感信息保护的核心,遵循"密钥远离数据"原则:

缓存命中
缓存未命中
应用
本地密钥缓存
密钥请求
使用缓存密钥
密钥管理服务
硬件安全模块 HSM
云密钥管理 KMS
密钥存储库
返回加密密钥
本地解密使用

4.3 密钥轮换策略

定期轮换密钥是安全最佳实践,轮换策略包括:

  1. 时间驱动轮换:按固定时间间隔轮换
  2. 使用量驱动轮换:达到使用次数上限后轮换
  3. 事件驱动轮换:安全事件发生后立即轮换
  4. 渐进式轮换:新旧密钥同时有效一段时间

密钥轮换的数学表示:

设密钥生命周期为 T T T,轮换周期为 Δ t \Delta t Δt,则在时间 t t t 时有效的密钥集合为:

K valid ( t ) = { k i ∣ t i ≤ t ≤ t i + T } K_{\text{valid}}(t) = \{k_i \mid t_i \leq t \leq t_i + T\} Kvalid(t)={kititti+T}

其中 t i t_i ti 是密钥 k i k_i ki 的创建时间。

5. Python环境配置管理实现

5.1 基础配置管理框架

"""
环境配置管理与敏感信息保护系统
设计原则:
1. 分层配置:系统级 > 环境级 > 应用级 > 实例级
2. 配置即代码:所有配置可版本控制
3. 安全优先:默认加密,显式解密
4. 类型安全:配置值有明确类型
"""

import os
import json
import yaml
import tomllib
from typing import Dict, Any, Optional, List, Union, TypeVar, Generic
from pathlib import Path
from enum import Enum
from dataclasses import dataclass, field, asdict
from abc import ABC, abstractmethod
import base64
import hashlib
import logging
from datetime import datetime, timedelta

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)

T = TypeVar('T')

class ConfigSource(Enum):
    """配置源枚举"""
    ENV_VAR = "env_var"
    FILE = "file"
    SECRET_STORE = "secret_store"
    CONFIG_SERVER = "config_server"
    DATABASE = "database"

class ConfigFormat(Enum):
    """配置格式枚举"""
    JSON = "json"
    YAML = "yaml"
    TOML = "toml"
    ENV = "env"
    INI = "ini"

class SecurityLevel(Enum):
    """安全级别枚举"""
    LOW = "low"       # 本地开发
    MEDIUM = "medium" # 测试环境
    HIGH = "high"     # 预生产
    CRITICAL = "critical"  # 生产环境

@dataclass
class ConfigMetadata:
    """配置元数据"""
    source: ConfigSource
    format: Optional[ConfigFormat] = None
    last_modified: Optional[datetime] = None
    checksum: Optional[str] = None
    security_level: SecurityLevel = SecurityLevel.MEDIUM
    tags: List[str] = field(default_factory=list)
    
    def update_checksum(self, content: str) -> None:
        """更新配置内容的校验和"""
        self.checksum = hashlib.sha256(content.encode()).hexdigest()
        self.last_modified = datetime.now()
    
    def validate_checksum(self, content: str) -> bool:
        """验证配置内容的完整性"""
        if not self.checksum:
            return True
        current_checksum = hashlib.sha256(content.encode()).hexdigest()
        return current_checksum == self.checksum

class ConfigValue(Generic[T]):
    """类型安全的配置值"""
    
    def __init__(
        self,
        value: T,
        value_type: type,
        is_sensitive: bool = False,
        encrypted: bool = False,
        source: Optional[ConfigMetadata] = None
    ):
        self._value = value
        self.value_type = value_type
        self.is_sensitive = is_sensitive
        self.encrypted = encrypted
        self.source = source
        self._validated = False
        
        # 类型检查
        if not isinstance(value, value_type):
            raise TypeError(
                f"期望类型 {value_type}, 实际类型 {type(value)}"
            )
    
    @property
    def value(self) -> T:
        """获取值(如果敏感则返回脱敏版本)"""
        if self.is_sensitive and not self._validated:
            return self._get_masked_value()
        return self._value
    
    def get_raw_value(self) -> T:
        """获取原始值(不脱敏)"""
        return self._value
    
    def _get_masked_value(self) -> str:
        """获取脱敏值"""
        if isinstance(self._value, str):
            if len(self._value) <= 4:
                return "***"
            return self._value[:2] + "*" * (len(self._value) - 4) + self._value[-2:]
        return "***"
    
    def validate(self, validator: callable) -> bool:
        """验证配置值"""
        try:
            result = validator(self._value)
            self._validated = result
            return result
        except Exception as e:
            logger.error(f"配置值验证失败: {e}")
            return False
    
    def __repr__(self) -> str:
        return f"ConfigValue({self.value}, type={self.value_type}, sensitive={self.is_sensitive})"

class ConfigSection:
    """配置节"""
    
    def __init__(self, name: str, description: str = ""):
        self.name = name
        self.description = description
        self._values: Dict[str, ConfigValue] = {}
        self._subsections: Dict[str, 'ConfigSection'] = {}
    
    def add_value(
        self,
        key: str,
        value: Any,
        value_type: type = str,
        is_sensitive: bool = False,
        description: str = "",
        validators: Optional[List[callable]] = None
    ) -> 'ConfigValue':
        """添加配置值"""
        
        # 创建配置值
        config_value = ConfigValue(
            value=value,
            value_type=value_type,
            is_sensitive=is_sensitive
        )
        
        # 验证
        if validators:
            for validator in validators:
                if not config_value.validate(validator):
                    raise ValueError(f"配置值 {key} 验证失败")
        
        self._values[key] = config_value
        return config_value
    
    def get_value(self, key: str, default: Any = None) -> Any:
        """获取配置值"""
        if key in self._values:
            return self._values[key].value
        return default
    
    def get_raw_value(self, key: str) -> Any:
        """获取原始配置值"""
        if key in self._values:
            return self._values[key].get_raw_value()
        raise KeyError(f"配置键不存在: {key}")
    
    def add_subsection(self, name: str, description: str = "") -> 'ConfigSection':
        """添加子节"""
        subsection = ConfigSection(name, description)
        self._subsections[name] = subsection
        return subsection
    
    def get_subsection(self, name: str) -> 'ConfigSection':
        """获取子节"""
        return self._subsections[name]
    
    def to_dict(self, mask_sensitive: bool = True) -> Dict:
        """转换为字典"""
        result = {}
        
        # 添加值
        for key, config_value in self._values.items():
            if mask_sensitive and config_value.is_sensitive:
                result[key] = config_value._get_masked_value()
            else:
                result[key] = config_value.value
        
        # 添加子节
        for name, subsection in self._subsections.items():
            result[name] = subsection.to_dict(mask_sensitive)
        
        return result
    
    def validate_all(self) -> Dict[str, bool]:
        """验证所有配置值"""
        results = {}
        
        for key, config_value in self._values.items():
            # 这里可以添加具体的验证逻辑
            results[key] = True
        
        for name, subsection in self._subsections.items():
            results.update({
                f"{name}.{sub_key}": value 
                for sub_key, value in subsection.validate_all().items()
            })
        
        return results

class ConfigurationManager:
    """配置管理器"""
    
    def __init__(
        self,
        app_name: str,
        environment: str = "development",
        security_level: SecurityLevel = SecurityLevel.MEDIUM
    ):
        self.app_name = app_name
        self.environment = environment
        self.security_level = security_level
        
        # 配置层次结构
        self._config_hierarchy: List[Dict] = []
        self._config_sources: Dict[ConfigSource, Any] = {}
        
        # 配置缓存
        self._config_cache: Dict[str, ConfigSection] = {}
        
        # 初始化根配置节
        self.root_section = ConfigSection("root", f"{app_name} 根配置")
        
        logger.info(f"初始化配置管理器: {app_name}, 环境: {environment}")
    
    def add_config_source(
        self,
        source: ConfigSource,
        config: Any,
        priority: int = 0
    ) -> None:
        """添加配置源"""
        self._config_hierarchy.append({
            'source': source,
            'config': config,
            'priority': priority
        })
        
        # 按优先级排序
        self._config_hierarchy.sort(key=lambda x: x['priority'], reverse=True)
        
        logger.info(f"添加配置源: {source.value}, 优先级: {priority}")
    
    def load_configuration(self) -> None:
        """加载所有配置"""
        logger.info("开始加载配置...")
        
        for source_info in self._config_hierarchy:
            source = source_info['source']
            config_data = source_info['config']
            
            try:
                if source == ConfigSource.ENV_VAR:
                    self._load_from_env_vars(config_data)
                elif source == ConfigSource.FILE:
                    self._load_from_file(config_data)
                elif source == ConfigSource.SECRET_STORE:
                    self._load_from_secret_store(config_data)
                elif source == ConfigSource.CONFIG_SERVER:
                    self._load_from_config_server(config_data)
                
                logger.info(f"配置源加载成功: {source.value}")
                
            except Exception as e:
                logger.error(f"配置源加载失败 {source.value}: {e}")
                if self.security_level in [SecurityLevel.HIGH, SecurityLevel.CRITICAL]:
                    raise
    
    def _load_from_env_vars(self, prefix: str) -> None:
        """从环境变量加载配置"""
        prefix = prefix.upper()
        
        for key, value in os.environ.items():
            if key.startswith(prefix):
                # 解析配置路径
                config_path = key[len(prefix):].lstrip('_').lower()
                
                # 处理嵌套配置(使用__作为分隔符)
                parts = config_path.split('__')
                current_section = self.root_section
                
                # 导航到目标节
                for part in parts[:-1]:
                    if part not in current_section._subsections:
                        current_section.add_subsection(part)
                    current_section = current_section._subsections[part]
                
                # 添加配置值
                config_key = parts[-1]
                
                # 判断是否为敏感信息
                is_sensitive = any(
                    sensitive_keyword in key.lower() 
                    for sensitive_keyword in ['key', 'secret', 'password', 'token']
                )
                
                current_section.add_value(
                    config_key,
                    value,
                    is_sensitive=is_sensitive
                )
    
    def _load_from_file(self, file_path: Union[str, Path]) -> None:
        """从文件加载配置"""
        file_path = Path(file_path)
        
        if not file_path.exists():
            logger.warning(f"配置文件不存在: {file_path}")
            return
        
        # 根据文件扩展名确定格式
        suffix = file_path.suffix.lower()
        
        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                content = f.read()
                
            if suffix == '.json':
                config_data = json.loads(content)
            elif suffix in ['.yaml', '.yml']:
                config_data = yaml.safe_load(content)
            elif suffix == '.toml':
                config_data = tomllib.loads(content)
            else:
                logger.error(f"不支持的配置文件格式: {suffix}")
                return
            
            # 递归加载配置数据
            self._load_dict_to_section(self.root_section, config_data)
            
        except Exception as e:
            logger.error(f"配置文件加载失败 {file_path}: {e}")
    
    def _load_dict_to_section(self, section: ConfigSection, data: Dict, parent_key: str = ""):
        """递归加载字典数据到配置节"""
        for key, value in data.items():
            current_key = f"{parent_key}.{key}" if parent_key else key
            
            if isinstance(value, dict):
                # 创建子节并递归加载
                subsection = section.add_subsection(key)
                self._load_dict_to_section(subsection, value, current_key)
            else:
                # 判断是否为敏感信息
                is_sensitive = any(
                    sensitive_keyword in current_key.lower()
                    for sensitive_keyword in ['key', 'secret', 'password', 'token', 'credential']
                )
                
                # 确定值类型
                if isinstance(value, bool):
                    value_type = bool
                elif isinstance(value, int):
                    value_type = int
                elif isinstance(value, float):
                    value_type = float
                elif isinstance(value, list):
                    value_type = list
                else:
                    value_type = str
                
                section.add_value(
                    key,
                    value,
                    value_type=value_type,
                    is_sensitive=is_sensitive
                )
    
    def _load_from_secret_store(self, store_config: Dict) -> None:
        """从密钥存储加载配置(抽象方法)"""
        # 具体实现取决于使用的密钥存储服务
        # 例如:AWS Secrets Manager, Azure Key Vault, HashiCorp Vault等
        logger.warning("密钥存储加载未实现,需要具体实现")
    
    def _load_from_config_server(self, server_config: Dict) -> None:
        """从配置服务器加载配置(抽象方法)"""
        # 例如:Spring Cloud Config, etcd, Consul等
        logger.warning("配置服务器加载未实现,需要具体实现")
    
    def get(self, key_path: str, default: Any = None) -> Any:
        """获取配置值"""
        parts = key_path.split('.')
        current_section = self.root_section
        
        # 导航到目标节
        for part in parts[:-1]:
            if part in current_section._subsections:
                current_section = current_section._subsections[part]
            else:
                logger.debug(f"配置路径不存在: {key_path}")
                return default
        
        # 获取值
        last_part = parts[-1]
        return current_section.get_value(last_part, default)
    
    def get_section(self, section_path: str) -> ConfigSection:
        """获取配置节"""
        if not section_path or section_path == ".":
            return self.root_section
        
        parts = section_path.split('.')
        current_section = self.root_section
        
        for part in parts:
            if part in current_section._subsections:
                current_section = current_section._subsections[part]
            else:
                raise KeyError(f"配置节不存在: {section_path}")
        
        return current_section
    
    def to_dict(self, mask_sensitive: bool = True) -> Dict:
        """转换为字典"""
        return self.root_section.to_dict(mask_sensitive)
    
    def validate_configuration(self) -> Dict[str, bool]:
        """验证所有配置"""
        return self.root_section.validate_all()
    
    def generate_config_report(self) -> Dict:
        """生成配置报告"""
        config_dict = self.to_dict(mask_sensitive=False)
        
        # 统计信息
        sensitive_count = self._count_sensitive_values(self.root_section)
        
        return {
            'app_name': self.app_name,
            'environment': self.environment,
            'security_level': self.security_level.value,
            'config_sources': [s['source'].value for s in self._config_hierarchy],
            'sensitive_values_count': sensitive_count,
            'total_values_count': self._count_total_values(self.root_section),
            'config_structure': config_dict
        }
    
    def _count_sensitive_values(self, section: ConfigSection) -> int:
        """统计敏感值数量"""
        count = 0
        
        for config_value in section._values.values():
            if config_value.is_sensitive:
                count += 1
        
        for subsection in section._subsections.values():
            count += self._count_sensitive_values(subsection)
        
        return count
    
    def _count_total_values(self, section: ConfigSection) -> int:
        """统计总配置值数量"""
        count = len(section._values)
        
        for subsection in section._subsections.values():
            count += self._count_total_values(subsection)
        
        return count

5.2 安全配置加密模块

"""
配置加密模块
支持对称加密、非对称加密和密钥派生
"""

import os
import json
from typing import Optional, Tuple, Union
from cryptography.fernet import Fernet, MultiFernet
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
import base64
import secrets


class EncryptionMethod(Enum):
    """加密方法枚举"""
    SYMMETRIC = "symmetric"  # 对称加密
    ASYMMETRIC = "asymmetric"  # 非对称加密
    FERNET = "fernet"  # Fernet加密(AES + HMAC)
    CHACHA20 = "chacha20"  # ChaCha20加密


class KeyManager:
    """密钥管理器"""
    
    def __init__(self, master_key: Optional[bytes] = None):
        self.master_key = master_key or self._generate_master_key()
        self._derived_keys: Dict[str, bytes] = {}
        self._key_cache = {}
    
    @staticmethod
    def _generate_master_key() -> bytes:
        """生成主密钥"""
        return secrets.token_bytes(32)  # 256位
    
    def derive_key(
        self,
        key_id: str,
        salt: Optional[bytes] = None,
        length: int = 32
    ) -> bytes:
        """派生密钥"""
        
        # 检查缓存
        cache_key = f"{key_id}:{salt.hex() if salt else 'no-salt'}:{length}"
        if cache_key in self._key_cache:
            return self._key_cache[cache_key]
        
        # 生成盐
        if salt is None:
            salt = secrets.token_bytes(16)
        
        # 使用PBKDF2派生密钥
        kdf = PBKDF2HMAC(
            algorithm=hashes.SHA256(),
            length=length,
            salt=salt,
            iterations=100000,
            backend=default_backend()
        )
        
        derived_key = kdf.derive(self.master_key)
        
        # 缓存结果
        self._derived_keys[key_id] = derived_key
        self._key_cache[cache_key] = derived_key
        
        return derived_key
    
    def generate_key_pair(self) -> Tuple[bytes, bytes]:
        """生成RSA密钥对"""
        private_key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
            backend=default_backend()
        )
        
        public_key = private_key.public_key()
        
        # 序列化
        private_pem = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption()
        )
        
        public_pem = public_key.public_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PublicFormat.SubjectPublicKeyInfo
        )
        
        return private_pem, public_pem


class ConfigEncryptor:
    """配置加密器"""
    
    def __init__(self, key_manager: Optional[KeyManager] = None):
        self.key_manager = key_manager or KeyManager()
        self.encryption_methods = {}
        
        # 注册默认加密方法
        self._register_default_methods()
    
    def _register_default_methods(self):
        """注册默认加密方法"""
        self.register_method(
            EncryptionMethod.FERNET,
            self._encrypt_fernet,
            self._decrypt_fernet
        )
        
        self.register_method(
            EncryptionMethod.SYMMETRIC,
            self._encrypt_symmetric,
            self._decrypt_symmetric
        )
    
    def register_method(
        self,
        method: EncryptionMethod,
        encrypt_func: callable,
        decrypt_func: callable
    ):
        """注册加密方法"""
        self.encryption_methods[method] = {
            'encrypt': encrypt_func,
            'decrypt': decrypt_func
        }
    
    def encrypt(
        self,
        plaintext: Union[str, bytes],
        key_id: str,
        method: EncryptionMethod = EncryptionMethod.FERNET,
        **kwargs
    ) -> str:
        """加密数据"""
        
        if method not in self.encryption_methods:
            raise ValueError(f"不支持的加密方法: {method}")
        
        # 转换为字节
        if isinstance(plaintext, str):
            plaintext_bytes = plaintext.encode('utf-8')
        else:
            plaintext_bytes = plaintext
        
        # 执行加密
        encrypt_func = self.encryption_methods[method]['encrypt']
        ciphertext = encrypt_func(plaintext_bytes, key_id, **kwargs)
        
        # 编码为字符串
        return base64.urlsafe_b64encode(ciphertext).decode('utf-8')
    
    def decrypt(
        self,
        ciphertext: str,
        key_id: str,
        method: EncryptionMethod = EncryptionMethod.FERNET,
        **kwargs
    ) -> str:
        """解密数据"""
        
        if method not in self.encryption_methods:
            raise ValueError(f"不支持的加密方法: {method}")
        
        # 解码字节
        ciphertext_bytes = base64.urlsafe_b64decode(ciphertext)
        
        # 执行解密
        decrypt_func = self.encryption_methods[method]['decrypt']
        plaintext_bytes = decrypt_func(ciphertext_bytes, key_id, **kwargs)
        
        # 解码为字符串
        return plaintext_bytes.decode('utf-8')
    
    def _encrypt_fernet(
        self,
        plaintext: bytes,
        key_id: str,
        **kwargs
    ) -> bytes:
        """Fernet加密"""
        # 派生密钥
        key = self.key_manager.derive_key(key_id)
        
        # 创建Fernet实例
        fernet_key = base64.urlsafe_b64encode(key[:32])  # Fernet需要32字节密钥
        fernet = Fernet(fernet_key)
        
        # 加密
        return fernet.encrypt(plaintext)
    
    def _decrypt_fernet(
        self,
        ciphertext: bytes,
        key_id: str,
        **kwargs
    ) -> bytes:
        """Fernet解密"""
        # 派生密钥
        key = self.key_manager.derive_key(key_id)
        
        # 创建Fernet实例
        fernet_key = base64.urlsafe_b64encode(key[:32])
        fernet = Fernet(fernet_key)
        
        # 解密
        return fernet.decrypt(ciphertext)
    
    def _encrypt_symmetric(
        self,
        plaintext: bytes,
        key_id: str,
        **kwargs
    ) -> bytes:
        """AES对称加密"""
        # 派生密钥
        key = self.key_manager.derive_key(key_id, length=32)
        
        # 生成IV
        iv = secrets.token_bytes(16)
        
        # 创建加密器
        cipher = Cipher(
            algorithms.AES(key),
            modes.GCM(iv),
            backend=default_backend()
        )
        
        encryptor = cipher.encryptor()
        
        # 加密
        ciphertext = encryptor.update(plaintext) + encryptor.finalize()
        
        # 组合IV和密文
        return iv + encryptor.tag + ciphertext
    
    def _decrypt_symmetric(
        self,
        ciphertext: bytes,
        key_id: str,
        **kwargs
    ) -> bytes:
        """AES对称解密"""
        # 派生密钥
        key = self.key_manager.derive_key(key_id, length=32)
        
        # 提取IV、认证标签和密文
        iv = ciphertext[:16]
        tag = ciphertext[16:32]
        actual_ciphertext = ciphertext[32:]
        
        # 创建解密器
        cipher = Cipher(
            algorithms.AES(key),
            modes.GCM(iv, tag),
            backend=default_backend()
        )
        
        decryptor = cipher.decryptor()
        
        # 解密
        return decryptor.update(actual_ciphertext) + decryptor.finalize()


class SecureConfigManager(ConfigurationManager):
    """安全配置管理器(带加密功能)"""
    
    def __init__(
        self,
        app_name: str,
        environment: str = "development",
        security_level: SecurityLevel = SecurityLevel.MEDIUM,
        encryption_enabled: bool = True
    ):
        super().__init__(app_name, environment, security_level)
        
        self.encryption_enabled = encryption_enabled
        self.encryptor = ConfigEncryptor() if encryption_enabled else None
        self.encrypted_values: Dict[str, Dict] = {}
    
    def _load_dict_to_section(self, section: ConfigSection, data: Dict, parent_key: str = ""):
        """重写:支持加密值的加载"""
        for key, value in data.items():
            current_key = f"{parent_key}.{key}" if parent_key else key
            
            if isinstance(value, dict):
                # 检查是否为加密值
                if self._is_encrypted_value(value):
                    # 处理加密值
                    self._handle_encrypted_value(section, key, value, current_key)
                else:
                    # 创建子节并递归加载
                    subsection = section.add_subsection(key)
                    self._load_dict_to_section(subsection, value, current_key)
            else:
                # 处理普通值
                is_sensitive = self._is_sensitive_key(current_key)
                section.add_value(key, value, is_sensitive=is_sensitive)
    
    def _is_encrypted_value(self, value_dict: Dict) -> bool:
        """判断是否为加密值"""
        return (
            isinstance(value_dict, dict) and
            'encrypted' in value_dict and
            value_dict['encrypted'] is True and
            'ciphertext' in value_dict
        )
    
    def _handle_encrypted_value(
        self,
        section: ConfigSection,
        key: str,
        value_dict: Dict,
        full_key: str
    ):
        """处理加密值"""
        if not self.encryption_enabled or not self.encryptor:
            logger.warning(f"加密功能未启用,忽略加密值: {full_key}")
            section.add_value(key, "[ENCRYPTED]", is_sensitive=True)
            return
        
        try:
            # 提取加密信息
            ciphertext = value_dict['ciphertext']
            key_id = value_dict.get('key_id', 'default')
            method = EncryptionMethod(value_dict.get('method', 'fernet'))
            
            # 解密
            plaintext = self.encryptor.decrypt(ciphertext, key_id, method)
            
            # 记录加密信息
            self.encrypted_values[full_key] = {
                'key_id': key_id,
                'method': method,
                'original_ciphertext': ciphertext
            }
            
            # 添加到配置节
            section.add_value(key, plaintext, is_sensitive=True)
            
            logger.info(f"成功解密配置值: {full_key}")
            
        except Exception as e:
            logger.error(f"解密配置值失败 {full_key}: {e}")
            
            # 安全地处理解密失败
            if self.security_level in [SecurityLevel.HIGH, SecurityLevel.CRITICAL]:
                raise
            else:
                section.add_value(key, f"[DECRYPTION_FAILED: {e}]", is_sensitive=True)
    
    def encrypt_value(
        self,
        plaintext: str,
        key_id: str = "default",
        method: EncryptionMethod = EncryptionMethod.FERNET
    ) -> Dict:
        """加密配置值"""
        if not self.encryption_enabled or not self.encryptor:
            raise RuntimeError("加密功能未启用")
        
        ciphertext = self.encryptor.encrypt(plaintext, key_id, method)
        
        return {
            'encrypted': True,
            'ciphertext': ciphertext,
            'key_id': key_id,
            'method': method.value,
            'timestamp': datetime.now().isoformat()
        }
    
    def to_encrypted_dict(self) -> Dict:
        """转换为加密字典(用于存储)"""
        config_dict = self.to_dict(mask_sensitive=False)
        
        def encrypt_sensitive_values(data: Dict, path: str = "") -> Dict:
            result = {}
            
            for key, value in data.items():
                current_path = f"{path}.{key}" if path else key
                
                if isinstance(value, dict):
                    # 递归处理字典
                    result[key] = encrypt_sensitive_values(value, current_path)
                else:
                    # 检查是否为敏感值
                    config_section = self.get_section(path if path else ".")
                    config_value = config_section._values.get(key)
                    
                    if config_value and config_value.is_sensitive:
                        # 加密敏感值
                        encrypted = self.encrypt_value(
                            str(value),
                            key_id="config_key"
                        )
                        result[key] = encrypted
                    else:
                        result[key] = value
            
            return result
        
        return encrypt_sensitive_values(config_dict)

5.3 环境感知配置加载器

"""
环境感知配置加载器
根据运行环境自动加载相应配置
"""

import sys
import platform
from pathlib import Path
from typing import Dict, Any, Optional


class EnvironmentDetector:
    """环境检测器"""
    
    @staticmethod
    def detect_environment() -> Dict[str, Any]:
        """检测运行环境"""
        
        return {
            'python_version': sys.version.split()[0],
            'platform': platform.platform(),
            'system': platform.system(),
            'node': platform.node(),
            'processor': platform.processor(),
            'is_container': EnvironmentDetector._is_container(),
            'is_ci': EnvironmentDetector._is_ci_environment(),
            'is_cloud': EnvironmentDetector._is_cloud_environment(),
        }
    
    @staticmethod
    def _is_container() -> bool:
        """判断是否在容器中运行"""
        # 检查常见的容器指示文件
        container_indicators = [
            '/.dockerenv',
            '/run/.containerenv',
            '/proc/1/cgroup'
        ]
        
        for indicator in container_indicators:
            if Path(indicator).exists():
                return True
        
        # 检查cgroup信息
        try:
            with open('/proc/1/cgroup', 'r') as f:
                content = f.read()
                if 'docker' in content or 'kubepods' in content:
                    return True
        except:
            pass
        
        return False
    
    @staticmethod
    def _is_ci_environment() -> bool:
        """判断是否在CI环境中运行"""
        ci_vars = [
            'CI',
            'CONTINUOUS_INTEGRATION',
            'JENKINS_HOME',
            'GITLAB_CI',
            'TRAVIS',
            'CIRCLECI',
            'GITHUB_ACTIONS',
            'BITBUCKET_BUILD_NUMBER'
        ]
        
        for var in ci_vars:
            if os.environ.get(var):
                return True
        
        return False
    
    @staticmethod
    def _is_cloud_environment() -> Optional[str]:
        """判断是否在云环境中运行"""
        # AWS检测
        if Path('/sys/hypervisor/uuid').exists():
            try:
                with open('/sys/hypervisor/uuid', 'r') as f:
                    if f.read(3).lower() == 'ec2':
                        return 'aws'
            except:
                pass
        
        # Azure检测
        if Path('/sys/class/dmi/id/sys_vendor').exists():
            try:
                with open('/sys/class/dmi/id/sys_vendor', 'r') as f:
                    if 'microsoft' in f.read().lower():
                        return 'azure'
            except:
                pass
        
        # GCP检测
        try:
            import urllib.request
            import urllib.error
            
            req = urllib.request.Request(
                'http://metadata.google.internal/computeMetadata/v1/',
                headers={'Metadata-Flavor': 'Google'}
            )
            
            try:
                urllib.request.urlopen(req, timeout=1)
                return 'gcp'
            except urllib.error.URLError:
                pass
        except:
            pass
        
        return None


class EnvironmentAwareConfigLoader:
    """环境感知配置加载器"""
    
    def __init__(
        self,
        base_config_dir: Union[str, Path],
        app_name: str,
        default_env: str = "development"
    ):
        self.base_config_dir = Path(base_config_dir)
        self.app_name = app_name
        self.default_env = default_env
        
        # 环境检测
        self.environment_info = EnvironmentDetector.detect_environment()
        self.current_environment = self._determine_environment()
        
        logger.info(f"检测到环境: {self.current_environment}")
        logger.info(f"环境信息: {self.environment_info}")
    
    def _determine_environment(self) -> str:
        """确定当前环境"""
        
        # 1. 检查环境变量
        env_var = os.environ.get('APP_ENV') or os.environ.get('ENVIRONMENT')
        if env_var:
            return env_var.lower()
        
        # 2. 根据环境特征判断
        if self.environment_info['is_ci']:
            return 'ci'
        
        cloud_env = self.environment_info['is_cloud']
        if cloud_env:
            if cloud_env == 'aws':
                # 尝试从EC2标签获取环境
                return self._get_aws_environment() or 'production'
            elif cloud_env == 'azure':
                return 'production'
            elif cloud_env == 'gcp':
                return 'production'
        
        # 3. 根据主机名模式判断
        hostname = platform.node().lower()
        if 'prod' in hostname or 'production' in hostname:
            return 'production'
        elif 'stag' in hostname or 'staging' in hostname:
            return 'staging'
        elif 'test' in hostname or 'testing' in hostname:
            return 'testing'
        elif 'dev' in hostname or 'development' in hostname:
            return 'development'
        
        # 4. 默认环境
        return self.default_env
    
    def _get_aws_environment(self) -> Optional[str]:
        """从AWS元数据获取环境信息"""
        # 这里可以扩展为从EC2标签或实例元数据获取环境信息
        # 简化实现:检查实例标签
        try:
            import urllib.request
            
            # 尝试获取实例标签
            req = urllib.request.Request(
                'http://169.254.169.254/latest/meta-data/tags/instance/Environment',
                timeout=1
            )
            
            with urllib.request.urlopen(req) as response:
                env_tag = response.read().decode('utf-8').strip().lower()
                if env_tag:
                    return env_tag
        except:
            pass
        
        return None
    
    def get_config_files(self) -> List[Path]:
        """获取应加载的配置文件列表"""
        
        config_files = []
        
        # 基础配置文件
        base_files = [
            self.base_config_dir / 'config.yaml',
            self.base_config_dir / 'config.json',
            self.base_config_dir / 'config.toml',
        ]
        
        # 环境特定配置文件
        env_files = [
            self.base_config_dir / f'config.{self.current_environment}.yaml',
            self.base_config_dir / f'config.{self.current_environment}.json',
            self.base_config_dir / f'config.{self.current_environment}.toml',
        ]
        
        # 本地覆盖文件(仅开发环境)
        local_files = [
            self.base_config_dir / 'config.local.yaml',
            self.base_config_dir / 'config.local.json',
            self.base_config_dir / 'config.local.toml',
        ]
        
        # 收集存在的文件
        for file_list in [base_files, env_files]:
            for file_path in file_list:
                if file_path.exists():
                    config_files.append(file_path)
        
        # 本地文件只在非生产环境加载
        if self.current_environment != 'production':
            for file_path in local_files:
                if file_path.exists():
                    config_files.append(file_path)
        
        logger.info(f"找到配置文件: {[f.name for f in config_files]}")
        return config_files
    
    def load_configuration(self) -> Dict[str, Any]:
        """加载所有配置"""
        
        config_data = {}
        config_files = self.get_config_files()
        
        for config_file in config_files:
            try:
                file_config = self._load_config_file(config_file)
                
                # 深度合并配置
                config_data = self._deep_merge(config_data, file_config)
                
                logger.info(f"加载配置文件: {config_file.name}")
                
            except Exception as e:
                logger.error(f"加载配置文件失败 {config_file}: {e}")
        
        # 添加环境信息
        config_data['environment'] = {
            'name': self.current_environment,
            'info': self.environment_info
        }
        
        return config_data
    
    def _load_config_file(self, file_path: Path) -> Dict:
        """加载单个配置文件"""
        
        suffix = file_path.suffix.lower()
        
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        if suffix == '.json':
            return json.loads(content)
        elif suffix in ['.yaml', '.yml']:
            return yaml.safe_load(content)
        elif suffix == '.toml':
            return tomllib.loads(content)
        else:
            raise ValueError(f"不支持的配置文件格式: {suffix}")
    
    def _deep_merge(self, dict1: Dict, dict2: Dict) -> Dict:
        """深度合并两个字典"""
        result = dict1.copy()
        
        for key, value in dict2.items():
            if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                result[key] = self._deep_merge(result[key], value)
            else:
                result[key] = value
        
        return result

5.4 完整的配置管理系统

"""
完整的配置管理系统
集成配置加载、加密、环境感知和验证
"""

class CompleteConfigSystem:
    """完整的配置系统"""
    
    def __init__(
        self,
        app_name: str,
        config_base_dir: Union[str, Path] = "config",
        security_level: SecurityLevel = SecurityLevel.MEDIUM,
        enable_encryption: bool = True
    ):
        self.app_name = app_name
        self.config_base_dir = Path(config_base_dir)
        self.security_level = security_level
        
        # 创建必要的目录
        self._create_directories()
        
        # 初始化组件
        self.env_loader = EnvironmentAwareConfigLoader(
            self.config_base_dir,
            app_name
        )
        
        self.secure_config_manager = SecureConfigManager(
            app_name=app_name,
            environment=self.env_loader.current_environment,
            security_level=security_level,
            encryption_enabled=enable_encryption
        )
        
        # 加载配置
        self._load_all_configurations()
    
    def _create_directories(self):
        """创建配置目录结构"""
        directories = [
            self.config_base_dir,
            self.config_base_dir / 'secrets',
            self.config_base_dir / 'environments',
            self.config_base_dir / 'templates',
        ]
        
        for directory in directories:
            directory.mkdir(parents=True, exist_ok=True)
    
    def _load_all_configurations(self):
        """加载所有配置"""
        
        # 1. 从环境变量加载
        self.secure_config_manager.add_config_source(
            ConfigSource.ENV_VAR,
            f"{self.app_name.upper()}_",
            priority=100  # 最高优先级
        )
        
        # 2. 从文件加载
        config_files = self.env_loader.get_config_files()
        for config_file in config_files:
            self.secure_config_manager.add_config_source(
                ConfigSource.FILE,
                config_file,
                priority=50
            )
        
        # 3. 加载密钥文件
        secrets_dir = self.config_base_dir / 'secrets'
        if secrets_dir.exists():
            for secrets_file in secrets_dir.glob('*.yaml'):
                self.secure_config_manager.add_config_source(
                    ConfigSource.FILE,
                    secrets_file,
                    priority=75  # 较高优先级
                )
        
        # 4. 加载配置
        self.secure_config_manager.load_configuration()
        
        logger.info(f"配置加载完成,共加载 {len(config_files)} 个配置文件")
    
    def get(self, key: str, default: Any = None) -> Any:
        """获取配置值"""
        return self.secure_config_manager.get(key, default)
    
    def get_section(self, section: str) -> ConfigSection:
        """获取配置节"""
        return self.secure_config_manager.get_section(section)
    
    def validate(self) -> Dict[str, Any]:
        """验证配置"""
        validation_results = self.secure_config_manager.validate_configuration()
        
        # 额外的验证逻辑
        warnings = []
        errors = []
        
        # 检查必需配置
        required_configs = self._get_required_configs()
        for config_key in required_configs:
            if not self.get(config_key):
                errors.append(f"必需配置缺失: {config_key}")
        
        # 检查敏感配置是否加密
        if self.secure_config_manager.encryption_enabled:
            unencrypted_sensitive = self._find_unencrypted_sensitive()
            if unencrypted_sensitive:
                warnings.append(f"发现未加密的敏感配置: {unencrypted_sensitive}")
        
        return {
            'valid': len(errors) == 0,
            'validation_results': validation_results,
            'errors': errors,
            'warnings': warnings,
            'environment': self.env_loader.current_environment,
            'config_count': self.secure_config_manager._count_total_values(
                self.secure_config_manager.root_section
            )
        }
    
    def _get_required_configs(self) -> List[str]:
        """获取必需配置列表"""
        # 这里可以根据应用需求定义必需配置
        # 例如从配置文件或注解中读取
        return [
            'database.host',
            'database.port',
            'app.secret_key'
        ]
    
    def _find_unencrypted_sensitive(self) -> List[str]:
        """查找未加密的敏感配置"""
        unencrypted = []
        
        def traverse_section(section: ConfigSection, path: str = ""):
            for key, config_value in section._values.items():
                current_path = f"{path}.{key}" if path else key
                
                if config_value.is_sensitive:
                    # 检查是否在加密值记录中
                    if current_path not in self.secure_config_manager.encrypted_values:
                        unencrypted.append(current_path)
            
            for sub_name, subsection in section._subsections.items():
                sub_path = f"{path}.{sub_name}" if path else sub_name
                traverse_section(subsection, sub_path)
        
        traverse_section(self.secure_config_manager.root_section)
        return unencrypted
    
    def generate_config_template(self) -> Dict:
        """生成配置模板"""
        
        template = {
            'app': {
                'name': self.app_name,
                'environment': self.env_loader.current_environment,
                'debug': {
                    'description': '调试模式',
                    'type': 'bool',
                    'default': False,
                    'sensitive': False
                },
                'secret_key': {
                    'description': '应用密钥',
                    'type': 'string',
                    'sensitive': True,
                    'encrypted': True
                }
            },
            'database': {
                'host': {
                    'description': '数据库主机',
                    'type': 'string',
                    'default': 'localhost'
                },
                'port': {
                    'description': '数据库端口',
                    'type': 'int',
                    'default': 5432
                },
                'username': {
                    'description': '数据库用户名',
                    'type': 'string',
                    'sensitive': True
                },
                'password': {
                    'description': '数据库密码',
                    'type': 'string',
                    'sensitive': True,
                    'encrypted': True
                }
            },
            'api': {
                'timeout': {
                    'description': 'API超时时间(秒)',
                    'type': 'int',
                    'default': 30
                },
                'retries': {
                    'description': '重试次数',
                    'type': 'int',
                    'default': 3
                }
            }
        }
        
        return template
    
    def export_config(self, format: ConfigFormat = ConfigFormat.YAML) -> str:
        """导出配置"""
        
        config_dict = self.secure_config_manager.to_dict(mask_sensitive=True)
        
        if format == ConfigFormat.JSON:
            return json.dumps(config_dict, indent=2, ensure_ascii=False)
        elif format == ConfigFormat.YAML:
            return yaml.dump(config_dict, default_flow_style=False, allow_unicode=True)
        elif format == ConfigFormat.TOML:
            import toml
            return toml.dumps(config_dict)
        else:
            raise ValueError(f"不支持的导出格式: {format}")
    
    def generate_security_report(self) -> Dict:
        """生成安全报告"""
        
        config_report = self.secure_config_manager.generate_config_report()
        validation_results = self.validate()
        
        return {
            'application': {
                'name': self.app_name,
                'environment': self.env_loader.current_environment,
                'security_level': self.security_level.value
            },
            'config_summary': {
                'total_config_values': config_report['total_values_count'],
                'sensitive_values': config_report['sensitive_values_count'],
                'sensitive_percentage': (
                    config_report['sensitive_values_count'] / 
                    max(config_report['total_values_count'], 1) * 100
                )
            },
            'encryption_status': {
                'enabled': self.secure_config_manager.encryption_enabled,
                'encrypted_values_count': len(self.secure_config_manager.encrypted_values),
                'unencrypted_sensitive': self._find_unencrypted_sensitive()
            },
            'validation': validation_results,
            'environment_info': self.env_loader.environment_info,
            'recommendations': self._generate_security_recommendations()
        }
    
    def _generate_security_recommendations(self) -> List[str]:
        """生成安全建议"""
        recommendations = []
        
        # 检查安全级别
        if self.security_level != SecurityLevel.CRITICAL:
            recommendations.append("考虑提高安全级别到CRITICAL")
        
        # 检查加密状态
        if not self.secure_config_manager.encryption_enabled:
            recommendations.append("启用配置加密功能")
        
        # 检查敏感配置数量
        config_report = self.secure_config_manager.generate_config_report()
        sensitive_count = config_report['sensitive_values_count']
        
        if sensitive_count == 0:
            recommendations.append("未发现敏感配置,请检查配置定义")
        elif sensitive_count > 10:
            recommendations.append(f"发现{sensitive_count}个敏感配置,建议使用密钥管理服务")
        
        # 检查环境
        if self.env_loader.current_environment == 'production':
            if not self.secure_config_manager.encryption_enabled:
                recommendations.append("生产环境必须启用配置加密")
        
        return recommendations


# 使用示例
def example_usage():
    """使用示例"""
    
    # 创建配置系统
    config_system = CompleteConfigSystem(
        app_name="MyApp",
        config_base_dir="./config",
        security_level=SecurityLevel.HIGH,
        enable_encryption=True
    )
    
    # 获取配置值
    db_host = config_system.get("database.host", "localhost")
    db_port = config_system.get("database.port", 5432)
    
    print(f"数据库连接: {db_host}:{db_port}")
    
    # 获取配置节
    database_section = config_system.get_section("database")
    print(f"数据库配置: {database_section.to_dict()}")
    
    # 验证配置
    validation = config_system.validate()
    print(f"配置验证: {'通过' if validation['valid'] else '失败'}")
    
    if not validation['valid']:
        print(f"错误: {validation['errors']}")
    
    # 生成安全报告
    security_report = config_system.generate_security_report()
    print(f"安全报告生成完成")
    
    # 导出配置
    yaml_config = config_system.export_config(ConfigFormat.YAML)
    print(f"YAML配置导出完成,长度: {len(yaml_config)} 字符")
    
    return config_system


if __name__ == "__main__":
    # 运行示例
    example_usage()

6. 敏感信息保护最佳实践

6.1 密钥管理最佳实践

6.1.1 密钥存储策略
class KeyStorageStrategy:
    """密钥存储策略"""
    
    STRATEGIES = {
        'local_file': {
            'security': 'low',
            'complexity': 'low',
            'recommended_for': ['development', 'testing']
        },
        'encrypted_file': {
            'security': 'medium',
            'complexity': 'medium',
            'recommended_for': ['staging', 'pre-production']
        },
        'hardware_module': {
            'security': 'high',
            'complexity': 'high',
            'recommended_for': ['production', 'critical']
        },
        'cloud_kms': {
            'security': 'high',
            'complexity': 'medium',
            'recommended_for': ['production', 'cloud']
        }
    }
    
    @classmethod
    def recommend_strategy(
        cls,
        environment: str,
        security_requirements: str
    ) -> str:
        """推荐密钥存储策略"""
        
        recommendations = []
        
        for strategy, info in cls.STRATEGIES.items():
            if environment in info['recommended_for']:
                # 计算匹配分数
                score = 0
                
                if security_requirements == 'high' and info['security'] == 'high':
                    score += 3
                elif security_requirements == 'medium' and info['security'] in ['medium', 'high']:
                    score += 2
                else:
                    score += 1
                
                recommendations.append((strategy, score, info))
        
        # 按分数排序
        recommendations.sort(key=lambda x: x[1], reverse=True)
        
        return recommendations[0][0] if recommendations else 'encrypted_file'
6.1.2 密钥轮换自动化
class KeyRotationAutomator:
    """密钥轮换自动化"""
    
    def __init__(self, rotation_policy: Dict):
        self.rotation_policy = rotation_policy
        self.key_versions = {}  # key_id -> List[KeyVersion]
    
    def schedule_rotation(self, key_id: str, key_type: str):
        """安排密钥轮换"""
        
        policy = self.rotation_policy.get(key_type, {})
        rotation_interval = policy.get('interval_days', 90)
        grace_period = policy.get('grace_period_days', 7)
        
        # 计算轮换时间
        next_rotation = datetime.now() + timedelta(days=rotation_interval)
        
        logger.info(
            f"安排密钥轮换: {key_id}, "
            f"下次轮换: {next_rotation}, "
            f"宽限期: {grace_period}天"
        )
        
        return {
            'key_id': key_id,
            'next_rotation': next_rotation,
            'grace_period': grace_period,
            'action_required': next_rotation - timedelta(days=grace_period) <= datetime.now()
        }
    
    def rotate_key(self, key_id: str, new_key: bytes) -> bool:
        """执行密钥轮换"""
        
        try:
            # 记录旧密钥版本
            if key_id in self.key_versions:
                old_versions = self.key_versions[key_id]
                
                # 保留最近2个版本用于解密旧数据
                if len(old_versions) >= 2:
                    old_versions.pop(0)
            else:
                self.key_versions[key_id] = []
            
            # 添加新版本
            key_version = {
                'key': new_key,
                'created_at': datetime.now(),
                'version': len(self.key_versions[key_id]) + 1,
                'active': True
            }
            
            self.key_versions[key_id].append(key_version)
            
            logger.info(f"密钥轮换完成: {key_id}, 版本: {key_version['version']}")
            
            return True
            
        except Exception as e:
            logger.error(f"密钥轮换失败 {key_id}: {e}")
            return False
    
    def get_active_key(self, key_id: str) -> Optional[bytes]:
        """获取当前激活的密钥"""
        
        if key_id not in self.key_versions:
            return None
        
        versions = self.key_versions[key_id]
        
        # 返回最新的激活密钥
        for version in reversed(versions):
            if version['active']:
                return version['key']
        
        return None

6.2 敏感信息检测与防护

6.2.1 敏感信息扫描器
class SensitiveDataScanner:
    """敏感信息扫描器"""
    
    # 敏感信息模式
    PATTERNS = {
        'api_key': r'(?i)(api[_-]?key|access[_-]?token)[\s]*[=:][\s]*[\'"]([a-zA-Z0-9]{20,})[\'"]',
        'password': r'(?i)(password|passwd|pwd)[\s]*[=:][\s]*[\'"]([^\'"\s]{6,})[\'"]',
        'secret_key': r'(?i)(secret[_-]?key)[\s]*[=:][\s]*[\'"]([a-zA-Z0-9]{16,})[\'"]',
        'jwt_token': r'eyJ[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}',
        'aws_key': r'(?i)AKIA[0-9A-Z]{16}',
        'private_key': r'-----BEGIN (RSA|DSA|EC|OPENSSH) PRIVATE KEY-----',
        'database_url': r'(?i)(mysql|postgresql|mongodb)://[^\s"\']+',
        'email': r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
        'credit_card': r'\b(?:\d[ -]*?){13,16}\b',
        'phone': r'(\+?\d{1,3}[-.]?)?\(?\d{3}\)?[-.]?\d{3}[-.]?\d{4}',
    }
    
    def __init__(self, confidence_threshold: float = 0.7):
        self.confidence_threshold = confidence_threshold
        self.compiled_patterns = {
            name: re.compile(pattern) 
            for name, pattern in self.PATTERNS.items()
        }
    
    def scan_file(self, file_path: Union[str, Path]) -> List[Dict]:
        """扫描文件中的敏感信息"""
        
        file_path = Path(file_path)
        if not file_path.exists():
            return []
        
        findings = []
        
        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                content = f.read()
                
                # 逐行扫描
                lines = content.split('\n')
                for line_num, line in enumerate(lines, 1):
                    for pattern_name, pattern in self.compiled_patterns.items():
                        matches = pattern.finditer(line)
                        
                        for match in matches:
                            # 计算置信度
                            confidence = self._calculate_confidence(
                                pattern_name, match.group(), line
                            )
                            
                            if confidence >= self.confidence_threshold:
                                finding = {
                                    'file': str(file_path),
                                    'line': line_num,
                                    'type': pattern_name,
                                    'match': match.group(),
                                    'confidence': confidence,
                                    'context': self._get_context(lines, line_num),
                                    'severity': self._get_severity(pattern_name)
                                }
                                
                                findings.append(finding)
            
        except Exception as e:
            logger.error(f"扫描文件失败 {file_path}: {e}")
        
        return findings
    
    def _calculate_confidence(
        self, 
        pattern_type: str, 
        match: str, 
        line: str
    ) -> float:
        """计算匹配置信度"""
        
        base_confidence = 0.5
        
        # 根据模式类型调整
        if pattern_type in ['api_key', 'aws_key', 'private_key']:
            base_confidence = 0.9
        elif pattern_type in ['password', 'secret_key']:
            base_confidence = 0.8
        elif pattern_type == 'jwt_token':
            base_confidence = 0.95
        
        # 根据上下文调整
        context_indicators = [
            ('secret', 0.2),
            ('key', 0.1),
            ('password', 0.15),
            ('token', 0.1),
            ('credential', 0.15),
        ]
        
        line_lower = line.lower()
        for indicator, boost in context_indicators:
            if indicator in line_lower:
                base_confidence += boost
        
        return min(base_confidence, 1.0)
    
    def _get_context(self, lines: List[str], line_num: int, context_lines: int = 2) -> str:
        """获取上下文"""
        start = max(0, line_num - context_lines - 1)
        end = min(len(lines), line_num + context_lines)
        
        context_lines_list = lines[start:end]
        
        # 添加行号
        numbered_context = []
        for i, line in enumerate(context_lines_list, start + 1):
            prefix = '>>>' if i == line_num else '   '
            numbered_context.append(f"{prefix}{i:4}: {line}")
        
        return '\n'.join(numbered_context)
    
    def _get_severity(self, pattern_type: str) -> str:
        """获取严重级别"""
        
        severity_map = {
            'api_key': 'high',
            'aws_key': 'critical',
            'private_key': 'critical',
            'password': 'high',
            'secret_key': 'high',
            'jwt_token': 'medium',
            'database_url': 'medium',
            'email': 'low',
            'credit_card': 'high',
            'phone': 'low'
        }
        
        return severity_map.get(pattern_type, 'medium')
    
    def scan_directory(
        self, 
        directory: Union[str, Path], 
        extensions: Optional[List[str]] = None
    ) -> Dict[str, List]:
        """扫描目录中的敏感信息"""
        
        directory = Path(directory)
        if not directory.exists():
            return {}
        
        default_extensions = [
            '.py', '.js', '.ts', '.java', '.go', 
            '.yaml', '.yml', '.json', '.toml',
            '.env', '.properties', '.cfg', '.ini'
        ]
        
        extensions = extensions or default_extensions
        
        all_findings = {}
        
        for ext in extensions:
            pattern = f'**/*{ext}'
            
            for file_path in directory.glob(pattern):
                if file_path.is_file():
                    findings = self.scan_file(file_path)
                    
                    if findings:
                        all_findings[str(file_path)] = findings
        
        return all_findings
    
    def generate_report(self, findings: Dict[str, List]) -> Dict:
        """生成扫描报告"""
        
        total_findings = sum(len(f) for f in findings.values())
        
        # 按类型统计
        by_type = {}
        by_severity = {
            'critical': 0,
            'high': 0,
            'medium': 0,
            'low': 0
        }
        
        for file_findings in findings.values():
            for finding in file_findings:
                # 按类型统计
                finding_type = finding['type']
                by_type[finding_type] = by_type.get(finding_type, 0) + 1
                
                # 按严重级别统计
                severity = finding['severity']
                by_severity[severity] += 1
        
        return {
            'scan_summary': {
                'total_files_scanned': len(findings),
                'total_findings': total_findings,
                'findings_by_type': by_type,
                'findings_by_severity': by_severity,
                'critical_issues': by_severity['critical'],
                'high_issues': by_severity['high']
            },
            'detailed_findings': findings,
            'recommendations': self._generate_recommendations(by_severity)
        }
    
    def _generate_recommendations(self, by_severity: Dict) -> List[str]:
        """生成建议"""
        
        recommendations = []
        
        if by_severity['critical'] > 0:
            recommendations.append(
                "发现关键级别问题,需要立即处理"
            )
        
        if by_severity['high'] > 3:
            recommendations.append(
                f"发现{by_severity['high']}个高优先级问题,建议本周内解决"
            )
        
        if by_severity['medium'] > 10:
            recommendations.append(
                f"发现{by_severity['medium']}个中优先级问题,建议本月内解决"
            )
        
        # 通用建议
        recommendations.extend([
            "将敏感信息移出代码库,使用环境变量或配置服务",
            "对配置文件中的敏感信息进行加密",
            "定期运行敏感信息扫描",
            "在CI/CD流水线中加入敏感信息检查"
        ])
        
        return recommendations

7. 集成与部署

7.1 CI/CD集成

class CICDIntegrator:
    """CI/CD集成器"""
    
    def __init__(self, config_system: CompleteConfigSystem):
        self.config_system = config_system
    
    def pre_deployment_check(self) -> Dict:
        """部署前检查"""
        
        checks = {
            'config_validation': self._check_config_validation(),
            'sensitive_data': self._check_sensitive_data(),
            'security_level': self._check_security_level(),
            'environment': self._check_environment(),
            'dependencies': self._check_dependencies()
        }
        
        # 汇总结果
        all_passed = all(check['passed'] for check in checks.values())
        
        return {
            'passed': all_passed,
            'checks': checks,
            'recommendations': self._generate_deployment_recommendations(checks)
        }
    
    def _check_config_validation(self) -> Dict:
        """检查配置验证"""
        validation = self.config_system.validate()
        
        return {
            'passed': validation['valid'],
            'details': validation,
            'message': '配置验证' + ('通过' if validation['valid'] else '失败')
        }
    
    def _check_sensitive_data(self) -> Dict:
        """检查敏感数据"""
        # 运行敏感信息扫描
        scanner = SensitiveDataScanner()
        
        # 扫描配置目录
        config_dir = self.config_system.config_base_dir
        findings = scanner.scan_directory(config_dir)
        
        report = scanner.generate_report(findings)
        
        critical_issues = report['scan_summary']['critical_issues']
        high_issues = report['scan_summary']['high_issues']
        
        passed = (critical_issues == 0 and high_issues == 0)
        
        return {
            'passed': passed,
            'details': report,
            'message': f"敏感数据检查: 关键{critical_issues}个, 高{high_issues}个"
        }
    
    def _check_security_level(self) -> Dict:
        """检查安全级别"""
        current_level = self.config_system.security_level
        
        # 根据环境要求安全级别
        env_requirements = {
            'production': SecurityLevel.CRITICAL,
            'staging': SecurityLevel.HIGH,
            'testing': SecurityLevel.MEDIUM,
            'development': SecurityLevel.LOW
        }
        
        env = self.config_system.env_loader.current_environment
        required_level = env_requirements.get(env, SecurityLevel.MEDIUM)
        
        # 检查是否满足要求
        level_order = {
            SecurityLevel.LOW: 1,
            SecurityLevel.MEDIUM: 2,
            SecurityLevel.HIGH: 3,
            SecurityLevel.CRITICAL: 4
        }
        
        passed = level_order[current_level] >= level_order[required_level]
        
        return {
            'passed': passed,
            'details': {
                'current': current_level.value,
                'required': required_level.value,
                'environment': env
            },
            'message': f"安全级别: {current_level.value} (要求: {required_level.value})"
        }
    
    def _check_environment(self) -> Dict:
        """检查环境"""
        env = self.config_system.env_loader.current_environment
        
        # 检查环境特定配置
        required_configs = {
            'production': ['app.secret_key', 'database.password'],
            'staging': ['app.secret_key', 'database.password'],
            'testing': ['database.host'],
            'development': ['database.host']
        }
        
        missing_configs = []
        required = required_configs.get(env, [])
        
        for config_key in required:
            if not self.config_system.get(config_key):
                missing_configs.append(config_key)
        
        passed = len(missing_configs) == 0
        
        return {
            'passed': passed,
            'details': {
                'environment': env,
                'missing_configs': missing_configs
            },
            'message': f"环境检查: {env}" + 
                      (f", 缺失配置: {missing_configs}" if missing_configs else "")
        }
    
    def _check_dependencies(self) -> Dict:
        """检查依赖"""
        # 这里可以检查配置系统依赖的其他服务
        # 例如:密钥管理服务、配置服务器等
        
        return {
            'passed': True,
            'details': {},
            'message': '依赖检查通过'
        }
    
    def _generate_deployment_recommendations(self, checks: Dict) -> List[str]:
        """生成部署建议"""
        
        recommendations = []
        
        for check_name, check_result in checks.items():
            if not check_result['passed']:
                recommendations.append(
                    f"检查失败: {check_result['message']}"
                )
        
        # 如果所有检查都通过,给出确认建议
        if all(check['passed'] for check in checks.values()):
            recommendations.append("所有检查通过,可以安全部署")
        
        return recommendations
    
    def generate_deployment_report(self) -> Dict:
        """生成部署报告"""
        
        pre_check = self.pre_deployment_check()
        security_report = self.config_system.generate_security_report()
        
        return {
            'timestamp': datetime.now().isoformat(),
            'application': self.config_system.app_name,
            'environment': self.config_system.env_loader.current_environment,
            'pre_deployment_check': pre_check,
            'security_report': security_report,
            'deployment_decision': self._make_deployment_decision(pre_check)
        }
    
    def _make_deployment_decision(self, pre_check: Dict) -> Dict:
        """做出部署决策"""
        
        if not pre_check['passed']:
            return {
                'approved': False,
                'reason': '预部署检查失败',
                'action': '修复问题后重试'
            }
        
        # 检查是否有关键问题
        sensitive_check = pre_check['checks']['sensitive_data']
        if sensitive_check['details']['scan_summary']['critical_issues'] > 0:
            return {
                'approved': False,
                'reason': '发现关键敏感信息问题',
                'action': '立即修复'
            }
        
        # 环境特定决策
        env = self.config_system.env_loader.current_environment
        
        if env == 'production':
            # 生产环境更严格
            high_issues = sensitive_check['details']['scan_summary']['high_issues']
            
            if high_issues > 0:
                return {
                    'approved': False,
                    'reason': f'生产环境发现{high_issues}个高优先级问题',
                    'action': '修复后重新检查'
                }
        
        return {
            'approved': True,
            'reason': '所有检查通过',
            'action': '可以部署',
            'notes': '建议在低峰期部署'
        }

7.2 监控与告警

class ConfigMonitoringSystem:
    """配置监控系统"""
    
    def __init__(self, config_system: CompleteConfigSystem):
        self.config_system = config_system
        self.metrics = {
            'config_changes': [],
            'sensitive_access': [],
            'validation_errors': []
        }
        self.alerts = []
    
    def track_config_change(
        self,
        key: str,
        old_value: Any,
        new_value: Any,
        user: str,
        reason: str
    ):
        """跟踪配置变更"""
        
        change_record = {
            'timestamp': datetime.now(),
            'key': key,
            'old_value': self._mask_sensitive_value(key, old_value),
            'new_value': self._mask_sensitive_value(key, new_value),
            'user': user,
            'reason': reason,
            'environment': self.config_system.env_loader.current_environment
        }
        
        self.metrics['config_changes'].append(change_record)
        
        # 检查是否需要告警
        self._check_change_for_alerts(change_record)
        
        logger.info(f"配置变更记录: {key} by {user}")
    
    def track_sensitive_access(self, key: str, user: str, purpose: str):
        """跟踪敏感信息访问"""
        
        access_record = {
            'timestamp': datetime.now(),
            'key': key,
            'user': user,
            'purpose': purpose,
            'environment': self.config_system.env_loader.current_environment
        }
        
        self.metrics['sensitive_access'].append(access_record)
        
        # 检查异常访问
        self._check_access_for_alerts(access_record)
    
    def _mask_sensitive_value(self, key: str, value: Any) -> Any:
        """脱敏敏感值"""
        
        # 检查是否为敏感键
        if any(sensitive in key.lower() 
               for sensitive in ['password', 'secret', 'key', 'token']):
            return '[MASKED]'
        
        return value
    
    def _check_change_for_alerts(self, change_record: Dict):
        """检查配置变更是否需要告警"""
        
        alerts_rules = [
            {
                'condition': lambda r: 'password' in r['key'].lower(),
                'severity': 'high',
                'message': '密码配置变更'
            },
            {
                'condition': lambda r: 'secret' in r['key'].lower(),
                'severity': 'high',
                'message': '密钥配置变更'
            },
            {
                'condition': lambda r: 'production' in r['environment'] and 
                                      r['user'] != 'deployment_system',
                'severity': 'critical',
                'message': '生产环境手动配置变更'
            }
        ]
        
        for rule in alerts_rules:
            if rule['condition'](change_record):
                alert = {
                    'type': 'config_change',
                    'severity': rule['severity'],
                    'message': rule['message'],
                    'details': change_record,
                    'timestamp': datetime.now()
                }
                
                self.alerts.append(alert)
                self._send_alert(alert)
    
    def _check_access_for_alerts(self, access_record: Dict):
        """检查敏感信息访问是否需要告警"""
        
        # 计算访问频率
        recent_access = [
            r for r in self.metrics['sensitive_access']
            if (datetime.now() - r['timestamp']).total_seconds() < 300  # 5分钟内
        ]
        
        if len(recent_access) > 10:  # 5分钟内超过10次访问
            alert = {
                'type': 'sensitive_access_frequency',
                'severity': 'high',
                'message': '敏感信息访问频率异常',
                'details': {
                    'access_count': len(recent_access),
                    'time_window': '5分钟',
                    'user': access_record['user']
                },
                'timestamp': datetime.now()
            }
            
            self.alerts.append(alert)
            self._send_alert(alert)
    
    def _send_alert(self, alert: Dict):
        """发送告警"""
        
        # 这里可以实现告警发送逻辑
        # 例如:发送到Slack、邮件、短信等
        
        logger.warning(
            f"配置告警 [{alert['severity'].upper()}]: {alert['message']}"
        )
        
        # 简化的告警发送
        if alert['severity'] == 'critical':
            # 发送紧急告警
            print(f"!!! 紧急告警: {alert['message']}")
        elif alert['severity'] == 'high':
            # 发送高优先级告警
            print(f"!! 高优先级告警: {alert['message']}")
    
    def generate_monitoring_report(
        self, 
        time_range_hours: int = 24
    ) -> Dict:
        """生成监控报告"""
        
        cutoff_time = datetime.now() - timedelta(hours=time_range_hours)
        
        # 过滤时间范围内的数据
        recent_changes = [
            c for c in self.metrics['config_changes']
            if c['timestamp'] > cutoff_time
        ]
        
        recent_access = [
            a for a in self.metrics['sensitive_access']
            if a['timestamp'] > cutoff_time
        ]
        
        recent_alerts = [
            a for a in self.alerts
            if a['timestamp'] > cutoff_time
        ]
        
        return {
            'time_range': f"最近{time_range_hours}小时",
            'config_changes': {
                'total': len(recent_changes),
                'by_user': self._group_by_user(recent_changes),
                'by_environment': self._group_by_environment(recent_changes)
            },
            'sensitive_access': {
                'total': len(recent_access),
                'top_keys': self._get_top_keys(recent_access, 5),
                'by_user': self._group_by_user(recent_access)
            },
            'alerts': {
                'total': len(recent_alerts),
                'by_severity': self._group_by_severity(recent_alerts),
                'recent_alerts': recent_alerts[-10:]  # 最近10个告警
            },
            'recommendations': self._generate_monitoring_recommendations(
                recent_changes, recent_access, recent_alerts
            )
        }
    
    def _group_by_user(self, records: List[Dict]) -> Dict:
        """按用户分组"""
        groups = {}
        
        for record in records:
            user = record.get('user', 'unknown')
            groups[user] = groups.get(user, 0) + 1
        
        return groups
    
    def _group_by_environment(self, records: List[Dict]) -> Dict:
        """按环境分组"""
        groups = {}
        
        for record in records:
            env = record.get('environment', 'unknown')
            groups[env] = groups.get(env, 0) + 1
        
        return groups
    
    def _get_top_keys(self, records: List[Dict], top_n: int) -> List[Dict]:
        """获取最常访问的键"""
        key_counts = {}
        
        for record in records:
            key = record.get('key', 'unknown')
            key_counts[key] = key_counts.get(key, 0) + 1
        
        sorted_keys = sorted(
            key_counts.items(), 
            key=lambda x: x[1], 
            reverse=True
        )[:top_n]
        
        return [{'key': k, 'count': v} for k, v in sorted_keys]
    
    def _group_by_severity(self, alerts: List[Dict]) -> Dict:
        """按严重级别分组"""
        groups = {
            'critical': 0,
            'high': 0,
            'medium': 0,
            'low': 0
        }
        
        for alert in alerts:
            severity = alert.get('severity', 'medium')
            groups[severity] = groups.get(severity, 0) + 1
        
        return groups
    
    def _generate_monitoring_recommendations(
        self,
        changes: List[Dict],
        access: List[Dict],
        alerts: List[Dict]
    ) -> List[str]:
        """生成监控建议"""
        
        recommendations = []
        
        # 分析配置变更
        if len(changes) > 20:
            recommendations.append(
                f"配置变更频繁({len(changes)}次),建议审查变更流程"
            )
        
        # 分析敏感信息访问
        if len(access) > 100:
            recommendations.append(
                f"敏感信息访问频繁({len(access)}次),建议优化访问模式"
            )
        
        # 分析告警
        critical_alerts = [a for a in alerts if a['severity'] == 'critical']
        if critical_alerts:
            recommendations.append(
                f"发现{len(critical_alerts)}个关键告警,需要立即处理"
            )
        
        # 通用建议
        if not recommendations:
            recommendations.append("监控状态正常,继续保持")
        
        recommendations.extend([
            "定期审查配置变更日志",
            "设置敏感信息访问阈值告警",
            "定期进行配置安全审计"
        ])
        
        return recommendations

8. 测试与验证

8.1 单元测试

import pytest
import tempfile
import os
from pathlib import Path


class TestConfigurationManager:
    """配置管理器测试"""
    
    @pytest.fixture
    def temp_config_dir(self):
        """创建临时配置目录"""
        with tempfile.TemporaryDirectory() as tmpdir:
            config_dir = Path(tmpdir) / "config"
            config_dir.mkdir()
            
            # 创建配置文件
            config_data = {
                'app': {
                    'name': 'TestApp',
                    'debug': True,
                    'secret_key': 'test-secret-123'
                },
                'database': {
                    'host': 'localhost',
                    'port': 5432,
                    'password': 'db-secret-password'
                }
            }
            
            config_file = config_dir / "config.yaml"
            with open(config_file, 'w') as f:
                yaml.dump(config_data, f)
            
            yield config_dir
    
    def test_config_loading(self, temp_config_dir):
        """测试配置加载"""
        
        config_system = CompleteConfigSystem(
            app_name="TestApp",
            config_base_dir=temp_config_dir,
            security_level=SecurityLevel.MEDIUM,
            enable_encryption=False
        )
        
        # 测试获取配置值
        assert config_system.get("app.name") == "TestApp"
        assert config_system.get("app.debug") is True
        assert config_system.get("database.host") == "localhost"
        assert config_system.get("database.port") == 5432
        
        # 测试敏感信息脱敏
        app_section = config_system.get_section("app")
        secret_key_value = app_section.get_value("secret_key")
        
        # 由于是敏感信息,应该返回脱敏值
        assert secret_key_value != "test-secret-123"
        assert "***" in secret_key_value
    
    def test_config_validation(self, temp_config_dir):
        """测试配置验证"""
        
        config_system = CompleteConfigSystem(
            app_name="TestApp",
            config_base_dir=temp_config_dir,
            security_level=SecurityLevel.HIGH
        )
        
        validation = config_system.validate()
        
        assert isinstance(validation, dict)
        assert 'valid' in validation
        assert 'errors' in validation
        assert 'warnings' in validation
    
    def test_environment_detection(self):
        """测试环境检测"""
        
        # 模拟不同环境变量
        os.environ['APP_ENV'] = 'testing'
        
        detector = EnvironmentDetector()
        env_info = detector.detect_environment()
        
        assert 'python_version' in env_info
        assert 'platform' in env_info
        assert 'system' in env_info


class TestSensitiveDataScanner:
    """敏感信息扫描器测试"""
    
    @pytest.fixture
    def temp_file_with_secrets(self):
        """创建包含敏感信息的临时文件"""
        with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
            f.write("""
# 测试文件包含敏感信息
API_KEY = "sk_test_1234567890abcdef"
PASSWORD = "super_secret_password"
DATABASE_URL = "postgresql://user:pass@localhost/db"
EMAIL = "test@example.com"
            
# 安全代码
DEBUG = True
PORT = 8080
            """)
            temp_file = f.name
        
        yield temp_file
        
        # 清理
        os.unlink(temp_file)
    
    def test_scan_file(self, temp_file_with_secrets):
        """测试文件扫描"""
        
        scanner = SensitiveDataScanner(confidence_threshold=0.6)
        findings = scanner.scan_file(temp_file_with_secrets)
        
        assert len(findings) >= 3  # 应该至少找到API_KEY, PASSWORD, DATABASE_URL
        
        # 检查找到的类型
        finding_types = {f['type'] for f in findings}
        assert 'api_key' in finding_types
        assert 'password' in finding_types
        assert 'database_url' in finding_types
        
        # 检查置信度
        for finding in findings:
            assert finding['confidence'] >= 0.6
    
    def test_confidence_calculation(self):
        """测试置信度计算"""
        
        scanner = SensitiveDataScanner()
        
        # 测试不同模式的置信度
        test_cases = [
            ('api_key', 'API_KEY = "sk_test_123456"', 0.9),
            ('password', 'password = "123456"', 0.8),
            ('email', 'email = "test@example.com"', 0.5),
        ]
        
        for pattern_type, line, expected_confidence in test_cases:
            confidence = scanner._calculate_confidence(
                pattern_type, "dummy_match", line
            )
            
            # 允许一定误差
            assert abs(confidence - expected_confidence) < 0.2


class TestEncryption:
    """加密测试"""
    
    def test_key_derivation(self):
        """测试密钥派生"""
        
        key_manager = KeyManager()
        
        # 派生不同ID的密钥
        key1 = key_manager.derive_key("test_key_1")
        key2 = key_manager.derive_key("test_key_2")
        key1_again = key_manager.derive_key("test_key_1")
        
        assert len(key1) == 32  # 256位
        assert len(key2) == 32
        assert key1 == key1_again  # 相同ID应该派生相同密钥
        assert key1 != key2  # 不同ID应该派生不同密钥
    
    def test_encryption_decryption(self):
        """测试加密解密"""
        
        encryptor = ConfigEncryptor()
        plaintext = "This is a secret message"
        
        # 加密
        ciphertext = encryptor.encrypt(
            plaintext,
            key_id="test_key",
            method=EncryptionMethod.FERNET
        )
        
        # 解密
        decrypted = encryptor.decrypt(
            ciphertext,
            key_id="test_key",
            method=EncryptionMethod.FERNET
        )
        
        assert decrypted == plaintext
        assert ciphertext != plaintext
    
    def test_wrong_key_decryption(self):
        """测试错误密钥解密"""
        
        encryptor = ConfigEncryptor()
        plaintext = "Secret data"
        
        ciphertext = encryptor.encrypt(
            plaintext,
            key_id="correct_key",
            method=EncryptionMethod.FERNET
        )
        
        # 使用错误密钥尝试解密
        with pytest.raises(Exception):
            encryptor.decrypt(
                ciphertext,
                key_id="wrong_key",
                method=EncryptionMethod.FERNET
            )


if __name__ == '__main__':
    # 运行测试
    pytest.main([__file__, '-v'])

8.2 集成测试

class IntegrationTestSuite:
    """集成测试套件"""
    
    @staticmethod
    def run_all_tests():
        """运行所有集成测试"""
        
        print("=" * 60)
        print("环境配置管理与敏感信息保护系统 - 集成测试")
        print("=" * 60)
        
        test_results = {
            'total': 0,
            'passed': 0,
            'failed': 0,
            'tests': []
        }
        
        # 测试1:完整配置系统
        print("\n1. 测试完整配置系统...")
        try:
            with tempfile.TemporaryDirectory() as tmpdir:
                config_dir = Path(tmpdir) / "config"
                config_dir.mkdir()
                
                # 创建配置文件
                config_data = {
                    'app': {
                        'name': 'IntegrationTestApp',
                        'debug': False,
                        'secret_key': {
                            'encrypted': True,
                            'ciphertext': 'dummy_ciphertext',
                            'key_id': 'test',
                            'method': 'fernet'
                        }
                    },
                    'database': {
                        'host': 'db.example.com',
                        'port': 5432,
                        'username': 'admin',
                        'password': 'secret_db_password'
                    }
                }
                
                config_file = config_dir / "config.yaml"
                with open(config_file, 'w') as f:
                    yaml.dump(config_data, f)
                
                # 创建配置系统
                config_system = CompleteConfigSystem(
                    app_name="IntegrationTestApp",
                    config_base_dir=config_dir,
                    security_level=SecurityLevel.HIGH,
                    enable_encryption=True
                )
                
                # 验证配置
                validation = config_system.validate()
                
                if validation['valid']:
                    print("  ✓ 配置系统测试通过")
                    test_results['passed'] += 1
                else:
                    print(f"  ✗ 配置系统测试失败: {validation['errors']}")
                    test_results['failed'] += 1
                
                test_results['total'] += 1
                
        except Exception as e:
            print(f"  ✗ 配置系统测试异常: {e}")
            test_results['failed'] += 1
            test_results['total'] += 1
        
        # 测试2:敏感信息扫描
        print("\n2. 测试敏感信息扫描...")
        try:
            scanner = SensitiveDataScanner()
            
            with tempfile.TemporaryDirectory() as tmpdir:
                # 创建测试文件
                test_file = Path(tmpdir) / "test.py"
                test_file.write_text("""
API_KEY = "sk_test_1234567890"
PASSWORD = "test_pass_123"
EMAIL = "test@example.com"
                """)
                
                findings = scanner.scan_file(test_file)
                report = scanner.generate_report({str(test_file): findings})
                
                if report['scan_summary']['total_findings'] >= 2:
                    print("  ✓ 敏感信息扫描测试通过")
                    test_results['passed'] += 1
                else:
                    print(f"  ✗ 敏感信息扫描测试失败,找到 {report['scan_summary']['total_findings']} 个问题")
                    test_results['failed'] += 1
                
                test_results['total'] += 1
                
        except Exception as e:
            print(f"  ✗ 敏感信息扫描测试异常: {e}")
            test_results['failed'] += 1
            test_results['total'] += 1
        
        # 测试3:CI/CD集成
        print("\n3. 测试CI/CD集成...")
        try:
            with tempfile.TemporaryDirectory() as tmpdir:
                config_dir = Path(tmpdir) / "config"
                config_dir.mkdir()
                
                config_system = CompleteConfigSystem(
                    app_name="CICDTest",
                    config_base_dir=config_dir,
                    security_level=SecurityLevel.MEDIUM
                )
                
                cicd = CICDIntegrator(config_system)
                report = cicd.generate_deployment_report()
                
                if 'deployment_decision' in report:
                    print("  ✓ CI/CD集成测试通过")
                    test_results['passed'] += 1
                else:
                    print("  ✗ CI/CD集成测试失败")
                    test_results['failed'] += 1
                
                test_results['total'] += 1
                
        except Exception as e:
            print(f"  ✗ CI/CD集成测试异常: {e}")
            test_results['failed'] += 1
            test_results['total'] += 1
        
        # 测试4:监控系统
        print("\n4. 测试监控系统...")
        try:
            with tempfile.TemporaryDirectory() as tmpdir:
                config_dir = Path(tmpdir) / "config"
                config_dir.mkdir()
                
                config_system = CompleteConfigSystem(
                    app_name="MonitoringTest",
                    config_base_dir=config_dir
                )
                
                monitor = ConfigMonitoringSystem(config_system)
                
                # 模拟一些事件
                monitor.track_config_change(
                    key="app.secret_key",
                    old_value="old_secret",
                    new_value="new_secret",
                    user="test_user",
                    reason="key rotation"
                )
                
                monitor.track_sensitive_access(
                    key="database.password",
                    user="app_server",
                    purpose="database connection"
                )
                
                report = monitor.generate_monitoring_report(time_range_hours=1)
                
                if (report['config_changes']['total'] > 0 and 
                    report['sensitive_access']['total'] > 0):
                    print("  ✓ 监控系统测试通过")
                    test_results['passed'] += 1
                else:
                    print("  ✗ 监控系统测试失败")
                    test_results['failed'] += 1
                
                test_results['total'] += 1
                
        except Exception as e:
            print(f"  ✗ 监控系统测试异常: {e}")
            test_results['failed'] += 1
            test_results['total'] += 1
        
        # 输出测试结果
        print("\n" + "=" * 60)
        print("测试结果汇总:")
        print("=" * 60)
        
        print(f"总测试数: {test_results['total']}")
        print(f"通过: {test_results['passed']}")
        print(f"失败: {test_results['failed']}")
        
        success_rate = (test_results['passed'] / test_results['total'] * 100 
                       if test_results['total'] > 0 else 0)
        print(f"成功率: {success_rate:.1f}%")
        
        if test_results['failed'] == 0:
            print("\n所有测试通过! ✓")
        else:
            print("\n有测试失败,请检查! ✗")
        
        return test_results

9. 部署与运维指南

9.1 生产环境部署清单

class ProductionDeploymentChecklist:
    """生产环境部署清单"""
    
    CHECKLIST = {
        'pre_deployment': [
            {
                'id': 'SEC-001',
                'description': '配置加密已启用',
                'required': True,
                'severity': 'critical'
            },
            {
                'id': 'SEC-002',
                'description': '所有敏感配置已加密',
                'required': True,
                'severity': 'critical'
            },
            {
                'id': 'SEC-003',
                'description': '安全级别设置为CRITICAL',
                'required': True,
                'severity': 'high'
            },
            {
                'id': 'SEC-004',
                'description': '密钥管理服务已配置',
                'required': True,
                'severity': 'high'
            },
            {
                'id': 'OPS-001',
                'description': '配置验证通过',
                'required': True,
                'severity': 'high'
            },
            {
                'id': 'OPS-002',
                'description': '敏感信息扫描无关键问题',
                'required': True,
                'severity': 'high'
            },
            {
                'id': 'OPS-003',
                'description': '备份和恢复计划已测试',
                'required': True,
                'severity': 'medium'
            }
        ],
        'post_deployment': [
            {
                'id': 'MON-001',
                'description': '配置监控已启用',
                'required': True,
                'severity': 'high'
            },
            {
                'id': 'MON-002',
                'description': '告警规则已配置',
                'required': True,
                'severity': 'high'
            },
            {
                'id': 'MON-003',
                'description': '审计日志已开启',
                'required': True,
                'severity': 'medium'
            },
            {
                'id': 'SEC-005',
                'description': '定期密钥轮换计划已设置',
                'required': True,
                'severity': 'medium'
            }
        ]
    }
    
    @classmethod
    def verify_checklist(
        cls,
        config_system: CompleteConfigSystem,
        stage: str = 'pre_deployment'
    ) -> Dict:
        """验证检查清单"""
        
        if stage not in cls.CHECKLIST:
            raise ValueError(f"未知阶段: {stage}")
        
        checklist = cls.CHECKLIST[stage]
        results = []
        
        for item in checklist:
            result = {
                'id': item['id'],
                'description': item['description'],
                'required': item['required'],
                'severity': item['severity'],
                'status': 'pending',
                'details': ''
            }
            
            try:
                # 执行检查
                check_method = getattr(cls, f"_check_{item['id'].replace('-', '_')}")
                passed, details = check_method(config_system)
                
                result['status'] = 'passed' if passed else 'failed'
                result['details'] = details
                
            except AttributeError:
                result['status'] = 'not_implemented'
                result['details'] = '检查方法未实现'
            
            except Exception as e:
                result['status'] = 'error'
                result['details'] = str(e)
            
            results.append(result)
        
        # 汇总
        total_checks = len(results)
        passed_checks = len([r for r in results if r['status'] == 'passed'])
        failed_required = [
            r for r in results 
            if r['status'] != 'passed' and r['required']
        ]
        
        deployment_approved = len(failed_required) == 0
        
        return {
            'stage': stage,
            'timestamp': datetime.now().isoformat(),
            'results': results,
            'summary': {
                'total_checks': total_checks,
                'passed_checks': passed_checks,
                'failed_required': len(failed_required),
                'success_rate': (passed_checks / total_checks * 100) if total_checks > 0 else 0,
                'deployment_approved': deployment_approved
            },
            'failed_required_items': [
                {'id': r['id'], 'description': r['description']}
                for r in failed_required
            ]
        }
    
    @staticmethod
    def _check_SEC_001(config_system: CompleteConfigSystem) -> Tuple[bool, str]:
        """检查配置加密已启用"""
        enabled = config_system.secure_config_manager.encryption_enabled
        return enabled, f"加密启用: {enabled}"
    
    @staticmethod
    def _check_SEC_002(config_system: CompleteConfigSystem) -> Tuple[bool, str]:
        """检查所有敏感配置已加密"""
        unencrypted = config_system._find_unencrypted_sensitive()
        return len(unencrypted) == 0, f"未加密敏感配置: {len(unencrypted)}"
    
    @staticmethod
    def _check_SEC_003(config_system: CompleteConfigSystem) -> Tuple[bool, str]:
        """检查安全级别设置为CRITICAL"""
        is_critical = config_system.security_level == SecurityLevel.CRITICAL
        return is_critical, f"安全级别: {config_system.security_level.value}"
    
    @staticmethod
    def _check_OPS_001(config_system: CompleteConfigSystem) -> Tuple[bool, str]:
        """检查配置验证通过"""
        validation = config_system.validate()
        return validation['valid'], f"验证结果: {validation['valid']}, 错误: {len(validation['errors'])}"
    
    @staticmethod
    def _check_OPS_002(config_system: CompleteConfigSystem) -> Tuple[bool, str]:
        """检查敏感信息扫描无关键问题"""
        scanner = SensitiveDataScanner()
        config_dir = config_system.config_base_dir
        findings = scanner.scan_directory(config_dir)
        report = scanner.generate_report(findings)
        
        critical_issues = report['scan_summary']['critical_issues']
        return critical_issues == 0, f"关键问题: {critical_issues}"
    
    # 其他检查方法的实现...

9.2 灾难恢复计划

class DisasterRecoveryPlan:
    """灾难恢复计划"""
    
    def __init__(self, config_system: CompleteConfigSystem):
        self.config_system = config_system
        self.backup_dir = config_system.config_base_dir / "backups"
        self.backup_dir.mkdir(exist_ok=True)
    
    def create_backup(self, description: str = "") -> Path:
        """创建配置备份"""
        
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
        backup_name = f"config_backup_{timestamp}"
        
        if description:
            backup_name += f"_{description.replace(' ', '_')}"
        
        backup_path = self.backup_dir / f"{backup_name}.zip"
        
        try:
            # 导出当前配置
            config_dict = self.config_system.secure_config_manager.to_dict(
                mask_sensitive=False
            )
            
            # 转换为YAML
            config_yaml = yaml.dump(config_dict, default_flow_style=False)
            
            # 创建ZIP备份
            import zipfile
            
            with zipfile.ZipFile(backup_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                # 添加配置
                zipf.writestr("config.yaml", config_yaml)
                
                # 添加元数据
                metadata = {
                    'timestamp': timestamp,
                    'description': description,
                    'app_name': self.config_system.app_name,
                    'environment': self.config_system.env_loader.current_environment,
                    'backup_version': '1.0'
                }
                
                zipf.writestr("metadata.json", json.dumps(metadata, indent=2))
            
            logger.info(f"配置备份创建成功: {backup_path}")
            
            # 清理旧备份(保留最近10个)
            self._cleanup_old_backups(keep_count=10)
            
            return backup_path
            
        except Exception as e:
            logger.error(f"配置备份创建失败: {e}")
            raise
    
    def _cleanup_old_backups(self, keep_count: int = 10):
        """清理旧备份"""
        
        backups = list(self.backup_dir.glob("config_backup_*.zip"))
        
        if len(backups) > keep_count:
            # 按修改时间排序
            backups.sort(key=lambda x: x.stat().st_mtime)
            
            # 删除最旧的备份
            to_delete = backups[:-keep_count]
            
            for backup in to_delete:
                try:
                    backup.unlink()
                    logger.info(f"删除旧备份: {backup.name}")
                except Exception as e:
                    logger.error(f"删除备份失败 {backup}: {e}")
    
    def list_backups(self) -> List[Dict]:
        """列出所有备份"""
        
        backups = []
        
        for backup_file in self.backup_dir.glob("config_backup_*.zip"):
            try:
                import zipfile
                
                with zipfile.ZipFile(backup_file, 'r') as zipf:
                    # 读取元数据
                    metadata_str = zipf.read("metadata.json").decode('utf-8')
                    metadata = json.loads(metadata_str)
                    
                    backups.append({
                        'file': backup_file.name,
                        'path': str(backup_file),
                        'size': backup_file.stat().st_size,
                        'modified': datetime.fromtimestamp(
                            backup_file.stat().st_mtime
                        ).isoformat(),
                        'metadata': metadata
                    })
                    
            except Exception as e:
                logger.error(f"读取备份信息失败 {backup_file}: {e}")
        
        # 按修改时间排序
        backups.sort(key=lambda x: x['modified'], reverse=True)
        
        return backups
    
    def restore_backup(self, backup_name: str) -> bool:
        """恢复备份"""
        
        backup_path = self.backup_dir / backup_name
        
        if not backup_path.exists():
            logger.error(f"备份文件不存在: {backup_name}")
            return False
        
        try:
            import zipfile
            
            with zipfile.ZipFile(backup_path, 'r') as zipf:
                # 读取配置
                config_yaml = zipf.read("config.yaml").decode('utf-8')
                config_dict = yaml.safe_load(config_yaml)
                
                # 读取元数据
                metadata_str = zipf.read("metadata.json").decode('utf-8')
                metadata = json.loads(metadata_str)
            
            # 验证备份环境
            current_env = self.config_system.env_loader.current_environment
            backup_env = metadata.get('environment')
            
            if current_env != backup_env:
                logger.warning(
                    f"备份环境({backup_env})与当前环境({current_env})不匹配"
                )
                # 可以在这里添加确认逻辑
            
            # 恢复配置
            # 注意:这里需要根据实际情况实现恢复逻辑
            # 可能涉及直接写入配置文件或更新配置服务
            
            logger.info(f"配置恢复成功: {backup_name}")
            logger.info(f"备份信息: {metadata}")
            
            return True
            
        except Exception as e:
            logger.error(f"配置恢复失败: {e}")
            return False
    
    def generate_recovery_plan(self) -> Dict:
        """生成灾难恢复计划"""
        
        # 获取当前配置状态
        config_report = self.config_system.generate_security_report()
        
        # 列出可用备份
        backups = self.list_backups()
        
        # 最近备份
        latest_backup = backups[0] if backups else None
        
        return {
            'application': self.config_system.app_name,
            'environment': self.config_system.env_loader.current_environment,
            'recovery_point_objective': "15分钟",  # RPO
            'recovery_time_objective': "1小时",     # RTO
            'current_state': {
                'config_status': config_report['validation']['valid'],
                'last_validation': datetime.now().isoformat(),
                'critical_issues': config_report['config_summary']['sensitive_values_count']
            },
            'backup_status': {
                'total_backups': len(backups),
                'latest_backup': latest_backup['metadata'] if latest_backup else None,
                'backup_frequency': "每天自动备份"
            },
            'recovery_steps': [
                "1. 确认故障范围",
                "2. 选择恢复点(备份)",
                "3. 停止应用程序",
                "4. 恢复配置备份",
                "5. 验证配置完整性",
                "6. 重启应用程序",
                "7. 功能验证",
                "8. 监控系统状态"
            ],
            'contact_list': [
                {"role": "系统管理员", "contact": "admin@example.com"},
                {"role": "安全负责人", "contact": "security@example.com"},
                {"role": "开发负责人", "contact": "dev@example.com"}
            ],
            'verification_tests': [
                "配置验证通过",
                "应用程序启动正常",
                "敏感功能测试",
                "监控系统告警检查"
            ]
        }

10. 总结与展望

10.1 核心价值总结

本文介绍了完整的环境配置管理与敏感信息保护系统,其主要价值体现在:

  1. 安全性:通过加密、脱敏、访问控制等多层保护机制
  2. 可靠性:配置验证、备份恢复、监控告警确保系统稳定
  3. 可维护性:清晰的配置结构、版本控制、环境隔离
  4. 可观测性:完整的监控、审计、报告功能
  5. 合规性:满足数据保护法规和行业安全标准

10.2 未来发展方向

  1. AI驱动的配置优化:使用机器学习分析配置模式,自动优化配置
  2. 零信任配置管理:基于身份的细粒度配置访问控制
  3. 量子安全加密:为后量子时代准备加密算法
  4. 配置即代码的演进:更强大的声明式配置语言和工具
  5. 边缘计算配置管理:分布式环境下的配置同步与一致性

10.3 实施建议

对于不同规模的组织,实施建议如下:

组织规模建议方案优先级
初创公司基础配置管理 + 敏感信息扫描
中小企业完整配置系统 + 基础加密中高
大型企业企业级配置中心 + 密钥管理服务
金融机构最高安全级别 + 审计合规 + 灾难恢复最高

附录

A. 安全合规检查清单

  1. GDPR合规:个人数据保护、加密、访问日志
  2. HIPAA合规:医疗信息安全、审计追踪
  3. PCI DSS合规:支付数据保护、密钥管理
  4. SOC 2合规:安全控制、配置管理
  5. ISO 27001:信息安全管理体系

B. 性能优化建议

  1. 配置缓存策略:LRU缓存、分层缓存
  2. 懒加载机制:按需加载配置
  3. 增量更新:只同步变更的配置
  4. 连接池优化:配置服务连接管理

C. 故障排除指南

  1. 配置加载失败:检查文件权限、格式、编码
  2. 加密解密错误:检查密钥版本、算法兼容性
  3. 环境检测异常:检查系统信息、环境变量
  4. 性能问题:监控配置访问频率、优化热点

免责声明:本文提供的代码和方案仅供参考,生产环境中请根据具体需求进行安全审计和测试。安全配置应结合具体业务场景和安全要求进行调整,建议咨询安全专家进行合规性评估。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

闲人编程

你的鼓励就是我最大的动力,谢谢

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值