Better non-root permission handling (#55)

This commit is contained in:
Chris Caron 2021-10-30 16:58:15 -04:00 committed by GitHub
parent ddb209264b
commit e65b80cb11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 121 additions and 50 deletions

View File

@ -21,32 +21,28 @@ RUN apt-get update -qq && \
COPY ./requirements.txt /etc/requirements.txt
RUN pip3 install -q -r /etc/requirements.txt gunicorn
# Nginx configuration
RUN echo "daemon off;" >> /etc/nginx/nginx.conf
COPY /etc/nginx.conf /etc/nginx/conf.d/nginx.conf
# Copy our static content in place
COPY apprise_api/static /usr/share/nginx/html/s/
# Supervisor configuration
COPY /etc/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
# set work directory
WORKDIR /opt/apprise
# Copy over Apprise API
COPY apprise_api/ webapp
# Change port of gunicorn
RUN sed -i -e 's/:8000/:8080/g' /opt/apprise/webapp/gunicorn.conf.py
# Cleanup
RUN apt-get remove -y -qq build-essential libffi-dev libssl-dev python-dev && \
apt-get clean autoclean && \
apt-get autoremove --yes && \
rm -rf /var/lib/{apt,dpkg,cache,log}/
EXPOSE 8000
VOLUME /config
# Configuration Permissions (to run nginx as a non-root user)
RUN umask 0002 && \
mkdir -p /config /run/apprise && \
chown www-data:www-data -R /run/apprise /var/lib/nginx /config
CMD ["/usr/bin/supervisord"]
# Handle running as a non-root user (www-data is id/gid 33)
USER www-data
VOLUME /config
EXPOSE 8000
CMD ["/usr/bin/supervisord", "-c", "/opt/apprise/webapp/etc/supervisord.conf"]

View File

@ -2,7 +2,7 @@
Take advantage of [Apprise](https://github.com/caronc/apprise) through your network with a user-friendly API.
- Send notifications to more then 65+ services.
- Send notifications to more then 70+ services.
- An incredibly lightweight gateway to Apprise.
- A production ready micro-service at your disposal.
@ -51,6 +51,7 @@ A `docker-compose.yml` file is already set up to grant you an instant production
docker-compose up
```
### Config Directory Permissions
Under the hood, An NginX services is reading/writing your configuration files as the user (and group) `www-data` which generally has the id of `33`. In preparation so that you don't get the error: `An error occured saving configuration.` consider also setting up your local `/var/lib/apprise/config` permissions as:

View File

@ -107,6 +107,19 @@ class AddTests(SimpleTestCase):
)
assert response.status_code == 400
# Test the handling of underlining disk/write exceptions
with patch('os.makedirs') as mock_mkdirs:
mock_mkdirs.side_effect = OSError()
# We'll fail to write our key now
response = self.client.post(
'/add/{}'.format(key),
data=json.dumps({'urls': 'mailto://user:pass@yahoo.ca'}),
content_type='application/json',
)
# internal errors are correctly identified
assert response.status_code == 500
# Test the handling of underlining disk/write exceptions
with patch('gzip.open') as mock_open:
mock_open.side_effect = OSError()

View File

@ -36,7 +36,7 @@ from django.conf import settings
import logging
# Get an instance of a logger
logger = logging.getLogger(__name__)
logger = logging.getLogger('django')
class AppriseStoreMode(object):
@ -120,7 +120,13 @@ class AppriseConfigCache(object):
# First two characters are reserved for cache level directory writing.
path, filename = self.path(key)
os.makedirs(path, exist_ok=True)
try:
os.makedirs(path, exist_ok=True)
except OSError:
# Permission error
logger.error('Could not create directory {}'.format(path))
return False
# Write our file to a temporary file
_, tmp_path = tempfile.mkstemp(suffix='.tmp', dir=path)

View File

@ -0,0 +1,73 @@
daemon off;
worker_processes auto;
pid /run/apprise/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
default_type application/octet-stream;
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
##
# Logging Settings
##
access_log /dev/stdout;
error_log /dev/stdout info;
##
# Gzip Settings
##
gzip on;
##
# Host Configuration
##
client_body_buffer_size 256k;
client_body_in_file_only off;
server {
listen 8000;
# Main Website
location / {
include /etc/nginx/uwsgi_params;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:8080;
# Give ample time for notifications to fire
proxy_read_timeout 120s;
}
# Static Content
location /s/ {
root /usr/share/nginx/html;
index index.html;
}
# 404 error handling
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
}

View File

@ -1,16 +1,19 @@
[supervisord]
nodaemon=true
pidfile=/run/apprise/supervisord.pid
logfile=/dev/null
logfile_maxbytes=0
user=www-data
[program:nginx]
command=/usr/sbin/nginx
command=/usr/sbin/nginx -c /opt/apprise/webapp/etc/nginx.conf
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0
stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:gunicorn]
command=gunicorn -c /opt/apprise/webapp/gunicorn.conf.py --worker-tmp-dir /dev/shm core.wsgi
user=www-data
command=gunicorn -c /opt/apprise/webapp/gunicorn.conf.py -b :8080 --worker-tmp-dir /dev/shm core.wsgi
directory=/opt/apprise/webapp
stdout_logfile=/dev/stdout
stdout_logfile_maxbytes=0

View File

@ -5,4 +5,13 @@ services:
build: .
container_name: apprise
ports:
- 8000:8000
- 8000:8000
user: "www-data:www-data"
volumes:
- ./apprise_api:/opt/apprise/webapp:ro
# if uncommenting the below, you will need to type the following
# otherwise the django instance won't have permissions to write
# to the directory correctly:
# $> chown -R 33:33 ./config
# $> chmod -R 775 ./config
# - ./config:/config:rw

View File

@ -1,30 +0,0 @@
server {
listen 8000;
# Main Website
location / {
include uwsgi_params;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:8080;
# Give ample time for notifications to fire
proxy_read_timeout 120s;
}
# Static Content
location /s/ {
root /usr/share/nginx/html;
index index.html;
}
# 404 error handling
error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}