After a year of building enterprise platforms, I kept solving the same problems:
- How do I handle JWT auth with RBAC that actually scales?
- Why does every project need its own logging configuration?
- How do I manage secrets across Azure Key Vault and local dev?
- What’s the cleanest way to handle database connection pooling?
So I extracted the patterns into 10 reusable packages and open sourced them.
The Netrun Service Library
All packages are MIT licensed and available on PyPI:
pip install netrun-auth netrun-logging netrun-config
The Foundation Layer
netrun-logging - Structured logging that doesn’t suck
Built on Structlog for ~2.9x performance improvement over stdlib. The killer feature? Automatic redaction of sensitive fields:
from netrun_logging ...
After a year of building enterprise platforms, I kept solving the same problems:
- How do I handle JWT auth with RBAC that actually scales?
- Why does every project need its own logging configuration?
- How do I manage secrets across Azure Key Vault and local dev?
- What’s the cleanest way to handle database connection pooling?
So I extracted the patterns into 10 reusable packages and open sourced them.
The Netrun Service Library
All packages are MIT licensed and available on PyPI:
pip install netrun-auth netrun-logging netrun-config
The Foundation Layer
netrun-logging - Structured logging that doesn’t suck
Built on Structlog for ~2.9x performance improvement over stdlib. The killer feature? Automatic redaction of sensitive fields:
from netrun_logging import get_logger
logger = get_logger(__name__)
# This automatically redacts the password field
logger.info("user_login",
username="daniel",
password="secret123", # Logged as "password": "[REDACTED]"
ip_address="192.168.1.1"
)
netrun-errors - Exception hierarchy that maps to HTTP
Instead of catching generic exceptions, use typed errors:
from netrun_errors import NotFoundError, ValidationError
@app.get("/users/{user_id}")
async def get_user(user_id: str):
user = await db.get_user(user_id)
if not user:
raise NotFoundError("User", user_id) # Returns 404
return user
The Auth Layer
netrun-auth - JWT + RBAC + Multi-tenant isolation
This was the hardest one to get right. Uses Casbin for policy-based access control:
from netrun_auth import JWTAuthenticator, require_permission
auth = JWTAuthenticator(
secret_key="your-secret",
algorithm="HS256"
)
@app.get("/admin/users")
@require_permission("users:read")
async def list_users(user = Depends(auth.get_current_user)):
# Only users with users:read permission can access
return await get_users()
The multi-tenant isolation ensures users can only access their own tenant’s data:
@require_tenant_access
async def get_tenant_data(tenant_id: str, user = Depends(auth.get_current_user)):
# Automatically validates user.tenant_id == tenant_id
return await db.get_tenant_data(tenant_id)
The Config Layer
netrun-config - Azure Key Vault with local fallback
Works in production with Key Vault and locally with .env files:
from netrun_config import AzureKeyVaultConfig
config = AzureKeyVaultConfig(
vault_url="https://my-vault.vault.azure.net",
cache_ttl=300 # Cache secrets for 5 minutes
)
# In production: fetches from Key Vault
# Locally: falls back to environment variables
db_password = await config.get_secret("database-password")
The LLM Layer
netrun-llm - Multi-provider orchestration
This one was fun. Abstracts away the differences between LLM providers:
from netrun_llm import LLMOrchestrator
llm = LLMOrchestrator(
providers=["azure-openai", "ollama", "claude"],
fallback_enabled=True
)
# Automatically fails over if primary provider is down
response = await llm.complete(
prompt="Summarize this document",
model="gpt-4",
fallback_model="llama2" # Use Ollama if Azure is down
)
The Data Layer
netrun-db-pool - Async SQLAlchemy that handles connection storms
Connection pooling with automatic health checks:
from netrun_db_pool import DatabasePool
pool = DatabasePool(
url="postgresql+asyncpg://...",
pool_size=20,
max_overflow=10,
health_check_interval=30
)
async with pool.session() as session:
result = await session.execute(query)
The Design Philosophy
Soft Dependencies
Every package works standalone. But when you install multiple packages, they automatically integrate:
netrun-auth + netrun-logging = Auth events automatically logged
netrun-config + netrun-logging = Secret access audited
netrun-db-pool + netrun-errors = Connection errors typed
This is achieved through runtime detection:
try:
from netrun_logging import get_logger
logger = get_logger(__name__)
except ImportError:
import logging
logger = logging.getLogger(__name__)
Zero Config Defaults
Every package has sensible defaults. You don’t need to configure anything to get started:
from netrun_auth import JWTAuthenticator
# Works with defaults
auth = JWTAuthenticator()
# Or customize everything
auth = JWTAuthenticator(
secret_key="...",
algorithm="RS256",
issuer="my-app",
audience=["api", "web"]
)
Testing First
netrun-pytest-fixtures provides unified test fixtures:
# conftest.py
pytest_plugins = ["netrun_pytest_fixtures"]
# Your tests automatically get:
# - mock_auth: Pre-configured auth bypass
# - mock_db: In-memory SQLite
# - mock_config: Environment-based config
# - mock_llm: Deterministic LLM responses
What’s Next
I’m actively maintaining these packages. Current priorities:
- Better documentation (it’s in the READMEs but needs a proper docs site)
- More LLM providers (Anthropic Claude API, Google Gemini)
- OpenTelemetry tracing across all packages
Try It Out
pip install netrun-auth netrun-logging netrun-config
MIT licensed. Issues and PRs welcome.
What patterns do you use for cross-cutting concerns in your FastAPI apps? I’d love to hear what I’m missing.