- Stable udev device symlinks (/dev/jmri/nce, /dev/jmri/loconet, /dev/jmri/lcc) - jmri-monitor: polls Leviton Decora Smart switch to start/stop JMRI automatically - Quiet hours 1-10 AM (no polling) - 30s off-delay before shutdown - LCRR config cloned from Gitea (ssh://gitea.mk-labs.cloud:2221/rblundon/LCRR.git) - ~/.jmri symlinked to LCRR repo for GitOps config management - jmri-gui: X11 remote GUI access (PanelPro/DecoderPro) via ssh -X as jmri user - Stops daemon, launches GUI, restarts daemon on exit if layout still on - jmri user gets login shell + SSH key for GUI sessions - Full JRE installed (openjdk-21-jre) for AWT/X11 support
5.2 KiB
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
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:
<paste generated value from step 1>
3. Update ExternalSecret Configuration
File: cluster/applications/couchdb/externalsecret.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:
# 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
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
# 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:
- ✅ Externalize erlangCookie (SELECTED) - Works with current architecture
- ❌ Chart auto-generation - Conflicts with ExternalSecret ownership
- ❌ Dual-secret approach - Requires Helm chart customization
- ❌ 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/couchdbv4.6.3