L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

performing-service-account-credential-rotation

performing-service-account-credential-rotation

跨 Active Directory、云平台和应用程序数据库自动化服务账户凭据轮换,消除陈旧密钥并降低泄露风险。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: performing-service-account-credential-rotation description: 跨 Active Directory、云平台和应用程序数据库自动化服务账户凭据轮换,消除陈旧密钥并降低泄露风险。 domain: cybersecurity subdomain: identity-access-management tags: [service-accounts, credential-rotation, secrets-management, pam, automation, vault] version: "1.0" author: mahipal license: Apache-2.0

执行服务账户凭据轮换

概述

服务账户是应用程序、守护进程、CI/CD 流水线和自动化流程用于向系统和 API 认证的非人类身份。这些账户通常具有较高权限,其凭据(密码、API 密钥、证书、令牌)往往长期有效且在团队间共享,使其成为攻击者的主要目标。凭据轮换是按计划系统性替换这些密钥、将新凭据传播到所有依赖系统,并在轮换后验证服务连续性的流程。

前置条件

  • 跨 AD、云和应用程序的所有服务账户清单
  • 密钥管理平台(HashiCorp Vault、AWS Secrets Manager、Azure Key Vault 或 CyberArk)
  • 服务依赖映射(哪些服务使用哪些凭据)
  • 轮换窗口的变更管理流程
  • 轮换后的服务健康监控

核心概念

服务账户类型

类型平台凭据轮换方法
Active Directory 服务账户Windows/AD密码gMSA(自动)或 PAM 管理
AWS IAM 用户AWS访问密钥/Secret 密钥AWS Secrets Manager 轮换 Lambda
GCP 服务账户GCPJSON 密钥文件通过 IAM API 进行密钥轮换
Azure 服务主体Azure客户端密钥/证书Key Vault + 轮换策略
数据库服务账户SQL/Oracle/Postgres密码Vault 动态密钥
API 密钥SaaS 应用程序API 令牌应用特定 API

组托管服务账户(gMSA)

Windows gMSA 由 Active Directory 提供自动密码管理:

  • AD 每 30 天自动轮换密码
  • 密码为 240 字节,加密随机生成
  • 多台服务器可同时使用同一 gMSA
  • 无管理员知晓或管理密码
  • 消除 Windows 服务的手动轮换需求

轮换架构

密钥管理器 / Vault
        │
        ├── 轮换触发(计划或按需)
        │
        ├── 生成新凭据
        │
        ├── 在源系统更新凭据(AD、云 IAM、数据库)
        │
        ├── 在所有消费方更新凭据:
        │   ├── 应用程序配置
        │   ├── CI/CD 流水线密钥
        │   ├── Kubernetes 密钥
        │   └── 其他依赖服务
        │
        ├── 验证服务健康:
        │   ├── 健康检查端点
        │   ├── 认证测试
        │   └── 功能冒烟测试
        │
        └── 撤销旧凭据(宽限期后)

实施步骤

步骤 1:发现和盘点服务账户

枚举所有服务账户及其依赖关系:

# Active Directory:查找所有服务账户
Get-ADServiceAccount -Filter * -Properties *
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties ServicePrincipalName,PasswordLastSet,LastLogonDate

# 查找密码超过 90 天的账户
$threshold = (Get-Date).AddDays(-90)
Get-ADUser -Filter {PasswordLastSet -lt $threshold -and Enabled -eq $true} -Properties PasswordLastSet,ServicePrincipalName |
    Where-Object {$_.ServicePrincipalName} |
    Select-Object Name, PasswordLastSet, ServicePrincipalName

步骤 2:为 Windows 服务实施 gMSA

# 创建 KDS 根密钥(一次性,全域范围)
Add-KdsRootKey -EffectiveImmediately

# 创建 gMSA 账户
New-ADServiceAccount -Name "svc-webapp-gmsa" `
    -DNSHostName "svc-webapp-gmsa.corp.example.com" `
    -PrincipalsAllowedToRetrieveManagedPassword "WebServerGroup" `
    -KerberosEncryptionType AES128,AES256

# 在目标服务器上安装
Install-ADServiceAccount -Identity "svc-webapp-gmsa"

# 测试账户
Test-ADServiceAccount -Identity "svc-webapp-gmsa"

# 配置 IIS 应用程序池使用 gMSA
# 将标识设置为:CORP\svc-webapp-gmsa$

步骤 3:使用 Secrets Manager 轮换 AWS 访问密钥

import boto3
import json

def rotate_iam_access_key(secret_arn, iam_username):
    """通过 Secrets Manager 轮换 IAM 用户的访问密钥。"""
    iam = boto3.client("iam")
    sm = boto3.client("secretsmanager")

    # 创建新访问密钥
    new_key = iam.create_access_key(UserName=iam_username)
    new_access_key = new_key["AccessKey"]["AccessKeyId"]
    new_secret_key = new_key["AccessKey"]["SecretAccessKey"]

    # 在 Secrets Manager 中存储新凭据
    sm.put_secret_value(
        SecretId=secret_arn,
        SecretString=json.dumps({
            "accessKeyId": new_access_key,
            "secretAccessKey": new_secret_key,
            "username": iam_username,
        })
    )

    # 列出旧访问密钥并停用
    keys = iam.list_access_keys(UserName=iam_username)
    for key in keys["AccessKeyMetadata"]:
        if key["AccessKeyId"] != new_access_key and key["Status"] == "Active":
            iam.update_access_key(
                UserName=iam_username,
                AccessKeyId=key["AccessKeyId"],
                Status="Inactive"
            )

    return {"new_key_id": new_access_key, "old_keys_deactivated": True}

步骤 4:使用 Vault 进行数据库凭据轮换

import hvac

def configure_vault_database_rotation(vault_url, vault_token, db_config):
    """配置 HashiCorp Vault 实现数据库凭据自动轮换。"""
    client = hvac.Client(url=vault_url, token=vault_token)

    # 启用数据库密钥引擎
    client.sys.enable_secrets_engine(
        backend_type="database",
        path="database"
    )

    # 配置数据库连接
    client.secrets.database.configure(
        name=db_config["name"],
        plugin_name="postgresql-database-plugin",
        connection_url=f"postgresql://{{{{username}}}}:{{{{password}}}}@"
                       f"{db_config['host']}:{db_config['port']}/{db_config['database']}",
        allowed_roles=[db_config["role_name"]],
        username=db_config["admin_user"],
        password=db_config["admin_password"],
    )

    # 创建动态凭据角色
    client.secrets.database.create_role(
        name=db_config["role_name"],
        db_name=db_config["name"],
        creation_statements=[
            "CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}';",
            f"GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \"{{{{name}}}}\";"
        ],
        default_ttl="1h",
        max_ttl="24h",
    )

    return {"status": "configured", "role": db_config["role_name"]}

步骤 5:轮换后验证

每次轮换后,验证服务连续性:

import requests
import time

def verify_service_health(service_endpoints, max_retries=3, delay=10):
    """检查凭据轮换后服务是否正常。"""
    results = []
    for endpoint in service_endpoints:
        for attempt in range(max_retries):
            try:
                response = requests.get(
                    endpoint["health_url"],
                    timeout=10,
                    headers=endpoint.get("headers", {})
                )
                healthy = response.status_code == 200
                results.append({
                    "service": endpoint["name"],
                    "status": "healthy" if healthy else f"unhealthy ({response.status_code})",
                    "attempt": attempt + 1,
                })
                if healthy:
                    break
            except requests.RequestException as e:
                results.append({
                    "service": endpoint["name"],
                    "status": f"error: {str(e)}",
                    "attempt": attempt + 1,
                })
            if attempt < max_retries - 1:
                time.sleep(delay)

    return results

验证清单

  • 完整的服务账户清单及依赖映射
  • 为所有符合条件的 Windows 服务账户实施 gMSA
  • 通过密钥管理器轮换云访问密钥(AWS、GCP、Azure)
  • 通过动态密钥(Vault)或轮换策略管理数据库凭据
  • 定义轮换计划(根据风险级别为 30-90 天)
  • 轮换后健康检查自动化
  • 为轮换失败配置告警
  • 宽限期后撤销旧凭据
  • 轮换事件已记录且可审计
  • 回滚流程已记录并测试

参考资料

Skills enregistrées