Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[2.11.0-rc2] Redis reconfiguration can yield multiple requirepass directives #7386

Open
cfm opened this issue Dec 13, 2024 · 1 comment
Open

Comments

@cfm
Copy link
Member

cfm commented Dec 13, 2024

Description

We now set or reset a requirepass directive in /etc/redis/redis.conf in three places, with different conditions and via different mechanisms:

  1. Initial installation playbook:
    - name: Add 32-byte value for "redis password" to /etc/redis/redis.conf.
    lineinfile:
    dest: "/etc/redis/redis.conf"
    regexp: "^requirepass"
    line: "requirepass {{ redis_password.stdout }}"
    insertafter: EOF
    when: not config.stat.exists
    register: redis_conf
  2. securedrop-app-code.postinst:
    echo "requirepass $password" | sudo -u redis tee -a /etc/redis/redis.conf
  3. Backup-restoration playbook:
    - name: Remove Redis password line from /etc/redis/redis.conf, if it exists
    lineinfile:
    path: /etc/redis/redis.conf
    state: absent
    regexp: "^requirepass .*$"
    - name: Reconfigure securedrop-app-code, regenerating Redis config vi postint
    command: dpkg-reconfigure securedrop-app-code

This has evolved ad hoc and can lead to inconsistent (and difficult-to-reproduce) configuration.

Steps to Reproduce

Long-running QA instance....

Expected Behavior

Consistent Redis configuration, including exactly one requirepass directive.

Actual Behavior

I run etckeeper on my QA instance for forensic purposes. On automatic upgrade to securedrop-app-code_2.11.0~rc1, etckeeper recorded (NB. QA values; no real secrets leaking here):

From 4f76e15a7698d6d695d5f7682c093114a01c07f0 Mon Sep 17 00:00:00 2001
From: root <root@app>
Date: Wed, 11 Dec 2024 03:15:56 +0000
Subject: [PATCH 2/2] committing changes in /etc made by "/usr/bin/python3
 /usr/bin/unattended-upgrade"

Package changes:
---
 redis/redis.conf | 1 +
 1 file changed, 1 insertion(+)

diff --git a/redis/redis.conf b/redis/redis.conf
index 3052aff..8704f5d 100644
--- a/redis/redis.conf
+++ b/redis/redis.conf
@@ -1371,3 +1371,4 @@ rdb-save-incremental-fsync yes
 # active-defrag-max-scan-fields 1000
 
 requirepass iECwDLwqmO2gDCJgMkaUMKkmtqgTih3IF951DMmO0PA=
+requirepass LeabNIFsavoNC6yQm1tjaCn+vCsFBLYFNMPxKHQzq7s=
-- 
2.25.1

Comments

@legoktm and I discussed adding a "re/configure Redis" script that:

  1. would be our sole entry-point for Redis configuration across Ansible playbooks and postinst scripts;
  2. would enforce consistency across both Redis's own and consumers' configuration; and
  3. wouldn't be strictly idempotent, but could be safely rerun without violating that consistency.
@cfm cfm added this to the SecureDrop 2.12.0 milestone Dec 13, 2024
legoktm added a commit that referenced this issue Dec 14, 2024
Code to set and reset Redis passwords has now proliferated into the
postinst, dev environment, ansible provisioning and backup restore.
Instead of maintaining separate code for this, write a single script
that handles it all.

A new `securedrop-set-redis-auth` tool offers three operations:
* check: verify all the passwords are in sync (for testinfra checks)
* reset: forcibly change the password everywhere (for backup restore)
* reset-if-needed: change the password everywhere if needed (for
postinst)

Fixes #7386.
@legoktm
Copy link
Member

legoktm commented Dec 14, 2024

I worked on the script today: b98381e, but I haven't tried to integrate it into anything yet. It needs some integration/unit tests too.

(I was itching to try using memsec, but it's totally overkill and also the password is already unencrypted in Python's memory.)

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

No branches or pull requests

2 participants