| @@ -1,13 +1,18 @@ | |||||
| # 2019-01-xx | |||||
| # 2019-01-29 | |||||
| ## Running container processes as non-root | |||||
| ## Running container processes as non-root, without capabilities and read-only | |||||
| To improve security, this playbook no longer starts container processes as the `root` user. | To improve security, this playbook no longer starts container processes as the `root` user. | ||||
| Most containers were dropping privileges anyway, but we were trusting them with `root` privileges until they would do that. | Most containers were dropping privileges anyway, but we were trusting them with `root` privileges until they would do that. | ||||
| Not anymore -- container processes now start as a non-root user (usually `matrix`) from the get-go. | Not anymore -- container processes now start as a non-root user (usually `matrix`) from the get-go. | ||||
| For additional security, various [capabilities are also dropped](https://github.com/projectatomic/atomic-site/issues/203) for all containers. | |||||
| For additional security, various capabilities are also dropped (see [why it's important](https://github.com/projectatomic/atomic-site/issues/203)) for all containers. | |||||
| Additionally, most containers now use a read-only filesystem (see [why it's important](https://www.projectatomic.io/blog/2015/12/making-docker-images-write-only-in-production/)). | |||||
| Containers are given write access only to the directories they need to write to. | |||||
| A minor breaking change is the `matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size` variable having being renamed to `matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb` (note the `_mb` suffix). The new variable expects a number value (e.g. `25M` -> `25`). | |||||
| If you weren't customizing this variable, this wouldn't affect you. | |||||
| ## matrix-mailer is now based on Exim, not Postfix | ## matrix-mailer is now based on Exim, not Postfix | ||||
| @@ -158,7 +158,7 @@ matrix_nginx_proxy_enabled: true | |||||
| matrix_nginx_proxy_proxy_matrix_client_api_addr_with_container: "{{ 'matrix-corporal:41080' if matrix_corporal_enabled else 'matrix-synapse:8008' }}" | matrix_nginx_proxy_proxy_matrix_client_api_addr_with_container: "{{ 'matrix-corporal:41080' if matrix_corporal_enabled else 'matrix-synapse:8008' }}" | ||||
| matrix_nginx_proxy_proxy_matrix_client_api_addr_sans_container: "{{ 'localhost:41080' if matrix_corporal_enabled else 'localhost:8008' }}" | matrix_nginx_proxy_proxy_matrix_client_api_addr_sans_container: "{{ 'localhost:41080' if matrix_corporal_enabled else 'localhost:8008' }}" | ||||
| matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size: "{{ matrix_synapse_max_upload_size_mb }}M" | |||||
| matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb: "{{ matrix_synapse_max_upload_size_mb }}" | |||||
| matrix_nginx_proxy_proxy_matrix_enabled: true | matrix_nginx_proxy_proxy_matrix_enabled: true | ||||
| matrix_nginx_proxy_proxy_riot_enabled: "{{ matrix_riot_web_enabled }}" | matrix_nginx_proxy_proxy_riot_enabled: "{{ matrix_riot_web_enabled }}" | ||||
| @@ -13,6 +13,7 @@ ExecStart=/usr/bin/docker run --rm --name matrix-corporal \ | |||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --network={{ matrix_docker_network }} \ | --network={{ matrix_docker_network }} \ | ||||
| {% if matrix_corporal_container_expose_ports %} | {% if matrix_corporal_container_expose_ports %} | ||||
| -p 127.0.0.1:41080:41080 \ | -p 127.0.0.1:41080:41080 \ | ||||
| @@ -13,6 +13,8 @@ ExecStart=/usr/bin/docker run --rm --name matrix-coturn \ | |||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --tmpfs=/var/tmp:rw,noexec,nosuid,size=100m \ | |||||
| -p 3478:3478 \ | -p 3478:3478 \ | ||||
| -p 3478:3478/udp \ | -p 3478:3478/udp \ | ||||
| -p {{ matrix_coturn_turn_udp_min_port }}-{{ matrix_coturn_turn_udp_max_port }}:{{ matrix_coturn_turn_udp_min_port }}-{{ matrix_coturn_turn_udp_max_port }}/udp \ | -p {{ matrix_coturn_turn_udp_min_port }}-{{ matrix_coturn_turn_udp_max_port }}:{{ matrix_coturn_turn_udp_min_port }}-{{ matrix_coturn_turn_udp_max_port }}/udp \ | ||||
| @@ -11,6 +11,8 @@ ExecStart=/usr/bin/docker run --rm --name matrix-mailer \ | |||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_mailer_container_user_uid }}:{{ matrix_mailer_container_user_gid }} \ | --user={{ matrix_mailer_container_user_uid }}:{{ matrix_mailer_container_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --tmpfs=/var/spool/exim:rw,noexec,nosuid,size=100m \ | |||||
| --network={{ matrix_docker_network }} \ | --network={{ matrix_docker_network }} \ | ||||
| --env-file={{ matrix_mailer_base_path }}/env-mailer \ | --env-file={{ matrix_mailer_base_path }}/env-mailer \ | ||||
| --hostname={{ hostname_matrix }} \ | --hostname={{ hostname_matrix }} \ | ||||
| @@ -12,17 +12,23 @@ Wants={{ service }} | |||||
| Type=simple | Type=simple | ||||
| ExecStartPre=-/usr/bin/docker kill matrix-mxisd | ExecStartPre=-/usr/bin/docker kill matrix-mxisd | ||||
| ExecStartPre=-/usr/bin/docker rm matrix-mxisd | ExecStartPre=-/usr/bin/docker rm matrix-mxisd | ||||
| # mxisd writes an SQLite shared library (libsqlitejdbc.so) to /tmp and executes it from there, | |||||
| # so /tmp needs to be mounted with an exec option. | |||||
| ExecStart=/usr/bin/docker run --rm --name matrix-mxisd \ | ExecStart=/usr/bin/docker run --rm --name matrix-mxisd \ | ||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --tmpfs=/tmp:rw,exec,nosuid,size=10m \ | |||||
| --network={{ matrix_docker_network }} \ | --network={{ matrix_docker_network }} \ | ||||
| {% if matrix_mxisd_container_expose_port %} | {% if matrix_mxisd_container_expose_port %} | ||||
| -p 127.0.0.1:8090:8090 \ | -p 127.0.0.1:8090:8090 \ | ||||
| {% endif %} | {% endif %} | ||||
| -v {{ matrix_mxisd_config_path }}:/etc/mxisd:ro \ | -v {{ matrix_mxisd_config_path }}:/etc/mxisd:ro \ | ||||
| -v {{ matrix_mxisd_data_path }}:/var/mxisd \ | |||||
| -v {{ matrix_mxisd_data_path }}:/var/mxisd:rw \ | |||||
| {{ matrix_mxisd_docker_image }} | {{ matrix_mxisd_docker_image }} | ||||
| ExecStop=-/usr/bin/docker kill matrix-mxisd | ExecStop=-/usr/bin/docker kill matrix-mxisd | ||||
| ExecStop=-/usr/bin/docker rm matrix-mxisd | ExecStop=-/usr/bin/docker rm matrix-mxisd | ||||
| Restart=always | Restart=always | ||||
| @@ -44,7 +44,10 @@ matrix_nginx_proxy_proxy_matrix_identity_api_addr_sans_container: "localhost:809 | |||||
| matrix_nginx_proxy_proxy_matrix_client_api_addr_with_container: "matrix-synapse:8008" | matrix_nginx_proxy_proxy_matrix_client_api_addr_with_container: "matrix-synapse:8008" | ||||
| matrix_nginx_proxy_proxy_matrix_client_api_addr_sans_container: "localhost:8008" | matrix_nginx_proxy_proxy_matrix_client_api_addr_sans_container: "localhost:8008" | ||||
| # This needs to be equal or higher than the maximum upload size accepted by Synapse. | # This needs to be equal or higher than the maximum upload size accepted by Synapse. | ||||
| matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size: "25M" | |||||
| matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb: 25 | |||||
| # The tmpfs at /tmp needs to be large enough to handle multiple concurrent file uploads. | |||||
| matrix_nginx_proxy_tmp_directory_size_mb: "{{ matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb * 50 }}" | |||||
| # A list of strings containing additional configuration blocks to add to the matrix domain's server configuration. | # A list of strings containing additional configuration blocks to add to the matrix domain's server configuration. | ||||
| matrix_nginx_proxy_proxy_matrix_additional_server_configuration_blocks: [] | matrix_nginx_proxy_proxy_matrix_additional_server_configuration_blocks: [] | ||||
| @@ -85,4 +88,4 @@ matrix_ssl_lets_encrypt_support_email: "{{ host_specific_matrix_ssl_lets_encrypt | |||||
| matrix_ssl_base_path: "{{ matrix_base_data_path }}/ssl" | matrix_ssl_base_path: "{{ matrix_base_data_path }}/ssl" | ||||
| matrix_ssl_config_dir_path: "{{ matrix_ssl_base_path }}/config" | matrix_ssl_config_dir_path: "{{ matrix_ssl_base_path }}/config" | ||||
| matrix_ssl_log_dir_path: "{{ matrix_ssl_base_path }}/log" | |||||
| matrix_ssl_log_dir_path: "{{ matrix_ssl_base_path }}/log" | |||||
| @@ -116,7 +116,7 @@ server { | |||||
| proxy_set_header X-Forwarded-For $remote_addr; | proxy_set_header X-Forwarded-For $remote_addr; | ||||
| client_body_buffer_size 25M; | client_body_buffer_size 25M; | ||||
| client_max_body_size {{ matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size }}; | |||||
| client_max_body_size {{ matrix_nginx_proxy_proxy_matrix_client_api_client_max_body_size_mb }}M; | |||||
| proxy_max_temp_file_size 0; | proxy_max_temp_file_size 0; | ||||
| } | } | ||||
| @@ -12,10 +12,13 @@ Wants={{ service }} | |||||
| Type=simple | Type=simple | ||||
| ExecStartPre=-/usr/bin/docker kill matrix-nginx-proxy | ExecStartPre=-/usr/bin/docker kill matrix-nginx-proxy | ||||
| ExecStartPre=-/usr/bin/docker rm matrix-nginx-proxy | ExecStartPre=-/usr/bin/docker rm matrix-nginx-proxy | ||||
| ExecStart=/usr/bin/docker run --rm --name matrix-nginx-proxy \ | ExecStart=/usr/bin/docker run --rm --name matrix-nginx-proxy \ | ||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_nginx_proxy_tmp_directory_size_mb }}m \ | |||||
| --network={{ matrix_docker_network }} \ | --network={{ matrix_docker_network }} \ | ||||
| -p 80:8080 \ | -p 80:8080 \ | ||||
| -p 443:8443 \ | -p 443:8443 \ | ||||
| @@ -24,6 +27,7 @@ ExecStart=/usr/bin/docker run --rm --name matrix-nginx-proxy \ | |||||
| -v {{ matrix_ssl_config_dir_path }}:{{ matrix_ssl_config_dir_path }}:ro \ | -v {{ matrix_ssl_config_dir_path }}:{{ matrix_ssl_config_dir_path }}:ro \ | ||||
| -v {{ matrix_static_files_base_path }}:{{ matrix_static_files_base_path }}:ro \ | -v {{ matrix_static_files_base_path }}:{{ matrix_static_files_base_path }}:ro \ | ||||
| {{ matrix_nginx_proxy_docker_image }} | {{ matrix_nginx_proxy_docker_image }} | ||||
| ExecStop=-/usr/bin/docker kill matrix-nginx-proxy | ExecStop=-/usr/bin/docker kill matrix-nginx-proxy | ||||
| ExecStop=-/usr/bin/docker rm matrix-nginx-proxy | ExecStop=-/usr/bin/docker rm matrix-nginx-proxy | ||||
| ExecReload=/usr/bin/docker exec matrix-nginx-proxy /usr/sbin/nginx -s reload | ExecReload=/usr/bin/docker exec matrix-nginx-proxy /usr/sbin/nginx -s reload | ||||
| @@ -73,7 +73,7 @@ | |||||
| - name: Note about Postgres importing alternative | - name: Note about Postgres importing alternative | ||||
| debug: | debug: | ||||
| msg: > | |||||
| msg: >- | |||||
| Importing Postgres database using the following command: `{{ matrix_postgres_import_command }}`. | Importing Postgres database using the following command: `{{ matrix_postgres_import_command }}`. | ||||
| If this crashes, you can stop Postgres (`systemctl stop matrix-postgres`), | If this crashes, you can stop Postgres (`systemctl stop matrix-postgres`), | ||||
| delete its existing data (`rm -rf {{ matrix_postgres_data_path }}/*`), start it again (`systemctl start matrix-postgres`) | delete its existing data (`rm -rf {{ matrix_postgres_data_path }}/*`), start it again (`systemctl start matrix-postgres`) | ||||
| @@ -11,9 +11,12 @@ ExecStart=/usr/bin/docker run --rm --name matrix-postgres \ | |||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --tmpfs=/tmp:rw,noexec,nosuid,size=100m \ | |||||
| --tmpfs=/run/postgresql:rw,noexec,nosuid,size=100m \ | |||||
| --network={{ matrix_docker_network }} \ | --network={{ matrix_docker_network }} \ | ||||
| --env-file={{ matrix_postgres_base_path }}/env-postgres-server \ | --env-file={{ matrix_postgres_base_path }}/env-postgres-server \ | ||||
| -v {{ matrix_postgres_data_path }}:/var/lib/postgresql/data \ | |||||
| -v {{ matrix_postgres_data_path }}:/var/lib/postgresql/data:rw \ | |||||
| -v /etc/passwd:/etc/passwd:ro \ | -v /etc/passwd:/etc/passwd:ro \ | ||||
| {{ matrix_postgres_docker_image_to_use }} | {{ matrix_postgres_docker_image_to_use }} | ||||
| ExecStop=-/usr/bin/docker stop matrix-postgres | ExecStop=-/usr/bin/docker stop matrix-postgres | ||||
| @@ -13,6 +13,8 @@ ExecStart=/usr/bin/docker run --rm --name matrix-riot-web \ | |||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --read-only \ | |||||
| --tmpfs=/tmp:rw,noexec,nosuid,size=10m \ | |||||
| -v {{ matrix_riot_web_data_path }}/nginx.conf:/etc/nginx/nginx.conf:ro \ | -v {{ matrix_riot_web_data_path }}/nginx.conf:/etc/nginx/nginx.conf:ro \ | ||||
| -v /dev/null:/etc/nginx/conf.d/default.conf:ro \ | -v /dev/null:/etc/nginx/conf.d/default.conf:ro \ | ||||
| -v {{ matrix_riot_web_data_path }}/config.json:/etc/riot-web/config.json:ro \ | -v {{ matrix_riot_web_data_path }}/config.json:/etc/riot-web/config.json:ro \ | ||||
| @@ -39,6 +39,9 @@ matrix_synapse_max_upload_size_mb: 10 | |||||
| matrix_synapse_max_log_file_size_mb: 100 | matrix_synapse_max_log_file_size_mb: 100 | ||||
| matrix_synapse_max_log_files_count: 10 | matrix_synapse_max_log_files_count: 10 | ||||
| # The tmpfs at /tmp needs to be large enough to handle multiple concurrent file uploads. | |||||
| matrix_synapse_tmp_directory_size_mb: "{{ matrix_synapse_max_upload_size_mb * 50 }}" | |||||
| # Log levels | # Log levels | ||||
| # Possible options are defined here https://docs.python.org/3/library/logging.html#logging-levels | # Possible options are defined here https://docs.python.org/3/library/logging.html#logging-levels | ||||
| # warning: setting log level to DEBUG will make synapse log sensitive information such | # warning: setting log level to DEBUG will make synapse log sensitive information such | ||||
| @@ -187,4 +190,4 @@ matrix_mautrix_whatsapp_enabled: false | |||||
| matrix_mautrix_whatsapp_docker_image: "tulir/mautrix-whatsapp:latest" | matrix_mautrix_whatsapp_docker_image: "tulir/mautrix-whatsapp:latest" | ||||
| matrix_mautrix_whatsapp_base_path: "{{ matrix_base_data_path }}/mautrix-whatsapp" | |||||
| matrix_mautrix_whatsapp_base_path: "{{ matrix_base_data_path }}/mautrix-whatsapp" | |||||
| @@ -18,11 +18,14 @@ ExecStartPre=-/usr/bin/docker rm matrix-synapse | |||||
| # we'd write files to the local filesystem and fusermount will complain. | # we'd write files to the local filesystem and fusermount will complain. | ||||
| ExecStartPre=/bin/sleep 5 | ExecStartPre=/bin/sleep 5 | ||||
| {% endif %} | {% endif %} | ||||
| ExecStart=/usr/bin/docker run --rm --name matrix-synapse \ | ExecStart=/usr/bin/docker run --rm --name matrix-synapse \ | ||||
| --log-driver=none \ | --log-driver=none \ | ||||
| --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| --cap-drop=ALL \ | --cap-drop=ALL \ | ||||
| --entrypoint=python \ | --entrypoint=python \ | ||||
| --read-only \ | |||||
| --tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_synapse_tmp_directory_size_mb }}m \ | |||||
| --network={{ matrix_docker_network }} \ | --network={{ matrix_docker_network }} \ | ||||
| -e SYNAPSE_CACHE_FACTOR={{ matrix_synapse_cache_factor }} \ | -e SYNAPSE_CACHE_FACTOR={{ matrix_synapse_cache_factor }} \ | ||||
| {% if matrix_synapse_federation_enabled %} | {% if matrix_synapse_federation_enabled %} | ||||
| @@ -31,14 +34,15 @@ ExecStart=/usr/bin/docker run --rm --name matrix-synapse \ | |||||
| {% if matrix_synapse_container_expose_client_server_api_port %} | {% if matrix_synapse_container_expose_client_server_api_port %} | ||||
| -p 127.0.0.1:8008:8008 \ | -p 127.0.0.1:8008:8008 \ | ||||
| {% endif %} | {% endif %} | ||||
| -v {{ matrix_synapse_config_dir_path }}:/data \ | |||||
| -v {{ matrix_synapse_run_path }}:/matrix-run \ | |||||
| -v {{ matrix_synapse_config_dir_path }}:/data:ro \ | |||||
| -v {{ matrix_synapse_run_path }}:/matrix-run:rw \ | |||||
| -v {{ matrix_synapse_base_path }}/storage:/matrix-media-store-parent:slave \ | -v {{ matrix_synapse_base_path }}/storage:/matrix-media-store-parent:slave \ | ||||
| {% for volume in matrix_synapse_container_additional_volumes %} | {% for volume in matrix_synapse_container_additional_volumes %} | ||||
| -v {{ volume.src }}:{{ volume.dst }}:{{ volume.options }} \ | -v {{ volume.src }}:{{ volume.dst }}:{{ volume.options }} \ | ||||
| {% endfor %} | {% endfor %} | ||||
| {{ matrix_synapse_docker_image }} \ | {{ matrix_synapse_docker_image }} \ | ||||
| -m synapse.app.homeserver -c /data/homeserver.yaml | -m synapse.app.homeserver -c /data/homeserver.yaml | ||||
| ExecStop=-/usr/bin/docker kill matrix-synapse | ExecStop=-/usr/bin/docker kill matrix-synapse | ||||
| ExecStop=-/usr/bin/docker rm matrix-synapse | ExecStop=-/usr/bin/docker rm matrix-synapse | ||||
| Restart=always | Restart=always | ||||