secrets-management
Secrets and credentials management best practices
معلومات المصدر
- المستودع
- ffsshhttiikk/opencode-agents-skills
- آخر نشاط في المصدر
- ٢٨ فبراير ٢٠٢٦ في ٢٢:٥٤
- لغة SKILL.md المكتشفة
- الإنجليزية
- النجوم
- ٣
- التفرعات
- ٢
خيارات التثبيت
يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.
مراجعة ملفات المصدر
اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.
عرض SKILL.md
SKILL.md
تعليمات المصدر · معاينة للقراءة فقط- name
- secrets-management
- description
- Secrets and credentials management best practices
- license
- MIT
- compatibility
- opencode
- metadata
- {"audience":"developers","category":"security"}
## What I do
- Manage application secrets securely
- Use environment variables properly
- Integrate with secret managers
- Handle API keys and credentials
- Implement secret rotation
- Audit secret access
- Prevent secret leaks
- Use encryption appropriately
## When to use me
When handling credentials, API keys, or sensitive configuration.
## Secret Management Hierarchy
```
1. Environment Variables (for containers)
- Set at deployment time
- Easy rotation
- Limited size
2. Secret Manager (Vault, AWS Secrets Manager)
- Encrypted storage
- Access control
- Audit logging
3. CI/CD Secrets (GitHub Secrets, GitLab CI Variables)
- Pipeline-only access
- Never in code
4. Local Development (.env files)
- .env should be in .gitignore
- Use template .env.example
5. Hardware Security Modules (HSM)
- Maximum security
- For cryptographic keys
```
## Environment Variables
```bash
# .env file (NEVER commit to git)
# Copy this to .env and fill in values
DATABASE_URL=postgresql://user:password@localhost:5432/db
REDIS_URL=redis://localhost:6379
SECRET_KEY=your-secret-key-change-in-production
API_KEY=your-api-key
JWT_SECRET=your-jwt-secret
ENCRYPTION_KEY=your-encryption-key
# .env.example (safe to commit)
DATABASE_URL=
REDIS_URL=
SECRET_KEY=
API_KEY=
JWT_SECRET=
ENCRYPTION_KEY=
```
```python
from pydantic import BaseModel
from functools import lru_cache
from typing import Optional
class Settings(BaseModel):
"""Application settings from environment."""
# Required
database_url: str
secret_key: str
api_key: str
# Optional with defaults
debug: bool = False
log_level: str = "info"
# Computed
@property
def is_production(self) -> bool:
return not self.debug
@classmethod
def from_env(cls) -> 'Settings':
"""Load settings from environment."""
import os
return cls(
database_url=os.getenv("DATABASE_URL"),
secret_key=os.getenv("SECRET_KEY"),
api_key=os.getenv("API_KEY"),
debug=os.getenv("DEBUG", "").lower() == "true",
log_level=os.getenv("LOG_LEVEL", "info"),
)
@lru_cache()
def get_settings() -> Settings:
"""Get cached settings."""
return Settings.from_env()
```
## AWS Secrets Manager
```python
import boto3
import json
from botocore.exceptions import ClientError
class AWSSecretsManager:
"""Retrieve secrets from AWS Secrets Manager."""
def __init__(self, region: str = "us-east-1") -> None:
self.client = boto3.client('secretsmanager', region_name=region)
def get_secret(self, secret_name: str) -> dict:
"""Retrieve secret by name."""
try:
response = self.client.get_secret_value(SecretId=secret_name)
# Secret may be in either format
if 'SecretString' in response:
return json.loads(response['SecretString'])
else:
return json.loads(
bytes(
response['SecretBinary'],
encoding='utf-8'
)
)
except ClientError as e:
if e.response['Error']['Code'] == 'DecryptionFailureException':
raise DecryptionError("Secret cannot be decrypted")
elif e.response['Error']['Code'] == 'ResourceNotFoundException':
raise SecretNotFoundError(f"Secret {secret_name} not found")
else:
raise
def get_database_credentials(self) -> dict:
"""Get database credentials from named secret."""
return self.get_secret("myapp/database")
def rotate_secret(
self,
secret_name: str,
rotation_lambda: str
) -> None:
"""Enable automatic rotation for a secret."""
self.client.rotate_secret(
SecretId=secret_name,
RotationLambdaARN=rotation_lambda,
RotationRules={
'AutomaticallyAfterDays': 30,
}
)
# Usage
secrets = AWSSecretsManager()
creds = secrets.get_database_credentials()
```
## HashiCorp Vault
```python
import hvac
import os
class VaultClient:
"""Client for HashiCorp Vault."""
def __init__(
self,
vault_addr: str = None,
vault_token: str = None,
mount_point: str = 'secret'
) -> None:
self.vault_addr = vault_addr or os.getenv('VAULT_ADDR')
self.vault_token = vault_token or os.getenv('VAULT_TOKEN')
self.mount_point = mount_point
if not self.vault_addr or not self.vault_token:
raise ValueError("Vault address and token required")
self.client = hvac.Client(
url=self.vault_addr,
token=self.vault_token,
)
def get_secret(self, path: str) -> dict:
"""Read secret from Vault."""
try:
response = self.client.secrets.kv.v2.read_secret_version(
path=path,
mount_point=self.mount_point,
)
return response['data']['data']
except hvac.exceptions.InvalidPath:
raise SecretNotFoundError(f"Secret not found: {path}")
def set_secret(self, path: str, secret: dict) -> None:
"""Write secret to Vault."""
self.client.secrets.kv.v2.create_or_update_secret(
path=path,
secret=secret,
mount_point=self.mount_point,
)
@property
def is_authenticated(self) -> bool:
"""Check if client is authenticated."""
return self.client.is_authenticated()
# Usage with Vault Agent
# VAULT_ADDR and VAULT_TOKEN are auto-injected by Vault Agent
vault = VaultClient()
secrets = vault.get_secret('myapp/database')
```
## Kubernetes Secrets
```yaml
# Secret manifest
apiVersion: v1
kind: Secret
metadata:
name: myapp-secrets
type: Opaque
data:
# Base64 encoded values
database_url: cG9zdGdyZXNxbDovL3VzZXI6cGFzc3dvcmRAbG9jYWxob3N0OjU0MzIvZGI=
api_key: base64encodedapikey
jwt_secret: base64encodedjwttoken
```
```python
# Accessing Kubernetes secrets
from kubernetes import client, config
def get_k8s_secret(secret_name: str, namespace: str = "default") -> dict:
"""Read secret from Kubernetes."""
config.load_incluster_config()
v1 = client.CoreV1Api()
secret = v1.read_namespaced_secret(
name=secret_name,
namespace=namespace,
)
return {
key: base64.b64decode(value).decode('utf-8')
for key, value in secret.data.items()
}
# Using secrets in pods (mounted as files)
# Mounted at /etc/secrets/
with open('/etc/secrets/database_url', 'r') as f:
database_url = f.read().strip()
```
## Secret Rotation Pattern
```python
from abc import ABC, abstractmethod
from datetime import datetime, timedelta
class SecretRotator(ABC):
"""Base class for secret rotation."""
def __init__(self, rotation_period_days: int = 30) -> None:
self.rotation_period = timedelta(days=rotation_period_days)
self.last_rotated: Optional[datetime] = None
@abstractmethod
def generate_new_secret(self) -> str:
"""Generate a new secret value."""
pass
@abstractmethod
def store_secret(self, secret: str) -> None:
"""Store the new secret."""
pass
@abstractmethod
def update_consumers(self, old_secret: str, new_secret: str) -> None:
"""Update all consumers with new secret."""
pass
def rotate(self) -> None:
"""Perform rotation."""
old_secret = self.get_current_secret()
new_secret = self.generate_new_secret()
# Store new secret
self.store_secret(new_secret)
# Update consumers
self.update_consumers(old_secret, new_secret)
self.last_rotated = datetime.utcnow()
class APIKeyRotator(SecretRotator):
"""Rotator for API keys."""
def generate_new_secret(self) -> str:
import secrets
return secrets.token_urlsafe(32)
def store_secret(self, secret: str) -> None:
# Store in secrets manager
secrets_manager.set_secret("myapp/api_key", secret)
def update_consumers(self, old_secret: str, new_secret: str) -> None:
# Update environment variables
# Update Kubernetes secrets
# Notify running services
pass
def get_current_secret(self) -> str:
return secrets_manager.get_secret("myapp/api_key")
```
## Preventing Leaks
```python
import re
# Pre-commit hook to detect secrets
SECRET_PATTERNS = [
r'(api[_-]?key|apikey)[_-]?\s*[:=]\s*["\']?[A-Za-z0-9_]{20,}["\']?',
r'(secret[_-]?key|secretkey)[_-]?\s*[:=]\s*["\']?[A-Za-z0-9_]{20,}["\']?',
r'(token|accesstoken)[_-]?\s*[:=]\s*["\']?[A-Za-z0-9_.-]{20,}["\']?',
r'-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----',
r'AKIA[0-9A-Z]{ AWS Access16}', # Key ID
]
def scan_for_secrets(content: str) -> list:
"""Scan content for potential secrets."""
findings = []
for pattern in SECRET_PATTERNS:
matches = re.finditer(pattern, content, re.IGNORECASE)
for match in matches:
findings.append({
'pattern': pattern,
'match': match.group()[:50] + '...',
'position': match.span(),
})
return findings
```
## Best Practices
```
1. Never commit secrets to version control
- Use .gitignore for .env files
- Run pre-commit hooks
2. Use secret managers in production
- Don't use environment variables for production secrets
- AWS Secrets Manager, HashiCorp Vault, GCP Secret Manager
3. Rotate secrets regularly
- Automated rotation where possible
- Document rotation procedures
4. Least privilege access
- Grant minimum required permissions
- Use IAM policies
5. Audit secret access
- Log who accesses what secrets
- Alert on unusual access patterns
6. Use different secrets per environment
- Never use same secret in dev and prod
- Prevents credential stuffing
7. Use encryption at rest and in transit
- TLS for transmission
- Encrypted storage
8. Have a breach response plan
- Know how to rotate all secrets
- Have emergency contacts
```
عرض على GitHub