Automates service account credential rotation across Active Directory, AWS/GCP/Azure IAM, and databases using gMSA, Secrets Manager, Vault. Eliminates stale keys to reduce breach risks.
npx claudepluginhub killvxk/cybersecurity-skills-zhThis skill uses the workspace's default tool permissions.
服务账户是应用程序、守护进程、CI/CD 流水线和自动化流程用于向系统和 API 认证的非人类身份。这些账户通常具有较高权限,其凭据(密码、API 密钥、证书、令牌)往往长期有效且在团队间共享,使其成为攻击者的主要目标。凭据轮换是按计划系统性替换这些密钥、将新凭据传播到所有依赖系统,并在轮换后验证服务连续性的流程。
Guides service account credential rotation across Active Directory, AWS, GCP, Azure, and databases to eliminate stale secrets and reduce compromise risk.
Automates service account credential rotation across Active Directory, AWS, GCP, Azure, and databases using Vault or cloud secrets managers. For security audits, incident response, and reducing stale secrets risk.
Audits service accounts across Active Directory, AWS, Azure, GCP, databases, and apps to identify orphaned, over-privileged, and non-compliant accounts with missing owners or poor credential rotation. For IAM governance and compliance like SOX/PCI.
Share bugs, ideas, or general feedback.
服务账户是应用程序、守护进程、CI/CD 流水线和自动化流程用于向系统和 API 认证的非人类身份。这些账户通常具有较高权限,其凭据(密码、API 密钥、证书、令牌)往往长期有效且在团队间共享,使其成为攻击者的主要目标。凭据轮换是按计划系统性替换这些密钥、将新凭据传播到所有依赖系统,并在轮换后验证服务连续性的流程。
| 类型 | 平台 | 凭据 | 轮换方法 |
|---|---|---|---|
| Active Directory 服务账户 | Windows/AD | 密码 | gMSA(自动)或 PAM 管理 |
| AWS IAM 用户 | AWS | 访问密钥/Secret 密钥 | AWS Secrets Manager 轮换 Lambda |
| GCP 服务账户 | GCP | JSON 密钥文件 | 通过 IAM API 进行密钥轮换 |
| Azure 服务主体 | Azure | 客户端密钥/证书 | Key Vault + 轮换策略 |
| 数据库服务账户 | SQL/Oracle/Postgres | 密码 | Vault 动态密钥 |
| API 密钥 | SaaS 应用程序 | API 令牌 | 应用特定 API |
Windows gMSA 由 Active Directory 提供自动密码管理:
密钥管理器 / Vault
│
├── 轮换触发(计划或按需)
│
├── 生成新凭据
│
├── 在源系统更新凭据(AD、云 IAM、数据库)
│
├── 在所有消费方更新凭据:
│ ├── 应用程序配置
│ ├── CI/CD 流水线密钥
│ ├── Kubernetes 密钥
│ └── 其他依赖服务
│
├── 验证服务健康:
│ ├── 健康检查端点
│ ├── 认证测试
│ └── 功能冒烟测试
│
└── 撤销旧凭据(宽限期后)
枚举所有服务账户及其依赖关系:
# 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
# 创建 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$
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}
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"]}
每次轮换后,验证服务连续性:
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