Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/samples/deployments/k8s/charts/presidio/.helmignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,12 @@
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# CI/test artifacts
ci/
21 changes: 18 additions & 3 deletions docs/samples/deployments/k8s/charts/presidio/Chart.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
apiVersion: v2
description: A context aware, born to the cloud, customizable data loss prevention service
name: presidio
version: 2.0
appVersion: latest
description: Presidio services (analyzer + anonymizer, optional image-redactor) — context-aware PII detection, anonymization, and image redaction
type: application
home: https://github.com/microsoft/presidio
sources:
- https://github.com/microsoft/presidio
keywords:
- presidio
- pii
- anonymization
- data-loss-prevention
- privacy
maintainers:
- name: Presidio Maintainers
url: https://github.com/microsoft/presidio
# Chart version — bump on any chart change (SemVer).
version: 0.2.0
# Tracks the Presidio app release this chart targets. Quoted because "latest" is not SemVer.
appVersion: "latest"
134 changes: 134 additions & 0 deletions docs/samples/deployments/k8s/charts/presidio/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# Presidio Helm chart

Deploys the [Presidio](https://github.com/microsoft/presidio) stack to Kubernetes — the
`presidio-analyzer` (PII detection) and `presidio-anonymizer` (PII anonymization) text
services, plus an optional `presidio-image-redactor` (PII redaction in images). It mirrors the
`docker-compose-text.yml` / `docker-compose-image.yml` topology and is scaffolded from
`helm create` following community best practices.

> Scope: the analyzer and anonymizer are enabled by default. The image-redactor is **disabled
> by default** (`imageRedactor.enabled=true` to opt in) — it bundles spaCy NLP models and
> Tesseract OCR, so it is heavy and slow to start. The transformers NLP engine and Ollama
> remain out of scope for this chart.

## Prerequisites

- Kubernetes 1.23+
- Helm 3.8+
- An Ingress controller (only if `ingress.enabled=true`); the default path rules assume
[ingress-nginx](https://kubernetes.github.io/ingress-nginx/)

## Install

```bash
# From this chart directory: docs/samples/deployments/k8s/charts/presidio
helm install presidio . --namespace presidio --create-namespace

# Override the image tag (defaults to the chart appVersion)
helm install presidio . --namespace presidio --create-namespace --set image.tag=latest

# Custom values
helm install presidio . --namespace presidio --create-namespace -f my-values.yaml
```

Check rollout (the analyzer loads NLP models on first start and can take a few minutes):

```bash
kubectl rollout status deployment/presidio-presidio-analyzer -n presidio
helm test presidio -n presidio
```

## Uninstall

```bash
helm uninstall presidio
```

## What gets deployed

| Resource | analyzer | anonymizer | image-redactor |
| --- | --- | --- | --- |
| Enabled by default | ✅ | ✅ | ❌ (`imageRedactor.enabled`) |
| Deployment | ✅ | ✅ | ✅ |
| Service (ClusterIP) | ✅ | ✅ | ✅ |
| HorizontalPodAutoscaler | optional (`analyzer.autoscaling.enabled`) | optional (`anonymizer.autoscaling.enabled`) | optional (`imageRedactor.autoscaling.enabled`) |
| ServiceAccount (shared) | ✅ (`serviceAccount.create`) | | |
| Ingress (shared, routes all enabled) | optional (`ingress.enabled`) | | |

Pods run as the non-root UID `1001` baked into the Presidio images, with `ALL` capabilities
dropped, `allowPrivilegeEscalation: false`, and the `RuntimeDefault` seccomp profile.

Enable the image-redactor with:

```bash
helm install presidio . --namespace presidio --create-namespace --set imageRedactor.enabled=true
```

## Configuration

### Global

| Key | Default | Description |
| --- | --- | --- |
| `image.registry` | `mcr.microsoft.com` | Registry for both images. Set `""` for bare repos. |
| `image.pullPolicy` | `IfNotPresent` | Default pull policy. |
| `image.tag` | `""` | Default tag; empty falls back to chart `appVersion`. |
| `imagePullSecrets` | `[]` | Private registry pull secrets. |
| `serviceAccount.create` | `true` | Create a shared ServiceAccount. |
| `serviceAccount.automount` | `false` | Mount the SA token (Presidio does not call the K8s API). |
| `podSecurityContext` | non-root 1001 | Pod-level security context for all components. |
| `securityContext` | drop ALL caps | Container-level security context for all components. |
| `nodeSelector` / `tolerations` / `affinity` | empty | Default scheduling; per-component overrides supported. |
| `ingress.enabled` | `false` | Enable the shared Ingress. |
| `ingress.className` | `nginx` | IngressClass. |
| `ingress.hosts` | `presidio.local` | Host/path rules; each path maps to a `service` alias (`analyzer`, `anonymizer`, `image-redactor`). |

### Per component (`analyzer.*`, `anonymizer.*`, `imageRedactor.*`)

| Key | analyzer default | anonymizer default | imageRedactor default | Description |
| --- | --- | --- | --- | --- |
| `enabled` | `true` | `true` | `false` | Toggle the component. |
| `image.repository` | `presidio-analyzer` | `presidio-anonymizer` | `presidio-image-redactor` | Image repo (joined with `image.registry`). |
| `replicaCount` | `1` | `1` | `1` | Replicas (ignored when autoscaling is on). |
| `containerPort` | `3000` | `3000` | `3000` | Listen port; exported as the `PORT` env var. |
| `workers` | `1` | `1` | `1` | gunicorn workers; exported as the `WORKERS` env var. |
| `extraEnv` | `[]` | `[]` | `[]` | Extra environment variables. |
| `service.type` / `service.port` | `ClusterIP` / `8080` | `ClusterIP` / `8080` | `ClusterIP` / `8080` | Service exposure. |
| `resources` | 1.5–3Gi / 1.5–2 CPU | 128–512Mi / 0.125–0.5 CPU | 1.5–3Gi / 1.5–2 CPU | Requests/limits. |
| `startupProbe` / `livenessProbe` / `readinessProbe` | `/health` | `/health` | `/health` | HTTP probes. |
| `autoscaling.enabled` | `false` | `false` | `false` | Enable the HPA. |

> The image-redactor exposes `POST /redact` (multipart image upload) in addition to `/health`.
> Note the [`docker-compose-image.yml`](../../../../../../docker-compose-image.yml) reference sets
> `PORT=5001`, but this chart standardizes every component on container port `3000` (the image's
> Dockerfile default).

## Scaling caveat

Balancing traffic across **more than one replica** of a service requires a service mesh
(e.g. Linkerd or Istio) because the clients hold persistent connections — see
[microsoft/presidio#304](https://github.com/microsoft/presidio/issues/304). Plain
`replicaCount > 1` or HPA without a mesh may not distribute load evenly.

## Example: enable Ingress

```yaml
ingress:
enabled: true
className: nginx
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
hosts:
- host: presidio.example.com
paths:
- path: /analyzer(/|$)(.*)
pathType: ImplementationSpecific
service: analyzer
- path: /anonymizer(/|$)(.*)
pathType: ImplementationSpecific
service: anonymizer
Comment on lines +116 to +129
# Only routed when imageRedactor.enabled is true.
- path: /image-redactor(/|$)(.*)
pathType: ImplementationSpecific
service: image-redactor
```
43 changes: 38 additions & 5 deletions docs/samples/deployments/k8s/charts/presidio/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,42 @@
presidio is now installed!
Presidio has been deployed. 🎉

To find out about your newly configured system, run:
Release: {{ .Release.Name }}
Namespace: {{ .Release.Namespace }}

$ helm status {{ .Release.Name }}
Services deployed:
{{- if .Values.analyzer.enabled }}
- presidio-analyzer → {{ include "presidio.componentFullname" (dict "root" $ "name" "analyzer") }}:{{ .Values.analyzer.service.port }}
{{- end }}
{{- if .Values.anonymizer.enabled }}
- presidio-anonymizer → {{ include "presidio.componentFullname" (dict "root" $ "name" "anonymizer") }}:{{ .Values.anonymizer.service.port }}
{{- end }}
{{- if .Values.imageRedactor.enabled }}
- presidio-image-redactor → {{ include "presidio.componentFullname" (dict "root" $ "name" "image-redactor") }}:{{ .Values.imageRedactor.service.port }}
{{- end }}

To test your new Presidio service, forward the ports: the Analyzer publishes a service at port 8080. To use the Analyzer, you first need to forward this port to your local IP address:
NOTE: the analyzer{{ if .Values.imageRedactor.enabled }} and image-redactor{{ end }} load NLP models on first start and can
take a few minutes to become Ready. Watch rollout with:

$ kubectl port-forward -n presidio $(kubectl get pod -n presidio -l app=demo-presidio-analyzer -o jsonpath='{.items[0].metadata.name}') 8080:8080
kubectl --namespace {{ .Release.Namespace }} rollout status deployment/{{ include "presidio.componentFullname" (dict "root" $ "name" "analyzer") }}

{{- if .Values.ingress.enabled }}

Reach the services via the configured Ingress:
{{- range $host := .Values.ingress.hosts }}
{{- range $host.paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} → {{ .service }}
{{- end }}
{{- end }}
{{- else }}

No Ingress is enabled. Test a service from your machine with port-forward, e.g. the anonymizer:

kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "presidio.componentFullname" (dict "root" $ "name" "anonymizer") }} {{ .Values.anonymizer.service.port }}:{{ .Values.anonymizer.service.port }}
curl http://localhost:{{ .Values.anonymizer.service.port }}/health

Then anonymize a sample:

curl -X POST http://localhost:{{ .Values.anonymizer.service.port }}/anonymize \
-H "Content-Type: application/json" \
-d '{"text":"My name is Bond.","anonymizers":{"DEFAULT":{"type":"replace","new_value":"ANONYMIZED"}},"analyzer_results":[{"start":11,"end":15,"score":0.8,"entity_type":"PERSON"}]}'
{{- end }}
Loading
Loading