diff --git a/Makefile b/Makefile index cdef268..8dab36c 100644 --- a/Makefile +++ b/Makefile @@ -69,7 +69,7 @@ lint: ${LINT_YAML} ${LINT_ANSIBLE} ${SKIP_FILE} @printf "Running yamllint...\n" -@${LINT_YAML} ${YAML_FILES} @. ${SKIP_FILE}; printf "Running ansible-lint with SKIP_LIST: [%s]...\n" "$$ANSIBLE_LINT_SKIP_LIST" - -@. ${SKIP_FILE}; ${LINT_ANSIBLE} -x $$ANSIBLE_LINT_SKIP_LIST ${YAML_FILES} + -@. ${SKIP_FILE}; ${LINT_ANSIBLE} -x $$ANSIBLE_LINT_SKIP_LIST ansible/ lint-ci: ${SKIP_FILE} @printf "Running yamllint...\n" diff --git a/ansible/roles/http/defaults/main.yml b/ansible/roles/http/defaults/main.yml index 386d0ba..0ec4ea7 100644 --- a/ansible/roles/http/defaults/main.yml +++ b/ansible/roles/http/defaults/main.yml @@ -10,6 +10,7 @@ pi_server_name: pi.bdebyl.net assistant_server_name: assistant.bdebyl.net home_server_name: home.bdebyl.net parts_server_name: parts.bdebyl.net +video_server_name: video.bdebyl.net install_path: /usr/share nginx_path: /etc/nginx diff --git a/ansible/roles/http/tasks/http.yml b/ansible/roles/http/tasks/http.yml index e56bcaa..5a3cda4 100644 --- a/ansible/roles/http/tasks/http.yml +++ b/ansible/roles/http/tasks/http.yml @@ -19,6 +19,18 @@ - sites-available tags: http +- name: ensure http/s directories exist + become: true + file: + path: "{{ item }}" + state: directory + owner: http + group: http + loop: + - /srv/http + - /srv/http/letsencrypt + tags: http + - name: chown http user home become: true file: @@ -39,6 +51,7 @@ - "{{ pi_server_name }}.conf" - "{{ home_server_name }}.conf" - "{{ assistant_server_name }}.conf" + - "{{ video_server_name }}.conf" - "{{ parts_server_name }}.conf" notify: restart_nginx tags: http @@ -62,5 +75,11 @@ - "{{ parts_server_name }}.conf" - "{{ home_server_name }}.conf" - "{{ assistant_server_name }}.conf" + - "{{ video_server_name }}.conf" notify: restart_nginx tags: http + +- name: validate nginx configurations + become: true + shell: nginx -t + tags: http diff --git a/ansible/roles/http/tasks/https.yml b/ansible/roles/http/tasks/https.yml index f6582c9..eaa02fa 100644 --- a/ansible/roles/http/tasks/https.yml +++ b/ansible/roles/http/tasks/https.yml @@ -7,6 +7,7 @@ mode: 0644 loop: - "{{ ci_server_name }}.https.conf" + - "{{ parts_server_name }}.https.conf" notify: restart_nginx tags: https @@ -18,5 +19,6 @@ state: link loop: - "{{ ci_server_name }}.https.conf" + - "{{ parts_server_name }}.https.conf" notify: restart_nginx tags: https diff --git a/ansible/roles/http/tasks/modsec.yml b/ansible/roles/http/tasks/modsec.yml index af49cde..502abc5 100644 --- a/ansible/roles/http/tasks/modsec.yml +++ b/ansible/roles/http/tasks/modsec.yml @@ -35,36 +35,37 @@ - name: setup modsec and coreruleset configs become: true - file: + copy: src: "{{ item.src }}" dest: "{{ item.dest }}" - state: link force: true mode: 0644 + remote_src: true loop: "{{ modsec_conf_links }}" notify: restart_nginx tags: modsec - name: setup coreruleset rules become: true - file: + copy: src: "{{ crs_rules_path }}/{{ item.name }}.conf" dest: "{{ modsec_rules_path }}/{{ item.name }}.conf" - state: "{{ item.enabled | ternary('link', 'absent') }}" force: true mode: 0644 + remote_src: true + when: item.enabled loop: "{{ crs_rule_links }}" notify: restart_nginx tags: modsec, modsec_rules - name: setup coreruleset data become: true - file: + copy: src: "{{ crs_rules_path }}/{{ item }}.data" dest: "{{ modsec_rules_path }}/{{ item }}.data" - state: link force: true mode: 0644 + remote_src: true loop: "{{ crs_data_links }}" notify: restart_nginx tags: modsec, modsec_rules diff --git a/ansible/roles/http/tasks/security.yml b/ansible/roles/http/tasks/security.yml index 17f94a5..5b98a6d 100644 --- a/ansible/roles/http/tasks/security.yml +++ b/ansible/roles/http/tasks/security.yml @@ -9,4 +9,6 @@ - access - error notify: restart_fail2ban - tags: http, security + tags: + - http + - security diff --git a/ansible/roles/http/templates/nginx/sites/assistant.bdebyl.net.conf.j2 b/ansible/roles/http/templates/nginx/sites/assistant.bdebyl.net.conf.j2 index 8b10fee..1cc6e2e 100644 --- a/ansible/roles/http/templates/nginx/sites/assistant.bdebyl.net.conf.j2 +++ b/ansible/roles/http/templates/nginx/sites/assistant.bdebyl.net.conf.j2 @@ -2,6 +2,9 @@ upstream hass { server 127.0.0.1:8123; } server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + listen 80; server_name {{ assistant_server_name }}; diff --git a/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.http.conf.j2 b/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.http.conf.j2 index 48cc792..27fb53b 100644 --- a/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.http.conf.j2 +++ b/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.http.conf.j2 @@ -4,7 +4,7 @@ server { server_name {{ ci_server_name }}; location /.well-known { - root /srv/http; + root /srv/http/letsencrypt; try_files $uri $uri/ =404; } diff --git a/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.https.conf.j2 b/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.https.conf.j2 index ac93ae5..857f2ec 100644 --- a/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.https.conf.j2 +++ b/ansible/roles/http/templates/nginx/sites/ci.bdebyl.net.https.conf.j2 @@ -3,6 +3,9 @@ upstream drone { } server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + listen 443 ssl http2; listen [::]:443 ssl http2; server_name {{ ci_server_name }}; @@ -22,9 +25,6 @@ server { ssl_stapling_verify on; location / { - modsecurity on; - modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; - add_header Allow "GET, POST, HEAD" always; add_header Content-Security-Policy "default-src 'self'; img-src 'self' https://*.githubusercontent.com; frame-ancestors 'self'; base-uri 'none',base-uri 'self'; form-action 'self'" always; add_header Referrer-Policy "same-origin" always; diff --git a/ansible/roles/http/templates/nginx/sites/home.bdebyl.net.conf.j2 b/ansible/roles/http/templates/nginx/sites/home.bdebyl.net.conf.j2 index 526eca6..bf48527 100644 --- a/ansible/roles/http/templates/nginx/sites/home.bdebyl.net.conf.j2 +++ b/ansible/roles/http/templates/nginx/sites/home.bdebyl.net.conf.j2 @@ -4,6 +4,9 @@ geo $whitelisted { } server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + listen 80 default_server; server_name {{ home_server_name }}; if ($whitelisted = 1) { diff --git a/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.conf.j2 b/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.conf.j2 index dfd4b67..ed07b9c 100644 --- a/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.conf.j2 +++ b/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.conf.j2 @@ -3,20 +3,20 @@ geo $whitelisted { 192.168.1.0/24 1; } -upstream partkeepr { - server localhost:8081; -} - server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + listen 80; + listen [::]:80; server_name {{ parts_server_name }}; - if ($whitelisted = 0) { - return 302 $scheme://bdebyl.net$request_uri; - } + location /.well-known { + root /srv/http/letsencrypt; + try_files $uri $uri/ =404; + } location / { - proxy_pass http://partkeepr; - proxy_connect_timeout 1s; + return 302 https://$host$request_uri; } } diff --git a/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.https.conf.j2 b/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.https.conf.j2 new file mode 100644 index 0000000..cd3c164 --- /dev/null +++ b/ansible/roles/http/templates/nginx/sites/parts.bdebyl.net.https.conf.j2 @@ -0,0 +1,56 @@ +geo $whitelisted { + default 0; + 192.168.1.0/24 1; +} + +upstream partkeepr { + server localhost:8081; +} + +server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name {{ parts_server_name }}; + + ssl_certificate /etc/letsencrypt/live/{{ parts_server_name }}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/{{ parts_server_name }}/privkey.pem; + ssl_trusted_certificate /etc/letsencrypt/live/{{ parts_server_name }}/fullchain.pem; + ssl_dhparam /etc/ssl/certs/dhparam.pem; + + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + ssl_session_timeout 1d; + ssl_stapling on; + ssl_stapling_verify on; + + if ($whitelisted = 0) { + return 302 $scheme://bdebyl.net$request_uri; + } + + location / { + add_header Referrer-Policy "same-origin" always; + # add_header Strict-Transport-Security "max-age=630720000; includeSubDomains" always; + add_header X-Content-Type-Options "nosniff" always; + + # Sent from upstream: + # add_header X-Frame-Options "SAMEORIGIN"; + # add_header X-XSS-Protection "1; mode=block"; + + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header X-Forwarded-Proto $scheme; + + proxy_buffering off; + proxy_http_version 1.1; + proxy_pass http://partkeepr; + proxy_redirect off; + + chunked_transfer_encoding off; + } +} diff --git a/ansible/roles/http/templates/nginx/sites/pi.bdebyl.net.conf.j2 b/ansible/roles/http/templates/nginx/sites/pi.bdebyl.net.conf.j2 index 630823f..473c5bd 100644 --- a/ansible/roles/http/templates/nginx/sites/pi.bdebyl.net.conf.j2 +++ b/ansible/roles/http/templates/nginx/sites/pi.bdebyl.net.conf.j2 @@ -5,6 +5,9 @@ # server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + listen 80; listen [::]:80; diff --git a/ansible/roles/http/templates/nginx/sites/video.bdebyl.net.conf.j2 b/ansible/roles/http/templates/nginx/sites/video.bdebyl.net.conf.j2 new file mode 100644 index 0000000..b7a6d70 --- /dev/null +++ b/ansible/roles/http/templates/nginx/sites/video.bdebyl.net.conf.j2 @@ -0,0 +1,24 @@ +upstream shinobi { + server 127.0.0.1:8085; +} + +server { + modsecurity on; + modsecurity_rules_file {{ nginx_path }}/modsec_includes.conf; + + listen 80; + server_name {{ video_server_name }}; + + location / { + allow 192.168.1.0/24; + allow 127.0.0.1; + deny all; + + proxy_set_header X-Forwarded-For $remote_addr; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + + proxy_buffering off; + proxy_pass http://shinobi; + } +} \ No newline at end of file diff --git a/ansible/roles/motion/defaults/main.yml b/ansible/roles/motion/defaults/main.yml index df8a412..870fe9a 100644 --- a/ansible/roles/motion/defaults/main.yml +++ b/ansible/roles/motion/defaults/main.yml @@ -1,6 +1,2 @@ --- -deps: [ - motion -] - -motion_target_dir: "{{ nfs_root }}/motion" +deps: ["cifs-utils"] diff --git a/ansible/roles/motion/meta/main.yml b/ansible/roles/motion/meta/main.yml index d8bd180..ed97d53 100644 --- a/ansible/roles/motion/meta/main.yml +++ b/ansible/roles/motion/meta/main.yml @@ -1,3 +1 @@ --- -dependencies: - - role: nfs diff --git a/ansible/roles/motion/tasks/deps.yml b/ansible/roles/motion/tasks/deps.yml index 3eab821..af84294 100644 --- a/ansible/roles/motion/tasks/deps.yml +++ b/ansible/roles/motion/tasks/deps.yml @@ -1,7 +1,9 @@ --- -- name: install motion +- name: install shinobi dependencies become: true pacman: name: "{{ deps }}" state: present - tags: deps + tags: + - deps + - motion diff --git a/ansible/roles/motion/tasks/motion.yml b/ansible/roles/motion/tasks/motion.yml index 4be23e5..2ebd2cc 100644 --- a/ansible/roles/motion/tasks/motion.yml +++ b/ansible/roles/motion/tasks/motion.yml @@ -1,51 +1,50 @@ --- -- name: give motion user nfs permissions +- name: create shinobi user become: true user: - name: motion - groups: "{{ nfs_group }}" - append: true - notify: - - restart_motion + name: "{{ motion_user }}" + shell: /bin/nologin + tags: motion -- name: create motion directory +- name: mount shinob videos folder become: true file: - path: "{{ motion_target_dir }}" + path: /mnt/shinobi state: directory - owner: "{{ nfs_user }}" - group: "{{ nfs_group }}" - mode: 0777 + owner: "{{ motion_user }}" + group: "{{ motion_user }}" + mode: 0755 + tags: motion -- name: template motion config +- name: mount smb via cifs become: true - template: - src: templates/motion.conf.j2 - dest: /etc/motion/motion.conf - mode: 0644 - backup: true - notify: - - restart_motion + mount: + path: /mnt/shinobi + src: "//{{ motion_hostname }}/share/GardenCamera" + fstype: cifs + # yamllint disable-line rule:line-length + opts: "username={{ motion_user }},password={{ motion_pass }},workgroup=workgroup,iocharset=utf8,uid={{ motion_user }},gid={{ motion_user }}" + state: mounted + tags: motion -- name: create motion systemd override directory +- name: create shinobi data volume become: true - file: - path: /etc/systemd/system/motion.service.d/ - state: directory - mode: 0644 + docker_volume: + name: shinobi_data + tags: motion -- name: template motion systemd override - become: true - template: - src: templates/motion.service.override.j2 - dest: /etc/systemd/system/motion.service.d/override.conf - mode: 0644 - notify: - - restart_motion - -- name: enable (now) motion.service - become: true - service: - name: motion.service - state: stopped - enabled: false +- name: create shinobi server container + diff: false + docker_container: + name: shinobi + image: migoller/shinobidocker:latest + recreate: true + restart: true + restart_policy: on-failure + restart_retries: 3 + volumes: + - "shinobi_data:/var/lib/mysql" + - "/mnt/shinobi:/opt/shinobi/videos" + ports: + - "8085:8080" + tags: motion diff --git a/ansible/roles/motion/templates/motion.conf.j2 b/ansible/roles/motion/templates/motion.conf.j2 deleted file mode 100644 index 1249a58..0000000 --- a/ansible/roles/motion/templates/motion.conf.j2 +++ /dev/null @@ -1,171 +0,0 @@ -# Rename this distribution example file to motion.conf -# -# This config file was generated by motion 4.3.2 -# Documentation: /usr/share/doc/motion/motion_guide.html -# -# This file contains only the basic configuration options to get a -# system working. There are many more options available. Please -# consult the documentation for the complete list of all options. -# - -############################################################ -# System control configuration parameters -############################################################ - -# Start in daemon (background) mode and release terminal. -daemon on - -# Start in Setup-Mode, daemon disabled. -setup_mode off - -# File to store the process ID. -; pid_file value - -# File to write logs messages into. If not defined stderr and syslog is used. -; log_file value - -# Level of log messages [1..9] (EMG, ALR, CRT, ERR, WRN, NTC, INF, DBG, ALL). -log_level 6 - -# Target directory for pictures, snapshots and movies -target_dir {{ motion_target_dir }} - -# Video device (e.g. /dev/video0) to be used for capturing. -; videodevice /dev/video0 - -# Parameters to control video device. See motion_guide.html -; vid_control_params value - -# The full URL of the network camera stream. -netcam_url rtsp://{{ motion_hostname }}:{{ motion_port }}/h264?username={{ motion_user }}&password={{ motion_pass }} - -# Name of mmal camera (e.g. vc.ril.camera for pi camera). -; mmalcam_name value - -# Camera control parameters (see raspivid/raspistill tool documentation) -; mmalcam_control_params value - -############################################################ -# Image Processing configuration parameters -############################################################ - -# Image width in pixels. -width 3840 - -# Image height in pixels. -height 2160 - -# Maximum number of frames to be captured per second. -framerate 20 - -# Text to be overlayed in the lower left corner of images -text_left NatureCam - -# Text to be overlayed in the lower right corner of images. -text_right %Y-%m-%d\n%T-%q - -############################################################ -# Motion detection configuration parameters -############################################################ - -# Always save pictures and movies even if there was no motion. -emulate_motion off - -# Threshold for number of changed pixels that triggers motion. -threshold 165900 - -# Noise threshold for the motion detection. -; noise_level 32 - -# Despeckle the image using (E/e)rode or (D/d)ilate or (l)abel. -despeckle_filter EedDl - -# Number of images that must contain motion to trigger an event. -minimum_motion_frames 1 - -# Gap in seconds of no motion detected that triggers the end of an event. -event_gap 60 - -# The number of pre-captured (buffered) pictures from before motion. -pre_capture 80 - -# Number of frames to capture after motion is no longer detected. -post_capture 300 - -############################################################ -# Script execution configuration parameters -############################################################ - -# Command to be executed when an event starts. -; on_event_start value - -# Command to be executed when an event ends. -; on_event_end value - -# Command to be executed when a movie file is closed. -; on_movie_end value - -############################################################ -# Picture output configuration parameters -############################################################ - -# Output pictures when motion is detected -picture_output off - -# File name(without extension) for pictures relative to target directory -picture_filename %Y%m%d%H%M%S-%q - -############################################################ -# Movie output configuration parameters -############################################################ - -# Create movies of motion events. -movie_output on - -# Maximum length of movie in seconds. -movie_max_time 30 - -# The encoding quality of the movie. (0=use bitrate. 1=worst quality, 100=best) -movie_quality 45 - -# Container/Codec to used for the movie. See motion_guide.html -movie_codec mp4 - -# File name(without extension) for movies relative to target directory -movie_filename %Y%m%d-%H_%M_%S - -############################################################ -# Webcontrol configuration parameters -############################################################ - -# Port number used for the webcontrol. -webcontrol_port 8080 - -# Restrict webcontrol connections to the localhost. -webcontrol_localhost on - -# Type of configuration options to allow via the webcontrol. -webcontrol_parms 0 - -############################################################ -# Live stream configuration parameters -############################################################ - -# The port number for the live stream. -stream_port 8081 - -# Restrict stream connections to the localhost. -stream_localhost on - -############################################################## -# Camera config files - One for each camera. -############################################################## -; camera /usr/etc/motion/camera1.conf -; camera /usr/etc/motion/camera2.conf -; camera /usr/etc/motion/camera3.conf -; camera /usr/etc/motion/camera4.conf - -############################################################## -# Directory to read '.conf' files for cameras. -############################################################## -; camera_dir /usr/etc/motion/conf.d diff --git a/ansible/roles/motion/templates/motion.service.override.j2 b/ansible/roles/motion/templates/motion.service.override.j2 deleted file mode 100644 index 78422bb..0000000 --- a/ansible/roles/motion/templates/motion.service.override.j2 +++ /dev/null @@ -1,2 +0,0 @@ -[Service] -User={{ nfs_user }} diff --git a/ansible/roles/ssl/tasks/certbot.yml b/ansible/roles/ssl/tasks/certbot.yml index 34afbfa..72b4391 100644 --- a/ansible/roles/ssl/tasks/certbot.yml +++ b/ansible/roles/ssl/tasks/certbot.yml @@ -1,8 +1,16 @@ --- +- name: stat dhparam + become: true + stat: + path: /etc/ssl/certs/dhparam.pem + register: dhparam + tags: ssl + - name: generate openssl dhparam for nginx become: true command: | openssl dhparam -out /etc/ssl/certs/dhparam.pem 2048 + when: not dhparam.stat.exists args: creates: /etc/ssl/certs/dhparam.pem tags: ssl @@ -10,9 +18,12 @@ - name: create ssl certificate for ci server become: true command: | - certbot certonly --webroot --webroot-path=/srv/http \ - -m {{ ci_server_email }} --agree-tos \ - -d {{ ci_server_name }} + certbot certonly --webroot --webroot-path=/srv/http/letsencrypt \ + -m {{ ssl_email }} --agree-tos \ + -d {{ item }} args: - creates: "/etc/letsencrypt/live/{{ ci_server_name }}" + creates: "/etc/letsencrypt/live/{{ item }}" + loop: + - "{{ ci_server_name }}" + - "{{ parts_server_name }}" tags: ssl diff --git a/ansible/vars/vault.yml b/ansible/vars/vault.yml index 511ae70..d34358f 100644 Binary files a/ansible/vars/vault.yml and b/ansible/vars/vault.yml differ