Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 145 additions & 1 deletion docs/core-concepts/observability/logging.md
Original file line number Diff line number Diff line change
@@ -1 +1,145 @@
# Logging
---
title: Logging
---

Kubedoop gives every product the same logging controls: per-container log levels that you set on a
role or a single role group, and an optional [Vector](https://vector.dev/) agent that ships the
resulting files to an aggregator.

## Where logs go

Containers write under `/kubedoop/log/`, one directory per container:

```text
/kubedoop/log/<container>/<container>.<suffix>
```

The suffix depends on the logging framework the product uses. Both the console stream and these
files are produced, and they are configured independently — see below.

## Configuring log levels

Logging lives under `config`, so it can be set on a role and refined per role group:

```yaml
apiVersion: trino.kubedoop.dev/v1alpha1
kind: TrinoCluster
metadata:
name: trino
spec:
coordinator:
config:
logging:
containers:
trino:
console:
level: INFO
file:
level: DEBUG
loggers:
io.trino.server:
level: DEBUG
roleGroups:
default:
replicas: 1
```

The structure is:

| Key | Meaning |
|-----|---------|
| `containers.<name>` | The container these settings apply to |
| `containers.<name>.console.level` | Threshold for the console (stdout) appender |
| `containers.<name>.file.level` | Threshold for the file appender |
| `containers.<name>.loggers.<name>.level` | Threshold for one named logger |
| `enableVectorAgent` | Whether to inject the Vector sidecar |

Every `level` takes one of:

```text
FATAL ERROR WARN INFO DEBUG TRACE
```

### Unset means inherit

`level` has no default in the CRD, deliberately. Leaving it out means "inherit":

- a role group that omits it takes the role's value
- when nobody sets it, the product's own default applies — root logger at `INFO`, with no threshold
on the appender

This is why writing an empty `console: {}` in a role group does not quietly override a `DEBUG` you
set at the role level. If the field carried a CRD default, the API server would fill it as soon as
the enclosing object existed, and the role's value could never win.

### Levels are mapped for non-Java products

Kubedoop's level names follow the Java convention. Products whose logging framework uses different
names get them mapped:

| Kubedoop | Mapped to |
|----------|-----------|
| `FATAL` | `CRITICAL` |
| `ERROR` | `ERROR` |
| `WARN` | `WARNING` |
| `INFO` | `INFO` |
| `DEBUG` | `DEBUG` |
| `TRACE` | `DEBUG` |

`TRACE` and `DEBUG` collapse onto the same level for those products, so asking for `TRACE` will not
get you more than `DEBUG` there.

## Shipping logs with Vector

Setting `enableVectorAgent: true` injects a Vector sidecar that tails the log directory and forwards
to an aggregator you run:

```yaml
spec:
clusterConfig:
vectorAggregatorConfigMapName: vector-aggregator-discovery
coordinator:
config:
logging:
enableVectorAgent: true
```

The aggregator's address is not written in the cluster resource. Instead
`vectorAggregatorConfigMapName` names a ConfigMap in the same namespace holding a single key:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: vector-aggregator-discovery
data:
ADDRESS: http://vector-aggregator.default.svc.cluster.local:6000
```

This indirection means the aggregator can move without editing every product cluster.

### Enabling the agent without an aggregator fails loudly

If the Vector agent is enabled and the product actually produces logs, but
`vectorAggregatorConfigMapName` is empty, reconciliation fails rather than shipping a sidecar with
nowhere to send:

```text
vector agent is enabled but vectorAggregatorConfigMapName is not configured (role "coordinator", group "default")
```

A named ConfigMap that cannot be resolved fails the same way, and the message says which check
failed:

```text
configmap default/vector-aggregator-discovery missing "ADDRESS" key
configmap default/vector-aggregator-discovery has empty "ADDRESS" value
```

This is deliberate. A silently mis-wired log pipeline looks healthy right up until you need the
logs.

## Related

- [Roles and role groups](../common-configuration-mechanisms/roles-and-role-groups.md)
- [Configuration overrides](../common-configuration-mechanisms/overrides.md)
248 changes: 246 additions & 2 deletions docs/core-concepts/security/authentication.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,247 @@
# Authentication
---
title: Authentication
---

TODO
Authentication in Kubedoop is split in two. An `AuthenticationClass` describes *how* to
authenticate — an LDAP server, an OIDC issuer, a static list of users — once, for the whole
cluster. A product then names the class it wants to use. The identity provider is configured in one
place, and any number of clusters point at it.

## AuthenticationClass

`AuthenticationClass` belongs to the `authentication.kubedoop.dev/v1alpha1` API group and is
**cluster-scoped**, so it has no namespace and is visible to every product in the cluster. Its short
name is `authclass`:

```bash
kubectl get authclass
```

The spec is a single `provider` block naming one mechanism:

```yaml
apiVersion: authentication.kubedoop.dev/v1alpha1
kind: AuthenticationClass
metadata:
name: ldap
spec:
provider:
ldap:
hostname: openldap.default.svc.cluster.local
port: 389
searchBase: ou=users,dc=example,dc=com
bindCredentials:
secretClass: ldap-bind
```

| Provider | Describes |
|----------|-----------|
| `static` | A Secret holding user credentials |
| `ldap` | An LDAP or Active Directory server |
| `oidc` | An OpenID Connect issuer |
| `tls` | Client-certificate authentication |
| `kerberos` | A Kerberos realm |

### Set exactly one provider

All five fields are optional in the schema and **nothing rejects a class that sets several, or
none**. Products resolve the provider by checking fields in a fixed order and taking the first
match, so a class with both `oidc` and `ldap` authenticates via OIDC and silently ignores the LDAP
block. Trino, for example, checks `oidc`, then `static`, then `ldap`.

Treat "exactly one provider per class" as a rule you enforce yourself. Two mechanisms means two
classes.

### Not every product supports every provider

The API defines five providers; a given operator implements the subset that makes sense for its
product. Trino handles `oidc`, `static` and `ldap`. Pointing a Trino cluster at a class whose
provider is `tls` or `kerberos` yields no authenticator at all, without a rejection at apply time.

Check the operator's own documentation before assuming a provider is wired up.

## Referencing a class from a product

Products take the class by name. Trino accepts a list, so a cluster can offer more than one method:

```yaml
apiVersion: trino.kubedoop.dev/v1alpha1
kind: TrinoCluster
metadata:
name: trino
spec:
clusterConfig:
authentication:
- authenticationClass: ldap
```

Because the class is cluster-scoped, `authenticationClass` is just a name — there is no namespace to
qualify.

## static

The simplest provider: a Secret in the product's namespace holding user credentials.

```yaml
spec:
provider:
static:
userCredentialsSecret:
name: trino-users
```

The keys inside that Secret are **product-specific** — each product reads the format its own
authentication mechanism expects, so consult the operator's documentation for the layout. The
`AuthenticationClass` only carries the Secret's name.

## ldap

```yaml
spec:
provider:
ldap:
hostname: openldap.default.svc.cluster.local
port: 389
searchBase: ou=users,dc=example,dc=com
searchFilter: ""
bindCredentials:
secretClass: ldap-bind
ldapFieldNames:
uid: uid
group: memberof
email: mail
givenName: givenName
surname: sn
```

| Field | Required | Default |
|-------|----------|---------|
| `hostname` | yes | — |
| `port` | no | `389`, or `636` when `tls` is set |
| `bindCredentials` | yes | — |
| `searchBase` | no | `""` |
| `searchFilter` | no | `""` |
| `ldapFieldNames` | no | see below |
| `tls` | no | — |

`bindCredentials.secretClass` names a SecretClass whose Secret must contain two keys:

| Key | Meaning |
|-----|---------|
| `user` | Bind DN, for example `cn=admin,dc=example,dc=com` |
| `password` | Bind password |

`ldapFieldNames` maps Kubedoop's notion of a user attribute onto your directory's schema. The
defaults suit a standard OpenLDAP layout:

| Field | Default |
|-------|---------|
| `uid` | `uid` |
| `group` | `memberof` |
| `email` | `mail` |
| `givenName` | `givenName` |
| `surname` | `sn` |

Active Directory uses different attribute names — `sAMAccountName` rather than `uid`, typically —
so an AD-backed class will need these set explicitly.

## oidc

```yaml
spec:
provider:
oidc:
hostname: keycloak.default.svc.cluster.local
port: 8080
rootPath: /realms/kubedoop
principalClaim: preferred_username
providerHint: keycloak
scopes:
- openid
- email
```

| Field | Required | Default |
|-------|----------|---------|
| `hostname` | yes | — |
| `port` | no | — |
| `principalClaim` | yes | — |
| `providerHint` | yes | — |
| `rootPath` | no | `/` |
| `scopes` | no | — |
| `tls` | no | — |

`principalClaim` is the claim in the ID token the product treats as the username.

**`providerHint` currently accepts only `keycloak`.** It is a required field with an enumerated
value, so any other issuer is rejected at apply time. Keycloak is the supported OIDC issuer today.

### Client credentials live with the product, not the class

The `AuthenticationClass` describes the issuer. The client ID and secret belong to the individual
cluster, so they are supplied where the class is referenced:

```yaml
spec:
clusterConfig:
authentication:
- authenticationClass: keycloak
oidc:
clientCredentialsSecret: trino-oidc-client
extraScopes:
- profile
```

That Secret must contain:

| Key |
|-----|
| `CLIENT_ID` |
| `CLIENT_SECRET` |

They are passed into the pod as environment variables.

## tls and kerberos

```yaml
spec:
provider:
tls:
clientCertSecretClass: trino-client-tls
```

```yaml
spec:
provider:
kerberos:
kerberosStorageClass: kerberos
```

`tls` authenticates clients by the certificate they present, issued by the named SecretClass.
`kerberos` points at the StorageClass backing Kerberos credential delivery. Support for both is
product-dependent — see the note above.

## TLS verification

`ldap` and `oidc` both accept a `tls` block, and when present its `verification` is **required**:

```yaml
tls:
verification:
server:
caCert:
secretClass: tls
```

| `verification` | Behaviour |
|----------------|-----------|
| `server.caCert.secretClass` | Verify against the CA published by that SecretClass |
| `server.caCert.webPki: {}` | Verify against the system's public CA bundle |
| `none: {}` | Do not verify the certificate |

Setting `tls` on an LDAP provider also moves the default port from 389 to 636.

## Related

- [Roles and role groups](../common-configuration-mechanisms/roles-and-role-groups.md)
- [S3](../resources/s3.md)
Loading
Loading