Lynguine Secure Credential Management

Overview

Lynguine’s secure credential management system provides enterprise-grade security for API credentials, OAuth tokens, and other sensitive authentication data. This system addresses critical vulnerabilities in credential storage and access while maintaining backward compatibility with existing configurations.

Features

Core Security Features

  • Multiple Storage Backends: Environment variables, encrypted files, and cloud vault integration

  • End-to-End Encryption: AES encryption with PBKDF2 key derivation for stored credentials

  • Access Control: Role-based access control with fine-grained permissions

  • Audit Logging: Comprehensive security event logging for compliance

  • Rate Limiting: Protection against brute force attacks

  • Credential Rotation: Support for automatic credential rotation

  • Secure Error Handling: Prevents credential leakage in logs and exceptions

Integration Features

  • Backward Compatible: Works with existing lynguine configurations

  • Credential References: Use ${credential:name} syntax in configuration files

  • Migration Tools: Automated migration from plain-text credentials

  • Validation: Credential format and type validation

  • Caching: TTL-based caching for performance

Quick Start

Installation

The basic credential system works out of the box. For encrypted storage, install the cryptography library:

pip install cryptography

Basic Usage

1. Storing Credentials

from lynguine.security import set_credential

# Store Google Sheets OAuth credentials
google_creds = {
    "client_id": "your-client-id",
    "client_secret": "your-client-secret",
    "redirect_uri": "http://localhost:8080"
}

set_credential("google_sheets_oauth", google_creds)

2. Using Credentials in Configuration

Update your _lynguine.yml or machine.yml:

google_oauth: ${credential:google_sheets_oauth}

3. Retrieving Credentials Programmatically

from lynguine.security import get_credential

creds = get_credential("google_sheets_oauth")
print(f"Client ID: {creds['value']['client_id']}")

Storage Backends

Environment Variables

Best for: Development, CI/CD pipelines, containerized environments

# Set credential as environment variable
export LYNGUINE_CRED_GOOGLE_SHEETS_OAUTH='{"client_id":"...","client_secret":"..."}'
from lynguine.security import EnvironmentCredentialProvider, CredentialManager

provider = EnvironmentCredentialProvider(prefix="LYNGUINE_CRED")
manager = CredentialManager(providers=[provider])

Advantages:

  • No additional dependencies

  • Easy integration with deployment systems

  • No file storage required

Disadvantages:

  • Credentials visible in process environment

  • Not suitable for long-term storage

  • Limited to process lifetime

Encrypted Files

Best for: Production environments, persistent storage, desktop applications

from lynguine.security import EncryptedFileCredentialProvider, CredentialManager

# Set master key (do this once, store securely!)
import os
os.environ["LYNGUINE_MASTER_KEY"] = "your-secure-master-password"

provider = EncryptedFileCredentialProvider(
    storage_path="~/.lynguine/credentials",
    master_key=os.environ["LYNGUINE_MASTER_KEY"]
)

manager = CredentialManager(providers=[provider])

Advantages:

  • Strong encryption (AES via Fernet)

  • Persistent storage

  • Secure file permissions (0600)

  • Metadata tracking

Disadvantages:

  • Requires cryptography library

  • Master key management required

  • Slower than environment variables

Cloud Vaults (Future)

Support for HashiCorp Vault and AWS Secrets Manager is planned for future releases.

Access Control

Basic Access Control

from lynguine.security import AccessPolicy, AccessLevel

policy = AccessPolicy()

# Allow specific user read access to production credentials
policy.add_rule(
    credential_pattern="prod_*",
    user_pattern="prod_user",
    access_level=AccessLevel.READ
)

# Allow admins full access to all credentials
policy.add_rule(
    credential_pattern="*",
    user_pattern="admin",
    access_level=AccessLevel.ADMIN
)

Access Levels

  • NONE: No access

  • READ: Can retrieve credentials

  • WRITE: Can create and update credentials

  • DELETE: Can delete credentials

  • ADMIN: Full access to all operations

Authorization

from lynguine.security import CredentialAccessController, AccessLevel

controller = CredentialAccessController()

# Authorize access before retrieving credentials
controller.authorize_access(
    credential_key="google_sheets_oauth",
    operation=AccessLevel.READ,
    user="current_user",
    context="data_processing"
)

Audit Logging

Enable Audit Logging

from lynguine.security import AuditLogger, AuditEventType

# Create audit logger
audit_logger = AuditLogger(
    log_path="~/.lynguine/audit.log",
    enable_file=True,
    enable_console=False
)

Query Audit Events

from datetime import datetime, timedelta

