Skip to main content
All operator CRDs

KafkaUser

Expand a field to see its description, example, and default behavior. Nested fields are grouped under their parent.

API group
krabka.io
Scope
Namespaced
Resource name
kafkausers
Short names
ku

Required fields must be present when their parent object exists. [] denotes an array item; {key} denotes a map value. status is written by the operator. Reconcile-time checks and runtime defaults can add requirements beyond the schema.

Examples are illustrative JSON values. Open “View JSON example” for an object or array. Adapt names, endpoints, and credentials to your cluster. Kubernetes applies schema defaults when the containing object exists. Runtime and omission notes describe operator behavior. Status examples show reported data.

Runtime notes and domain examples were reviewed against operator source at b409b56.

View the complete CRD manifest at 618d621
Example manifest

This example includes the required spec fields. Adapt its values and create any referenced resources before applying it.

apiVersion: krabka.io/v1alpha1
kind: KafkaUser
metadata:
  name: example
  namespace: default
  labels:
    krabka.io/cluster: my-cluster
spec:
  authentication:
    type: scram-sha-512
    iterations: 8192
    passwordLength: 32

krabka.io/v1alpha1

Served API version · Storage version · 51 schema entries

Complete OpenAPI schema (JSON)
{
  "description": "Auto-generated derived type for KafkaUserSpec via `CustomResource`",
  "properties": {
    "spec": {
      "properties": {
        "authentication": {
          "description": "Tagged enum on `type`, in the same shape as Strimzi.\n\nThe wire shape is flat and Strimzi-compatible. `type` is the discriminator,\nand the per-variant config fields are siblings of `type`. The custom\n`schema_with` writes a structural schema by hand, because the\n`StructuralSchemaRewriter` of kube-rs 3.x panics when `oneOf` branches\nshare a `type` property with different `enum` values. That is the default\nschemars output for tagged-union enums. This is the same workaround as\n`Storage` in `kafka_node_pool.rs`.\n\nThe operator enforces the cross-variant constraints at reconcile time, and\nthe apiserver does not. One such constraint is that `iterations` is valid\nonly when `type=scram-sha-512`.",
          "properties": {
            "iterations": {
              "maximum": 1000000,
              "minimum": 4096,
              "type": "integer"
            },
            "maxLifetime": {
              "type": "string"
            },
            "passwordLength": {
              "maximum": 256,
              "minimum": 16,
              "type": "integer"
            },
            "renewBeforeExpiry": {
              "type": "string"
            },
            "renewalDays": {
              "maximum": 3650,
              "minimum": 1,
              "type": "integer"
            },
            "renewers": {
              "items": {
                "pattern": "^User:.+$",
                "type": "string"
              },
              "type": "array"
            },
            "type": {
              "enum": [
                "scram-sha-512",
                "scram-sha-256",
                "tls",
                "tls-external",
                "delegation-token"
              ],
              "type": "string"
            },
            "validityDays": {
              "maximum": 36500,
              "minimum": 1,
              "type": "integer"
            }
          },
          "required": [
            "type"
          ],
          "type": "object"
        },
        "authorization": {
          "description": "Authorization is optional. A user with no ACLs can still\nauthenticate. When this field is absent, the operator skips ACL\nreconciliation.",
          "nullable": true,
          "oneOf": [
            {
              "required": [
                "type"
              ]
            }
          ],
          "properties": {
            "acls": {
              "default": [],
              "items": {
                "description": "One rule from `spec.authorization.acls`. The operator expands it into one\n`(resource, operation, host, type)` tuple per `operations` entry at\nreconcile time.",
                "properties": {
                  "host": {
                    "description": "Source-address pattern. `\"*\"` is the wildcard. Defaults to `\"*\"` when\nomitted.",
                    "type": "string"
                  },
                  "operations": {
                    "description": "Non-empty list. The reconciler refuses an empty `operations` with\n`Ready=False reason=InvalidSpec`.",
                    "items": {
                      "description": "All 11 Kafka ACL operations. Matches the discriminants in\n`org.apache.kafka.common.acl.AclOperation`.",
                      "enum": [
                        "All",
                        "Read",
                        "Write",
                        "Create",
                        "Delete",
                        "Alter",
                        "Describe",
                        "ClusterAction",
                        "DescribeConfigs",
                        "AlterConfigs",
                        "IdempotentWrite"
                      ],
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "resource": {
                    "properties": {
                      "name": {
                        "type": "string"
                      },
                      "patternType": {
                        "default": "literal",
                        "description": "`literal` for an exact match, or `prefixed` for resources whose name\nstarts with `name`. Defaults to `literal`.",
                        "enum": [
                          "literal",
                          "prefixed"
                        ],
                        "type": "string"
                      },
                      "type": {
                        "enum": [
                          "topic",
                          "group",
                          "cluster",
                          "transactional-id"
                        ],
                        "type": "string"
                      }
                    },
                    "required": [
                      "name",
                      "type"
                    ],
                    "type": "object"
                  },
                  "type": {
                    "default": "allow",
                    "description": "`allow` or `deny`; defaults to `allow`.",
                    "enum": [
                      "allow",
                      "deny"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "operations",
                  "resource"
                ],
                "type": "object"
              },
              "type": "array"
            },
            "type": {
              "enum": [
                "simple"
              ],
              "type": "string"
            }
          },
          "type": "object"
        },
        "quotas": {
          "description": "Optional per-user client quotas (KIP-13/124/257). This field maps\nonto Kafka's `(user)` quota entity through `AlterClientQuotas`, which\nis `api_key` 49. When the field is absent, the operator does not touch\nthe broker's quota state. When the field is present, the operator\ndrives the broker's quota keys for `User:<name>` toward the spec. It\nsets the configured fields and tombstones the omitted ones.",
          "nullable": true,
          "properties": {
            "consumerByteRate": {
              "description": "Maximum consume-side bytes/sec. Backed by `consumer_byte_rate`.",
              "format": "int32",
              "minimum": 0,
              "nullable": true,
              "type": "integer"
            },
            "controllerMutationRate": {
              "description": "KIP-599 controller-mutation rate in creates and deletes per second.\nBacked by `controller_mutation_rate`.",
              "format": "double",
              "nullable": true,
              "type": "number"
            },
            "producerByteRate": {
              "description": "Maximum produce-side bytes/sec. Backed by `producer_byte_rate`.",
              "format": "int32",
              "minimum": 0,
              "nullable": true,
              "type": "integer"
            },
            "requestPercentage": {
              "description": "Maximum percentage of a request-handler thread's time that the user\ncan consume, in the range `0..=100`. Backed by `request_percentage`.",
              "format": "int32",
              "maximum": 100,
              "minimum": 0,
              "nullable": true,
              "type": "integer"
            }
          },
          "type": "object"
        }
      },
      "required": [
        "authentication"
      ],
      "type": "object"
    },
    "status": {
      "nullable": true,
      "properties": {
        "conditions": {
          "default": [],
          "description": "Standard Kubernetes-style condition list. It shows `Ready`.",
          "items": {
            "properties": {
              "lastTransitionTime": {
                "description": "RFC3339 timestamp.",
                "type": "string"
              },
              "message": {
                "description": "Human-readable message.",
                "type": "string"
              },
              "reason": {
                "description": "CamelCase machine reason.",
                "type": "string"
              },
              "status": {
                "description": "`True`, `False`, or `Unknown`.",
                "type": "string"
              },
              "type": {
                "description": "For example, `Ready`.",
                "type": "string"
              }
            },
            "required": [
              "lastTransitionTime",
              "message",
              "reason",
              "status",
              "type"
            ],
            "type": "object"
          },
          "type": "array"
        },
        "delegationTokenExpiryTimestampMs": {
          "description": "Current `expiry_timestamp_ms` of the operator-managed delegation\ntoken. Each successful renew extends it. The operator compares it\nagainst `now` to decide when to renew, as\n`spec.authentication.renewBeforeExpiry` specifies.",
          "format": "int64",
          "nullable": true,
          "type": "integer"
        },
        "delegationTokenId": {
          "description": "Persisted `token_id`, a UUID, of the operator-managed delegation\ntoken for this user. The operator uses it across reconciles to find the\nsame token with `DescribeDelegationToken`. It is present once the\noperator has issued a token with `CreateDelegationToken`.",
          "nullable": true,
          "type": "string"
        },
        "delegationTokenMaxTimestampMs": {
          "description": "Token's absolute upper bound, which is `max_timestamp_ms`. A renew can\nnever push `expiry_timestamp_ms` past this bound. The operator stops\nthe renews and surfaces `TokenExpiring` once no more extension is\npossible.",
          "format": "int64",
          "nullable": true,
          "type": "integer"
        },
        "external": {
          "default": false,
          "description": "`true` once the operator has reconciled a credential-less user with\n`type: tls-external`. It appears in `kubectl describe ku`, so that\noperators can see that the operator does not own this user's\ncredentials.",
          "type": "boolean"
        },
        "observedGeneration": {
          "description": "`metadata.generation` of the last successfully-reconciled spec.",
          "format": "int64",
          "nullable": true,
          "type": "integer"
        },
        "quotasInSync": {
          "default": false,
          "description": "True once the operator has reflected the spec's `quotas`, if any, in\nthe broker's `(user)` client-quota state. False when `spec.quotas` is\n`None`, because the operator then does not touch broker quotas.",
          "type": "boolean"
        },
        "scramSha256": {
          "default": false,
          "description": "True once SCRAM-SHA-256 credentials are provisioned.",
          "type": "boolean"
        },
        "scramSha512": {
          "default": false,
          "description": "True once SCRAM-SHA-512 credentials are provisioned.",
          "type": "boolean"
        },
        "secret": {
          "description": "Name of the Kubernetes Secret holding the user's password.",
          "nullable": true,
          "type": "string"
        },
        "tls": {
          "default": false,
          "description": "`true` once a TLS user has a current cert Secret. It has the same\nshape as `scram_sha512`.",
          "type": "boolean"
        },
        "tlsCertNotAfter": {
          "description": "RFC3339 timestamp of the user cert's `notAfter`. Present when\n`tls == true`.",
          "nullable": true,
          "type": "string"
        },
        "tlsPrincipal": {
          "description": "The principal string that the operator pinned in ACLs. It is\n`User:CN=alice` for TLS users, and `User:alice` for SCRAM and\n`tls-external` users. It is always filled in when the user is\nprovisioned. It is load-bearing for the debug of ACL-match problems.",
          "nullable": true,
          "type": "string"
        },
        "username": {
          "description": "Effective Kafka principal name. It matches `metadata.name`.",
          "nullable": true,
          "type": "string"
        }
      },
      "type": "object"
    }
  },
  "required": [
    "spec"
  ],
  "title": "KafkaUser",
  "type": "object"
}

spec

spec object Required 3 fields
Example
View JSON example
{
  "authentication": {
    "type": "scram-sha-512",
    "iterations": 8192,
    "passwordLength": 32
  }
}
Default No schema default
Not declared
authentication object Required 8 fields

Tagged enum on type, in the same shape as Strimzi.

The wire shape is flat and Strimzi-compatible. type is the discriminator, and the per-variant config fields are siblings of type. The custom schema_with writes a structural schema by hand, because the StructuralSchemaRewriter of kube-rs 3.x panics when oneOf branches share a type property with different enum values. That is the default schemars output for tagged-union enums. This is the same workaround as Storage in kafka_node_pool.rs.

The operator enforces the cross-variant constraints at reconcile time, and the apiserver does not. One such constraint is that iterations is valid only when type=scram-sha-512.

Example
View JSON example
{
  "type": "scram-sha-512",
  "iterations": 8192,
  "passwordLength": 32
}
Default No schema default
Not declared
iterations integer Optional
Example
8192
Default Runtime / omission

8192 for SCRAM-SHA-512 or SCRAM-SHA-256. Applies only to SCRAM authentication.

Validation and schema details
Maximum
1000000
Minimum
4096
#
maxLifetime string Optional
Example
"7d"
Default Runtime / omission

Use the broker's delegation_token_max_lifetime (documented default 7d); the broker also caps an explicit lifetime.

#
passwordLength integer Optional
Example
32
Default Runtime / omission

32 raw bytes (44 base64 characters) for a generated SCRAM password. Existing password Secrets are retained.

Validation and schema details
Maximum
256
Minimum
16
#
renewBeforeExpiry string Optional
Example
"24h"
Default Runtime / omission

24h for delegation-token authentication. The controller requires at least 60s.

#
renewalDays integer Optional
Example
30
Default Runtime / omission

30 days before expiry for TLS certificate renewal. Applies only to type tls.

Validation and schema details
Maximum
3650
Minimum
1
#
renewers array Optional 1 field
Example
View JSON example
[
  "User:bob"
]
Default Runtime / omission

[] for delegation-token authentication.

[] string Array item
Example
"User:bob"
Default No independent default
Defined by the parent
Validation and schema details
Pattern
"^User:.+$"
#
#
type string Required
Example
"scram-sha-512"
Default No schema default
Not declared
Allowed values"scram-sha-512""scram-sha-256""tls""tls-external""delegation-token"
#
validityDays integer Optional
Example
365
Default Runtime / omission

365 days for TLS client certificates. Applies only to type tls.

Validation and schema details
Maximum
36500
Minimum
1
#
#
authorization object | null Optional 3 fields

Authorization is optional. A user with no ACLs can still authenticate. When this field is absent, the operator skips ACL reconciliation.

Example
View JSON example
{
  "type": "simple",
  "acls": [
    {
      "resource": {
        "type": "topic",
        "name": "orders",
        "patternType": "literal"
      },
      "operations": [
        "Read",
        "Describe"
      ],
      "host": "*",
      "type": "allow"
    }
  ]
}
Default Runtime / omission

Absent: the operator skips ACL reconciliation.

Validation and schema details
Exactly one option must match
[
  {
    "required": [
      "type"
    ]
  }
]
acls array Optional 1 field
Example
View JSON example
[
  {
    "operations": [
      "Read",
      "Describe"
    ],
    "resource": {
      "name": "orders",
      "type": "topic"
    }
  }
]
Default Schema default
[]
[] object Array item 4 fields

One rule from spec.authorization.acls. The operator expands it into one (resource, operation, host, type) tuple per operations entry at reconcile time.

Example
View JSON example
{
  "operations": [
    "Read",
    "Describe"
  ],
  "resource": {
    "name": "orders",
    "type": "topic"
  }
}
Default No independent default
Defined by the parent
host string Optional

Source-address pattern. "*" is the wildcard. Defaults to "*" when omitted.

Example
"*"
Default Runtime / omission
  • (all source addresses).
#
operations array Required 1 field

Non-empty list. The reconciler refuses an empty operations with Ready=False reason=InvalidSpec.

Example
View JSON example
[
  "Read",
  "Describe"
]
Default No schema default
Not declared
[] string Array item

All 11 Kafka ACL operations. Matches the discriminants in org.apache.kafka.common.acl.AclOperation.

Example
"All"
Default No independent default
Defined by the parent
Allowed values"All""Read""Write""Create""Delete""Alter""Describe""ClusterAction""DescribeConfigs""AlterConfigs""IdempotentWrite"
#
#
resource object Required 3 fields
Example
View JSON example
{
  "name": "orders",
  "type": "topic"
}
Default No schema default
Not declared
name string Required
Example
"orders"
Default No schema default
Not declared
#
patternType string Optional

literal for an exact match, or prefixed for resources whose name starts with name. Defaults to literal.

Example
"literal"
Default Schema default
"literal"
Allowed values"literal""prefixed"
#
type string Required
Example
"topic"
Default No schema default
Not declared
Allowed values"topic""group""cluster""transactional-id"
#
#
type string Optional

allow or deny; defaults to allow.

Example
"allow"
Default Schema default
"allow"
Allowed values"allow""deny"
#
#
#
type string Required
Example
"simple"
Default No schema default
Not declared
Allowed values"simple"
#
oneOf option 1 any Schema option

spec.authorization oneOf option 1

Example
View JSON example
{
  "type": "simple",
  "acls": [
    {
      "resource": {
        "type": "topic",
        "name": "orders",
        "patternType": "literal"
      },
      "operations": [
        "Read",
        "Describe"
      ],
      "host": "*",
      "type": "allow"
    }
  ]
}
Default Runtime / omission

Absent: the operator skips ACL reconciliation.

#
#
quotas object | null Optional 4 fields

Optional per-user client quotas (KIP-13/124/257). This field maps onto Kafka's (user) quota entity through AlterClientQuotas, which is api_key 49. When the field is absent, the operator does not touch the broker's quota state. When the field is present, the operator drives the broker's quota keys for User:<name> toward the spec. It sets the configured fields and tombstones the omitted ones.

Example
View JSON example
{
  "producerByteRate": 1048576,
  "consumerByteRate": 2097152,
  "requestPercentage": 55,
  "controllerMutationRate": 10.5
}
Default Runtime / omission

Absent: the operator does not manage quotas. {} removes all managed quota overrides.

consumerByteRate integer | null (int32) Optional

Maximum consume-side bytes/sec. Backed by consumer_byte_rate.

Example
2097152
Default Runtime / omission

Absent quotas: leave broker state unchanged. When quotas is present, omit this field to remove this quota override.

Validation and schema details
Minimum
0
#
controllerMutationRate number | null (double) Optional

KIP-599 controller-mutation rate in creates and deletes per second. Backed by controller_mutation_rate.

Example
10.5
Default Runtime / omission

Absent quotas: leave broker state unchanged. When quotas is present, omit this field to remove this quota override.

#
producerByteRate integer | null (int32) Optional

Maximum produce-side bytes/sec. Backed by producer_byte_rate.

Example
1048576
Default Runtime / omission

Absent quotas: leave broker state unchanged. When quotas is present, omit this field to remove this quota override.

Validation and schema details
Minimum
0
#
requestPercentage integer | null (int32) Optional

Maximum percentage of a request-handler thread's time that the user can consume, in the range 0..=100. Backed by request_percentage.

Example
55
Default Runtime / omission

Absent quotas: leave broker state unchanged. When quotas is present, omit this field to remove this quota override.

Validation and schema details
Maximum
100
Minimum
0
#
#
#

status

status object | null Optional 14 fields
Example
View JSON example
{
  "conditions": [
    {
      "lastTransitionTime": "2026-10-05T12:00:00Z",
      "message": "The resource is ready.",
      "reason": "Reconciled",
      "status": "True",
      "type": "Ready"
    }
  ]
}
Default No schema default
Not declared
conditions array Optional 1 field

Standard Kubernetes-style condition list. It shows Ready.

Example
View JSON example
[
  {
    "lastTransitionTime": "2026-10-05T12:00:00Z",
    "message": "The resource is ready.",
    "reason": "Reconciled",
    "status": "True",
    "type": "Ready"
  }
]
Default Schema default
[]
[] object Array item 5 fields
Example
View JSON example
{
  "lastTransitionTime": "2026-10-05T12:00:00Z",
  "message": "The resource is ready.",
  "reason": "Reconciled",
  "status": "True",
  "type": "Ready"
}
Default No schema default
Not declared
lastTransitionTime string Required

RFC3339 timestamp.

Example
"2026-10-05T12:00:00Z"
Default No schema default
Not declared
#
message string Required

Human-readable message.

Example
"The resource is ready."
Default No schema default
Not declared
#
reason string Required

CamelCase machine reason.

Example
"Reconciled"
Default No schema default
Not declared
#
status string Required

True, False, or Unknown.

Example
"True"
Default No schema default
Not declared
#
type string Required

For example, Ready.

Example
"Ready"
Default No schema default
Not declared
#
#
#
delegationTokenExpiryTimestampMs integer | null (int64) Optional

Current expiry_timestamp_ms of the operator-managed delegation token. Each successful renew extends it. The operator compares it against now to decide when to renew, as spec.authentication.renewBeforeExpiry specifies.

Example
1
Default No schema default
Not declared
#
delegationTokenId string | null Optional

Persisted token_id, a UUID, of the operator-managed delegation token for this user. The operator uses it across reconciles to find the same token with DescribeDelegationToken. It is present once the operator has issued a token with CreateDelegationToken.

Example
"019bbdb3-fec4-7780-9978-8805004f5d96"
Default No schema default
Not declared
#
delegationTokenMaxTimestampMs integer | null (int64) Optional

Token's absolute upper bound, which is max_timestamp_ms. A renew can never push expiry_timestamp_ms past this bound. The operator stops the renews and surfaces TokenExpiring once no more extension is possible.

Example
1
Default No schema default
Not declared
#
external boolean Optional

true once the operator has reconciled a credential-less user with type: tls-external. It appears in kubectl describe ku, so that operators can see that the operator does not own this user's credentials.

Example
false
Default Schema default
false
#
observedGeneration integer | null (int64) Optional

metadata.generation of the last successfully-reconciled spec.

Example
1
Default No schema default
Not declared
#
quotasInSync boolean Optional

True once the operator has reflected the spec's quotas, if any, in the broker's (user) client-quota state. False when spec.quotas is None, because the operator then does not touch broker quotas.

Example
false
Default Schema default
false
#
scramSha256 boolean Optional

True once SCRAM-SHA-256 credentials are provisioned.

Example
false
Default Schema default
false
#
scramSha512 boolean Optional

True once SCRAM-SHA-512 credentials are provisioned.

Example
false
Default Schema default
false
#
secret string | null Optional

Name of the Kubernetes Secret holding the user's password.

Example
"alice"
Default No schema default
Not declared
#
tls boolean Optional

true once a TLS user has a current cert Secret. It has the same shape as scram_sha512.

Example
false
Default Schema default
false
#
tlsCertNotAfter string | null Optional

RFC3339 timestamp of the user cert's notAfter. Present when tls == true.

Example
"2027-10-05T00:00:00Z"
Default No schema default
Not declared
#
tlsPrincipal string | null Optional

The principal string that the operator pinned in ACLs. It is User:CN=alice for TLS users, and User:alice for SCRAM and tls-external users. It is always filled in when the user is provisioned. It is load-bearing for the debug of ACL-match problems.

Example
"User:CN=alice"
Default No schema default
Not declared
#
username string | null Optional

Effective Kafka principal name. It matches metadata.name.

Example
"alice"
Default No schema default
Not declared
#
#

Resource schema

Resource schema object Resource schema

Auto-generated derived type for KafkaUserSpec via CustomResource

Example
View JSON example
{
  "apiVersion": "krabka.io/v1alpha1",
  "kind": "KafkaUser",
  "metadata": {
    "name": "example",
    "namespace": "default",
    "labels": {
      "krabka.io/cluster": "my-cluster"
    }
  },
  "spec": {
    "authentication": {
      "type": "scram-sha-512",
      "iterations": 8192,
      "passwordLength": 32
    }
  }
}
Default No resource default
None
#