OPA/Kyverno Migration Strategies¶
Migration paths between OPA and Kyverno. Phased rollout strategies, policy translation examples, and hybrid deployment patterns.
Read the Decision Guide First
Before migrating, read the Decision Guide to understand which approach fits your requirements.
Migration Paths Overview¶
| Starting Point | Migration Target | Timeline | Risk Level |
|---|---|---|---|
| Kyverno → OPA | Full migration | 2-4 months | Medium |
| OPA → Kyverno | Supplement (hybrid) | 2-4 weeks | Low |
| None → Hybrid | Deploy both | 1-2 months | Medium |
Kyverno to OPA Migration¶
When to Migrate¶
Migrate from Kyverno to OPA when:
- Policy scope expands beyond Kubernetes (Terraform, APIs)
- Kyverno's JMESPath hits complexity limits
- Team grows policy expertise and needs advanced features
- External data integration becomes critical
Migration Strategy¶
Phase your migration to minimize disruption.
Phase 1: Run Both in Parallel (2-4 weeks)¶
- Deploy Gatekeeper alongside Kyverno
- Run both in audit mode
- Compare violation reports for consistency
- Build team expertise with Rego
Phase 2: Translate Policies (4-8 weeks)¶
- Start with simplest policies (label requirements)
- Rewrite in Rego using constraint templates
- Test with
opa testframework - Deploy OPA policies in audit mode
- Validate behavior matches Kyverno
Phase 3: Switch Enforcement (2-4 weeks)¶
- Enable OPA enforcement one policy at a time
- Disable corresponding Kyverno policy
- Monitor for 48 hours before proceeding
- Document any behavioral differences
Phase 4: Decommission Kyverno (1-2 weeks)¶
- Verify all policies migrated
- Run final audit comparison
- Remove Kyverno policies
- Uninstall Kyverno operator
Policy Translation Examples¶
Label Requirement¶
Kyverno uses pattern matching:
OPA uses Rego logic:
violation[{"msg": msg}] {
not input.review.object.metadata.labels.team
msg := "Team label is required"
}
Image Registry Allowlist¶
Kyverno pattern:
OPA Rego:
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not startswith(container.image, "registry.example.com/")
msg := sprintf("Image %v not from approved registry", [container.image])
}
Full Examples
See Kyverno Templates and OPA Templates for complete policy definitions.
OPA Supplemented with Kyverno¶
When to Supplement¶
Add Kyverno to an existing OPA deployment when:
- You need image signature verification (Cosign)
- You want resource generation (network policies, quotas)
- You need mutation capabilities
Hybrid Strategy¶
Define clear boundaries between engines.
OPA Handles:
- Complex compliance logic
- Multi-platform policies
- Cross-resource validation
- External data integration
Kyverno Handles:
- Image signature verification
- Resource mutation
- Resource generation
- Simple validation
Hybrid Deployment Example¶
Kyverno handles image signatures:
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-images
spec:
validationFailureAction: enforce
rules:
- name: verify-cosign
match:
resources:
kinds: [Pod]
verifyImages:
- image: "registry.example.com/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----
OPA handles time-based compliance:
package kubernetes.admission
deny[msg] {
input.request.kind.kind == "Deployment"
input.request.object.metadata.namespace == "production"
not is_recently_approved(input.request.object)
msg := "Production requires approval within 7 days"
}
is_recently_approved(deployment) {
deployment.metadata.labels["approved-by"]
deployment.metadata.labels["scan-date"]
scan_time := time.parse_rfc3339_ns(deployment.metadata.labels["scan-date"])
time.now_ns() - scan_time < 604800000000000 # 7 days
}
Hybrid Deployment Best Practices¶
Policy Ownership¶
Document which engine owns which policy types:
| Policy Type | Engine | Rationale |
|---|---|---|
| Image verification | Kyverno | Built-in Cosign support |
| Label validation | Kyverno | Simple YAML patterns |
| Time-based compliance | OPA | Complex date logic |
| Cross-namespace rules | OPA | Rego query capabilities |
| Resource generation | Kyverno | Native generation support |
| External data | OPA | HTTP data sources |
Conflict Prevention¶
Most Restrictive Wins¶
If both engines validate the same resource, both must pass. The more restrictive policy takes precedence.
Single Source of Truth¶
Each policy type should be owned by one engine only. Don't duplicate validation logic.
Avoid this conflict:
# Kyverno: requires team, environment
# OPA: requires team, owner
# CONFLICT: inconsistent requirements
Instead, choose one engine for label validation:
Testing Strategy¶
Test both engines in parallel:
# Test Kyverno policies
kyverno test --policy-dir policies/kyverno
# Test OPA policies
opa test policies/opa --explain=full
# Integration test
kubectl apply --dry-run=server -f test-deployment.yaml
Migration Checklist¶
Pre-migration:
- [ ] Backup existing policies
- [ ] Document current violation patterns
- [ ] Establish rollback procedures
During migration:
- [ ] Run both engines in audit mode
- [ ] Compare violation reports
- [ ] Test policy translations
- [ ] Monitor admission latency
Post-migration:
- [ ] All policies migrated
- [ ] No increase in false positives
- [ ] Team trained on new tooling
- [ ] Documentation updated
Next Steps¶
- Decision Guide → - Framework for choosing between OPA and Kyverno
- Detailed Comparison → - Capability and ecosystem comparison
- Kyverno Templates → - Ready-to-use Kyverno policies
- OPA Templates → - OPA constraint templates
- Usage Guide → - Customization workflow
- Template Library Overview → - Back to main page
External References¶
- Kyverno Documentation
- OPA/Gatekeeper Documentation
- Kyverno Testing Guide
- OPA Testing Guide
- Gatekeeper Constraint Templates