Make (most) containers run with a read-only filesystem
This commit is contained in:
		
							
								
								
									
										13
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -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. | ||||
|  | ||||
| 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. | ||||
|  | ||||
| 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 | ||||
|   | ||||
| @@ -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_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_riot_enabled: "{{ matrix_riot_web_enabled }}" | ||||
|   | ||||
| @@ -13,6 +13,7 @@ ExecStart=/usr/bin/docker run --rm --name matrix-corporal \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--read-only \ | ||||
| 			--network={{ matrix_docker_network }} \ | ||||
| 			{% if matrix_corporal_container_expose_ports %} | ||||
| 			-p 127.0.0.1:41080:41080 \ | ||||
|   | ||||
| @@ -13,6 +13,8 @@ ExecStart=/usr/bin/docker run --rm --name matrix-coturn \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--read-only \ | ||||
| 			--tmpfs=/var/tmp:rw,noexec,nosuid,size=100m \ | ||||
| 			-p 3478:3478 \ | ||||
| 			-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 \ | ||||
|   | ||||
| @@ -11,6 +11,8 @@ ExecStart=/usr/bin/docker run --rm --name matrix-mailer \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_mailer_container_user_uid }}:{{ matrix_mailer_container_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--read-only \ | ||||
| 			--tmpfs=/var/spool/exim:rw,noexec,nosuid,size=100m \ | ||||
| 			--network={{ matrix_docker_network }} \ | ||||
| 			--env-file={{ matrix_mailer_base_path }}/env-mailer \ | ||||
| 			--hostname={{ hostname_matrix }} \ | ||||
|   | ||||
| @@ -12,17 +12,23 @@ Wants={{ service }} | ||||
| Type=simple | ||||
| ExecStartPre=-/usr/bin/docker kill 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 \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--read-only \ | ||||
| 			--tmpfs=/tmp:rw,exec,nosuid,size=10m \ | ||||
| 			--network={{ matrix_docker_network }} \ | ||||
| 			{% if matrix_mxisd_container_expose_port %} | ||||
| 			-p 127.0.0.1:8090:8090 \ | ||||
| 			{% endif %} | ||||
| 			-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 }} | ||||
|  | ||||
| ExecStop=-/usr/bin/docker kill matrix-mxisd | ||||
| ExecStop=-/usr/bin/docker rm matrix-mxisd | ||||
| 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_sans_container: "localhost:8008" | ||||
| # 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. | ||||
| 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_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; | ||||
|  | ||||
| 		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; | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -12,10 +12,13 @@ Wants={{ service }} | ||||
| Type=simple | ||||
| ExecStartPre=-/usr/bin/docker kill matrix-nginx-proxy | ||||
| ExecStartPre=-/usr/bin/docker rm matrix-nginx-proxy | ||||
|  | ||||
| ExecStart=/usr/bin/docker run --rm --name matrix-nginx-proxy \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--read-only \ | ||||
| 			--tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_nginx_proxy_tmp_directory_size_mb }}m \ | ||||
| 			--network={{ matrix_docker_network }} \ | ||||
| 			-p 80:8080 \ | ||||
| 			-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_static_files_base_path }}:{{ matrix_static_files_base_path }}:ro \ | ||||
| 			{{ matrix_nginx_proxy_docker_image }} | ||||
|  | ||||
| ExecStop=-/usr/bin/docker kill matrix-nginx-proxy | ||||
| ExecStop=-/usr/bin/docker rm matrix-nginx-proxy | ||||
| ExecReload=/usr/bin/docker exec matrix-nginx-proxy /usr/sbin/nginx -s reload | ||||
|   | ||||
| @@ -73,7 +73,7 @@ | ||||
|  | ||||
| - name: Note about Postgres importing alternative | ||||
|   debug: | ||||
|     msg: > | ||||
|     msg: >- | ||||
|       Importing Postgres database using the following command: `{{ matrix_postgres_import_command }}`. | ||||
|       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`) | ||||
|   | ||||
| @@ -11,9 +11,12 @@ ExecStart=/usr/bin/docker run --rm --name matrix-postgres \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--read-only \ | ||||
| 			--tmpfs=/tmp:rw,noexec,nosuid,size=100m \ | ||||
| 			--tmpfs=/run/postgresql:rw,noexec,nosuid,size=100m \ | ||||
| 			--network={{ matrix_docker_network }} \ | ||||
| 			--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 \ | ||||
| 			{{ matrix_postgres_docker_image_to_use }} | ||||
| ExecStop=-/usr/bin/docker stop matrix-postgres | ||||
|   | ||||
| @@ -13,6 +13,8 @@ ExecStart=/usr/bin/docker run --rm --name matrix-riot-web \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--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 /dev/null:/etc/nginx/conf.d/default.conf: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_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 | ||||
| # 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 | ||||
| @@ -187,4 +190,4 @@ matrix_mautrix_whatsapp_enabled: false | ||||
|  | ||||
| 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. | ||||
| ExecStartPre=/bin/sleep 5 | ||||
| {% endif %} | ||||
|  | ||||
| ExecStart=/usr/bin/docker run --rm --name matrix-synapse \ | ||||
| 			--log-driver=none \ | ||||
| 			--user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ | ||||
| 			--cap-drop=ALL \ | ||||
| 			--entrypoint=python \ | ||||
| 			--read-only \ | ||||
| 			--tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_synapse_tmp_directory_size_mb }}m \ | ||||
| 			--network={{ matrix_docker_network }} \ | ||||
| 			-e SYNAPSE_CACHE_FACTOR={{ matrix_synapse_cache_factor }} \ | ||||
| 			{% 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 %} | ||||
| 			-p 127.0.0.1:8008:8008 \ | ||||
| 			{% 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 \ | ||||
| 			{% for volume in matrix_synapse_container_additional_volumes %} | ||||
| 			-v {{ volume.src }}:{{ volume.dst }}:{{ volume.options }} \ | ||||
| 			{% endfor %} | ||||
| 			{{ matrix_synapse_docker_image }} \ | ||||
| 			-m synapse.app.homeserver -c /data/homeserver.yaml | ||||
|  | ||||
| ExecStop=-/usr/bin/docker kill matrix-synapse | ||||
| ExecStop=-/usr/bin/docker rm matrix-synapse | ||||
| Restart=always | ||||
|   | ||||
		Reference in New Issue
	
	Block a user