PlainID Content Control

Prev Next

PlainID includes the AI Content Controls Service, a self-hosted service that categorizes prompts and masks sensitive data in the content that flows through agentic AI applications. Gateways, Authorizers, SDKs, and AI agents call the service to learn what a prompt is about and to mask sensitive entities before content reaches a model or a user. Categorization supports input guardrails, and masking supports response guardrails. The service analyzes and transforms content only. The PlainID Policy Decision Point (PDP) evaluates Policies and makes every authorization decision.

The service runs in a customer-managed Kubernetes cluster and installs with a Helm chart. It reads its category catalog from an Asset Type in a PlainID Environment, so administrators manage categories in the Platform and the service picks up changes automatically. Categorization uses a large language model (LLM) provider that the administrator configures. Masking runs locally in the same pod and does not need an LLM.

For more information on Input and Output Guardrail prompts, refer to our documentation on Input & Output Guardrails.

Capabilities

Capability Endpoint Description
Prompt categorization POST /v1/categorize Classifies a single prompt or a full conversation against the category catalog of an Asset Type. Callers can also send their own categories in the request, which the service adds to the catalog and labels by source.
Content masking POST /v1/mask Detects sensitive entities in text and masks them. The configuration sets a default masking operator and can override it per entity type.
Category refresh POST /v1/admin/categories/refresh Forces an immediate catalog refresh for one Asset Type (?asset_type_id=) or for every cached Asset Type.
Liveness GET /healthz Reports liveness, the active configuration hash, and the status of each capability.
Readiness GET /readyz Reports ready when the category catalog has loaded and masking is available or still within its grace window.
Metrics GET /metrics Exposes metrics in Prometheus format.

Prerequisites

Before deploying the service, make sure the following are in place:

  • A Kubernetes cluster with Helm installed
  • The PlainID Tenant ID and Environment ID
  • PlainID API credentials: an API token, or a client ID and client secret
  • Credentials for a supported LLM provider, such as Amazon Bedrock or Azure OpenAI
  • An Asset Type in the Environment that holds the categories to classify against

Deploying the service

  1. Create a Kubernetes secret that holds the PlainID credentials and the LLM provider credentials.

  2. Install the chart, passing the Tenant ID, Environment ID, and secret name:

    helm install ccs plainid-content-controls \
      --set config.plainid.tenant_id=<tenant-id> \
      --set config.plainid.env_id=<environment-id> \
      --set existingSecret=<secret-name>
    
  3. Wait for the pod to report ready, then call GET /healthz to confirm that each capability reports a healthy status.

The chart ships tenant_id and env_id empty on purpose. If either value is missing, the pod does not start, which prevents the service from reading categories from the wrong Environment.

Each pod runs three containers: the service and two Microsoft Presidio containers (analyzer and anonymizer) that perform masking.

Configuring the service

The service reads configuration from a YAML file (mounted as a ConfigMap) and from environment variables. When both set the same key, the environment variable takes precedence. In the Helm chart, every value under config.* becomes part of the ConfigMap.

Environment variables use the PLAINID_ prefix, with a double underscore for each level of nesting:

PLAINID_CONFIG_FILE=/etc/plainid/config.yaml
PLAINID_CLASSIFICATION__LLM__MODEL=<provider>/<model-id>
PLAINID_PLAINID__CLIENT_SECRET=<client-secret>

Set secrets only through environment variables, never in the configuration file. This includes the PlainID client secret or API token and the masking encryption key. Provider credentials such as AZURE_API_KEY or AWS credentials use the provider's standard environment variable names.

The service validates its configuration at startup and refuses to start if anything is invalid, for example a classification prompt template that does not reference the category list.

Category source

By default, the service loads categories from an Asset Type in the PlainID Environment and refreshes them in the background. For testing without a Platform connection, a static catalog can replace the Asset Type:

plainid:
  categories:
    source: static
    static:
      - {id: c1, name: HR, description: "Human resources, compensation, hiring"}

LLM provider

POST /v1/categorize is the only endpoint that needs an LLM provider. Masking, health, and metrics work do not require one.

When using Amazon Bedrock:

  • Use the inference-profile model ID, which includes a region prefix such as us.
  • Set AWS_REGION_NAME to the region the credential belongs to. A mismatch causes every call to fail authentication, regardless of the model.
  • The service automatically switches to prompt-instructed JSON output, because Bedrock does not accept structured-output requests.

Working with the service

  1. Correlate requests. Send an X-Request-ID header with each call. The service echoes it in the response and includes it in every log and audit record when the log format is json. Provide this ID to PlainID Support when reporting an issue.
  2. Pick up category changes immediately. Call POST /v1/admin/categories/refresh after changing categories in the Platform, rather than waiting for the next background refresh.
  3. Monitor the service. Scrape /metrics with Prometheus and watch the per-capability status in /healthz.

Notes

  • Masking outage: If the Presidio containers restart or go down, POST /v1/mask returns 503 until they recover. The pod stays in service, and categorization keeps working.
  • Grace window: Readiness tolerates a masking outage for a configured grace window. After the window expires, the pod reports not ready.
  • Input size: The configuration sets size limits per prompt and per conversation, and determines whether the service truncates or rejects input that exceeds them.
  • No caller authentication. The service does not authenticate callers. Restrict access at the network layer, for example with Kubernetes network policies, so that only the gateways, Authorizers, and agents that use the service can reach it.
  • Listener address. The container entrypoint controls the listening host and port. Setting service.host or service.port in the configuration file has no effect.
  • Correlation IDs do not pass through to the Platform, the LLM provider, or Presidio.
  • Masking uses Microsoft Presidio, an open-source data protection and de-identification SDK. For more information, see microsoft.github.io/presidio.

© 2026 PlainID LTD. All rights reserved.