# CouchDB erlangCookie Fix - Implementation Guide ## Summary **Problem**: CouchDB deployment fails because `erlangCookie` is missing from the ExternalSecret configuration. **Decision**: Externalize `erlangCookie` to 1Password (pragmatic approach) **Rationale**: - ExternalSecret architecture requires ownership of the entire secret - Mixing externalized and chart-generated fields in the same secret is not supported - Single-node deployment makes erlangCookie rotation unnecessary - This is an acceptable deviation from the pure Harbor pattern given the architectural constraints ## Implementation Steps ### 1. Generate erlangCookie Value ```bash openssl rand -hex 20 ``` Example output: `f4e3c2b1a9d8e7f6c5b4a3d2e1f0a9b8c7d6e5f4` ### 2. Add to 1Password - **Vault**: `mk-labs` - **Item**: `couchdb` - **Field Name**: `erlang-cookie` - **Field Type**: password (concealed) - **Value**: `` ### 3. Update ExternalSecret Configuration File: `cluster/applications/couchdb/externalsecret.yaml` ```yaml apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: couchdb-credentials namespace: couchdb labels: app.kubernetes.io/name: couchdb app.kubernetes.io/part-of: mk-labs spec: refreshInterval: 1h secretStoreRef: kind: ClusterSecretStore name: onepassword-connect target: name: couchdb-admin creationPolicy: Owner template: engineVersion: v2 data: adminUsername: "admin" adminPassword: "{{ .adminPassword }}" cookieAuthSecret: "{{ .cookieAuthSecret }}" erlangCookie: "{{ .erlangCookie }}" # ← ADD THIS LINE data: - secretKey: adminPassword remoteRef: key: couchdb property: admin-password - secretKey: cookieAuthSecret remoteRef: key: couchdb property: cookie-auth-secret - secretKey: erlangCookie # ← ADD THIS BLOCK remoteRef: key: couchdb property: erlang-cookie ``` ### 4. Update values.yaml Documentation (Optional) File: `cluster/applications/couchdb/values.yaml` Update the comment block at line 9-10: ```yaml # Admin credentials managed via ExternalSecret # See externalsecret.yaml for 1Password integration # # NOTE: erlangCookie is externalized to 1Password for architectural # simplicity (ExternalSecret ownership model). In a pure Harbor pattern, # this would be chart-generated, but single-node deployment makes this # acceptable. The erlangCookie is treated as an immutable infrastructure # secret (generate once, never rotate). createAdminSecret: false extraSecretName: "couchdb-admin" ``` ### 5. Commit and Push ```bash cd ~/git/homelab git add cluster/applications/couchdb/externalsecret.yaml git add cluster/applications/couchdb/values.yaml # if modified git commit -m "fix(couchdb): add erlangCookie to ExternalSecret from 1Password" git push origin main ``` ### 6. Verify Deployment ```bash # Watch ExternalSecret sync kubectl get externalsecret -n couchdb couchdb-credentials -w # Wait for: SecretSynced # Verify secret created with all four keys kubectl get secret -n couchdb couchdb-admin -o yaml # Should contain: adminUsername, adminPassword, cookieAuthSecret, erlangCookie # Watch ArgoCD sync kubectl get application -n argocd couchdb -w # Wait for: Healthy/Synced # Watch pod startup kubectl get pods -n couchdb -w # Wait for: Running # Test CouchDB access kubectl port-forward -n couchdb svc/couchdb-svc-couchdb 5984:5984 & curl http://localhost:5984/ # Expected: {"couchdb":"Welcome","version":"3.5.1"} ``` ## Why Not Follow Harbor Pattern Exactly? **Harbor Pattern**: Only user-facing credentials externalized, internal secrets chart-generated. **CouchDB Constraint**: ExternalSecret uses `creationPolicy: Owner`, which takes full ownership of the target secret. This prevents the Helm chart from adding auto-generated fields to the same secret. **Options Considered**: 1. ✅ **Externalize erlangCookie** (SELECTED) - Works with current architecture 2. ❌ Chart auto-generation - Conflicts with ExternalSecret ownership 3. ❌ Dual-secret approach - Requires Helm chart customization 4. ❌ Disable ExternalSecret - Loses 1Password integration for admin password **Decision**: Pragmatic approach wins. erlangCookie is treated as an infrastructure secret (generate once, never rotate), which is acceptable for a single-node deployment. ## Secret Classification | Secret | Type | 1Password? | Rationale | |------------------|---------------|------------|------------------------------------| | adminUsername | User-facing | No* | Static value, hardcoded in template | | adminPassword | User-facing | ✅ YES | User login credential | | cookieAuthSecret | Gray area | ✅ YES | Session security, periodic rotation | | erlangCookie | Internal | ✅ YES** | Architectural constraint | \* Hardcoded in ExternalSecret template (not fetched from 1Password) \*\* Pragmatic deviation from Harbor pattern due to ExternalSecret architecture ## References - Full analysis: `/home/hermes/couchdb-erlangcookie-analysis.txt` - Harbor pattern: `/home/hermes/harbor-simplification-complete.txt` - CouchDB Helm chart: `apache/couchdb` v4.6.3