Skip to content

[bug] Log files in /opt/openwisp2/log/ can be created as root which prevents write from www-data user #627

Description

@pandafy

The ownership of log files in /opt/openwisp2/log/ can be set to root:root during deployment. This affects most log files created in the log directory and can prevent www-data processes (uWSGI, celery, nginx worker) from writing to them.

Affected Files

Log File Created By Root Ownership Cause
uwsgi.log supervisord supervisor runs as root
celery.log supervisord supervisor runs as root
celerybeat.log supervisord supervisor runs as root
celery-network.log supervisord supervisor runs as root
celery-monitoring.log supervisord supervisor runs as root
celery-firmware-upgrader.log supervisord supervisor runs as root
daphne.log supervisord supervisor runs as root
nginx.access.log nginx master nginx master runs as root
nginx.error.log nginx master nginx master runs as root
openwisp2.log Django RotatingFileHandler Created as www-data by uWSGI, but can become root-owned when load_initial_data.py or cron jobs run as root first

Steps To Reproduce

  1. Deploy OpenWISP2 using this role with become: true.
  2. Supervisord (running as root) creates all supervisor log files (uwsgi.log, celery.log, etc.) with root:root ownership.
  3. Nginx master (running as root) creates nginx.access.log and nginx.error.log with root:root ownership.
  4. The load_initial_data task (tasks/django.yml:226) runs as root, causing Django's RotatingFileHandler (templates/openwisp2/settings.py:487-494) to create openwisp2.log as root:root 0644.
  5. Alternatively, any of the cron jobs (tasks/cron.yml:1-29) run as root and can trigger a log rollover, creating a new file as root.
  6. www-data processes (uWSGI, celery, nginx worker) fail to write to root-owned log files.

Expected behavior

All log files in /opt/openwisp2/log/ should be owned by {{ www_user }}:{{ www_group }} so that application processes running as www-data can write to them.

Root Cause Analysis

  1. Log directory missing owner (tasks/django.yml:16-24):
- name: Create openwisp2 log directory
  ansible.builtin.file:
    path: "{{ openwisp2_path }}/log"
    state: directory
    group: "{{ www_group }}"
    mode: "0770"
    recurse: true

No owner is specified, so the directory is created as root:{{ www_group }} when running with become: true.

  1. Supervisor log files created as root (templates/supervisor/*.j2):
    All supervisor templates specify stdout_logfile in the log directory. Supervisord runs as root and therefore creates these log files as root:root, even though child processes run as www-data.

  2. Nginx log files created as root (templates/nginx/site-conf.j2:25-26):
    Nginx master (root) creates nginx.access.log and nginx.error.log with root ownership.

  3. load_initial_data runs as root (tasks/django.yml:226-236):
    The task uses ansible.builtin.command without become_user: "{{ www_user }}". When django.setup() runs it instantiates RotatingFileHandler which may create openwisp2.log as root:root.

  4. Cron jobs run as root (tasks/cron.yml:1-29):
    All three cron tasks use become: true without become_user, so they execute as root and can create or roll over openwisp2.log as root.

  5. No logrotate for supervisor/Django logs:
    Logrotate is configured for nginx logs with a create 0640 {{ www_user }} {{ www_group }} directive, but there is no equivalent logrotate configuration for the 7 supervisor log files or openwisp2.log.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog
    Status
    To do (ansible/docker)

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions