Skip to content

Conversation

@aleksanderaleksic
Copy link

Summary

Introduces the System CRD to provide a more declarative and extensible approach to configuring NATS authentication backends, replacing the implicit label-based secret discovery mechanism.

Key changes:

  • New System CRD (nauth.io/v1alpha1) for explicit operator credentials configuration
  • Accounts can now reference a System via spec.systemRef for credential resolution
  • Introduces a Provider/Resolver pattern enabling future support for third-party NATS backends
  • Full backward compatibility maintained - existing deployments without systemRef continue to work

Motivation

The current nauth implementation requires secrets to be labeled with nauth.io/secret-type: operator-sign and nauth.io/secret-type: system-account-user-creds for the controller to discover operator credentials. This approach has limitations:

  1. Implicit configuration - The relationship between accounts and credentials is not explicit in the CRD
  2. Single system only - Only one NATS system can be managed per namespace
  3. No extensibility - Adding support for managed NATS providers (e.g., Synadia Cloud) would require significant rework

The new System CRD addresses these issues by:

  • Making credential references explicit and declarative via secretRef fields
  • Allowing multiple systems to coexist (each account references its system)
  • Introducing a Provider interface that can be implemented for different backends

New CRD Schema

apiVersion: nauth.io/v1alpha1
kind: System
metadata:
  name: my-nats-system
  namespace: nauth
spec:
  operatorSigningKeySecretRef:
    name: operator-signing-key
    key: seed
  systemAccountUserCredsSecretRef:
    name: system-account-creds
    key: user.creds

Accounts reference a System via systemRef:

apiVersion: nauth.io/v1alpha1
kind: Account
metadata:
  name: my-account
  namespace: nauth
spec:
  systemRef:
    kind: System
    name: my-nats-system
    namespace: nauth
  # ... rest of account spec

Architecture

flowchart TD
    AR[AccountReconciler] -->|resolves| R[Resolver]
    AR -->|delegates| P[Provider\ninterface]
    R -->|creates| F[Factory]
    F -->|creates| P
    P -.->|implements| NP[nauth.Provider]
    NP -->|wraps| AM[account.Manager]
    NP -->|wraps| UM[user.Manager]
Loading
  • Resolver: Determines which Provider to use based on Account.Spec.SystemRef
  • Provider: Interface for account/user operations (CreateAccount, CreateUser, etc.)
  • Factory: Creates Provider instances configured with the appropriate System

Backward Compatibility

  • Accounts without systemRef continue to use the legacy label-based secret discovery
  • Existing deployments require no changes
  • The legacy approach may be deprecated in a future release

Future Extensibility

This architecture enables adding new system backends. For example, Synadia Cloud support could be added as:

apiVersion: synadia.nauth.io/v1alpha1
kind: System
metadata:
  name: ngs-system
spec:
  teamId: "team-id"
  credentialsSecretRef:
    name: synadia-credentials
    key: token

Each backend would implement the system.Provider interface with its specific logic.

Test Plan

  • Unit tests pass (make test)
  • E2E tests pass (make test-e2e)
  • New E2E test suite (system-ref-test) validates the System approach:
    • Creates System with secretRefs (no legacy labels)
    • Creates Account with systemRef
    • Verifies no fallback to legacy label-based discovery
    • Creates User and verifies credentials

@aleksanderaleksic aleksanderaleksic requested a review from a team as a code owner January 27, 2026 05:47
@aleksanderaleksic aleksanderaleksic changed the title Refactor system Make nauth support multiple systems Jan 27, 2026
@aleksanderaleksic aleksanderaleksic changed the title Make nauth support multiple systems feat: Make nauth support multiple systems Jan 27, 2026
@kejne
Copy link
Collaborator

kejne commented Jan 28, 2026

Hi! Thanks for the PR! Sorry for slow feedback, we'll have a look at the issue and PR to get an understanding since it's a quite big update.
Looks like you got most parts covered test-wise etc 👌
Most importantly to see that the concept does not clash and has a good migration path for current users.

Copy link
Collaborator

@thobiaskarlsson thobiaskarlsson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, I really like this addition. Some concerns found though, please have a look (and check PR workflow issues).

Regarding the PR description, in "Future Extensibility" your example says apiVersion: synadia.nauth.io/v1alpha1, don't you mean apiGroup: ...? I have posted an issue related to this as well in internal/system/resolver.go, please have a look.

@thobiaskarlsson
Copy link
Collaborator

@aleksanderaleksic , please rebase (and resolve conflicts), fix the commit sign-offs and comment on the conversations when you have resolved them so that we can perform a new renew and get this merged.

@wingsofovnia
Copy link
Contributor

wingsofovnia commented Feb 4, 2026

nit: System sounds a little bit ambiguous, especially when used without fqn: kubectl get system - unclear what system, what it does etc (same with generic account/user tbh; account in particular clashes with nack's account CRD). Even when fqn is used, it doesn't map onto any common NATS domain knowledge. Perhaps (Nats)Cluster, (Nats)ClusterConfig, (Nats)ClusterProvider?

Otherwise great addition! I personally prefer explicit refs like that over labels.

aleksanderaleksic and others added 17 commits February 5, 2026 22:01
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
…nfig

Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Use events.EventRecorder from k8s.io/client-go/tools/events instead of
record.EventRecorder to match the statusReporter interface requirements.

Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
Signed-off-by: Aleksander Aleksic <aleksander.aleksic@nordicsemi.no>
@aleksanderaleksic
Copy link
Author

aleksanderaleksic commented Feb 5, 2026

nit: System sounds a little bit ambiguous, especially when used without fqn: kubectl get system - unclear what system, what it does etc (same with generic account/user tbh; account in particular clashes with nack's account CRD). Even when fqn is used, it doesn't map onto any common NATS domain knowledge. Perhaps (Nats)Cluster, (Nats)ClusterConfig, (Nats)ClusterProvider?

@wingsofovnia
I agree, I think System came to my mind from Synadia cloud actually, where they have a concept of system.
I dont think its nitpicking to be honest, it should be a concept that is easy to understand and from your suggestion I would go with ClusterProvider or NatsCluster I think, let me know if I am gonna change it.
Naming is hard..

@thobiaskarlsson
Copy link
Collaborator

nit: System sounds a little bit ambiguous, especially when used without fqn: kubectl get system - unclear what system, what it does etc (same with generic account/user tbh; account in particular clashes with nack's account CRD). Even when fqn is used, it doesn't map onto any common NATS domain knowledge. Perhaps (Nats)Cluster, (Nats)ClusterConfig, (Nats)ClusterProvider?

@wingsofovnia I agree, I think System came to my mind from Synadia cloud actually, where they have a concept of system. I dont think its nitpicking to be honest, it should be a concept that is easy to understand and from your suggestion I would go with ClusterProvider or NatsCluster I think, let me know if I am gonna change it. Naming is hard..

It all looks good! Regarding the name, I truly believe NatsCluster and NatsClusterRef is the absolute most accurate, as we are also dealing with Kubernetes Clusters in this context there's no harm in being specific. Please apply the name change, then I'll be happy to merge and create a release. Thank you for this contribution! 🙏

@aleksanderaleksic
Copy link
Author

It all looks good! Regarding the name, I truly believe NatsCluster and NatsClusterRef is the absolute most accurate, as we are also dealing with Kubernetes Clusters in this context there's no harm in being specific. Please apply the name change, then I'll be happy to merge and create a release. Thank you for this contribution! 🙏

Okay, I will update the PR and resolve the conflicts :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants