Anonymize AWS infrastructure identifiers for secure LLM processing
Project description
CloudMask helps you safely share AWS infrastructure data with Large Language Models by anonymizing sensitive identifiers while maintaining structure and reversibility.
Features
- 🔒 Secure Anonymization: Hash-based deterministic anonymization
- 🔄 Reversible: Complete mapping for unanonymization
- 🏗️ Structure-Preserving: Maintains AWS resource ID prefixes (vpc-, i-, etc.)
- ⚙️ Configurable: YAML-based configuration for company names and custom patterns
- 🐍 Dual Interface: Use as CLI tool or Python library
- 📋 Clipboard Support: Direct clipboard anonymization for quick workflows
- 📦 Modern Python: Built with Python 3.10+ features (pattern matching, union types)
- 🚀 Minimal Dependencies: Only requires PyYAML and pyperclip
Requirements
- Python 3.10 or higher
- PyYAML 6.0+
CloudMask leverages modern Python features including structural pattern matching, union type operators, and built-in generic types.
Installation
pip install cloudmask-aws
Quick Start
CLI Usage
# Generate config file
cloudmask init-config
# Anonymize (mapping stored in ~/.cloudmask/mapping.json by default)
cloudmask anonymize -i infrastructure.txt -o anonymized.txt
# Anonymize clipboard content
cloudmask anonymize --clipboard
# Restore original values
cloudmask unanonymize -i llm-response.txt -o restored.txt
# Restore clipboard content
cloudmask unanonymize --clipboard
# Use custom mapping location if needed
cloudmask anonymize --clipboard -m /path/to/custom-mapping.json
Python Library Usage
from cloudmask import CloudMask, CloudUnmask, Storage
# Anonymize text
mask = CloudMask(seed="my-secret-seed")
anonymized = mask.anonymize("""
Instance i-1234567890abcdef0 is running in vpc-abcdef123456
Account: 123456789012
Company: Acme Corp
""")
# Save mapping to secure central location (~/.cloudmask/mapping.json)
mask.save_mapping(Storage.DefaultMappingPath)
# Unanonymize later
unmask = CloudUnmask(mapping_file=Storage.DefaultMappingPath)
original = unmask.unanonymize(anonymized)
Quick Function Usage
from cloudmask import anonymize, unanonymize
# One-liner anonymization
text, mapping = anonymize(
"Instance i-123 in account 123456789012",
seed="my-seed",
company_names=["Acme Corp"]
)
# Restore original
original = unanonymize(text, mapping)
Configuration
Create a ~/.cloudmask/config.yml file (or use cloudmask init-config):
company_names:
- Acme Corp
- Example Inc
- MyCompany LLC
custom_patterns:
- pattern: '\bTICKET-\d{4,6}\b'
name: ticket
- pattern: '\bPROJ-[A-Z0-9]+'
name: project
# Example: Match company domains
- pattern: '[a-zA-Z0-9][-a-zA-Z0-9.]*\.acme\.local\b'
name: domain
# Example: Match company emails
- pattern: '[a-zA-Z0-9._%+-]+@acme-corp\.local\b'
name: email
preserve_prefixes: true
anonymize_ips: true
anonymize_domains: false
seed: my-secret-seed
Custom Pattern Edge Cases
When creating custom patterns, be aware of:
- Case sensitivity: Patterns are case-insensitive by default
- Multi-level subdomains: Use
[-a-zA-Z0-9.]*to matchapp.corp.acme.local - HTML entities:
"in data is handled automatically - Email variations: Pattern supports
user+tag@domainanduser.name@domain - URLs and paths: Patterns work in
https://server.acme.local/path - Trailing punctuation: Word boundaries (
\b) handleserver.acme.local.
Test your patterns:
cloudmask anonymize -i test.txt -o output.txt
grep -i "sensitive-term" output.txt # Should return nothing
What Gets Anonymized?
- ✅ AWS Resource IDs (vpc-, i-, sg-, ami-, etc.)
- ✅ AWS Account IDs (12-digit numbers)
- ✅ AWS ARNs
- ✅ IP Addresses
- ✅ Company names (from config)
- ✅ Custom patterns (via regex)
- ✅ Domain names (optional)
Use Cases
- 🤖 LLM Assistance: Get help with infrastructure without exposing sensitive IDs
- 📊 Data Sharing: Share infrastructure diagrams and configs safely
- 🔍 Security Analysis: Analyze configs with external tools
- 📝 Documentation: Create shareable examples from real infrastructure
Advanced Usage
Using in Scripts
from cloudmask import CloudMask, Config
from pathlib import Path
# Load custom config
config = Config.from_yaml(Path("custom-config.yaml"))
# Create anonymizer
mask = CloudMask(config=config, seed="production-seed")
# Process multiple files
for file in Path("configs").glob("*.yaml"):
output = Path("anonymized") / file.name
mask.anonymize_file(file, output)
# Save single mapping for all files
mask.save_mapping("master-mapping.json")
Context Manager
from cloudmask import TemporaryMask
with TemporaryMask(seed="temp-seed") as mask:
anonymized = mask.anonymize("vpc-123 i-456")
# Process anonymized data
# Mapping is discarded after context exits
Batch Processing
from cloudmask import create_batch_anonymizer
# Create reusable anonymizer
anon = create_batch_anonymizer(seed="batch-seed")
# Use it multiple times
result1 = anon("vpc-123")
result2 = anon("i-456")
Central Storage
CloudMask stores mapping files in a secure central location by default:
~/.cloudmask/mapping.json
Benefits
- 🔐 Automatic Security: Files created with
600permissions (owner read/write only) - 📍 Centralized: All mappings in one location
- 🔄 Auto-Merge: New mappings are merged with existing ones (same seed required)
- ⚡ Convenient: No need to specify
-mflag for common workflows
Seed Verification
CloudMask tracks which seed created each mapping file. Mappings can only be merged if they use the same seed:
# First use
mask1 = CloudMask(seed="prod-seed")
mask1.anonymize("vpc-11111")
mask1.save_mapping(Storage.DefaultMappingPath) # Creates mapping
# Later use with SAME seed - mappings merge automatically
mask2 = CloudMask(seed="prod-seed")
mask2.anonymize("vpc-22222")
mask2.save_mapping(Storage.DefaultMappingPath) # Merges with existing
# Different seed - prevents accidental corruption
mask3 = CloudMask(seed="different-seed")
mask3.save_mapping(Storage.DefaultMappingPath) # ERROR: Seed mismatch
Custom Locations
You can still use custom mapping locations:
cloudmask anonymize -i file.txt -m /custom/path/mapping.json
mask.save_mapping("/custom/path/mapping.json")
Security Notes
⚠️ Keep your mapping files secure! They contain the reversible mappings.
- The
~/.cloudmask/directory is automatically secured with700permissions - Mapping files are created with
600permissions (owner only) - Store mapping files separately from anonymized data
- Use strong, unique seeds for different projects
- Don't commit mapping files to version control
- Consider encrypting mapping files for sensitive data
- Always use the same seed for a project to enable mapping merges
Contributing
Contributions welcome! Please check out the GitHub repository.
License
MIT License - see LICENSE file for details
Troubleshooting
Pattern Not Matching?
- Test the regex:
python -c "import re; print(re.search(r'your-pattern', 'test-string'))" - Check case sensitivity: Patterns are case-insensitive
- Verify word boundaries:
\bmay not work with special characters - Test with real data: Use small samples first
Data Still Leaking?
- Check pattern order: Custom patterns run before company names
- Verify pattern name: Use generic names like
domain, notacme-domain - Test thoroughly:
grep -i "sensitive" output.txt
Support
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cloudmask_aws-0.4.1.tar.gz.
File metadata
- Download URL: cloudmask_aws-0.4.1.tar.gz
- Upload date:
- Size: 448.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4557e509b9710784c78cf236e95a404c25ff87d3ccd7545ae1eab5177b929706
|
|
| MD5 |
4b50d57145215bae4b362b0067f361ea
|
|
| BLAKE2b-256 |
749731d9a29a44e09f475c2157f3a13f862cca7a3df952f3541e9324edbae5b7
|
File details
Details for the file cloudmask_aws-0.4.1-py3-none-any.whl.
File metadata
- Download URL: cloudmask_aws-0.4.1-py3-none-any.whl
- Upload date:
- Size: 31.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2ba455ed8836cf1ed264aaeebc80adf3a8ade1bbd3fb20e5932b472ff243ea70
|
|
| MD5 |
82829814344f0c57afac6db034b246fb
|
|
| BLAKE2b-256 |
edd8d5a7343f086d664f0df7f3679066a31abe45b9df8c9d3fac85df435965ed
|