Security Hardening

Memory Service is often placed behind agent applications and identity infrastructure. Treat the service as a sensitive data plane: it stores conversation content, attachment bytes, index material, and administrative metadata. This page is an operational checklist for deploying and maintaining that data plane.

Baseline Runtime

  • Run the container as non-root. The published image uses UID/GID 10001.
  • Use a read-only root filesystem and mount only the paths that must be writable.
  • Mount MEMORY_SERVICE_TEMP_DIR on a writable volume such as /var/lib/memory-service/tmp.
  • Drop Linux capabilities and set allowPrivilegeEscalation: false.
  • Disable Kubernetes service-account token mounting unless the pod explicitly needs the Kubernetes API.
  • Pin deployment images by immutable version or digest in production. The repository Kustomize examples keep deployment images paired with @sha256: digests, and Compose pins pulled third-party images while using non-latest local tags for services it builds locally.

Secrets

  • Generate unique values per environment for database passwords, API keys, OIDC client secrets, attachment store credentials, and encryption keys. Attachment download signing keys are derived from the configured encryption provider material; do not configure a separate attachment signing secret.
  • Use dek, kms, or vault as the primary encryption provider for production data. MEMORY_SERVICE_ENCRYPTION_ALLOW_PLAIN=true is an explicit unsafe opt-in.
  • Store production secrets in a secret manager or Kubernetes Secret managed by your deployment system.
  • Rotate any value that was checked into source control, printed in logs, or shared in a support bundle.

Network Exposure

  • Treat the repository compose.yaml as local-development infrastructure, not as a production network boundary.
  • Keep Prometheus, Grafana, databases, object storage consoles, and management endpoints off the public gateway.
  • Put browser-facing traffic behind TLS and configure MEMORY_SERVICE_BASE_URL to the externally reachable HTTPS origin.
  • Choose one transport per TCP listener outside testing mode: either disable plaintext when Memory Service terminates TLS, or disable in-process TLS when plaintext is restricted to an internal listener behind a TLS terminator. Set MEMORY_SERVICE_ALLOW_NON_LOOPBACK_PLAINTEXT=true only for the latter deployment boundary.
  • Keep request body deadlines enabled. Ordinary REST request bodies default to 30s; multipart attachment uploads default to 5m.
  • Configure forwarded client-IP trust with MEMORY_SERVICE_TRUSTED_PROXY_CIDRS. The resolved client IP keys pre-authentication source and authentication-failure rate limits. Trusting spoofable forwarded addresses lets callers evade those limits by changing their reported IP; failing to trust the actual proxy makes its clients share one rate-limit bucket. Leave the setting unset to trust no proxies. Universal ranges (0.0.0.0/0,::/0) intentionally accept forwarded client IPs from every peer and are appropriate only when direct callers choosing their reported IP is acceptable or a network boundary forces traffic through a controlled proxy.
  • Configure MEMORY_SERVICE_MANAGEMENT_PORT or MEMORY_SERVICE_MANAGEMENT_UNIX_SOCKET outside testing mode. Use MEMORY_SERVICE_MANAGEMENT_ON_MAIN_LISTENER=true only when the main listener is already inside an appropriate internal network boundary. Use MEMORY_SERVICE_MANAGEMENT_ALLOW_NON_LOOPBACK=true only with network policy or firewall rules that keep unauthenticated health and metrics endpoints internal.

Authentication

  • Require OIDC audience checks for production issuers.
  • Keep API-key clients scoped to the least privilege required by each agent or processor.
  • Disable wildcard credentialed CORS; list exact browser origins.
  • Keep admin APIs on a separate network path when possible.
  • Keep MEMORY_SERVICE_DEVELOPER_FRONTEND_AUTH_MODE=oidc in production. The api-key mode exposes its admin credential to browsers through /developer/config.json and is only intended for isolated local development.

Trusted User Assertion

  • Treat MEMORY_SERVICE_TRUSTED_USER_ID_CLIENTS as a security boundary. Use exact client IDs and trust only agent applications that authenticate end users before setting X-User-ID or gRPC x-user-id metadata.
  • Keep assertion trust separate from MEMORY_SERVICE_ROLES_ADMIN_CLIENTS, auditor roles, and indexer roles. Trusting a client to select a user must not grant administrative access.
  • Require a valid API key or OIDC token on every asserted request. X-User-ID is identity context, not a credential.
  • Strip public callers’ inbound X-User-ID at gateways unless they are intended to control the asserted identity. Memory Service’s trusted-client check remains mandatory even behind a gateway.
  • Protect API keys as secrets and rotate them independently of the trusted-client allowlist. Removing a client from the allowlist should stop delegation without invalidating its other authorized client operations.
  • Preserve both the authenticated client identity and effective user in security logs, but never log bearer tokens or API keys.
  • Attach user metadata per request or per derived gRPC stub. Do not mutate a shared client stub or global header map where concurrent users could leak identity into one another’s calls.
  • Verify that admin and system APIs ignore asserted-user metadata and that assertions from untrusted clients behave exactly like absent metadata.

Rate Limits and Diagnostics

  • Preserve X-Request-ID through ingress and gateway layers and include it in support workflows. REST error bodies include the same requestId; gRPC returns x-request-id metadata.
  • Keep local process rate limits enabled unless an ingress or gateway limiter already covers the same boundary. MEMORY_SERVICE_RATE_LIMIT_MODE=off is an explicit unsafe opt-out and exports memory_service_security_unsafe_config{reason="rate_limits_off"} 1.
  • Treat local limits as per-replica protection. In multi-replica deployments, enforce cluster-wide quotas at the ingress, gateway, or service mesh.

Attachments

  • Use S3-compatible storage for durable multi-node deployments.
  • Serve browser-downloadable attachments through the service so response headers can force safe content type and disposition decisions.

Upgrade and Rollback

  • Test the exact production configuration in staging before upgrading. Startup validation may now reject plaintext encryption, issuer-only OIDC trust, wildcard credentialed CORS, malformed proxy CIDRs, dual plaintext/TLS TCP listeners, missing management-listener decisions, non-loopback management binds without an explicit acknowledgement, or a missing developer frontend base URL.
  • Stop all old replicas before the breaking release. Mixed old/new binaries are unsupported.
  • Take coordinated database and attachment-object backups, then reset the datastore and attachment store before startup initializes schema version 1.
  • Rollback requires restoring both backups; the breaking release does not read pre-release schemas, MSEH v1 fields, or MSEH v2 attachment streams.