secrets-management

Secrets and credentials management best practices

ffsshhttiikk/opencode-agents-skills3 installsMITSynced Aug 22

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: secrets-management
description: Secrets and credentials management best practices
license: MIT
---

## 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
```

More Security skills

azure-cost

microsoft/azure-skills

Azure cost management: query costs, forecast spending, optimize to reduce waste. WHEN: \"Azure costs\", \"Azure bill\", \"cost breakdown\", \"how much am I spending\", \"forecast spending\", \"optimize costs\", \"reduce spending\", \"orphaned resources\", \"rightsize VMs\", \"cost spike\", \"reduce storage costs\", \"AKS cost\". DO NOT USE FOR: deploying resources, provisioning, diagnostics, or security audits.

355.6k

entra-app-registration

microsoft/azure-skills

Guides Microsoft Entra ID app registration, OAuth 2.0 authentication, and MSAL integration. USE FOR: create app registration, register Azure AD app, configure OAuth, set up authentication, add API permissions, generate service principal, MSAL example, console app auth, Entra ID setup, Azure AD authentication. DO NOT USE FOR: Key Vault secrets (use azure-keyvault-expiration-audit), general Azure resource security guidance.

318.9k

azure-messaging

microsoft/azure-skills

Troubleshoot and resolve issues with Azure Messaging SDKs for Event Hubs and Service Bus. Covers connection failures, authentication errors, message processing issues, and SDK configuration problems. WHEN: event hub SDK error, service bus SDK issue, messaging connection failure, AMQP error, event processor host issue, message lock lost, message lock expired, lock renewal, lock renewal batch, send timeout, receiver disconnected, SDK troubleshooting, azure messaging SDK, event hub consumer, service bus queue issue, topic subscription error, enable logging event hub, service bus logging, eventhub python, servicebus java, eventhub javascript, servicebus dotnet, event hub checkpoint, event hub not receiving messages, service bus dead letter, batch processing lock, session lock expired, idle timeout, connection inactive, link detach, slow reconnect, session error, duplicate events, offset reset, receive batch.

310.3k

← All Security skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY