Skip to content

Remove usage of create_auth and reset_password API#1697

Merged
tangledbytes merged 1 commit intonoobaa:masterfrom
tangledbytes:utkarsh/remove-password
Sep 12, 2025
Merged

Remove usage of create_auth and reset_password API#1697
tangledbytes merged 1 commit intonoobaa:masterfrom
tangledbytes:utkarsh/remove-password

Conversation

@tangledbytes
Copy link
Member

@tangledbytes tangledbytes commented Sep 8, 2025

Explain the changes

‼️ This PR depends on noobaa/noobaa-core#9211

This PR:

  1. Removes the usage of CreateAuthAPI and replaces it with generating tokens using a new utility function MakeAuthToken.
  2. Removes password reset functionality and ResetPasswordAPI and associated tests.

Issues: Fixed #xxx / Gap #xxx

Testing Instructions:

  • Doc added/updated
  • Tests added

Summary by CodeRabbit

  • Refactor

    • Remote authentication now uses internally generated JWTs for operator, admin, and metrics flows.
    • Removed client auth API surface and password-reset API/types; CLI password-reset command and test helpers removed.
  • Behavior Changes

    • Increased readiness polling cadence for backing stores and extended certain condition timeouts to 5 minutes.
  • Chores

    • Updated default container image tag to master-20250911.
    • JWT library promoted to a direct dependency; added token-generation utility.

@coderabbitai
Copy link

coderabbitai bot commented Sep 8, 2025

Walkthrough

Removed NB client CreateAuth and ResetPassword APIs/types and their CLI test/commands; replaced remote NB auth calls with local JWT signing via new util.MakeAuthToken using the server secret. Also made jwt a direct go.mod dependency, bumped default image tag, and increased select polling timeouts/intervals.

Changes

