Security
Templates Security Model
Threat model and security architecture for self-hosted application templates
Templates provide one-click deployment of self-hosted applications. This document outlines the security model for the template system, including isolation, updates, and customer data protection.
Security Goals
The Templates security model aims to provide:
- Application isolation — Each template instance runs in isolation from others
- Supply chain integrity — Template images and configurations are verified
- Automatic security updates — Critical patches applied without customer intervention
- Data persistence safety — Customer data survives updates and migrations
- Least privilege — Templates run with minimal required permissions
- Observability — Security events and anomalies are logged and alerted
Threat Model
In Scope (Threats We Protect Against)
- Container escape — Application breaking out of container isolation
- Image vulnerabilities — Known CVEs in base images or dependencies
- Configuration injection — Malicious config via environment variables
- Cross-template attacks — One template instance attacking another
- Secret leakage — Hardcoded credentials or exposed environment variables
- Privilege escalation — Container gaining host-level access
- Resource exhaustion — Template consuming excessive resources
- Supply chain poisoning — Compromised upstream images or packages
- Data loss during updates — Customer data corrupted or deleted on update
Out of Scope (Threats We Do Not Protect Against)
- Application vulnerabilities — SQL injection, XSS in the deployed app itself
- Weak default passwords — If customer doesn't change default credentials
- Misconfigured applications — Customer exposing services unintentionally
- Malicious templates — Templates we curate are trusted; custom templates are customer responsibility
- Data exfiltration by application — If the app itself is malicious or compromised
- Network attacks from within — Attacks originating from customer's other infrastructure
- Cryptographic breaks — Failure of container encryption or TLS
- Host compromise — If the underlying node is compromised, containers are at risk
External Threat Overview
Architecture Components
┌─────────────────────────────────────────────────────────────────┐
│ Template Controller │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Template Registry │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ PostgreSQL │ │ Gitea │ │ n8n │ │ │
│ │ │ Template │ │ Template │ │ Template │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────▼───────────────────────────┐ │
│ │ Template Runner (Kubernetes) │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ Pod Security Standards: Restricted │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ App │◀────▶│ Sidecar │ │ │ │
│ │ │ │ Container │ │ (Monitor) │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ Data │ │ Config │ │ │ │
│ │ │ │ Volume │ │ (Secrets) │ │ │ │
│ │ │ └─────────────┘ └─────────────┘ │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Trust Boundaries
Untrusted:
- Customer-provided configuration values
- External data sources (webhooks, APIs)
- User-uploaded files (if applicable)
Semi-Trusted:
- Template images (scanned, signed, but from external sources)
- Helm charts and Kubernetes manifests
Trusted:
- Template Controller (our code)
- Kubernetes control plane
- Container runtime (containerd)
- Secrets management (external-secrets operator)
Container Isolation
Templates run in Kubernetes with strict security contexts:
apiVersion: v1
kind: Pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
resources:
limits:
cpu: "1000m"
memory: "1Gi"
requests:
cpu: "100m"
memory: "256Mi"
volumeMounts:
- name: data
mountPath: /data
- name: tmp
mountPath: /tmp
volumes:
- name: data
persistentVolumeClaim:
claimName: template-data
- name: tmp
emptyDir: {}
Internal Threat Overview
Template Build Pipeline
1. Image Building
┌─────────────────────────────────────────────────────────────┐
│ Template Build Pipeline │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. SOURCE │
│ └── Pull from upstream (Docker Hub, GHCR, etc.) │
│ └── Verify image signature (cosign) │
│ │
│ 2. SCAN │
│ └── Trivy vulnerability scan │
│ └── Block if critical CVEs found │
│ │
│ 3. HARDEN │
│ └── Add security patches │
│ └── Remove unnecessary packages │
│ └── Configure non-root user │
│ │
│ 4. TEST │
│ └── Run in isolated environment │
│ └── Verify no privilege escalation │
│ │
│ 5. PUBLISH │
│ └── Push to internal registry │
│ └── Sign with Notary/Cosign │
│ └── Update vulnerability database │
│ │
└─────────────────────────────────────────────────────────────┘
2. Vulnerability Management
| Severity | Action | Timeline |
|---|---|---|
| Critical | Auto-update template | Within 24 hours |
| High | Notify customers, schedule update | Within 7 days |
| Medium | Include in next maintenance window | Next release |
| Low | Track, patch when convenient | As needed |
Secret Management
Templates requiring credentials use external secrets:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: postgres-credentials
spec:
refreshInterval: 1h
secretStoreRef:
kind: ClusterSecretStore
name: vault-backend
target:
name: postgres-secret
creationPolicy: Owner
data:
- secretKey: password
remoteRef:
key: templates/postgres
property: password
Security properties:
- Secrets never stored in Git
- Automatic rotation (database passwords every 30 days)
- Short-lived tokens where possible
- No secrets in environment variables (mounted as files)
Network Policies
Default deny-all with explicit allow rules:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-postgres
spec:
podSelector:
matchLabels:
app: web-app
policyTypes:
- Egress
egress:
- to:
- podSelector:
matchLabels:
app: postgres
ports:
- protocol: TCP
port: 5432
Update Mechanism
Templates update via GitOps (FluxCD):
┌─────────────────────────────────────────────────────────────┐
│ Update Flow │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. New image available │
│ │ │
│ ▼ │
│ 2. Automated PR to config repo │
│ │ │
│ ▼ │
│ 3. CI tests (backup, upgrade, verify) │
│ │ │
│ ▼ │
│ 4. Merge to main │
│ │ │
│ ▼ │
│ 5. Flux applies canary deployment │
│ │ │
│ ▼ │
│ 6. Health checks pass → full rollout │
│ │ │
│ ▼ │
│ 7. Old version scaled down (data preserved) │
│ │
└─────────────────────────────────────────────────────────────┘
Rollback:
- Automatic rollback if health checks fail
- One-click rollback via O2S
- Data snapshots before update
Data Protection
Persistence
Customer data is stored in PersistentVolumes:
| Storage Type | Use Case | Backup |
|---|---|---|
| Longhorn | Block storage for databases | Hourly snapshots |
| RustFS S3 | Object storage for files | Real-time replication |
Backup Strategy
# Velero backup schedule
apiVersion: velero.io/v1
kind: Schedule
metadata:
name: template-backup
spec:
schedule: "0 */6 * * *" # Every 6 hours
template:
includedNamespaces:
- template-*
snapshotVolumes: true
storageLocation: default
ttl: 720h0m0s # 30 days
Data Isolation
- Each template instance gets its own namespace
- PersistentVolumes are not shared between instances
- Cross-namespace access blocked by default
Security Controls Summary
| Control | Implementation | Verification |
|---|---|---|
| Image scanning | Trivy on build | CI/CD pipeline |
| Image signing | Cosign/Notary | Signature verification |
| Runtime security | Pod Security Standards | OPA/Gatekeeper |
| Network isolation | Cilium network policies | Connectivity tests |
| Secret management | External Secrets Operator | Audit logs |
| Update automation | FluxCD GitOps | Automated testing |
| Backup | Velero + Longhorn snapshots | Restore testing |
| Monitoring | Falco for runtime threats | Alerting rules |