Skip to main content

Common utilities for observability platform: auth, TLS, credentials, and proto stubs

Project description

Observability Common

Shared utilities for the observability platform, providing authentication, TLS configuration, and protocol buffer stubs used by all services.

Design

This package contains shared code including that for authentication, TLS handling, and gRPC communication. It includes:

  • Server-side auth providers: Validate incoming requests (JWT, mTLS, API keys)
  • Client-side auth hooks: Add credentials to outgoing requests
  • TLS configuration: Consistent TLS/mTLS setup across services
  • gRPC interceptors: Authentication enforcement for gRPC services
  • Protocol buffer stubs: Generated Python code for all service protos

Components

Server-Side Authentication (auth.py)

Auth providers validate incoming requests and extract entity/role information:

from observability_common import JWTAuthProvider, MTLSAuthProvider, APIKeyAuthProvider

# JWT validation with JWKS endpoint
jwt_provider = JWTAuthProvider(
    jwks_url="https://keycloak:8443/realms/myapp/protocol/openid-connect/certs",
    issuer="https://keycloak:8443/realms/myapp",
    entity_claim="preferred_username",
    roles_claim="roles",
)

# mTLS - extract entity from certificate
mtls_provider = MTLSAuthProvider(entity_source="cn")

# API key authentication
apikey_provider = APIKeyAuthProvider(
    metadata_key="x-api-key",
    static_keys={"dev-key": "developer", "prod-key": "service"},
)

# Chain multiple providers (try in order)
from observability_common import ChainAuthProvider
chain = ChainAuthProvider([jwt_provider, apikey_provider, mtls_provider])

# Validate a request
result = provider.authenticate(gRPC_context)
if result.authenticated:
    print(f"Entity: {result.entity}, Roles: {result.roles}")

Client-Side Authentication (auth_hooks.py)

Auth hooks add credentials to outgoing gRPC requests:

from observability_common import (
    NoAuthHook,
    APIKeyAuthHook,
    OIDCAuthHook,
    KeycloakAuthHook,
    BrowserAuthHook,
    DeviceAuthHook,
)

# No authentication
hook = NoAuthHook()

# Static API key
hook = APIKeyAuthHook(api_key="my-secret-key")

# OAuth2 client credentials
hook = OIDCAuthHook(
    token_url="https://keycloak:8443/realms/myapp/protocol/openid-connect/token",
    client_id="my-service",
    client_secret="secret",
    scope="openid profile",
)

# Browser-based OAuth2 with PKCE
hook = BrowserAuthHook(
    authorization_url="https://keycloak:8443/realms/myapp/protocol/openid-connect/auth",
    token_url="https://keycloak:8443/realms/myapp/protocol/openid-connect/token",
    client_id="my-cli",
    redirect_port=8400,
)

# Device authorization grant
hook = DeviceAuthHook(
    device_authorization_url="https://keycloak:8443/realms/myapp/protocol/openid-connect/auth/device",
    token_url="https://keycloak:8443/realms/myapp/protocol/openid-connect/token",
    client_id="my-device",
)

# Get metadata for gRPC calls
metadata = hook.get_metadata()  # Returns [("authorization", "Bearer ...")]

TLS Configuration (tls.py)

Consistent TLS setup for clients and servers:

from observability_common import TLSConfig, ServerTLSConfig, get_shared_tls_config

# Client TLS config
client_tls = TLSConfig(
    ca_path="certs/ca.crt",
    cert_path="certs/client.crt",  # For mTLS
    key_path="certs/client.key",
)
credentials = client_tls.to_grpc_credentials()

# Server TLS config
server_tls = ServerTLSConfig(
    cert_path="certs/server.crt",
    key_path="certs/server.key",
    ca_path="certs/ca.crt",  # For mTLS client verification
    require_client_auth=True,
)
credentials = server_tls.to_grpc_credentials()

# Shared config from environment
tls = get_shared_tls_config()  # Uses TLS_CA_PATH, TLS_CERT_PATH, TLS_KEY_PATH

gRPC Interceptors (grpc_interceptors.py)

Enforce authentication and authorization for gRPC services:

from observability_common import AuthInterceptor, require_role, get_auth_context

# Create interceptor with auth provider
interceptor = AuthInterceptor(auth_provider)

# Use in gRPC server
server = grpc.server(
    futures.ThreadPoolExecutor(),
    interceptors=[interceptor],
)

# In service methods, check roles
@require_role("admin")
def AdminOnlyMethod(self, request, context):
    auth = get_auth_context(context)
    print(f"Called by: {auth.entity}")

Authorization Config (auth_config.yaml)

Central entity-to-role mapping loaded from YAML:

from observability_common import load_auth_config, get_auth_config

# Load from file
config = load_auth_config("config/auth_config.yaml")

# Get roles for an entity
roles = config.get_roles_for_entity("my-service")  # ["admin", "reader"]

Protocol Buffer Stubs

Generated stubs for all platform services are in observability_common/proto/:

  • observability_pb2.py - Observability server messages
  • credential_server_pb2.py - Credential server messages
  • policy_engine_pb2.py - Policy engine messages
  • reference_monitor_pb2.py - Reference monitor messages

Regenerate with:

make proto  # From repo root

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

sasy_common-0.1.0.tar.gz (38.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sasy_common-0.1.0-py3-none-any.whl (49.2 kB view details)

Uploaded Python 3

File details

Details for the file sasy_common-0.1.0.tar.gz.

File metadata

  • Download URL: sasy_common-0.1.0.tar.gz
  • Upload date:
  • Size: 38.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.5.8

File hashes

Hashes for sasy_common-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5a3a9407eb5a5b015313a024ad4d06ceb5942eeab508fde33aa00fe0c59821f6
MD5 9c80078a2f581a31b8cc230abd09d2b4
BLAKE2b-256 061a91ca18d9f141858db441164b69b67b2461bd62dbe21404d756e677c27e64

See more details on using hashes here.

File details

Details for the file sasy_common-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for sasy_common-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 88b34aabd28c4d643da01f71abe7086f0e94e8bcf34c8c934956352165b69623
MD5 84f703305a5837a3d76a4909c7617476
BLAKE2b-256 08e0b57886880103e451a445a8a816023ada309f3b278c95654a1deaa256eecd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page