Cohort / File(s) Change summary
Dependencies
go.mod
Made github.com/golang-jwt/jwt/v4 v4.5.2 a direct dependency (removed // indirect).
NB client API surface
pkg/nb/api.go
Removed Client/RPCClient methods CreateAuthAPI and ResetPasswordAPI and their RPC call logic.
NB types
pkg/nb/types.go
Removed exported structs: CreateAuthParams, CreateAuthReply, ResetPasswordParams; minor formatting-only alignment edits elsewhere.
NooBaa account CLI
pkg/noobaaaccount/noobaaaccount.go
Removed password-related CLI command and helpers: CmdPasswd, RunPasswd, ResetPassword, PasswordResstrictions.
Account reconciler
pkg/noobaaaccount/reconciler.go
Replaced NBClient-based auth token creation with util.MakeAuthToken using server secret; token now written into account secret.
System config (phase4)
pkg/system/phase4_configuring.go
Replaced NBClient token creation for metrics/operator/admin with util.MakeAuthToken; updated error messages and secret writes.
Utility additions & timeouts
pkg/util/util.go
Added exported MakeAuthToken(payload map[string]any, secret []byte) (string, error) using HS256 (github.com/golang-jwt/jwt/v4). Increased NooBaaCondition timeout from 120s to 5m.
Tests (CLI)
test/cli/test_cli_functions.sh
Removed admin password reset flow and helpers (account_reset_password, get_admin_password); updated checks referencing new-default-backing-store.
BackingStore readiness
pkg/backingstore/backingstore.go
Increased wait.PollUntilContextCancel interval from 3s to 30s in WaitReady.
Image tag
pkg/options/options.go
Updated ContainerImageTag from "master-20250521" to "master-20250911".

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Reconciler as Reconciler
  participant SecretServer as Server Secret (jwt)
  participant Util as util.MakeAuthToken
  participant K8sSecret as Kubernetes Secret

  Note over Reconciler,SecretServer: Local JWT signing replaces NBClient CreateAuthAPI
  Reconciler->>SecretServer: read signing key (secretServer.StringData["jwt"])
  SecretServer-->>Reconciler: jwt signing key
  Reconciler->>Util: MakeAuthToken({system, role, email}, jwt)
  Util-->>Reconciler: signed JWT token
  Reconciler->>K8sSecret: write token to secret (auth_token / metrics key)
  Note over Reconciler,K8sSecret: NBClient.CreateAuthAPI call removed from this flow
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • achouhan09

Pre-merge checks (1 passed, 2 warnings)

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The PR description includes a clear "Explain the changes" section and notes the dependency on the core PR, but the "Issues" and "Testing Instructions" sections are empty and the doc/tests checklist is unchecked. It does not document the impact on public API (several exported types and methods were removed), lacks migration or compatibility guidance, and provides no concrete verification steps for reviewers or CI. Because those details are important for a change that removes exported APIs and CLI functionality, the description is incomplete. Please expand the PR description to include concrete testing instructions (step-by-step verification and expected results), add or reference any issue numbers, and explicitly document removed exported types/functions and their backward-compatibility or migration implications; link the dependent core PR and state its required status, and update the Doc/Tests checklist or explain why they are not needed. This will help reviewers validate correctness and assess user impact before merging.
Docstring Coverage ⚠️ Warning Docstring coverage is 68.75% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title Check ✅ Passed The title succinctly describes the primary change — removal of create_auth and reset_password API usage — and aligns directly with the main modifications in the changeset. It is concise, specific, and understandable for a teammate scanning PR history.

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d7751c5 and dd5e392.

📒 Files selected for processing (10)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (1 hunks)
  • pkg/noobaaaccount/reconciler.go (1 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (3 hunks)
  • test/cli/test_cli_functions.sh (1 hunks)
💤 Files with no reviewable changes (1)
  • pkg/nb/api.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • go.mod
  • pkg/util/util.go
  • pkg/options/options.go
  • pkg/backingstore/backingstore.go
  • test/cli/test_cli_functions.sh
  • pkg/noobaaaccount/noobaaaccount.go
  • pkg/nb/types.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/noobaaaccount/reconciler.go (3)
pkg/util/util.go (3)
  • KubeObject (283-293)
  • KubeCheck (569-590)
  • MakeAuthToken (2394-2410)
pkg/bundle/deploy.go (1)
  • File_deploy_internal_secret_empty_yaml (4902-4909)
pkg/options/options.go (3)
  • Namespace (57-57)
  • SystemName (50-50)
  • OperatorAccountEmail (47-47)
pkg/system/phase4_configuring.go (2)
pkg/util/util.go (1)
  • MakeAuthToken (2394-2410)
pkg/options/options.go (2)
  • OperatorAccountEmail (47-47)
  • AdminAccountEmail (44-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-admission-test
  • GitHub Check: run-cli-tests
  • GitHub Check: run-operator-tests
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-hac-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: golangci-lint
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-kms-tls-sa-test
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch 3 times, most recently from 2302de6 to 599a86b Compare September 9, 2025 06:58
@tangledbytes tangledbytes marked this pull request as ready for review September 9, 2025 06:59
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
pkg/system/phase4_configuring.go (2)

218-227: READY path: same signing-key guard as above; prefer r.NooBaa.Name; add TTL

  • Hydrate/validate server JWT before signing (same as metrics).
  • Minor: use r.NooBaa.Name consistently for the "system" claim (less surprise than r.Request.Name).
  • Add exp/iat to avoid never-expiring operator tokens.
@@
-			token, err := util.MakeAuthToken(map[string]any{
-				"system": r.Request.Name,
-				"role":   "operator",
-				"email":  options.OperatorAccountEmail,
-			}, []byte(r.SecretServer.StringData["jwt"]))
+			util.SecretResetStringDataFromData(r.SecretServer)
+			serverJWT := r.SecretServer.StringData["jwt"]
+			if serverJWT == "" {
+				return fmt.Errorf("server JWT secret is missing/empty")
+			}
+			token, err := util.MakeAuthToken(map[string]any{
+				"system": r.NooBaa.Name,
+				"role":   "operator",
+				"email":  options.OperatorAccountEmail,
+				/* requires util.MakeAuthToken to allow std claims:
+				"iat": time.Now().Unix(),
+				"exp": time.Now().Add(24*time.Hour).Unix(),
+				*/
+			}, []byte(serverJWT))

Confirm core PR 9211 accepts the "role", "system", and "email" claims exactly as used here for operator auth.


266-276: Endpoints admin token: add signing-key guard + TTL

  • Same signing-key hydration/empty check.
  • Add exp/iat for admin token as well.
@@
-	token, err := util.MakeAuthToken(map[string]any{
-		"system": r.Request.Name,
-		"role":   "admin",
-		"email":  options.AdminAccountEmail,
-	}, []byte(r.SecretServer.StringData["jwt"]))
+	util.SecretResetStringDataFromData(r.SecretServer)
+	serverJWT := r.SecretServer.StringData["jwt"]
+	if serverJWT == "" {
+		return fmt.Errorf("server JWT secret is missing/empty")
+	}
+	token, err := util.MakeAuthToken(map[string]any{
+		"system": r.NooBaa.Name,
+		"role":   "admin",
+		"email":  options.AdminAccountEmail,
+		/* requires util.MakeAuthToken to allow std claims:
+		"iat": time.Now().Unix(),
+		"exp": time.Now().Add(24*time.Hour).Unix(),
+		*/
+	}, []byte(serverJWT))
🧹 Nitpick comments (2)
pkg/noobaaaccount/reconciler.go (2)

48-50: SecretServer field is unused

Either wire this into the reconcile flow or remove to avoid confusion.


372-377: JWT best-practices: set issuer and TTL via MakeAuthToken (follow-up to util change)

Once MakeAuthToken adds standard claims, pass issuer/TTL as needed (or rely on defaults). No change required here if defaults are acceptable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b9cb9f0 and 599a86b.

📒 Files selected for processing (9)
  • go.mod (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (0 hunks)
  • pkg/noobaaaccount/reconciler.go (2 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (2 hunks)
  • test/cli/test_cli_functions.sh (0 hunks)
💤 Files with no reviewable changes (3)
  • test/cli/test_cli_functions.sh
  • pkg/nb/api.go
  • pkg/noobaaaccount/noobaaaccount.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/noobaaaccount/reconciler.go (3)
pkg/util/util.go (3)
  • KubeObject (283-293)
  • KubeCheck (569-590)
  • MakeAuthToken (2394-2406)
pkg/bundle/deploy.go (1)
  • File_deploy_internal_secret_empty_yaml (4902-4909)
pkg/options/options.go (3)
  • Namespace (57-57)
  • SystemName (50-50)
  • OperatorAccountEmail (47-47)
pkg/system/phase4_configuring.go (2)
pkg/util/util.go (1)
  • MakeAuthToken (2394-2406)
pkg/options/options.go (2)
  • OperatorAccountEmail (47-47)
  • AdminAccountEmail (44-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-admission-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-hac-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: golangci-lint
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-cli-tests
  • GitHub Check: run-operator-tests
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-azure-vault-test
🔇 Additional comments (3)
pkg/options/options.go (1)

33-33: Verify image compatibility and update docs
The noobaa-core:master-20250908 tag is present (HTTP 200), but the image’s version label couldn’t be parsed automatically. Manually confirm the image’s version falls within the supported semver range (>= 5.0.0 and < 6.0.0), and if this tag is meant to track a dated master build, update any release documentation to reflect that.

pkg/util/util.go (1)

31-31: LGTM: direct jwt/v4 import is correct

Matches the new direct dependency in go.mod.

go.mod (1)

141-141: Code only imports jwt/v4; go.mod is tidy
Verified no jwt/v5 import paths in code (only at pkg/util/util.go:31).

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from 599a86b to b8bcc85 Compare September 9, 2025 08:33
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/system/phase4_configuring.go (1)

259-276: Replace the early‐return in SetDesiredSecretEndpoints to guard on the token field and load the server JWT

In pkg/system/phase4_configuring.go within SetDesiredSecretEndpoints(), the check

if r.SecretEndpoints.UID != "" {
    return nil
}

skips minting auth_token for existing Secrets that lack it. Change to:

  • Load string data for SecretEndpoints before checking
  • Return early only if StringData["auth_token"] is non‐empty
  • Load string data for SecretServer and error if its “jwt” key is missing/empty

This ensures clusters upgraded from before this PR correctly receive a new auth token.

♻️ Duplicate comments (4)
pkg/nb/types.go (1)

568-577: API break: UpdateAccountParams.Name tag must remain name (not username)
This will break consumers of account_api.update_account() expecting name.

-type UpdateAccountParams struct {
-    Name       *string `json:"username,omitempty"`
+type UpdateAccountParams struct {
+    Name       *string `json:"name,omitempty"`
     Email      string  `json:"email"`
     NewEmail   *string `json:"new_email,omitempty"`
     AllowedIPs *[]struct {
         Start string `json:"start"`
         End   string `json:"end"`
     } `json:"ips,omitempty"`
     RoleConfig       interface{} `json:"role_config,omitempty"`
     RemoveRoleConfig bool        `json:"remove_role_config,omitempty"`
 }

Also update the struct comment above to reference account_api.update_account() instead of update_account_s3_access().

pkg/noobaaaccount/reconciler.go (2)

365-371: Guard missing/empty JWT key and prefer Secret.Data over StringData
Currently, if the secret lacks "jwt", token gets signed with an empty key. Use Data and validate presence.

-    if !util.KubeCheck(secretServer) {
-        return fmt.Errorf("cannot create an auth token for remote operator - server secret not found")
-    }
+    if !util.KubeCheck(secretServer) {
+        return fmt.Errorf("cannot create an auth token for remote operator - server secret not found")
+    }
+    jwtBytes := secretServer.Data["jwt"]
+    if len(jwtBytes) == 0 {
+        return fmt.Errorf("cannot create an auth token for remote operator - missing \"jwt\" key in server secret %q", secretServer.Name)
+    }

380-384: Prevent panics: check AccessKeys length and init StringData before writes
Indexing [0] can panic; StringData may be nil.

-    accessKeys := accountInfo.AccessKeys[0]
-    r.Secret.StringData["auth_token"] = token
-    r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
-    r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
+    var accessKeys nb.S3AccessKeys
+    if len(accountInfo.AccessKeys) == 0 {
+        log.Info("CreateAccountAPI did not return access keys. calling ReadAccountAPI to get keys..")
+        readAccountReply, err := r.NBClient.ReadAccountAPI(nb.ReadAccountParams{Email: r.NooBaaAccount.Name})
+        if err != nil {
+            return err
+        }
+        accessKeys = readAccountReply.AccessKeys[0]
+    } else {
+        accessKeys = accountInfo.AccessKeys[0]
+    }
+    if r.Secret.StringData == nil {
+        r.Secret.StringData = map[string]string{}
+    }
+    r.Secret.StringData["auth_token"] = token
+    r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
+    r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
pkg/system/phase4_configuring.go (1)

156-166: Hydrate server JWT secret and add exp/iat (TTL) to metrics token.

Load r.SecretServer.StringData from Data, ensure the signing key is non-empty, and set standard JWT timing claims to avoid never-expiring tokens.

Apply:

-	token, err := util.MakeAuthToken(map[string]any{
-		"system": r.NooBaa.Name,
-		"role":   "metrics",
-		"email":  options.OperatorAccountEmail,
-	}, []byte(r.SecretServer.StringData["jwt"]))
+	// Ensure signing key is loaded and non-empty
+	util.SecretResetStringDataFromData(r.SecretServer)
+	serverJWT := r.SecretServer.StringData["jwt"]
+	if serverJWT == "" {
+		return fmt.Errorf("server JWT secret is missing/empty")
+	}
+	token, err := util.MakeAuthToken(map[string]any{
+		"system": r.NooBaa.Name,
+		"role":   "metrics",
+		"email":  options.OperatorAccountEmail,
+		// token hardening
+		"iat": time.Now().Unix(),
+		"exp": time.Now().Add(1 * time.Hour).Unix(),
+	}, []byte(serverJWT))

Supporting change outside this file (to let util keep these std claims):

--- a/pkg/util/util.go
+++ b/pkg/util/util.go
@@
-	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system"}
+	// include standard timing claims
+	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system", "iat", "exp", "nbf"}

Note: plan rotation for metrics_token on JWT key change/expiry (re-mint token and update SecretMetricsAuth to trigger reloads).

🧹 Nitpick comments (3)
pkg/backingstore/backingstore.go (1)

947-949: Nit: simplify interval expression

Use a duration literal to avoid multiplying by time.Second at the call site.

-   interval := time.Duration(30)
-   err := wait.PollUntilContextCancel(ctx, interval*time.Second, true, func(ctx context.Context) (bool, error) {
+   interval := 30 * time.Second
+   err := wait.PollUntilContextCancel(ctx, interval, true, func(ctx context.Context) (bool, error) {
pkg/noobaaaccount/reconciler.go (1)

48-50: SecretServer field is unused

Either wire it into the token generation path or drop it to avoid confusion.

pkg/system/phase4_configuring.go (1)

415-426: Minor typos in comments/logs.

Low-impact polish for operator logs and comments.

@@
-						// Ignore mailformed addresses
+						// Ignore malformed addresses
@@
-						// Ignore mailformed addresses
+						// Ignore malformed addresses
@@
-	if _, err := url.Parse(endpoint); err != nil {
-		r.Logger.Errorf("Invalid formate URL %q", endpoint)
-		return fmt.Errorf("Invalid formate URL %q", endpoint)
+	if _, err := url.Parse(endpoint); err != nil {
+		r.Logger.Errorf("Invalid URL format %q", endpoint)
+		return fmt.Errorf("invalid URL format %q", endpoint)
@@
-	// make sure the name is ended with a valid charecter
+	// make sure the name ends with a valid character

Also applies to: 1329-1332, 1499-1501

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 599a86b and b8bcc85.

📒 Files selected for processing (10)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (0 hunks)
  • pkg/noobaaaccount/reconciler.go (2 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (2 hunks)
  • test/cli/test_cli_functions.sh (0 hunks)
💤 Files with no reviewable changes (3)
  • pkg/nb/api.go
  • pkg/noobaaaccount/noobaaaccount.go
  • test/cli/test_cli_functions.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/util/util.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/system/phase4_configuring.go (2)
pkg/util/util.go (1)
  • MakeAuthToken (2394-2410)
pkg/options/options.go (2)
  • OperatorAccountEmail (47-47)
  • AdminAccountEmail (44-44)
pkg/noobaaaccount/reconciler.go (3)
pkg/util/util.go (3)
  • KubeObject (283-293)
  • KubeCheck (569-590)
  • MakeAuthToken (2394-2410)
pkg/bundle/deploy.go (1)
  • File_deploy_internal_secret_empty_yaml (4902-4909)
pkg/options/options.go (3)
  • Namespace (57-57)
  • SystemName (50-50)
  • OperatorAccountEmail (47-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: golangci-lint
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-hac-test
  • GitHub Check: run-admission-test
  • GitHub Check: run-cli-tests
  • GitHub Check: run-operator-tests
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-core-config-map-tests
🔇 Additional comments (4)
go.mod (1)

141-141: Only jwt/v4 is imported; no v5 usage found

pkg/options/options.go (1)

33-33: LGTM: default image tag bump

Looks good; keep release notes/docs in sync with the new default tag.

pkg/nb/types.go (1)

289-290: Formatting-only change

No behavioral impact. OK.

pkg/system/phase4_configuring.go (1)

218-227: Hydrate and validate server JWT before token creation (pkg/system/phase4_configuring.go:218-227)

Call util.SecretResetStringDataFromData to populate StringData["jwt"], return an error if it’s empty, then invoke util.MakeAuthToken; e.g.:

-	token, err := util.MakeAuthToken(map[string]any{
-		"system": r.Request.Name,
-		"role":   "operator",
-		"email":  options.OperatorAccountEmail,
-	}, []byte(r.SecretServer.StringData["jwt"]))
+	// Ensure signing key is loaded and non-empty
+	util.SecretResetStringDataFromData(r.SecretServer)
+	serverJWT := r.SecretServer.StringData["jwt"]
+	if serverJWT == "" {
+		return fmt.Errorf("server JWT secret is missing/empty")
+	}
+	token, err := util.MakeAuthToken(map[string]any{
+		"system": r.Request.Name,
+		"role":   "operator",
+		"email":  options.OperatorAccountEmail,
+	}, []byte(serverJWT))

Consider adding TTL with automatic refresh to prevent operator token expiry at runtime.

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from b8bcc85 to 605c725 Compare September 9, 2025 14:32
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
pkg/noobaaaccount/reconciler.go (2)

364-369: Guard: verify server secret contains “jwt” and use Secret.Data bytes.

Avoid signing with a missing/empty key and prefer Data over StringData.

Apply:

 			secretServer := util.KubeObject(bundle.File_deploy_internal_secret_empty_yaml).(*corev1.Secret)
 			secretServer.Namespace = r.Request.Namespace
 			secretServer.Name = options.SystemName
 			if !util.KubeCheck(secretServer) {
 				return fmt.Errorf("cannot create an auth token for remote operator - server secret not found")
 			}
-
+			jwtBytes, ok := secretServer.Data["jwt"]
+			if !ok || len(jwtBytes) == 0 {
+				return fmt.Errorf("cannot create an auth token for remote operator - missing %q key in server secret %q", "jwt", secretServer.Name)
+			}

379-383: Fix potential panic and ensure StringData is initialized.

AccessKeys[0] can be empty on older cores; also StringData may be nil.

Apply:

-			accessKeys := accountInfo.AccessKeys[0]
-			r.Secret.StringData["auth_token"] = token
-			r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
-			r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
+			var accessKeys nb.S3AccessKeys
+			if len(accountInfo.AccessKeys) == 0 {
+				log.Info("CreateAccountAPI did not return access keys. calling ReadAccountAPI to get keys..")
+				readAccountReply, err := r.NBClient.ReadAccountAPI(nb.ReadAccountParams{Email: r.NooBaaAccount.Name})
+				if err != nil {
+					return err
+				}
+				if len(readAccountReply.AccessKeys) == 0 {
+					return fmt.Errorf("no access keys found for account %q", r.NooBaaAccount.Name)
+				}
+				accessKeys = readAccountReply.AccessKeys[0]
+			} else {
+				accessKeys = accountInfo.AccessKeys[0]
+			}
+			if r.Secret.StringData == nil {
+				r.Secret.StringData = map[string]string{}
+			}
+			r.Secret.StringData["auth_token"] = token
+			r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
+			r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
🧹 Nitpick comments (1)
test/cli/test_cli_flow.sh (1)

34-34: Don’t silently drop a destructive test; gate it behind a flag.

Keep coverage while avoiding accidental data wipes in CI.

Apply:

-    # check_default_backingstore #It deletes all the buckets and non-default accounts, creates new backingstore and attach it to default admin account and then deletes default backingstore
+    # It deletes all the buckets and non-default accounts, creates new backingstore and attach it to default admin account and then deletes default backingstore
+    if [[ "${RUN_DESTRUCTIVE_TESTS:-false}" == "true" ]]; then
+        check_default_backingstore
+    fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b8bcc85 and 605c725.

📒 Files selected for processing (11)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (0 hunks)
  • pkg/noobaaaccount/reconciler.go (1 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (2 hunks)
  • test/cli/test_cli_flow.sh (1 hunks)
  • test/cli/test_cli_functions.sh (0 hunks)
💤 Files with no reviewable changes (3)
  • test/cli/test_cli_functions.sh
  • pkg/noobaaaccount/noobaaaccount.go
  • pkg/nb/api.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • pkg/backingstore/backingstore.go
  • pkg/util/util.go
  • go.mod
  • pkg/options/options.go
  • pkg/system/phase4_configuring.go
  • pkg/nb/types.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/noobaaaccount/reconciler.go (3)
pkg/util/util.go (3)
  • KubeObject (283-293)
  • KubeCheck (569-590)
  • MakeAuthToken (2394-2410)
pkg/bundle/deploy.go (1)
  • File_deploy_internal_secret_empty_yaml (4902-4909)
pkg/options/options.go (2)
  • SystemName (50-50)
  • OperatorAccountEmail (47-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-hac-test
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-operator-tests
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-cli-tests
  • GitHub Check: run-admission-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-kms-dev-test
  • GitHub Check: golangci-lint
  • GitHub Check: run-core-config-map-tests

Comment on lines +371 to +375
token, err := util.MakeAuthToken(map[string]any{
"system": r.NooBaa.Name,
"role": "operator",
"email": options.OperatorAccountEmail,
}, []byte(secretServer.StringData["jwt"]))
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use validated jwtBytes and add a short-lived token expiry.

Sign with the validated bytes and include exp to avoid indefinite tokens.

Apply:

-			token, err := util.MakeAuthToken(map[string]any{
-				"system": r.NooBaa.Name,
-				"role":   "operator",
-				"email":  options.OperatorAccountEmail,
-			}, []byte(secretServer.StringData["jwt"]))
+			token, err := util.MakeAuthToken(map[string]any{
+				"system": r.NooBaa.Name,
+				"role":   "operator",
+				"email":  options.OperatorAccountEmail,
+				"exp":    time.Now().Add(24 * time.Hour).Unix(),
+			}, jwtBytes)

Additionally, allow exp in util.MakeAuthToken:

-	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system"}
+	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system", "exp", "iat"}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
token, err := util.MakeAuthToken(map[string]any{
"system": r.NooBaa.Name,
"role": "operator",
"email": options.OperatorAccountEmail,
}, []byte(secretServer.StringData["jwt"]))
// In pkg/noobaaaccount/reconciler.go (around lines 371–375)
token, err := util.MakeAuthToken(map[string]any{
"system": r.NooBaa.Name,
"role": "operator",
"email": options.OperatorAccountEmail,
"exp": time.Now().Add(24 * time.Hour).Unix(),
}, jwtBytes)
Suggested change
token, err := util.MakeAuthToken(map[string]any{
"system": r.NooBaa.Name,
"role": "operator",
"email": options.OperatorAccountEmail,
}, []byte(secretServer.StringData["jwt"]))
// In util.MakeAuthToken (allowedFields definition)
allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system", "exp", "iat"}
🤖 Prompt for AI Agents
In pkg/noobaaaccount/reconciler.go around lines 371 to 375, the MakeAuthToken
call is signing with the raw secretServer.StringData["jwt"] and produces a token
without expiry; replace the raw access with the validated jwtBytes variable (the
parsed/validated []byte) when calling util.MakeAuthToken and add an "exp" claim
set to a short TTL (e.g. now + few minutes) to the claims map so tokens are
short-lived; also update util.MakeAuthToken to accept and embed the exp claim
(or accept a claims map) and sign using the provided jwtBytes rather than the
secret string.

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from 605c725 to a88fa70 Compare September 9, 2025 16:02
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
test/cli/test_cli_functions.sh (2)

262-271: Bug: waiting on the wrong resource (polls NooBaa CR instead of BackingStore)

Inside wait_for_backingstore_ready the loop polls the NooBaa CR phase, not the BackingStore’s phase, and the initial status is redundantly assigned. This can mask failures or loop indefinitely.

Apply:

 function wait_for_backingstore_ready {
-    local status=$(kuberun silence get backingstore noobaa-default-backing-store -o 'jsonpath={.status.phase}')
-    local status=$(kuberun silence get backingstore ${1} -o 'jsonpath={.status.phase}')
+    local status
+    status=$(kuberun silence get backingstore ${1} -o 'jsonpath={.status.phase}')
     while [ "${status}" != "Ready" ]
     do
         echo_time "💬  Waiting for status Ready, Status is ${status}"
         sleep 10
-        status=$(kuberun silence get noobaa noobaa -o 'jsonpath={.status.phase}')
+        status=$(kuberun silence get backingstore ${1} -o 'jsonpath={.status.phase}')
     done
 }

1189-1191: Shell error: stray string executes as a command

This line runs a quoted string as a command and will fail with “command not found”.

Apply:

-    "💬 Deleting non-default accounts"
+    echo_time "💬 Deleting non-default accounts"
♻️ Duplicate comments (7)
pkg/util/util.go (1)

2393-2410: JWTs lack exp/iat and accept weak/empty keys

Tokens never expire and HS256 signs even with very short secrets. Enforce a minimum key length and add standard time claims by default. Also allow callers to override/augment with exp/iat if needed.

Apply:

-func MakeAuthToken(payload map[string]any, secret []byte) (string, error) {
-	if len(secret) == 0 {
-		return "", fmt.Errorf("jwt signing secret missing")
-	}
-
-	filtered := jwt.MapClaims{}
-
-	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system"}
-	for _, field := range allowedFields {
-		val, ok := payload[field]
-		if ok {
-			filtered[field] = val
-		}
-	}
-
-	return jwt.NewWithClaims(jwt.SigningMethodHS256, filtered).SignedString(secret)
-}
+func MakeAuthToken(payload map[string]any, secret []byte) (string, error) {
+	if len(secret) < 32 {
+		return "", fmt.Errorf("jwt signing secret missing or too short")
+	}
+	filtered := jwt.MapClaims{}
+	// allow selected custom and standard claims
+	allowedFields := []string{
+		"account_id", "system_id", "role", "extra", "authorized_by", "email", "system",
+		"iss", "sub", "iat", "exp", "nbf",
+	}
+	for _, field := range allowedFields {
+		if val, ok := payload[field]; ok {
+			filtered[field] = val
+		}
+	}
+	// set defaults if not provided
+	now := time.Now().UTC()
+	if _, ok := filtered["iat"]; !ok {
+		filtered["iat"] = now.Unix()
+	}
+	if _, ok := filtered["exp"]; !ok {
+		filtered["exp"] = now.Add(15 * time.Minute).Unix()
+	}
+	if _, ok := filtered["iss"]; !ok {
+		filtered["iss"] = "noobaa-operator"
+	}
+	if _, ok := filtered["sub"]; !ok {
+		if v, ok := filtered["account_id"]; ok {
+			filtered["sub"] = v
+		} else if v, ok := filtered["email"]; ok {
+			filtered["sub"] = v
+		}
+	}
+	token := jwt.NewWithClaims(jwt.SigningMethodHS256, filtered)
+	return token.SignedString(secret)
+}
pkg/noobaaaccount/reconciler.go (2)

364-375: Guard jwt key and add token TTL; sign with validated bytes

Ensure the server secret contains a non-empty "jwt" key before signing. Also make tokens short-lived.

Apply:

-            if !util.KubeCheck(secretServer) {
+            if !util.KubeCheck(secretServer) {
                 return fmt.Errorf("cannot create an auth token for remote operator - server secret not found")
             }
-
-            token, err := util.MakeAuthToken(map[string]any{
-                "system": r.NooBaa.Name,
-                "role":   "operator",
-                "email":  options.OperatorAccountEmail,
-            }, []byte(secretServer.StringData["jwt"]))
+            // hydrate and validate JWT key
+            util.SecretResetStringDataFromData(secretServer)
+            jwtKey := strings.TrimSpace(secretServer.StringData["jwt"])
+            if jwtKey == "" {
+                return fmt.Errorf("cannot create an auth token for remote operator - missing \"jwt\" key in server secret %q", secretServer.Name)
+            }
+            token, err := util.MakeAuthToken(map[string]any{
+                "system": r.NooBaa.Name,
+                "role":   "operator",
+                "email":  options.OperatorAccountEmail,
+                "iat":    time.Now().UTC().Unix(),
+                "exp":    time.Now().UTC().Add(24 * time.Hour).Unix(),
+            }, []byte(jwtKey))

379-383: Possible panic: AccessKeys[0] without length check

When AccessKeys is empty, indexing [0] panics. Mirror the fallback used in the non-remote path.

Apply:

-            accessKeys := accountInfo.AccessKeys[0]
-            r.Secret.StringData["auth_token"] = token
-            r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
-            r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
+            var accessKeys nb.S3AccessKeys
+            if len(accountInfo.AccessKeys) == 0 {
+                log.Info("CreateAccountAPI did not return access keys. calling ReadAccountAPI to get keys..")
+                readAccountReply, err := r.NBClient.ReadAccountAPI(nb.ReadAccountParams{Email: r.NooBaaAccount.Name})
+                if err != nil || len(readAccountReply.AccessKeys) == 0 {
+                    return fmt.Errorf("failed to obtain access keys for account %q", r.NooBaaAccount.Name)
+                }
+                accessKeys = readAccountReply.AccessKeys[0]
+            } else {
+                accessKeys = accountInfo.AccessKeys[0]
+            }
+            r.Secret.StringData["auth_token"] = token
+            r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
+            r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
pkg/system/phase4_configuring.go (3)

157-166: Metrics token: guard empty signing key and add exp/iat

Avoid minting with an empty key; add short TTL for metrics.

Apply:

-    token, err := util.MakeAuthToken(map[string]any{
-        "system": r.NooBaa.Name,
-        "role":   "metrics",
-        "email":  options.OperatorAccountEmail,
-    }, []byte(r.SecretServer.StringData["jwt"]))
+    util.SecretResetStringDataFromData(r.SecretServer)
+    serverJWT := strings.TrimSpace(r.SecretServer.StringData["jwt"])
+    if serverJWT == "" {
+        return fmt.Errorf("server JWT secret is missing/empty")
+    }
+    token, err := util.MakeAuthToken(map[string]any{
+        "system": r.NooBaa.Name,
+        "role":   "metrics",
+        "email":  options.OperatorAccountEmail,
+        "iat":    time.Now().UTC().Unix(),
+        "exp":    time.Now().UTC().Add(1 * time.Hour).Unix(),
+    }, []byte(serverJWT))

218-227: Operator token: guard signing key and add exp/iat

Same concern as metrics; make operator tokens time-bound.

Apply:

-            token, err := util.MakeAuthToken(map[string]any{
-                "system": r.Request.Name,
-                "role":   "operator",
-                "email":  options.OperatorAccountEmail,
-            }, []byte(r.SecretServer.StringData["jwt"]))
+            util.SecretResetStringDataFromData(r.SecretServer)
+            serverJWT := strings.TrimSpace(r.SecretServer.StringData["jwt"])
+            if serverJWT == "" {
+                return fmt.Errorf("server JWT secret is missing/empty")
+            }
+            token, err := util.MakeAuthToken(map[string]any{
+                "system": r.Request.Name,
+                "role":   "operator",
+                "email":  options.OperatorAccountEmail,
+                "iat":    time.Now().UTC().Unix(),
+                "exp":    time.Now().UTC().Add(24 * time.Hour).Unix(),
+            }, []byte(serverJWT))

266-276: Admin/endpoints token: guard signing key and add exp/iat

Prevent empty-key signing; include expiry.

Apply:

-    token, err := util.MakeAuthToken(map[string]any{
-        "system": r.Request.Name,
-        "role":   "admin",
-        "email":  options.AdminAccountEmail,
-    }, []byte(r.SecretServer.StringData["jwt"]))
+    util.SecretResetStringDataFromData(r.SecretServer)
+    serverJWT := strings.TrimSpace(r.SecretServer.StringData["jwt"])
+    if serverJWT == "" {
+        return fmt.Errorf("server JWT secret is missing/empty")
+    }
+    token, err := util.MakeAuthToken(map[string]any{
+        "system": r.Request.Name,
+        "role":   "admin",
+        "email":  options.AdminAccountEmail,
+        "iat":    time.Now().UTC().Unix(),
+        "exp":    time.Now().UTC().Add(24 * time.Hour).Unix(),
+    }, []byte(serverJWT))
pkg/nb/types.go (1)

568-577: JSON tag change breaks API: use name, not username

account_api.update_account expects "name"; switching to "username" will break clients.

Apply:

-    Name       *string `json:"username,omitempty"`
+    Name       *string `json:"name,omitempty"`

Also consider updating the struct comment to reference account_api.update_account().

🧹 Nitpick comments (1)
pkg/util/util.go (1)

1851-1862: Optional: use duration/context for polling

Hard-coding 5*60 seconds is fine; consider a time.Duration or context.WithTimeout to make this reusable/configurable.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 605c725 and a88fa70.

📒 Files selected for processing (10)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (0 hunks)
  • pkg/noobaaaccount/reconciler.go (1 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (3 hunks)
  • test/cli/test_cli_functions.sh (1 hunks)
💤 Files with no reviewable changes (2)
  • pkg/nb/api.go
  • pkg/noobaaaccount/noobaaaccount.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • go.mod
  • pkg/backingstore/backingstore.go
  • pkg/options/options.go
🧰 Additional context used
🧬 Code graph analysis (2)
pkg/noobaaaccount/reconciler.go (3)
pkg/util/util.go (3)
  • KubeObject (283-293)
  • KubeCheck (569-590)
  • MakeAuthToken (2394-2410)
pkg/bundle/deploy.go (1)
  • File_deploy_internal_secret_empty_yaml (4902-4909)
pkg/options/options.go (3)
  • Namespace (57-57)
  • SystemName (50-50)
  • OperatorAccountEmail (47-47)
pkg/system/phase4_configuring.go (2)
pkg/util/util.go (1)
  • MakeAuthToken (2394-2410)
pkg/options/options.go (2)
  • OperatorAccountEmail (47-47)
  • AdminAccountEmail (44-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-admission-test
  • GitHub Check: run-cli-tests
🔇 Additional comments (2)
test/cli/test_cli_functions.sh (1)

816-816: LGTM: normalize default_resource for legacy value

The fallback to noobaa-default-backing-store when default_resource is "backingstores" keeps tests compatible with older cores. No further changes needed.

pkg/nb/types.go (1)

289-290: LGTM

Formatting-only change; no API impact.

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from a88fa70 to 2170f04 Compare September 9, 2025 16:31
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
pkg/util/util.go (1)

2394-2410: JWTs lack exp/iat and accept trivially short secrets — add standard claims and enforce key length

Tokens are long-lived if leaked and can be signed with an empty/weak key. Add exp/iat (and optional iss/sub defaults) and require a minimum HS256 key length.

Apply:

 func MakeAuthToken(payload map[string]any, secret []byte) (string, error) {
-	if len(secret) == 0 {
-		return "", fmt.Errorf("jwt signing secret missing")
-	}
+	if len(secret) < 32 {
+		return "", fmt.Errorf("jwt signing secret missing or too short")
+	}

 	filtered := jwt.MapClaims{}

 	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system"}
 	for _, field := range allowedFields {
 		val, ok := payload[field]
 		if ok {
 			filtered[field] = val
 		}
 	}

-	return jwt.NewWithClaims(jwt.SigningMethodHS256, filtered).SignedString(secret)
+	now := time.Now().UTC()
+	filtered["iat"] = now.Unix()
+	filtered["exp"] = now.Add(15 * time.Minute).Unix()
+	if _, ok := filtered["iss"]; !ok {
+		filtered["iss"] = "noobaa-operator"
+	}
+	if _, ok := filtered["sub"]; !ok {
+		if v, ok := filtered["account_id"]; ok {
+			filtered["sub"] = v
+		} else if v, ok := filtered["email"]; ok {
+			filtered["sub"] = v
+		}
+	}
+	return jwt.NewWithClaims(jwt.SigningMethodHS256, filtered).SignedString(secret)
 }

Follow-up:

  • If noobaa-core expects specific iss/aud, set them accordingly; otherwise consider adding aud and verifying at the receiver.
  • If different TTLs are needed (operator vs metrics), we can add a TTL parameter variant while keeping this default.

I can thread TTL/issuer across call sites if you want.

🧹 Nitpick comments (1)
pkg/noobaaaccount/noobaaaccount.go (1)

265-275: Differentiate NotFound from other RPC failures

Replace the simple err == nil checks with explicit handling of “not found” RPC codes and fail fast on other errors:

-_, err = sysClient.NBClient.ReadPoolAPI(nb.ReadPoolParams{Name: newDefaultResource})
-isResourceBackingStore := err == nil
+isResourceBackingStore := false
+if _, err := sysClient.NBClient.ReadPoolAPI(nb.ReadPoolParams{Name: newDefaultResource}); err == nil {
+    isResourceBackingStore = true
+} else if rpcErr, ok := err.(*nb.RPCError); ok && rpcErr.RPCCode == "NO_SUCH_POOL" {
+    // backing store does not exist
+} else {
+    log.Fatalf("❌ ReadPoolAPI failed: %v", err)
+}

-_, err = sysClient.NBClient.ReadNamespaceResourceAPI(nb.ReadNamespaceResourceParams{Name: newDefaultResource})
-isResourceNamespaceStore := err == nil
+isResourceNamespaceStore := false
+if _, err := sysClient.NBClient.ReadNamespaceResourceAPI(nb.ReadNamespaceResourceParams{Name: newDefaultResource}); err == nil {
+    isResourceNamespaceStore = true
+} else if rpcErr, ok := err.(*nb.RPCError); ok && rpcErr.RPCCode == "NO_SUCH_NAMESPACE_RESOURCE" {
+    // namespace store does not exist
+} else {
+    log.Fatalf("❌ ReadNamespaceResourceAPI failed: %v", err)
+}

RPC codes “NO_SUCH_POOL” and “NO_SUCH_NAMESPACE_RESOURCE” are confirmed in the codebase. Also consider reusing the existing sysClient in RunUpdate rather than reconnecting.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a88fa70 and 2170f04.

📒 Files selected for processing (10)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (1 hunks)
  • pkg/noobaaaccount/reconciler.go (1 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (3 hunks)
  • test/cli/test_cli_functions.sh (1 hunks)
💤 Files with no reviewable changes (1)
  • pkg/nb/api.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • go.mod
  • pkg/noobaaaccount/reconciler.go
  • pkg/backingstore/backingstore.go
  • test/cli/test_cli_functions.sh
  • pkg/nb/types.go
  • pkg/system/phase4_configuring.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/noobaaaccount/noobaaaccount.go (2)
pkg/system/system.go (1)
  • Connect (1118-1203)
pkg/nb/types.go (2)
  • ReadPoolParams (257-259)
  • ReadNamespaceResourceParams (272-274)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-cli-tests
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-admission-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-operator-tests
  • GitHub Check: golangci-lint
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-hac-test
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-azure-vault-test
🔇 Additional comments (3)
pkg/options/options.go (1)

33-33: Confirm image tag availability and compatibility

Please verify the new tag "master-20250908" exists in your registry, satisfies the supported semver bounds (>= 5.0.0, < 6.0.0), and aligns with dependent noobaa-core PR #9211.

pkg/util/util.go (2)

31-31: Direct import of jwt/v4 is appropriate

Using github.com/golang-jwt/jwt/v4 is the right choice here.


1851-1864: Confirm reduced wait timeout is intentional

Changing timeout to 5 minutes may be tight on slow or busy clusters. Ensure this aligns with other polling intervals introduced in this PR (e.g., backingstore readiness).

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from 2170f04 to 2ecf175 Compare September 11, 2025 13:44
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
test/cli/test_cli_functions.sh (1)

818-833: Add error handling for failed default resource updates.

The function updates the default resource and verifies the change, but if the verification fails, it exits without attempting to restore the original state. Consider adding cleanup logic to restore the original default resource even on failure.

 test_noobaa account update ${account_name} --new_default_resource=${new_default_resource}
 local curr_default_resource=$(test_noobaa api account list_accounts {} -o json | jq -r '.accounts[0].default_resource')
 if [ "${new_default_resource}" != "${curr_default_resource}" ]
 then
     echo_time "❌ Looks like account not updated, Exiting"
+    # Attempt to restore original default resource before exiting
+    test_noobaa account update ${account_name} --new_default_resource=${default_resource} 2>/dev/null || true
     exit 1
 else
     echo_time "✅  Update account default_resource successful"
     test_noobaa account update ${account_name} --new_default_resource=${default_resource}
     curr_default_resource=$(test_noobaa api account list_accounts {} -o json | jq -r '.accounts[0].default_resource')
     if [ "${default_resource}" != "${curr_default_resource}" ]
     then
         echo_time "❌ Looks like account not updated to default state, Exiting"
         exit 1
     fi
 fi
♻️ Duplicate comments (3)
pkg/system/phase4_configuring.go (3)

157-161: Critical: Validate JWT secret before token generation.

The code directly uses r.SecretServer.StringData["jwt"] without checking if it exists or is empty. If the JWT secret is missing or empty, util.MakeAuthToken will fail or create invalid tokens.

+// Ensure the JWT secret is available and non-empty
+util.SecretResetStringDataFromData(r.SecretServer)
+jwtSecret := r.SecretServer.StringData["jwt"]
+if jwtSecret == "" {
+    return fmt.Errorf("server JWT secret is missing or empty")
+}
 token, err := util.MakeAuthToken(map[string]any{
     "system": r.NooBaa.Name,
     "role":   "metrics",
     "email":  options.OperatorAccountEmail,
-}, []byte(r.SecretServer.StringData["jwt"]))
+}, []byte(jwtSecret))

218-222: Critical: Validate JWT secret before operator token generation.

Similar to the metrics token generation, the JWT secret should be validated before use.

+// Ensure the JWT secret is available and non-empty
+util.SecretResetStringDataFromData(r.SecretServer)
+jwtSecret := r.SecretServer.StringData["jwt"]
+if jwtSecret == "" {
+    return fmt.Errorf("server JWT secret is missing or empty")
+}
 token, err := util.MakeAuthToken(map[string]any{
     "system": r.Request.Name,
     "role":   "operator",
     "email":  options.OperatorAccountEmail,
-}, []byte(r.SecretServer.StringData["jwt"]))
+}, []byte(jwtSecret))

266-270: Critical: Validate JWT secret before admin token generation.

The JWT secret validation is needed here as well for consistency and safety.

+// Ensure the JWT secret is available and non-empty
+util.SecretResetStringDataFromData(r.SecretServer)
+jwtSecret := r.SecretServer.StringData["jwt"]
+if jwtSecret == "" {
+    return fmt.Errorf("server JWT secret is missing or empty")
+}
 token, err := util.MakeAuthToken(map[string]any{
     "system": r.Request.Name,
     "role":   "admin",
     "email":  options.AdminAccountEmail,
-}, []byte(r.SecretServer.StringData["jwt"]))
+}, []byte(jwtSecret))
🧹 Nitpick comments (1)
test/cli/test_cli_functions.sh (1)

816-816: Centralize & document default-resource normalization ('backingstores' → 'noobaa-default-backing-store').

Normalization exists only in test/cli/test_cli_functions.sh (line 816); many tests/code reference the literal "noobaa-default-backing-store". Create a shared helper (or document the conversion) and update callers to use it.

Key locations: test/cli/test_cli_functions.sh:816 (normalization), test/cli/test_cli_functions.sh:703,1152,1166,1198–1206; pkg/cosi/cosi_cli_test.go; pkg/cosi/cosi_test.go; pkg/admission/test/integ/admission_integ_test.go.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2170f04 and 2ecf175.

📒 Files selected for processing (10)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (1 hunks)
  • pkg/noobaaaccount/reconciler.go (1 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (3 hunks)
  • test/cli/test_cli_functions.sh (1 hunks)
💤 Files with no reviewable changes (1)
  • pkg/nb/api.go
🚧 Files skipped from review as they are similar to previous changes (7)
  • pkg/backingstore/backingstore.go
  • pkg/noobaaaccount/noobaaaccount.go
  • pkg/util/util.go
  • pkg/noobaaaccount/reconciler.go
  • go.mod
  • pkg/nb/types.go
  • pkg/options/options.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/system/phase4_configuring.go (2)
pkg/util/util.go (1)
  • MakeAuthToken (2394-2410)
pkg/options/options.go (2)
  • OperatorAccountEmail (47-47)
  • AdminAccountEmail (44-44)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-hac-test
  • GitHub Check: run-admission-test
  • GitHub Check: run-cli-tests
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: run-operator-tests
  • GitHub Check: golangci-lint

@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from 2ecf175 to d7751c5 Compare September 12, 2025 05:43
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
pkg/noobaaaccount/reconciler.go (2)

364-376: Guard missing/empty JWT key and use validated bytes; add token expiry
If "jwt" is absent/blank, you’ll sign with an empty key. Also add exp/iat to avoid indefinite tokens. Use trimmed, validated bytes for signing.

Apply:

-			secretServer := util.KubeObject(bundle.File_deploy_internal_secret_empty_yaml).(*corev1.Secret)
+			secretServer := util.KubeObject(bundle.File_deploy_internal_secret_empty_yaml).(*corev1.Secret)
 			secretServer.Namespace = r.Request.Namespace
 			secretServer.Name = options.SystemName
 			if !util.KubeCheck(secretServer) {
 				return fmt.Errorf("cannot create an auth token for remote operator - server secret not found")
 			}
 
-			token, err := util.MakeAuthToken(map[string]any{
-				"system": r.NooBaa.Name,
-				"role":   "operator",
-				"email":  options.OperatorAccountEmail,
-			}, []byte(secretServer.StringData["jwt"]))
+			jwtKey := strings.TrimSpace(secretServer.StringData["jwt"])
+			if jwtKey == "" {
+				return fmt.Errorf("cannot create an auth token for remote operator - missing \"jwt\" key in server secret %q", secretServer.Name)
+			}
+			jwtBytes := []byte(jwtKey)
+
+			token, err := util.MakeAuthToken(map[string]any{
+				"system": r.NooBaa.Name,
+				"role":   "operator",
+				"email":  options.OperatorAccountEmail,
+				"iat":    time.Now().Unix(),
+				"exp":    time.Now().Add(24 * time.Hour).Unix(),
+			}, jwtBytes)

Additionally update util.MakeAuthToken allowlist to include exp/iat:

-	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system"}
+	allowedFields := []string{"account_id", "system_id", "role", "extra", "authorized_by", "email", "system", "exp", "iat"}

379-383: Nil map write and potential panic on AccessKeys[0]
StringData may be nil; writing to it panics. Also AccessKeys can be empty on older cores.

Apply:

-			accessKeys := accountInfo.AccessKeys[0]
-			r.Secret.StringData["auth_token"] = token
-			r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
-			r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
+			if r.Secret.StringData == nil {
+				r.Secret.StringData = map[string]string{}
+			}
+			var accessKeys nb.S3AccessKeys
+			if len(accountInfo.AccessKeys) == 0 {
+				log.Info("CreateAccountAPI did not return access keys. calling ReadAccountAPI to get keys..")
+				readAccountReply, err := r.NBClient.ReadAccountAPI(nb.ReadAccountParams{Email: r.NooBaaAccount.Name})
+				if err != nil || len(readAccountReply.AccessKeys) == 0 {
+					return fmt.Errorf("failed retrieving access keys for %q: %v", r.NooBaaAccount.Name, err)
+				}
+				accessKeys = readAccountReply.AccessKeys[0]
+			} else {
+				accessKeys = accountInfo.AccessKeys[0]
+			}
+			r.Secret.StringData["auth_token"] = token
+			r.Secret.StringData["AWS_ACCESS_KEY_ID"] = string(accessKeys.AccessKey)
+			r.Secret.StringData["AWS_SECRET_ACCESS_KEY"] = string(accessKeys.SecretKey)
🧹 Nitpick comments (3)
pkg/backingstore/backingstore.go (1)

947-949: 30s poll hurts UX; prefer shorter or configurable interval

30s between status checks makes CLI feel stalled and slows tests. Suggest 10s (or make it flag/env-configurable).

Apply:

-	interval := time.Duration(30)
+	// Poll every ~10s for a snappier UX; keep overall controller-side backoff unchanged.
+	interval := time.Duration(10)
test/cli/test_cli_functions.sh (2)

816-816: Avoid hardcoded alias “backingstores”; normalize via actual default resource
Literal “backingstores” is brittle across core versions/config. Prefer querying the system’s default and mapping once.

Apply:

-        if [ "${default_resource}" == "backingstores" ]; then default_resource="noobaa-default-backing-store"; fi
+        # Normalize default_resource from legacy alias to actual name
+        if [ "${default_resource}" == "backingstores" ] || [ -z "${default_resource}" ]; then
+            default_resource=$(test_noobaa silence api account list_accounts {} -o json | jq -r '.accounts[0].default_resource')
+        fi

1195-1195: Operator account may not exist — gate update or create first
If operator@noobaa.io isn’t present, this line fails the suite. Guard or ensure creation.

Apply:

-    test_noobaa account update operator@noobaa.io --new_default_resource=new-default-backing-store
+    if test_noobaa silence account list | awk '{print $1}' | grep -qx "operator@noobaa.io"; then
+        test_noobaa account update operator@noobaa.io --new_default_resource=new-default-backing-store
+    else
+        echo_time "ℹ️  Skipping operator account update (operator@noobaa.io not found)"
+    fi
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2ecf175 and d7751c5.

📒 Files selected for processing (10)
  • go.mod (1 hunks)
  • pkg/backingstore/backingstore.go (1 hunks)
  • pkg/nb/api.go (0 hunks)
  • pkg/nb/types.go (2 hunks)
  • pkg/noobaaaccount/noobaaaccount.go (1 hunks)
  • pkg/noobaaaccount/reconciler.go (1 hunks)
  • pkg/options/options.go (1 hunks)
  • pkg/system/phase4_configuring.go (3 hunks)
  • pkg/util/util.go (3 hunks)
  • test/cli/test_cli_functions.sh (2 hunks)
💤 Files with no reviewable changes (1)
  • pkg/nb/api.go
🚧 Files skipped from review as they are similar to previous changes (6)
  • pkg/util/util.go
  • pkg/options/options.go
  • pkg/noobaaaccount/noobaaaccount.go
  • pkg/system/phase4_configuring.go
  • go.mod
  • pkg/nb/types.go
🧰 Additional context used
🧬 Code graph analysis (1)
pkg/noobaaaccount/reconciler.go (3)
pkg/util/util.go (3)
  • KubeObject (283-293)
  • KubeCheck (569-590)
  • MakeAuthToken (2394-2410)
pkg/bundle/deploy.go (1)
  • File_deploy_internal_secret_empty_yaml (4902-4909)
pkg/options/options.go (3)
  • Namespace (57-57)
  • SystemName (50-50)
  • OperatorAccountEmail (47-47)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (13)
  • GitHub Check: run-core-config-map-tests
  • GitHub Check: run-kms-tls-sa-test
  • GitHub Check: cnpg-deployment-test
  • GitHub Check: run-hac-test
  • GitHub Check: run-azure-vault-test
  • GitHub Check: run-kms-key-rotate-test
  • GitHub Check: run-kms-tls-token-test
  • GitHub Check: run-kms-kmip-test
  • GitHub Check: run-admission-test
  • GitHub Check: golangci-lint
  • GitHub Check: run-kms-dev-test
  • GitHub Check: run-operator-tests
  • GitHub Check: run-cli-tests

Signed-off-by: Utkarsh Srivastava <srivastavautkarsh8097@gmail.com>
@tangledbytes tangledbytes force-pushed the utkarsh/remove-password branch from d7751c5 to dd5e392 Compare September 12, 2025 06:47
@tangledbytes tangledbytes merged commit a26fdde into noobaa:master Sep 12, 2025
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants