Common questions about deploying and using the Prowler Helm chart.
- General Questions
- Installation & Setup
- Configuration
- Storage & Persistence
- Security
- Scaling & Performance
- Cloud Provider Specific
- Troubleshooting
- Neo4j (Attack Paths)
Prowler is an open-source security tool for AWS, Azure, GCP, and Kubernetes security assessment and compliance checking. It performs security best practice checks, generates compliance reports, and helps identify security risks in your cloud infrastructure.
The Prowler Helm chart deploys the Prowler web application, which provides:
- Web UI for managing scans and viewing results
- REST API for programmatic access
- Background workers for executing security scans
- Database for storing scan results and configurations
Kubernetes:
- Version 1.21 or higher
- At least 3 nodes (for high availability)
- 8 GB RAM total across cluster
- 4 CPU cores total across cluster
For Development/Testing:
- Single node: 4 GB RAM, 2 CPU cores
- Can use Minikube, kind, k3s, or MicroK8s
For Production:
- Multiple nodes for high availability
- External managed databases (PostgreSQL, Redis/Valkey)
- Persistent storage with ReadWriteMany support
- Ingress controller for external access
See Installation Requirements for details.
This is a community-maintained Helm chart for deploying the Prowler web application. While it follows best practices and is actively maintained, for official support and enterprise features, please contact Prowler Cloud.
Prowler CLI:
- Command-line tool for one-time scans
- Runs locally or in CI/CD pipelines
- Outputs results to files (JSON, CSV, HTML)
- No database or web interface
Prowler Helm Chart (Web Application):
- Deploys web UI and API
- Continuous scanning with scheduling
- Stores results in database
- Multi-user access with authentication
- Historical trend analysis
- Team collaboration features
Both use the same Prowler scanning engine under the hood.
Short answer: No, not for basic installation.
Details:
The chart includes PostgreSQL and Valkey (Redis) as dependencies. For a quick start:
helm install prowler charts/prowler -n prowler --create-namespaceThe built-in databases work fine for:
- Development
- Testing
- Small deployments
- Single-cluster setups
For production, we recommend external managed databases:
- Better reliability and backup
- Automatic failover
- Better performance
- Independent scaling
See examples/values-external-db.yaml for setup instructions.
Method 1: Port Forward (Development)
kubectl port-forward -n prowler svc/prowler-ui 3000:3000Then visit http://localhost:3000
Method 2: Ingress (Production)
Enable ingress in your values:
ui:
ingress:
enabled: true
hosts:
- host: prowler.example.comThen visit https://prowler.example.com
There are no default credentials. You must create a superuser after installation:
kubectl exec -n prowler -it deployment/prowler-api -- \
python manage.py createsuperuserFollow the prompts to create username, email, and password.
Yes! This chart requires external PostgreSQL and Valkey/Redis instances. Create secrets with your credentials:
kubectl create secret generic prowler-postgres-secret -n prowler \
--from-literal=POSTGRES_HOST=your-db-host \
--from-literal=POSTGRES_PORT=5432 \
--from-literal=POSTGRES_ADMIN_USER=prowler_admin \
--from-literal=POSTGRES_ADMIN_PASSWORD=your-admin-password \
--from-literal=POSTGRES_USER=prowler \
--from-literal=POSTGRES_PASSWORD=your-user-password \
--from-literal=POSTGRES_DB=prowler_db
kubectl create secret generic prowler-valkey-secret -n prowler \
--from-literal=VALKEY_HOST=your-redis-host \
--from-literal=VALKEY_PORT=6379 \
--from-literal=VALKEY_PASSWORD=your-password \
--from-literal=VALKEY_DB=0Then install with:
helm install prowler charts/prowler -n prowlerSee examples/values-external-db.yaml for complete configuration.
Edit your values file or use --set:
api:
resources:
limits:
cpu: 2000m
memory: 2Gi
requests:
cpu: 500m
memory: 512MiOr with --set:
helm upgrade prowler charts/prowler \
--set api.resources.limits.cpu=2000m \
--set api.resources.limits.memory=2Gi \
-n prowlerThe default values.yaml includes commented recommendations for each component. See Resource Recommendations.
Enable Horizontal Pod Autoscaler for any component:
api:
autoscaling:
enabled: true
minReplicas: 3
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80Requirements:
- Metrics Server must be installed in your cluster
- Resource requests must be defined
- Recommended for API and Worker components
Cloud credentials should be provided via Kubernetes secrets or cloud provider IAM roles.
AWS (Recommended: IAM Roles for Service Accounts)
worker:
serviceAccount:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/prowler-scannerAzure (Recommended: Workload Identity)
worker:
serviceAccount:
annotations:
azure.workload.identity/client-id: "12345678-1234-1234-1234-123456789012"GCP (Recommended: Workload Identity)
worker:
serviceAccount:
annotations:
iam.gke.io/gcp-service-account: prowler@project.iam.gserviceaccount.comAlternative: Kubernetes Secrets Create a secret with cloud credentials and reference it:
worker:
secrets:
- prowler-aws-credentialsYes! You can use:
1. Cert-Manager (Recommended)
ui:
ingress:
enabled: true
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
tls:
- secretName: prowler-ui-tls
hosts:
- prowler.example.com2. Pre-existing Certificate
kubectl create secret tls prowler-ui-tls -n prowler \
--cert=path/to/tls.crt \
--key=path/to/tls.keyThen reference in values:
ui:
ingress:
enabled: true
tls:
- secretName: prowler-ui-tls
hosts:
- prowler.example.comProwler requires two types of storage:
1. Shared Storage (Required)
- Stores scan output files
- Must be shared between API and Worker pods
- Requires ReadWriteMany (RWX) if using PVC
2. Component Storage (Optional)
- API config storage: Prowler CLI configuration
- Worker config storage: Cloud credentials and config
It depends on your configuration:
Yes, if:
- Using PersistentVolumeClaim for shared storage
- Running multiple API or Worker replicas
- Want data persistence
No, if:
- Using emptyDir (data not persisted)
- Running single replica of API and Worker
- Using ReadWriteOnce with pod affinity
Cloud provider RWX options:
- AWS: EFS (via EFS CSI driver)
- Azure: Azure Files (Premium or Standard)
- GCP: Filestore
- On-premises: NFS, Ceph, GlusterFS
Yes, for development/testing:
sharedStorage:
type: emptyDirPros:
- Simple, no storage provisioning needed
- Fast (can use memory:
medium: Memory) - Works everywhere
Cons:
- Data lost when pods restart
- Not suitable for production
- Cannot share between nodes
Minimum (Development):
- Shared storage: 1 GB
- PostgreSQL: 8 GB
- Valkey: 1 GB
Recommended (Production):
- Shared storage: 50-100 GB (depends on scan frequency and retention)
- PostgreSQL: 100+ GB (database with backups)
- Valkey: 1-5 GB (task queue)
Growth factors:
- Number of cloud accounts scanned
- Scan frequency
- Data retention period
- Number of resources per account
The default configuration follows Kubernetes security best practices:
✅ Included:
- Pod Security Standards (restricted)
- Security contexts (non-root, dropped capabilities)
- ReadOnlyRootFilesystem where possible
- Seccomp profiles (RuntimeDefault)
- No hardcoded secrets
- Auto-generated encryption keys
- Strong PostgreSQL passwords
- TLS/SSL for ingress
- Network policies (available but disabled by default)
- External secrets management (e.g., External Secrets Operator)
- Regular security updates
Yes, for production. Network Policies provide defense-in-depth by restricting pod-to-pod communication.
Enable in values:
networkPolicy:
enabled: trueRequirements:
- CNI plugin with network policy support (Calico, Cilium, etc.)
- Not supported on: Basic kubenet (AKS), default GKE networks
What it does:
- Restricts ingress to UI/API from ingress controller only
- Allows egress to databases and cloud APIs
- Blocks unauthorized pod communication
Django keys (JWT signing, encryption) are auto-generated by a pre-install Kubernetes Job:
- Job runs before main installation
- Generates secure RSA keys for JWT
- Generates Fernet key for field encryption
- Stores in Kubernetes Secret
- Secret is mounted to API, Worker, Worker Beat pods
Key generation is:
- Automatic
- Secure (using Helm's
lookupfunction for persistence) - Unique per installation
For existing secrets: The chart uses Helm's lookup to detect existing secrets and reuses them across upgrades.
Yes! You can integrate with:
External Secrets Operator:
api:
djangoConfigKeys:
create: false # Disable built-in secret generation
secrets:
- prowler-django-keys # Reference external secretSealed Secrets:
kubeseal --format yaml < secret.yaml > sealed-secret.yaml
kubectl apply -f sealed-secret.yamlCloud Provider Secret Managers:
- AWS Secrets Manager (via External Secrets)
- Azure Key Vault (via CSI driver or External Secrets)
- Google Secret Manager (via External Secrets)
# 1. Delete existing secret
kubectl delete secret prowler-api-django-config-keys -n prowler
# 2. Delete generation job to trigger recreation
kubectl delete job prowler-generate-keys -n prowler
# 3. Upgrade Helm release (recreates job)
helm upgrade prowler charts/prowler -n prowler --reuse-values
# 4. Wait for job completion
kubectl wait --for=condition=complete job/prowler-generate-keys -n prowler
# 5. Restart pods to load new keys
kubectl rollout restart deployment -n prowlerAll users will need to log in again.
Development:
api: 1
ui: 1
worker: 1
worker_beat: 1 # Always 1Small Production (< 10 cloud accounts):
api: 2-3
ui: 2-3
worker: 2-3
worker_beat: 1Medium Production (10-100 accounts):
api: 3-5
ui: 3-5
worker: 5-10
worker_beat: 1Large Production (100+ accounts):
api: 5-10 (with autoscaling)
ui: 5-10 (with autoscaling)
worker: 10-50 (with autoscaling)
worker_beat: 1Note: Worker Beat should always be 1 (it's a scheduler, not a worker).
1. Scale Workers Horizontally
worker:
replicaCount: 10
autoscaling:
enabled: true
maxReplicas: 502. Increase Worker Resources
worker:
resources:
limits:
cpu: 4000m
memory: 4Gi3. Use Faster Storage
- Use SSD-backed storage
- Consider memory-backed emptyDir for temporary scan data
4. Optimize Database
- Use external managed database
- Enable connection pooling (PgBouncer, RDS Proxy)
- Scale database instance
5. Use Dedicated Worker Nodes
worker:
nodeSelector:
workload-type: prowler-worker
tolerations:
- key: "workload-type"
value: "prowler-worker"
effect: "NoSchedule"Common bottlenecks:
- Database connections - Solution: Use external database with connection pooling
- Worker concurrency - Solution: Scale worker replicas
- Storage I/O - Solution: Use faster storage or increase IOPS
- Cloud API rate limits - Solution: Distribute scans across time
- Memory limits - Solution: Increase worker memory limits
Monitor with:
kubectl top pods -n prowler
kubectl top nodesUsing IRSA (IAM Roles for Service Accounts):
- Create IAM role with Prowler permissions:
eksctl create iamserviceaccount \
--name prowler-worker \
--namespace prowler \
--cluster your-cluster \
--attach-policy-arn arn:aws:iam::aws:policy/SecurityAudit \
--approve- Configure in values:
worker:
serviceAccount:
create: true
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789:role/prowler-workerUsing Azure Workload Identity:
- Create managed identity and assign permissions
- Federate with Kubernetes service account
- Configure in values:
worker:
serviceAccount:
annotations:
azure.workload.identity/client-id: "your-client-id"
podLabels:
azure.workload.identity/use: "true"Using GCP Workload Identity:
- Create GCP service account with necessary roles
- Bind to Kubernetes service account
- Configure in values:
worker:
serviceAccount:
annotations:
iam.gke.io/gcp-service-account: prowler@project.iam.gserviceaccount.com- ✅ AWS: EFS (via EFS CSI driver)
- ✅ Azure: Azure Files (Standard and Premium tiers)
- ✅ GCP: Filestore
- ❌ AWS: EBS (ReadWriteOnce only)
- ❌ Azure: Azure Disks (ReadWriteOnce only)
- ❌ GCP: Persistent Disk (ReadWriteOnce only)
For single-AZ deployments, you can use ReadWriteOnce with single replicas or pod affinity.
See detailed troubleshooting: docs/troubleshooting.md#pod-startup-problems
Quick checks:
kubectl get pods -n prowler
kubectl logs -n prowler <pod-name>
kubectl describe pod -n prowler <pod-name>Common causes:
- Database connection failure
- Invalid configuration
- Resource limits too low
- Missing secrets
See: docs/troubleshooting.md#authentication-and-login-problems
Common causes:
- No superuser created yet
- Invalid Django keys
- API not accessible from UI
See: docs/troubleshooting.md#worker-and-celery-issues
Common causes:
- Workers not running
- Worker Beat not scheduling
- Cloud credentials not configured
- Database connection issues
api:
djangoConfig:
DJANGO_DEBUG: "True"
DJANGO_LOG_LEVEL: "DEBUG"For production debugging:
api:
djangoConfig:
DJANGO_LOG_LEVEL: "INFO" # or "DEBUG" temporarilyThen check logs:
kubectl logs -n prowler -l app.kubernetes.io/component=api -fNeo4j (DozerDB) is a graph database used by Prowler's Attack Paths feature (introduced in Prowler 5.17+). It stores relationships between cloud resources to identify potential attack paths and security risks.
Yes, for Prowler 5.17+. Neo4j is enabled by default in this chart. If you disable it (neo4j.enabled=false), the Attack Paths feature will not work and API/Worker pods may crash.
Neo4j password is auto-generated if not provided. To set your own:
helm install prowler charts/prowler \
--set neo4j.auth.password=your-secure-password \
-n prowlerThe auto-generated password is preserved across upgrades using Helm's lookup function.
Currently, the chart only supports the built-in Neo4j (DozerDB) deployment. External Neo4j support may be added in future versions.
Persistence is enabled by default. To explicitly configure it:
neo4j:
persistence:
enabled: true
size: 20Gi
storageClass: "your-storage-class"kubectl port-forward -n prowler svc/prowler-neo4j 7474:7474 7687:7687Then open http://localhost:7474 and login with:
- Username:
neo4j - Password: (the password you set during installation)
Default configuration:
- Requests: 2Gi memory, 500m CPU
- Limits: 4Gi memory, 2000m CPU
- Heap: 1G initial, 1G max
- Page cache: 1G
For large deployments (many cloud accounts), increase these values:
neo4j:
resources:
limits:
memory: 8Gi
config:
heapMaxSize: "4G"
pagecacheSize: "2G"- Troubleshooting Guide: docs/troubleshooting.md
- Upgrade Guide: UPGRADING.md
- Contributing: .github/CONTRIBUTING.md
- GitHub Issues: prowler-helm-chart/issues
- GitHub Discussions: prowler-helm-chart/discussions
- Prowler Documentation: docs.prowler.com