Financial Services
Defaults aligned with SOC2, PCI, GDPR, and HIPAA controls.
Why this bundle
Defaults aligned with SOC2, PCI, GDPR, and HIPAA controls.
Sixteen policies for data-criticality and residency labels, audit-retention floors, regulated-tier replication, FULL schema compatibility, secret-provider enforcement on connectors, and SSO-backed ApplicationGroups. Aimed at banks, insurers, healthcare, and payment processors where every topic, schema, and connector has to survive an audit.
Apply the whole bundle
One concatenated YAML stream with every ResourcePolicy in this bundle. Copy, save, apply.
# All policies in the Financial Services bundle (17 resources) # Save as bundle-financial-services.yaml then: conduktor apply -f bundle-financial-services.yaml # Each ResourcePolicy must still be linked via Application(Instance).spec.policyRef # or KafkaCluster.spec.policiesRef to take effect. --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: min-replication-factor spec: targetKind: Topic description: Production topics must have replication factor >= 3 rules: - condition: '!metadata.name.startsWith("prod.") || spec.replicationFactor >= 3' errorMessage: "Production topics must have replication factor >= 3" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: isr-alignment spec: targetKind: Topic description: min.insync.replicas must equal replicationFactor - 1 rules: - condition: '"min.insync.replicas" in spec.configs && int(string(spec.configs["min.insync.replicas"])) == int(spec.replicationFactor) - 1' errorMessage: "min.insync.replicas must equal replicationFactor - 1 (e.g. RF=3 -> min.insync.replicas=2)" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: max-retention-bound spec: targetKind: Topic description: retention.ms must be <= 30d and not infinite, unless labels.retention-justified == "true" rules: - condition: '("retention-justified" in metadata.labels && metadata.labels["retention-justified"] == "true") || ("retention.ms" in spec.configs && int(string(spec.configs["retention.ms"])) != -1 && int(string(spec.configs["retention.ms"])) <= 2592000000)' errorMessage: "retention.ms must be <= 30 days and not -1 (set label retention-justified=true to override)" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: schema-required-non-internal spec: targetKind: Topic description: Non-internal topics must declare a schema subject via labels.schema-subject rules: - condition: 'metadata.name.startsWith("__") || metadata.name.startsWith("_") || ("schema-subject" in metadata.labels && size(metadata.labels["schema-subject"]) > 0)' errorMessage: "Non-internal topics must set label schema-subject=<subject-name> (or be Schema-Registry-governed)" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: no-wildcard-acl-prod spec: targetKind: ApplicationGroup description: ApplicationGroups touching prod.* resources cannot use wildcard LITERAL resource patterns rules: - condition: 'spec.permissions.all(p, !(p.name.startsWith("prod.") || p.name == "*") || (p.patternType != "LITERAL" || p.name != "*"))' errorMessage: "Wildcard LITERAL resource is not allowed on production resources" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: topic-owner-label-required spec: targetKind: Topic description: every topic must carry owner (email) and data-criticality (C0..C3) labels rules: - condition: 'has(metadata.labels.owner) && metadata.labels.owner.matches("^[a-z0-9._-]+@[a-z0-9.-]+\\.[a-z]{2,}$") && "data-criticality" in metadata.labels && metadata.labels["data-criticality"] in ["C0", "C1", "C2", "C3"]' errorMessage: "metadata.labels.owner (email) and metadata.labels[\"data-criticality\"] (C0..C3) are required — unowned topics become stale and unpageable" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: subject-compatibility-not-none spec: targetKind: Subject description: spec.compatibility must be set and not NONE rules: - condition: 'has(spec.compatibility) && spec.compatibility in ["BACKWARD", "BACKWARD_TRANSITIVE", "FORWARD", "FORWARD_TRANSITIVE", "FULL", "FULL_TRANSITIVE"]' errorMessage: "spec.compatibility must be explicitly set and not NONE — NONE allows arbitrary schema changes that break downstream consumers" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: applicationgroup-no-wildcard-write spec: targetKind: ApplicationGroup description: wildcard (name="*") permissions cannot include write/create/delete on topics or connectors rules: - condition: 'spec.permissions.all(p, p.name != "*" || !p.permissions.exists(perm, perm in ["topicProduce", "topicCreate", "topicDelete", "kafkaConnectCreate", "kafkaConnectDelete"]))' errorMessage: "wildcard (name=\"*\") permissions cannot include write/create/delete on topics or connectors — scope by prefix instead" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: applicationgroup-prod-requires-external-group spec: targetKind: ApplicationGroup description: production ApplicationGroups must use externalGroups/externalGroupRegex (SSO sync) rules: - condition: '!spec.permissions.exists(p, p.appInstance.matches(".*-(prod|prd)$")) || (size(spec.members) == 0 && ((has(spec.externalGroups) && size(spec.externalGroups) > 0) || (has(spec.externalGroupRegex) && size(spec.externalGroupRegex) > 0)))' errorMessage: "production ApplicationGroups must use externalGroups/externalGroupRegex (SSO sync) — manual spec.members lists rot when staff leave" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: data-criticality-label-required spec: targetKind: Topic description: Every topic must declare metadata.labels.data-criticality in [C0,C1,C2,C3] rules: - condition: 'has(metadata.labels) && "data-criticality" in metadata.labels && metadata.labels["data-criticality"] in ["C0","C1","C2","C3"]' errorMessage: "Topic must set metadata.labels.data-criticality to one of C0, C1, C2, C3 (C0=public, C3=PHI/PCI)" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: data-residency-label-required spec: targetKind: Topic description: Every topic must declare metadata.labels.region for cross-border replication checks rules: - condition: 'has(metadata.labels) && "region" in metadata.labels && metadata.labels["region"] in ["eu","us","uk","apac","global"]' errorMessage: "Topic must set metadata.labels.region to one of eu, us, uk, apac, global — required for GDPR cross-border controls" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: audit-retention-floor spec: targetKind: Topic description: No infinite retention; audit-tagged topics must retain >= 7 years rules: - condition: '"retention.ms" in spec.configs && int(string(spec.configs["retention.ms"])) > 0' errorMessage: "retention.ms must be a finite positive value — retention.ms=-1 (infinite) is not allowed in a regulated cluster" - condition: '!(has(metadata.labels) && "audit" in metadata.labels && metadata.labels["audit"] == "true") || ("retention.ms" in spec.configs && int(string(spec.configs["retention.ms"])) >= 220752000000)' errorMessage: "Audit-tagged topics (metadata.labels.audit=true) must set retention.ms >= 220752000000 (7 years) for SOX/FINRA/HIPAA" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: min-isr-regulated-floor spec: targetKind: Topic description: C2/C3 topics need replicationFactor>=5 and min.insync.replicas>=3 rules: - condition: '!(has(metadata.labels) && "data-criticality" in metadata.labels && metadata.labels["data-criticality"] in ["C2","C3"]) || spec.replicationFactor >= 5' errorMessage: "Topics with data-criticality C2/C3 require replicationFactor >= 5" - condition: '!(has(metadata.labels) && "data-criticality" in metadata.labels && metadata.labels["data-criticality"] in ["C2","C3"]) || ("min.insync.replicas" in spec.configs && int(string(spec.configs["min.insync.replicas"])) >= 3)' errorMessage: "Topics with data-criticality C2/C3 require min.insync.replicas >= 3" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: subject-full-compatibility-regulated spec: targetKind: Subject description: Subjects flagged regulated=true must use FULL or FULL_TRANSITIVE compatibility rules: - condition: '!(has(metadata.labels) && "regulated" in metadata.labels && metadata.labels["regulated"] == "true") || spec.compatibility in ["FULL","FULL_TRANSITIVE"]' errorMessage: "Subjects tagged regulated=true must declare compatibility FULL or FULL_TRANSITIVE — no breaking changes for audit/fraud/claims consumers" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: connector-no-inline-credentials spec: targetKind: Connector description: Connector config must reference secrets via ${secret:...} / ${vault:...} rules: - condition: '!("connection.password" in spec.config) || spec.config["connection.password"].startsWith("${secret:") || spec.config["connection.password"].startsWith("${vault:") || spec.config["connection.password"].startsWith("${file:") || spec.config["connection.password"].startsWith("${env:")' errorMessage: "connection.password must be a secret reference (${secret:...}, ${vault:...}, ${file:...}, ${env:...}) — not an inline value" - condition: '!("consumer.override.sasl.jaas.config" in spec.config) || !spec.config["consumer.override.sasl.jaas.config"].contains("password=")' errorMessage: "consumer.override.sasl.jaas.config contains an inline password — use a secret-provider reference" - condition: '!("producer.override.sasl.jaas.config" in spec.config) || !spec.config["producer.override.sasl.jaas.config"].contains("password=")' errorMessage: "producer.override.sasl.jaas.config contains an inline password — use a secret-provider reference" - condition: '!("aws.secret.access.key" in spec.config) || spec.config["aws.secret.access.key"].startsWith("${")' errorMessage: "aws.secret.access.key must be a secret-provider reference, not an inline AWS key" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: connector-jdbc-host-allowlist spec: targetKind: Connector description: JDBC connectors may only target hosts under the approved internal DNS rules: - condition: '!("connector.class" in spec.config && spec.config["connector.class"].contains("Jdbc")) || ("connection.url" in spec.config && spec.config["connection.url"].matches("^jdbc:[a-z]+://[a-z0-9-]+\\.db\\.internal\\.[a-z]+(:[0-9]+)?/.*$"))' errorMessage: "JDBC connector connection.url must target *.db.internal.<corp> — public DBs and shadow-IT endpoints are not allowed" --- apiVersion: self-serve/v1 kind: ResourcePolicy metadata: name: topic-owner-slug-required spec: targetKind: Topic description: Every topic must declare metadata.labels.owner as a team slug rules: - condition: 'has(metadata.labels) && "owner" in metadata.labels && metadata.labels["owner"].matches("^[a-z][a-z0-9-]{1,38}$")' errorMessage: "Topic must set metadata.labels.owner to a team slug (e.g. payments-platform), not a person or TBD"
Each policy must still be linked via Application(Instance).spec.policyRef or KafkaCluster.spec.policiesRef to take effect.
Policies in this bundle
Grouped by category. Click any policy for the rationale, examples, and YAML.
Replication
3Retention
2Schema Enforcement
3Security & ACLs
3Operational Hygiene
4Connectors
2Enforce this bundle automatically?
Drop these YAMLs into Conduktor Console to get central enforcement, audit history, and pre-commit feedback for every change.
See Conduktor Console →