# Query last 24 hours of credential access events
events = audit_logger.query_events(
    event_type=AuditEventType.CREDENTIAL_ACCESS,
    start_time=datetime.now() - timedelta(days=1),
    limit=100
)

for event in events:
    print(f"{event['timestamp']}: {event['user']} accessed {event['credential_key']}")

Audit Event Types

  • CREDENTIAL_ACCESS: Credential retrieved

  • CREDENTIAL_CREATE: New credential created

  • CREDENTIAL_UPDATE: Credential modified

  • CREDENTIAL_DELETE: Credential deleted

  • ACCESS_DENIED: Access attempt denied

  • VALIDATION_FAILED: Credential validation failed

  • RATE_LIMIT_EXCEEDED: Rate limit triggered

Secure Logging

Prevent credential leakage in application logs:

from lynguine.security import get_secure_logger, setup_secure_logging

# Get a secure logger that automatically sanitizes sensitive data
logger = get_secure_logger(__name__)

# Sensitive data is automatically redacted
logger.info(f"Connecting with api_key={api_key}")
# Output: "Connecting with api_key=***API_KEY***"

# Set up secure logging for the entire application
setup_secure_logging(level=logging.INFO)

Custom Sanitization

from lynguine.security import sanitize_dict

sensitive_data = {
    "username": "john",
    "password": "secret123",
    "api_key": "abc-xyz-123"
}

sanitized = sanitize_dict(sensitive_data)
print(sanitized)
# {'username': 'john', 'password': '***', 'api_key': '***REDACTED***'}

Migration

Automated Migration

Migrate existing plain-text credentials to secure storage:

from lynguine.security import CredentialMigrator

# Set master key for encrypted storage
import os
os.environ["LYNGUINE_MASTER_KEY"] = "your-master-key"

# Create migrator
migrator = CredentialMigrator()

# Migrate Google Sheets credentials
report = migrator.migrate_google_sheets_credentials(
    config_file="~/.lynguine/config/machine.yml",
    credential_name="google_sheets_oauth",
    dry_run=False  # Set True to test first
)

print(f"Migrated: {len(report['migrated'])} credentials")
print(f"Errors: {len(report['errors'])} errors")

# Validate migration
validation = migrator.validate_migration("~/.lynguine/config/machine.yml")
if validation['valid']:
    print("✓ Migration successful")
else:
    print("✗ Issues found:", validation['issues'])

Manual Migration Steps

  1. Backup Configuration

    cp ~/.lynguine/config/machine.yml ~/.lynguine/config/machine.yml.backup
    
  2. Set Master Key

    export LYNGUINE_MASTER_KEY="your-secure-master-password"
    
  3. Store Credentials

    from lynguine.security import set_credential
    
    set_credential("google_sheets_oauth", {
        "client_id": "your-client-id",
        "client_secret": "your-client-secret"
    })
    
  4. Update Configuration

    Replace:

    google_oauth:
      client_id: your-client-id
      client_secret: your-client-secret
    

    With:

    google_oauth: ${credential:google_sheets_oauth}
    
  5. Test

    from lynguine import Interface
    
    interface = Interface.from_file("_lynguine.yml")
    # Should work without errors
    

Rollback

If migration fails, restore from backup:

migrator.rollback("/path/to/backup/machine.yml.backup_20231215_143022")

Advanced Configuration

Multiple Providers with Priority

from lynguine.security import (
    CredentialManager,
    EnvironmentCredentialProvider,
    EncryptedFileCredentialProvider
)

# Environment variables take priority (e.g., for dev overrides)
env_provider = EnvironmentCredentialProvider(prefix="LYNGUINE_CRED")

# Encrypted files for production credentials
file_provider = EncryptedFileCredentialProvider(
    storage_path="~/.lynguine/credentials",
    master_key=os.environ["LYNGUINE_MASTER_KEY"]
)

# Create manager with priority order
manager = CredentialManager(
    providers=[env_provider, file_provider],  # env checked first
    cache_ttl=300,  # 5 minute cache
    enable_cache=True
)

Custom Validators

from lynguine.security import get_credential_manager

manager = get_credential_manager()

# Register custom validator
def validate_google_oauth(credential):
    """Ensure Google OAuth has required fields."""
    if "value" not in credential:
        return False
    value = credential["value"]
    required = ["client_id", "client_secret", "redirect_uri"]
    return all(field in value for field in required)

manager.register_validator("google_oauth", validate_google_oauth)

# Credentials are now validated on retrieval
creds = manager.get_credential("google_auth", credential_type="google_oauth")

Rate Limiting

from lynguine.security import RateLimiter

# Limit to 100 requests per minute per user
limiter = RateLimiter(max_requests=100, time_window=60)

if not limiter.check_rate_limit("google_sheets_oauth", user="current_user"):
    raise Exception("Rate limit exceeded")

Security Best Practices

1. Master Key Management

DO:

  • Generate strong master keys (20+ characters, mixed case, numbers, symbols)

  • Store master key in secure key management system

  • Use different master keys for dev/staging/production

  • Rotate master key periodically

DON’T:

  • Hard-code master key in source code

  • Commit master key to version control

  • Share master key via email or chat

  • Use weak or predictable master keys

2. Credential Storage

DO:

  • Use encrypted file storage for production

  • Set restrictive file permissions (0600)

  • Store credentials outside of application directory

  • Back up encrypted credential files securely

DON’T:

  • Store credentials in plain text

  • Use world-readable permissions

  • Store credentials in application repository

  • Forget to backup credentials

3. Access Control

DO:

  • Implement principle of least privilege

  • Use specific credential patterns

  • Monitor audit logs regularly

  • Set up rate limiting

DON’T:

  • Grant blanket admin access

  • Ignore access denied events

  • Disable audit logging

  • Allow unlimited credential access

4. Credential Lifecycle

DO:

  • Rotate credentials regularly (90 days or less)

  • Revoke credentials immediately on compromise

  • Track credential usage via audit logs

  • Test credential rotation procedures

DON’T:

  • Use the same credentials indefinitely

  • Leave old credentials active after rotation

  • Forget to update credential references

  • Skip testing after rotation

Troubleshooting

Common Issues

“Credential not found” Error

# Check available credentials
from lynguine.security import get_credential_manager

manager = get_credential_manager()
print("Available credentials:", manager.list_credentials())

“Access denied” Error

# Check access policy
from lynguine.security import get_access_controller

controller = get_access_controller()
# Review and update policies as needed

“Cryptography library not available”

pip install cryptography

Wrong Master Key

If you get decryption errors:

  1. Verify master key is correct

  2. Check LYNGUINE_MASTER_KEY environment variable

  3. Ensure same master key was used for encryption

Migration Validation Failures

# Get detailed validation report
validation = migrator.validate_migration("config.yml")
print("Issues:", validation['issues'])

# Check each credential reference
for ref in validation['credential_references']:
    try:
        cred = manager.get_credential(ref)
        print(f"✓ {ref}: OK")
    except Exception as e:
        print(f"✗ {ref}: {e}")

API Reference

Core Functions

  • get_credential(key, credential_type=None, default=None): Retrieve a credential

  • set_credential(key, value, credential_type=None): Store a credential

  • get_credential_manager(): Get global credential manager

  • get_access_controller(): Get global access controller

Classes

  • CredentialManager: Central credential management

  • EnvironmentCredentialProvider: Environment variable backend

  • EncryptedFileCredentialProvider: Encrypted file backend

  • CredentialAccessController: Access control and auditing

  • AuditLogger: Security event logging

  • CredentialMigrator: Migration utilities

See module documentation for detailed API reference.

Examples

Example 1: Simple Google Sheets Integration

from lynguine.security import set_credential
from lynguine import Interface

# One-time setup: Store credentials
google_creds = {
    "client_id": "123456789.apps.googleusercontent.com",
    "client_secret": "your-client-secret",
    "redirect_uri": "http://localhost:8080"
}
set_credential("google_sheets_oauth", google_creds)

# Update _lynguine.yml:
# google_oauth: ${credential:google_sheets_oauth}

# Use normally
interface = Interface.from_file("_lynguine.yml")
data, _ = interface.read_inputs()

Example 2: Multi-Environment Setup

import os
from lynguine.security import (
    CredentialManager,
    EnvironmentCredentialProvider,
    EncryptedFileCredentialProvider
)

# Detect environment
env = os.environ.get("LYNGUINE_ENV", "development")

if env == "production":
    # Production: Use encrypted files only
    provider = EncryptedFileCredentialProvider(
        storage_path="/var/lynguine/credentials",
        master_key=os.environ["LYNGUINE_MASTER_KEY"]
    )
else:
    # Development: Use environment variables
    provider = EnvironmentCredentialProvider()

manager = CredentialManager(providers=[provider])

Example 3: Credential Rotation

from lynguine.security import get_credential_manager

manager = get_credential_manager()

# Store new credentials
new_creds = {
    "client_id": "new-client-id",
    "client_secret": "new-client-secret"
}

# Update with new credentials
manager.set_credential("google_sheets_oauth", new_creds)

# Invalidate cache to force refresh
if manager.cache:
    manager.cache.invalidate("google_sheets_oauth")

print("Credentials rotated successfully")

Support and Resources

License

This security module is part of Lynguine and is licensed under the same license as the main project.