diff --git a/CHANGELOG.md b/CHANGELOG.md index 35e0cec..f89fe36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/). ### Changed +- **Breaking:** Removed `pat.secret.hashedTokenKey` from PAT configuration. The + SHA256 hash is now computed automatically at seed time by Initium v1.0.4 using + MiniJinja's `sha256` and `base64encode` filters. Users only need to supply the + plaintext PAT token in their Kubernetes Secret. + **Migration:** Remove the `hashedToken` key from your PAT Secret and the + `pat.secret.hashedTokenKey` from your values. Only `pat.secret.tokenKey` (default: `"token"`) is needed. - **Breaking:** Replaced raw DSN secret (`server.secrets.storeDsn`) with structured `database.*` configuration. The chart now constructs the DSN internally from `database.type`, `database.host`, `database.port`, `database.user`, `database.name`, diff --git a/charts/netbird/README.md b/charts/netbird/README.md index c24867e..46c71e1 100644 --- a/charts/netbird/README.md +++ b/charts/netbird/README.md @@ -169,14 +169,14 @@ creation — useful for automation, CI/CD, and GitOps workflows. ### Generating a PAT NetBird PATs have the format `nbp_<30-char-secret><6-char-checksum>` (40 -chars total). The database stores a base64-encoded SHA256 hash. - -Generate a token and its hash: +chars total). The SHA256 hash required by the database is computed +automatically by the seed process (Initium v1.0.4+) — you only need to +generate the plaintext token. ```bash # Using Python python3 -c " -import hashlib, base64, secrets, zlib +import secrets, zlib secret = secrets.token_urlsafe(22)[:30] checksum = zlib.crc32(secret.encode()) & 0xffffffff chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' @@ -184,16 +184,12 @@ cs = '' v = checksum while v > 0: cs = chars[v % 62] + cs; v //= 62 token = 'nbp_' + secret + cs.rjust(6, '0') -hashed = base64.b64encode(hashlib.sha256(token.encode()).digest()).decode() -print(f'Token: {token}') -print(f'Hash: {hashed}') +print(f'Token: {token}') " -# Or using openssl +# Or using openssl (simplified checksum) TOKEN="nbp_$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9' | head -c30)000000" -HASH=$(printf '%s' "$TOKEN" | openssl dgst -sha256 -binary | openssl base64 -A) echo "Token: $TOKEN" -echo "Hash: $HASH" ``` ### Creating the Secret @@ -201,7 +197,6 @@ echo "Hash: $HASH" ```bash kubectl create secret generic netbird-pat \ --from-literal=token='nbp_...' \ - --from-literal=hashedToken='base64hash...' \ -n netbird ``` @@ -273,9 +268,8 @@ curl -H "Authorization: Token nbp_..." https://netbird.example.com/api/groups | Key | Type | Default | Description | |-----|------|---------|-------------| | `pat.enabled` | bool | `false` | Enable PAT seeding via post-install Job | -| `pat.secret.secretName` | string | `""` | Kubernetes Secret containing token and hash | +| `pat.secret.secretName` | string | `""` | Kubernetes Secret containing the plaintext PAT | | `pat.secret.tokenKey` | string | `"token"` | Key in Secret for the plaintext PAT | -| `pat.secret.hashedTokenKey` | string | `"hashedToken"` | Key in Secret for the base64-encoded SHA256 hash | | `pat.name` | string | `"helm-seeded-token"` | Display name for the PAT | | `pat.userId` | string | `"helm-seed-user"` | User ID for the service user | | `pat.accountId` | string | `"helm-seed-account"` | Account ID for the service user | diff --git a/charts/netbird/templates/_helpers.tpl b/charts/netbird/templates/_helpers.tpl index 7022e1c..c7d33c2 100644 --- a/charts/netbird/templates/_helpers.tpl +++ b/charts/netbird/templates/_helpers.tpl @@ -258,8 +258,9 @@ inserting a Personal Access Token into the database. The seed waits for the personal_access_tokens table (created by NetBird on startup via GORM AutoMigrate), then idempotently inserts the account, user, and PAT records. -MiniJinja placeholders: - {{ env.PAT_HASHED_TOKEN }} — base64-encoded SHA256 hash of the PAT +MiniJinja placeholders (Initium v1.0.4+): + {{ env.PAT_TOKEN | sha256("bytes") | base64_encode }} — computes the + base64-encoded SHA256 hash from the plaintext PAT at seed time. */}} {{- define "netbird.pat.seedSpec" -}} database: @@ -313,7 +314,7 @@ phases: - id: "helm-seeded-pat" user_id: {{ .Values.pat.userId | quote }} name: {{ .Values.pat.name | quote }} - hashed_token: "{{ "{{ env.PAT_HASHED_TOKEN }}" }}" + hashed_token: "{{ "{{ env.PAT_TOKEN | sha256(\"bytes\") | base64_encode }}" }}" expiration_date: {{ now | dateModify (printf "+%dh" (mul .Values.pat.expirationDays 24)) | date "2006-01-02 15:04:05" | quote }} created_by: {{ .Values.pat.userId | quote }} created_at: {{ now | date "2006-01-02 15:04:05" | quote }} diff --git a/charts/netbird/templates/pat-seed-job.yaml b/charts/netbird/templates/pat-seed-job.yaml index f43d299..abbefa6 100644 --- a/charts/netbird/templates/pat-seed-job.yaml +++ b/charts/netbird/templates/pat-seed-job.yaml @@ -64,11 +64,11 @@ spec: - --spec - /spec/pat-seed.yaml env: - - name: PAT_HASHED_TOKEN + - name: PAT_TOKEN valueFrom: secretKeyRef: name: {{ .Values.pat.secret.secretName }} - key: {{ .Values.pat.secret.hashedTokenKey }} + key: {{ .Values.pat.secret.tokenKey }} - name: DB_PASSWORD valueFrom: secretKeyRef: diff --git a/charts/netbird/templates/server-deployment.yaml b/charts/netbird/templates/server-deployment.yaml index 4f3de3d..96c4385 100644 --- a/charts/netbird/templates/server-deployment.yaml +++ b/charts/netbird/templates/server-deployment.yaml @@ -153,11 +153,11 @@ spec: - --spec - /spec/pat-seed.yaml env: - - name: PAT_HASHED_TOKEN + - name: PAT_TOKEN valueFrom: secretKeyRef: name: {{ .Values.pat.secret.secretName }} - key: {{ .Values.pat.secret.hashedTokenKey }} + key: {{ .Values.pat.secret.tokenKey }} securityContext: runAsUser: 0 readOnlyRootFilesystem: true diff --git a/charts/netbird/tests/pat-seed-configmap_test.yaml b/charts/netbird/tests/pat-seed-configmap_test.yaml index b721a30..adac189 100644 --- a/charts/netbird/tests/pat-seed-configmap_test.yaml +++ b/charts/netbird/tests/pat-seed-configmap_test.yaml @@ -145,14 +145,14 @@ tests: path: data["pat-seed.yaml"] pattern: "name: accounts" - - it: should use PAT_HASHED_TOKEN MiniJinja placeholder + - it: should compute hashed_token from PAT_TOKEN via sha256 and base64_encode set: pat.enabled: true pat.secret.secretName: my-pat-secret asserts: - matchRegex: path: data["pat-seed.yaml"] - pattern: "env\\.PAT_HASHED_TOKEN" + pattern: 'env\.PAT_TOKEN \| sha256\("bytes"\) \| base64_encode' - it: should seed account user and pat tables set: diff --git a/charts/netbird/tests/pat-seed-job_test.yaml b/charts/netbird/tests/pat-seed-job_test.yaml index 7fd9a40..229d1ad 100644 --- a/charts/netbird/tests/pat-seed-job_test.yaml +++ b/charts/netbird/tests/pat-seed-job_test.yaml @@ -161,11 +161,11 @@ tests: path: spec.template.spec.containers[0].image value: "ghcr.io/kitstream/initium:1.0.4" - - it: should inject PAT_HASHED_TOKEN env var from secret + - it: should inject PAT_TOKEN env var from secret set: pat.enabled: true pat.secret.secretName: my-pat-secret - pat.secret.hashedTokenKey: myHashKey + pat.secret.tokenKey: myTokenKey database.type: postgresql database.host: pg.example.com database.user: netbird @@ -175,11 +175,11 @@ tests: - contains: path: spec.template.spec.containers[0].env content: - name: PAT_HASHED_TOKEN + name: PAT_TOKEN valueFrom: secretKeyRef: name: my-pat-secret - key: myHashKey + key: myTokenKey - it: should inject DB_PASSWORD for postgresql set: diff --git a/charts/netbird/tests/server-deployment_test.yaml b/charts/netbird/tests/server-deployment_test.yaml index 5cb9e74..a5402aa 100644 --- a/charts/netbird/tests/server-deployment_test.yaml +++ b/charts/netbird/tests/server-deployment_test.yaml @@ -399,21 +399,21 @@ tests: - --spec - /spec/pat-seed.yaml - - it: should inject PAT_HASHED_TOKEN into sidecar + - it: should inject PAT_TOKEN into sidecar set: pat.enabled: true pat.secret.secretName: my-pat-secret - pat.secret.hashedTokenKey: myHash + pat.secret.tokenKey: myToken database.type: sqlite asserts: - contains: path: spec.template.spec.initContainers[1].env content: - name: PAT_HASHED_TOKEN + name: PAT_TOKEN valueFrom: secretKeyRef: name: my-pat-secret - key: myHash + key: myToken - it: should run sidecar as root for SQLite PVC access set: diff --git a/charts/netbird/values.yaml b/charts/netbird/values.yaml index 016e08d..d6f9347 100644 --- a/charts/netbird/values.yaml +++ b/charts/netbird/values.yaml @@ -84,27 +84,27 @@ database: # deployment. This enables immediate API access without manual token creation. # # Prerequisites: -# 1. Generate a PAT and its hash (see README for instructions) -# 2. Create a Kubernetes Secret with both values: +# 1. Generate a PAT token (see README for instructions) +# 2. Create a Kubernetes Secret with the token: # # kubectl create secret generic netbird-pat \ # --from-literal=token='nbp_...' \ -# --from-literal=hashedToken='base64hash...' \ # -n netbird +# +# The SHA256 hash required by the database is computed automatically at +# seed time by Initium (v1.0.4+) — you only need to supply the plaintext token. # ============================================================================= pat: # -- Enable PAT seeding. When true, a post-install Job inserts a # Personal Access Token into the database. enabled: false - # -- Kubernetes Secret containing the PAT credentials. + # -- Kubernetes Secret containing the PAT token. secret: - # -- Name of the existing Secret with token and hashed token. + # -- Name of the existing Secret holding the plaintext PAT. secretName: "" # -- Key in the Secret holding the plaintext PAT (e.g. "nbp_..."). tokenKey: "token" - # -- Key in the Secret holding the base64-encoded SHA256 hash. - hashedTokenKey: "hashedToken" # -- Display name for the seeded PAT. name: "helm-seeded-token" diff --git a/ci/scripts/e2e.sh b/ci/scripts/e2e.sh index 4ae045f..a9d21fd 100755 --- a/ci/scripts/e2e.sh +++ b/ci/scripts/e2e.sh @@ -162,8 +162,8 @@ EOF # NetBird PAT format: nbp_ (4) + secret (30) + base62(CRC32(secret)) (6) = 40 chars generate_pat_secret() { log "Generating PAT secret for testing..." - read -r PAT_TOKEN PAT_HASH < <(python3 -c " -import hashlib, base64, binascii + PAT_TOKEN=$(python3 -c " +import binascii BASE62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' def base62_encode(num, length=6): @@ -176,14 +176,11 @@ def base62_encode(num, length=6): secret = 'TestSecretValue1234567890ABCDE' # exactly 30 chars crc = binascii.crc32(secret.encode()) & 0xFFFFFFFF token = 'nbp_' + secret + base62_encode(crc) -h = base64.b64encode(hashlib.sha256(token.encode()).digest()).decode() -print(token, h) +print(token) ") log "Test PAT token: $PAT_TOKEN (length=${#PAT_TOKEN})" - log "Test PAT hash: $PAT_HASH" kubectl -n "$NAMESPACE" create secret generic netbird-pat \ - --from-literal=token="$PAT_TOKEN" \ - --from-literal=hashedToken="$PAT_HASH" + --from-literal=token="$PAT_TOKEN" } case "$BACKEND" in sqlite)