Skip to content

CEL validation for Datastore credentials and TLS configuration #746

@prometherion

Description

@prometherion

This is a good first issue to those happy to contribute to Kamaji

Kamaji supports a variety of Datastore drivers, such as:

  • etcd
  • NATS
  • MySQL
  • PostgreSQL

We should try to offload the TLS configuration from validation webhooks to Kubernetes CEL one.

Full requirement for etcd

For etcd, we require a secured connection (TLS) and client-based authentication since we don't rely on basic authentication.

apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
  name: default
spec:
  driver: etcd
  endpoints:
  - kamaji-etcd-0.kamaji-etcd.kamaji-system.svc.cluster.local:2379
  - kamaji-etcd-1.kamaji-etcd.kamaji-system.svc.cluster.local:2379
  - kamaji-etcd-2.kamaji-etcd.kamaji-system.svc.cluster.local:2379
  tlsConfig:  # !!! required !!!
    certificateAuthority:
      certificate:  # !!! at least one of secretReference, or content !!!
        secretReference:
          keyPath: ca.crt
          name: kamaji-etcd-certs
          namespace: kamaji-system
      privateKey:  # !!! at least one of secretReference, or content !!!
        secretReference:
          keyPath: ca.key
          name: kamaji-etcd-certs
          namespace: kamaji-system
    clientCertificate:  # !!! required !!!
      certificate:  # !!! at least one of secretReference, or content !!!
        secretReference:
          keyPath: tls.crt
          name: kamaji-etcd-root-client-certs
          namespace: kamaji-system
      privateKey:  # !!! at least one of secretReference, or content !!!
        secretReference:
          keyPath: tls.key
          name: kamaji-etcd-root-client-certs
          namespace: kamaji-system

RDBMS (such as MySQL, or PostgreSQL) and NATS

Although not production-grade and open to MITM attacks, some users have issues with TLS-based RDBMs and rely only on Basic Authentication.

apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
  name: postgresql-managed
spec:
  basicAuth:  # !!! required if not TLS tlsConfig is configured !!!
    password:  # !!! at least one of secretReference, or content !!!
      secretReference:
        keyPath: password
        name: postgres-bronze-superuser
        namespace: postgres-system
    username:  # !!! at least one of secretReference, or content !!!
      secretReference:
        keyPath: username
        name: postgres-bronze-superuser
        namespace: postgres-system
  driver: PostgreSQL
  endpoints:
  - postgres-bronze-rw.postgres-system.svc:5432

Otherwise, TLS based but with basic authentication:

apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
  name: postgresql-managed
spec:
  basicAuth:  # !!! required, TLS is set but with 
    password:  # !!! at least one of secretReference, or content !!!
      secretReference:
        keyPath: password
        name: postgres-bronze-superuser
        namespace: postgres-system
    username:  # !!! at least one of secretReference, or content !!!
      secretReference:
        keyPath: username
        name: postgres-bronze-superuser
        namespace: postgres-system
  driver: PostgreSQL
  endpoints:
  - postgres-bronze-rw.postgres-system.svc:5432
  tlsConfig:
    certificateAuthority:
      certificate:
        secretReference:  # !!! at least one of secretReference, or content !!!
          keyPath: ca.crt
          name: postgres-bronze-ca
          namespace: postgres-system

Eventually, the best solution:

apiVersion: kamaji.clastix.io/v1alpha1
kind: DataStore
metadata:
  name: postgresql-bronze
spec:
  driver: PostgreSQL
  endpoints:
    - postgres-bronze-rw.postgres-system.svc:5432
  basicAuth:  # this can be optional, client-based certificates authentication is enabled
    username:
      secretReference:
        name: postgres-bronze-superuser
        namespace: postgres-system
        keyPath: username
    password:
      secretReference:
        name: postgres-bronze-superuser
        namespace: postgres-system
        keyPath: password
  tlsConfig:
    certificateAuthority:
      certificate:
        secretReference:
          name: postgres-bronze-ca
          namespace: postgres-system
          keyPath: ca.crt
    clientCertificate:
      certificate:  # !!! at least one of secretReference, or content !!!
        secretReference:
          name: postgres-bronze-root-cert
          namespace: postgres-system
          keyPath: tls.crt
      privateKey:  # !!! at least one of secretReference, or content !!!
        secretReference:
          name: postgres-bronze-root-cert
          namespace: postgres-system
          keyPath: tls.key

Regarding NATS, the TLS requirements are pretty similar, even tho multi-tenancy on the datastore is not yet fully supported.

Development tips

CEL patterns are stored directly in the CRDs manifest, this can be triggered with the following command:

make crds

The generated manifest must be then installed in the cluster using Helm which doesn't handle properly CRDs updates, you will need to apply using kubectl:

kubectl apply -f charts/kamaji/crds/kamaji.clastix.io_datastores.yaml

Once done, validation can easily tested with kubectl create checking if creation fails or not, according to the expected validation cases.

Bonus

Having tests would be ideal, no need for e2e but a simple one (maybe based on bash) since CEL patterns are validated when creating resources in DryRun (DryRun=server)

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions