Verified Commit 0cf210bc authored by Lukas Schauer's avatar Lukas Schauer 🔓

initial commit

parents
group_vars/
host_vars/
hosts
[submodule "roles/nginx"]
path = roles/nginx
url = https://git.fslab.de/virtual-university/ansible-roles/nginx.git
[submodule "roles/common"]
path = roles/common
url = https://git.fslab.de/virtual-university/ansible-roles/common.git
[submodule "roles/videoportal/files/videoportal"]
path = roles/videoportal/files/videoportal
url = git@git.fslab.de:virtual-university/videoportal.git
# Videoportal Ansible
execute example:
ansible-playbook -u root -i hosts site.yml -t videoportal-code -l videoportal
tag and limits are optional, but recommended because deploying all services on all hosts takes ages.
Example `hosts`:
```
[jitsi-master]
[videoportal]
lectures.fslab.de
[videoportal-worker]
worker01.lectures.fslab.de worker_key=secr4t ansible_host=lectures.fslab.de
worker02.lectures.fslab.de worker_key=secr5t ansible_host=10.20.131.13
worker03.lectures.fslab.de worker_key=secr6t ansible_host=172.25.9.102 ansible_ssh_extra_args="-J root@orion.kurz.pw"
[videoportal-cdn]
cdn01.lectures.fslab.de videoportal_cdn_maxsize=15
```
Example `group_vars/all.yml`:
```
videoportal_secret_key: 'secr1t'
videoportal_cdn_password: 'secr2t'
videoportal_db_password: 'secr3t'
videoportal_debug: no
authorized_keys: |
# lukas
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIH7W3NIGeEGRHu63+dP7s6M5/s0uHODI4QV2Y1yOzDEq lukas2511
```
Example `host_vars/lectures.fslab.de`:
```
extra_hostnames:
- cdn00.lectures.fslab.de
email_host: some.server.example.com
email_host_user: 'noreply@example.com'
email_host_password: 'secr0t'
```
Subproject commit b985898fe70fd3354936059e615b0c6d0fe43406
Subproject commit 06ef545efda9dfdebd121e9dd4f33fb098c93af4
- name: Configure nginx
template:
src: "{{ item }}.conf.j2"
dest: "/etc/nginx/{{ item }}-conf.d/cdn.conf"
with_items:
- "http"
- "server"
register: nginxconf
- name: Reload nginx
command: systemctl reload nginx
when: nginxconf.changed
proxy_cache_path /var/lib/nginx/cache levels=1:2 keys_zone=STATIC:10m inactive=72h max_size={% if videoportal_cdn_maxsize is defined %}{{ videoportal_cdn_maxsize }}{% else %}10{% endif %}g;
resolver 8.8.8.8;
{% if inventory_hostname in groups['videoportal-cdn'] %}
proxy_buffering on;
proxy_cache STATIC;
{% else %}
proxy_buffering off;
proxy_cache off;
{% endif %}
proxy_hide_header "Strict-Transport-Security";
proxy_cache_valid 200 7d;
proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504;
proxy_cache_bypass $arg_nocache;
proxy_cache_key "$scheme$proxy_host$uri$is_args$args";
location /check_key {
internal;
proxy_pass https://lectures.fslab.de/api/check_key;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header "X-Original-URI" "$request_uri";
proxy_buffering off;
proxy_cache off;
}
location ~ ^/(?<lecture>[0-9]+)/(?<video>[0-9]+)/attachments/(?<attachment>[^/]+)$ {
auth_request /check_key;
add_header "X-Cache-Status" "$upstream_cache_status";
#add_header "Content-Disposition" "attachment; filename=${lecture}_${video}_${attachment}";
proxy_pass https://lectures.fslab.de/uploads/$lecture/$video/attachments/$attachment;
proxy_set_header Authorization "Basic {{ ('cdn:' + videoportal_cdn_password) | b64encode }}";
}
location ~ ^/(?<lecture>[0-9]+)/(?<video>[0-9]+)/thumbnail.jpg$ {
auth_request /check_key;
add_header "X-Cache-Status" "$upstream_cache_status";
proxy_pass https://lectures.fslab.de/uploads/$lecture/$video/thumbnail.jpg;
proxy_set_header Authorization "Basic {{ ('cdn:' + videoportal_cdn_password) | b64encode }}";
}
location ~ ^/(?<lecture>[0-9]+)/(?<video>[0-9]+)/(?<file>[^/]+)$ {
auth_request /check_key;
add_header "X-Cache-Status" "$upstream_cache_status";
add_header "Content-Disposition" "attachment; filename=${lecture}_${video}_${file}";
proxy_cache_key "$scheme$proxy_host$uri";
proxy_pass https://lectures.fslab.de/uploads/$lecture/$video/$file;
proxy_set_header Authorization "Basic {{ ('cdn:' + videoportal_cdn_password) | b64encode }}";
}
location ~ ^/(?<lecture>[0-9]+)/attachments/(?<attachment>[^/]+)$ {
auth_request /check_key;
add_header "X-Cache-Status" "$upstream_cache_status";
#add_header "Content-Disposition" "attachment; filename=${lecture}_${attachment}";
proxy_pass https://lectures.fslab.de/uploads/$lecture/attachments/$attachment;
proxy_set_header Authorization "Basic {{ ('cdn:' + videoportal_cdn_password) | b64encode }}";
}
- name: Generate Firewall rules
template:
src: "rules.{{ item }}.j2"
dest: "/etc/iptables/rules.{{ item }}"
with_items:
- v4
- v6
register: firewallconf
- name: Apply firewall rules
command: /etc/init.d/netfilter-persistent reload
when: firewallconf.changed
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -p udp --dport 13337 -j ACCEPT
-A INPUT -j REJECT
COMMIT
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmpv6 -j ACCEPT
-A INPUT -p tcp --dport 22 -j ACCEPT
-A INPUT -p tcp --dport 80 -j ACCEPT
-A INPUT -p tcp --dport 443 -j ACCEPT
-A INPUT -j REJECT
COMMIT
- name: Install dependencies
apt:
name:
- ffmpeg
- python3
- python3-requests
- progress
default_release: buster-backports
state: present
- name: Download latest worker script
get_url:
url: "https://lectures.fslab.de/api/update?key={{ worker_key }}"
dest: /usr/local/bin/worker.py
mode: "0700"
register: workerscript
- name: Configure systemd unit
template:
src: worker.service.j2
dest: /etc/systemd/system/worker.service
register: workerunit
- name: Enable systemd unit
systemd:
name: worker
enabled: yes
- name: Restart worker
systemd:
name: worker
state: restarted
daemon_reload: yes
when: workerscript.changed or workerunit.changed
[Unit]
Description=lectures.fslab.de worker
After=networking.target
[Service]
ExecStart=/usr/bin/python3 -u /usr/local/bin/worker.py
[Install]
WantedBy=multi-user.target
client_max_body_size 10000M;
access_log off;
location /uploads {
auth_basic "CDN Auth Required";
auth_basic_user_file /etc/nginx/cdn.htpasswd;
alias /var/lib/videoportal/uploads;
expires 7d;
}
location /static {
alias /var/lib/videoportal/static;
expires 1d;
}
location / {
uwsgi_pass unix:///run/videoportal.sock;
include uwsgi_params;
expires -1s;
}
[uwsgi]
chdir = /opt/videoportal
module = videoportal.wsgi
plugins = python3
uid = www-data
gid = www-data
master = true
processes = 10
socket = /run/videoportal.sock
vacuum = true
Subproject commit 92376fcb964985f3aba30a0b4e582615e0d032e5
- name: Install python dependencies
apt:
name:
- python3
- python3-django
- python3-django-auth-ldap
- python3-pil
- python3-passlib
- python3-psycopg2
- python-passlib
- python-psycopg2
- libjs-jquery
- uwsgi
- uwsgi-plugin-python3
state: latest
default_release: buster-backports
- name: Install postgresql
apt:
name:
- postgresql-11
state: latest
default_release: buster-backports
- name: Create postgresql user
postgresql_user:
name: lectures
password: "{{ videoportal_db_password }}"
become: yes
become_user: postgres
- name: Create postgresql database
postgresql_db:
name: lectures
owner: lectures
become: yes
become_user: postgres
- name: Synchronize videoportal sources
synchronize:
src: videoportal/
dest: /opt/videoportal/
archive: False
recursive: yes
links: yes
delete: yes
owner: no
group: no
perms: yes
times: no
checksum: yes
rsync_opts:
- "--exclude=uploads/"
- "--exclude=.git/"
- "--exclude=videoportal/settings.py"
- "--exclude=db.sqlite3"
register: videoportalfiles
- name: Configure videoportal
template:
src: settings.py.j2
dest: /opt/videoportal/videoportal/settings.py
- name: Create directories
file:
state: directory
owner: www-data
group: www-data
path: "{{ item }}"
with_items:
- "/var/lib/videoportal"
- "/var/lib/videoportal/static"
- "/var/lib/videoportal/uploads"
- name: Migrate database
command: /opt/videoportal/manage.py migrate
when: videoportalfiles.changed
become: yes
become_user: www-data
- name: Collect static files
command: /opt/videoportal/manage.py collectstatic --noinput
when: videoportalfiles.changed
become: yes
become_user: www-data
- name: Copy uwsgi config
copy:
src: uwsgi.ini
dest: /etc/uwsgi/apps-enabled/videoportal.ini
register: uwsgiconfig
- name: Restart uwsgi
command: systemctl restart uwsgi
when: uwsgiconfig.changed or videoportalfiles.changed
- name: Create htpasswd file
htpasswd:
path: /etc/nginx/cdn.htpasswd
name: cdn
password: '{{ videoportal_cdn_password }}'
owner: root
group: www-data
mode: 0640
register: nginxpasswd
- name: Copy nginx config
copy:
src: nginx.conf
dest: /etc/nginx/server-conf.d/videoportal.conf
register: nginxconf
- name: Reload nginx
command: systemctl reload nginx
when: nginxconf.changed or nginxpasswd.changed
import os
BASE_DIR = "/opt/videoportal"
SECRET_KEY = '{{ videoportal_secret_key }}'
CDN_PASSWORD = '{{ videoportal_cdn_password }}'
EMAIL_DOMAINS = [{% if videoportal_email_blacklist is defined %}{% for entry in videoportal_email_domains %}'{{ entry }}', {% endfor %}{% endif %}]
EMAIL_BLACKLIST = [{% if videoportal_email_blacklist is defined %}{% for entry in videoportal_email_blacklist %}'{{ entry }}', {% endfor %}{% endif %}]
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_TLS = True
EMAIL_HOST = '{{ email_host }}'
EMAIL_PORT = 587
EMAIL_HOST_USER = '{{ email_host_user }}'
EMAIL_HOST_PASSWORD = '{{ email_host_password }}'
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = {% if videoportal_debug is defined and videoportal_debug %}True{% else %}False{% endif %}
ALLOWED_HOSTS = ['lectures.fslab.de']
INSTALLED_APPS = [
'fhuser.apps.FhuserConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'videos',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'videoportal.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'videos.context_processors.media_url',
],
},
},
]
WSGI_APPLICATION = 'videoportal.wsgi.application'
# database
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'lectures',
'USER': 'lectures',
'PASSWORD': '{{ videoportal_db_password }}',
'HOST': 'localhost',
'PORT': '',
}
}
# internationalization
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'Europe/Berlin'
USE_I18N = True
DATE_FORMAT = 'd.m.Y'
DATETIME_FORMAT = 'd.m.Y H:i:s'
USE_L10N = False
USE_TZ = True
# authentication
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}
]
AUTH_USER_MODEL = 'fhuser.User'
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend',
'fhuser.ldap.CustomLDAPBackend',
]
import ldap
from django_auth_ldap.config import LDAPSearch, LDAPGroupQuery, PosixGroupType
AUTH_LDAP_SERVER_URI = "ldap://ldap.inf.fh-bonn-rhein-sieg.de:389"
AUTH_LDAP_START_TLS = True
AUTH_LDAP_USER_SEARCH = LDAPSearch("dc=fb02,dc=fh-bonn-rhein-sieg,dc=de", ldap.SCOPE_SUBTREE, "(uid=%(user)s)")
AUTH_LDAP_ALWAYS_UPDATE_USER = True
AUTH_LDAP_GLOBAL_OPTIONS = {
ldap.OPT_X_TLS_CACERTFILE: os.path.join(BASE_DIR, "videoportal/fb-ca.pem"),
}
AUTH_LDAP_USER_ATTR_MAP = {
"first_name": "givenName",
"last_name": "sn",
"email": "mail",
"user_class": "class"
}
AUTH_LDAP_GROUP_TYPE = PosixGroupType()
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(
"ou=groups,dc=fb02,dc=FH-Bonn-Rhein-Sieg,dc=DE", ldap.SCOPE_SUBTREE, "(objectClass=posixGroup)"
)
AUTH_LDAP_USER_FLAGS_BY_GROUP = {
"is_staff": LDAPGroupQuery("cn=fsl-admin,ou=fsl,ou=posix,ou=groups,dc=fb02,dc=FH-Bonn-Rhein-Sieg,dc=DE"),
"is_superuser": LDAPGroupQuery("cn=fsl-admin,ou=fsl,ou=posix,ou=groups,dc=fb02,dc=FH-Bonn-Rhein-Sieg,dc=DE"),
}
# static files
STATIC_URL = '/static/'
STATIC_ROOT = "/var/lib/videoportal/static"
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
# uploads
MEDIA_URL = 'https://lectures.fslab.de/cdn/'
MEDIA_ROOT = "/var/lib/videoportal/uploads"
# logging
if DEBUG:
LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {"console": {"class": "logging.StreamHandler"}},
"loggers": {"django_auth_ldap": {"level": "DEBUG", "handlers": ["console"]}},
}
EMAIL_DOMAINS.append('@schauer.so')
EMAIL_DOMAINS.append('@inf.h-brs.de')
---
- hosts: videoportal
roles:
- { role: common, tags: ['common'] }
- { role: videoportal-firewall, tags: ['firewall'] }
- { role: nginx, tags: ['nginx'] }
- { role: videoportal, tags: ['videoportal', 'videoportal-code'] }
- { role: videoportal-cdn, tags: ['videoportal', 'videoportal-cdn'] }
- hosts: videoportal-cdn
roles:
- { role: common, tags: ['common'] }
- { role: videoportal-firewall, tags: ['firewall'] }
- { role: nginx, tags: ['nginx'] }
- { role: videoportal-cdn, tags: ['videoportal', 'videoportal-cdn'] }
- hosts: videoportal-worker
roles:
- { role: videoportal-worker, tags: ['videoportal', 'videoportal-worker'] }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment