mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-06-25 11:45:32 +02:00
Compare commits
7 Commits
1ed26ab706
...
cfc052c129
Author | SHA1 | Date | |
---|---|---|---|
cfc052c129 | |||
20c3fdd455 | |||
68287c3c66 | |||
716c1c40e9 | |||
aa4d54c0c2 | |||
0ca33139b8 | |||
0114b30824 |
@ -2,7 +2,7 @@
|
|||||||
defaults_service_provider:
|
defaults_service_provider:
|
||||||
type: "legal" # Accepted Values: natural, legal
|
type: "legal" # Accepted Values: natural, legal
|
||||||
company:
|
company:
|
||||||
titel: "CyMaIS GbR"
|
titel: "CyMaIS by Kevin Veen-Birkenbach"
|
||||||
slogan: "CyMaIS — Empowering a Sovereign Digital Future."
|
slogan: "CyMaIS — Empowering a Sovereign Digital Future."
|
||||||
address:
|
address:
|
||||||
street: "Binary Avenue 01"
|
street: "Binary Avenue 01"
|
||||||
|
15
main.py
15
main.py
@ -162,12 +162,17 @@ if __name__ == "__main__":
|
|||||||
text=True
|
text=True
|
||||||
)
|
)
|
||||||
os.close(slave_fd)
|
os.close(slave_fd)
|
||||||
|
import errno
|
||||||
with os.fdopen(master_fd) as master:
|
with os.fdopen(master_fd) as master:
|
||||||
for line in master:
|
try:
|
||||||
ts = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
|
for line in master:
|
||||||
log_file.write(f"{ts} {line}")
|
ts = datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
|
||||||
log_file.flush()
|
log_file.write(f"{ts} {line}")
|
||||||
print(line, end='')
|
log_file.flush()
|
||||||
|
print(line, end='')
|
||||||
|
except OSError as e:
|
||||||
|
if e.errno != errno.EIO:
|
||||||
|
raise
|
||||||
proc.wait()
|
proc.wait()
|
||||||
rc = proc.returncode
|
rc = proc.returncode
|
||||||
else:
|
else:
|
||||||
|
@ -1,16 +1,27 @@
|
|||||||
|
- name: Check if docker is installed
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /usr/bin/docker
|
||||||
|
register: docker_bin
|
||||||
|
|
||||||
- name: "pkgmgr install"
|
- name: "pkgmgr install"
|
||||||
include_role:
|
include_role:
|
||||||
name: pkgmgr-install
|
name: pkgmgr-install
|
||||||
vars:
|
vars:
|
||||||
package_name: dockreap
|
package_name: dockreap
|
||||||
when: run_once_cleanup_docker_anonymous_volumes is not defined
|
when:
|
||||||
|
- run_once_cleanup_docker_anonymous_volumes is not defined
|
||||||
|
- docker_bin.stat.exists
|
||||||
|
|
||||||
- name: run dockreap with --no-confirmation
|
- name: run dockreap with --no-confirmation
|
||||||
command:
|
command:
|
||||||
cmd: "dockreap --no-confirmation"
|
cmd: "dockreap --no-confirmation"
|
||||||
when: run_once_cleanup_docker_anonymous_volumes is not defined
|
when:
|
||||||
|
- run_once_cleanup_docker_anonymous_volumes is not defined
|
||||||
|
- docker_bin.stat.exists
|
||||||
|
|
||||||
- name: mark dockreap as run
|
- name: mark dockreap as run
|
||||||
set_fact:
|
set_fact:
|
||||||
run_once_cleanup_docker_anonymous_volumes: true
|
run_once_cleanup_docker_anonymous_volumes: true
|
||||||
when: run_once_cleanup_docker_anonymous_volumes is not defined
|
when:
|
||||||
|
- run_once_cleanup_docker_anonymous_volumes is not defined
|
||||||
|
- docker_bin.stat.exists
|
||||||
|
5
roles/docker-nextcloud/Administration.md
Normal file
5
roles/docker-nextcloud/Administration.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Administration
|
||||||
|
|
||||||
|
## Logs
|
||||||
|
|
||||||
|
The logs you will find here on the host: **/var/lib/docker/volumes/nextcloud_data/_data/data/nextcloud.log**
|
@ -49,7 +49,7 @@ http {
|
|||||||
# will add the domain to a hardcoded list that is shipped
|
# will add the domain to a hardcoded list that is shipped
|
||||||
# in all major browsers and getting removed from this list
|
# in all major browsers and getting removed from this list
|
||||||
# could take several months.
|
# could take several months.
|
||||||
#add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
|
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains; preload;" always;
|
||||||
|
|
||||||
# set max upload size
|
# set max upload size
|
||||||
client_max_body_size 512M;
|
client_max_body_size 512M;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
configuration_file: "oauth2-proxy-keycloak.cfg" # Needs to be set true in the roles which use it
|
configuration_file: "oauth2-proxy-keycloak.cfg" # Needs to be set true in the roles which use it
|
||||||
version: "latest" # Docker Image version
|
version: "latest" # Docker Image version
|
||||||
allowed_roles: admin # Restrict it default to admin role. Use the vars/main.yml to open the specific role for other groups
|
allowed_roles: "admin" # Restrict it default to admin role. Use the vars/main.yml to open the specific role for other groups
|
||||||
features:
|
features:
|
||||||
matomo: true
|
matomo: true
|
||||||
css: true
|
css: true
|
||||||
|
@ -2,6 +2,11 @@ version: "13" # Update when available. Sadly no rolling release
|
|||||||
oauth2_proxy:
|
oauth2_proxy:
|
||||||
application: "proxy"
|
application: "proxy"
|
||||||
port: "80"
|
port: "80"
|
||||||
|
acl:
|
||||||
|
whitelist:
|
||||||
|
- "/users/me" # Necessary for Nextcloud Plugin to work
|
||||||
|
- "/api/" # Necessary for Nextcloud Plugin to work
|
||||||
|
- "/oauth/token" # Necessary for Nextcloud Plugin to work
|
||||||
ldap:
|
ldap:
|
||||||
filters:
|
filters:
|
||||||
administrators: True # Set true to filter administrators
|
administrators: True # Set true to filter administrators
|
||||||
|
@ -114,5 +114,8 @@ class LookupModule(LookupBase):
|
|||||||
|
|
||||||
cards.append(card)
|
cards.append(card)
|
||||||
|
|
||||||
|
# Sort A-Z
|
||||||
|
cards.sort(key=lambda c: c['title'].lower())
|
||||||
|
|
||||||
# Return the list of cards
|
# Return the list of cards
|
||||||
return [cards]
|
return [cards]
|
||||||
|
@ -43,9 +43,10 @@
|
|||||||
- name: Debug portfolio data
|
- name: Debug portfolio data
|
||||||
debug:
|
debug:
|
||||||
msg:
|
msg:
|
||||||
portfolio_cards: "{{ portfolio_cards }}"
|
portfolio_cards: "{{ portfolio_cards }}"
|
||||||
portfolio_menu_categories: "{{ portfolio_menu_categories}}"
|
portfolio_menu_categories: "{{ portfolio_menu_categories}}"
|
||||||
portfolio_menu_data: "{{ portfolio_menu_data }}"
|
portfolio_menu_data: "{{ portfolio_menu_data }}"
|
||||||
|
service_provider: "{{ service_provider }}"
|
||||||
when:
|
when:
|
||||||
- enable_debug | bool
|
- enable_debug | bool
|
||||||
- run_once_docker_portfolio is not defined
|
- run_once_docker_portfolio is not defined
|
||||||
|
@ -93,7 +93,7 @@ platform:
|
|||||||
source: {{service_provider.platform.favicon}}
|
source: {{service_provider.platform.favicon}}
|
||||||
company:
|
company:
|
||||||
titel: {{service_provider.company.titel}}
|
titel: {{service_provider.company.titel}}
|
||||||
subtitel: {{service_provider.company.subtitel}}
|
subtitel: {{service_provider.company.slogan}}
|
||||||
logo:
|
logo:
|
||||||
source: {{service_provider.company.logo}}
|
source: {{service_provider.company.logo}}
|
||||||
address:
|
address:
|
||||||
|
@ -5,7 +5,9 @@ version: "latest"
|
|||||||
oauth2_proxy:
|
oauth2_proxy:
|
||||||
application: "application"
|
application: "application"
|
||||||
port: "80"
|
port: "80"
|
||||||
location: "/admin/" # Protects the admin area
|
acl:
|
||||||
|
blacklist:
|
||||||
|
- "/admin/" # Protects the admin area
|
||||||
features:
|
features:
|
||||||
matomo: true
|
matomo: true
|
||||||
css: true
|
css: true
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
- name: reload health-msmtp.cymais.service
|
- name: "reload health-journalctl.cymais.service"
|
||||||
systemd:
|
systemd:
|
||||||
name: health-msmtp.cymais.service
|
name: health-journalctl.cymais.service
|
||||||
enabled: yes
|
enabled: yes
|
||||||
daemon_reload: yes
|
daemon_reload: yes
|
@ -1,5 +1,5 @@
|
|||||||
- name: "reload health-journalctl.cymais.service"
|
- name: reload health-msmtp.cymais.service
|
||||||
systemd:
|
systemd:
|
||||||
name: health-journalctl.cymais.service
|
name: health-msmtp.cymais.service
|
||||||
enabled: yes
|
enabled: yes
|
||||||
daemon_reload: yes
|
daemon_reload: yes
|
@ -15,21 +15,47 @@ server
|
|||||||
|
|
||||||
{% include 'roles/letsencrypt/templates/ssl_header.j2' %}
|
{% include 'roles/letsencrypt/templates/ssl_header.j2' %}
|
||||||
|
|
||||||
{% if applications | is_feature_enabled('oauth2',application_id) %}
|
{% if applications | is_feature_enabled('oauth2', application_id) %}
|
||||||
{% if applications[application_id].oauth2_proxy.location is defined %}
|
{% set acl = applications[application_id].oauth2_proxy.acl | default({}) %}
|
||||||
{# Exposed and Unprotected Location #}
|
|
||||||
|
{% if acl.blacklist is defined %}
|
||||||
|
{# 1. Expose everything by default, then protect blacklisted paths #}
|
||||||
|
{% set oauth2_proxy_enabled = false %}
|
||||||
|
{% set location = "/" %}
|
||||||
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
||||||
|
|
||||||
|
{% for loc in acl.blacklist %}
|
||||||
|
{% set oauth2_proxy_enabled = true %}
|
||||||
|
{% set location = loc %}
|
||||||
|
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% elif acl.whitelist is defined %}
|
||||||
|
{# 2. Protect everything by default, then expose whitelisted paths #}
|
||||||
{% set oauth2_proxy_enabled = true %}
|
{% set oauth2_proxy_enabled = true %}
|
||||||
{% set location = applications[application_id].oauth2_proxy.location %}
|
{% set location = "/" %}
|
||||||
{# Gated Location by OAuth2 Proxy #}
|
|
||||||
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
||||||
|
|
||||||
|
{% for loc in acl.whitelist %}
|
||||||
|
{% set oauth2_proxy_enabled = false %}
|
||||||
|
{% set location = loc %}
|
||||||
|
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
{# 3. OAuth2 enabled but no (or empty) ACL — protect all #}
|
||||||
{% set oauth2_proxy_enabled = true %}
|
{% set oauth2_proxy_enabled = true %}
|
||||||
{# Protected Domain by OAuth2 Proxy #}
|
{% set location = "/" %}
|
||||||
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2'%}
|
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
{# Exposed Domain - Not protected by OAuth2 Proxy #}
|
{# 4. OAuth2 completely disabled — expose all #}
|
||||||
|
{% set oauth2_proxy_enabled = false %}
|
||||||
|
{% set location = "/" %}
|
||||||
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
{% include 'roles/nginx-docker-reverse-proxy/templates/location/proxy_basic.conf.j2' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1199,3 +1199,8 @@ input.ng-empty::placeholder,.ng-empty::placeholder {
|
|||||||
background-color: rgba(var(--color-rgb-01-75), 0.9);
|
background-color: rgba(var(--color-rgb-01-75), 0.9);
|
||||||
border-color: var(--color-01-67)
|
border-color: var(--color-01-67)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-info {
|
||||||
|
--bs-alert-color: var(--color-03-14);
|
||||||
|
--bs-alert-bg: var(--color-01-86);
|
||||||
|
}
|
@ -12,9 +12,9 @@ server
|
|||||||
location /
|
location /
|
||||||
{
|
{
|
||||||
alias {{nginx.directories.data.files}}; {# Path to your file directory #}
|
alias {{nginx.directories.data.files}}; {# Path to your file directory #}
|
||||||
autoindex on; {# Enable directory listing #}
|
autoindex on; {# Enable directory listing #}
|
||||||
autoindex_exact_size off; {# Display sizes in a human-readable format #}
|
autoindex_exact_size off; {# Display sizes in a human-readable format #}
|
||||||
autoindex_localtime on; {# Show local time #}
|
autoindex_localtime on; {# Show local time #}
|
||||||
}
|
}
|
||||||
|
|
||||||
location /.well-known/ {
|
location /.well-known/ {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<h2>Information in accordance with § 5 TMG</h2>
|
<h2>Information in accordance with § 5 TMG</h2>
|
||||||
<p>
|
<p>
|
||||||
<strong>{{ service_provider.company.titel }}</strong><br>
|
<strong>{{ service_provider.company.titel }}</strong><br>
|
||||||
{{ service_provider.company.subtitel }}<br>
|
{{ service_provider.company.slogan }}<br>
|
||||||
<br>
|
<br>
|
||||||
<strong>Address:</strong><br>
|
<strong>Address:</strong><br>
|
||||||
{{ service_provider.company.address.street }}<br>
|
{{ service_provider.company.address.street }}<br>
|
||||||
|
@ -35,3 +35,4 @@ galaxy_info:
|
|||||||
dependencies:
|
dependencies:
|
||||||
- git
|
- git
|
||||||
- make
|
- make
|
||||||
|
- python-yaml
|
||||||
|
20
roles/python-yaml/README.md
Normal file
20
roles/python-yaml/README.md
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Python-Yaml
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This Ansible role installs the **python-yaml** package on the target system. It ensures that the Python `yaml` library is available for loading and processing YAML files.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Optimized for simplicity and idempotency, this role provides:
|
||||||
|
- Installation of the `python-yaml` package via the Pacman package manager.
|
||||||
|
- A mechanism to run the installation only once.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
The purpose of this role is to reliably provide the Python-YAML package so that Python scripts can work with YAML files.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **YAML Support:** Installs the `python-yaml` package, which supplies the `yaml` library for Python.
|
||||||
|
- **Idempotency:** Uses a fact to ensure that the installation runs only on the first execution.
|
24
roles/python-yaml/meta/main.yml
Normal file
24
roles/python-yaml/meta/main.yml
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
galaxy_info:
|
||||||
|
author: "Kevin Veen-Birkenbach"
|
||||||
|
description: >
|
||||||
|
Installs the `python-yaml` package to enable YAML support in Python.
|
||||||
|
license: "CyMaIS NonCommercial License (CNCL)"
|
||||||
|
license_url: "https://s.veen.world/cncl"
|
||||||
|
company: |
|
||||||
|
Kevin Veen-Birkenbach
|
||||||
|
Consulting & Coaching Solutions
|
||||||
|
https://www.veen.world
|
||||||
|
min_ansible_version: "2.9"
|
||||||
|
platforms:
|
||||||
|
- name: Archlinux
|
||||||
|
versions:
|
||||||
|
- rolling
|
||||||
|
galaxy_tags:
|
||||||
|
- python
|
||||||
|
- yaml
|
||||||
|
- package
|
||||||
|
- installation
|
||||||
|
- automation
|
||||||
|
repository: "https://s.veen.world/cymais"
|
||||||
|
issue_tracker_url: "https://s.veen.world/cymaisissues"
|
||||||
|
documentation: "https://s.veen.world/cymais"
|
11
roles/python-yaml/tasks/main.yml
Normal file
11
roles/python-yaml/tasks/main.yml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
---
|
||||||
|
- name: python-yaml install
|
||||||
|
pacman:
|
||||||
|
name: python-yaml
|
||||||
|
state: present
|
||||||
|
when: run_once_python_yaml is not defined
|
||||||
|
|
||||||
|
- name: run the python_yaml tasks once
|
||||||
|
set_fact:
|
||||||
|
run_once_python_yaml: true
|
||||||
|
when: run_once_python_yaml is not defined
|
@ -35,7 +35,7 @@
|
|||||||
{{
|
{{
|
||||||
defaults_applications |
|
defaults_applications |
|
||||||
canonical_domains_map(primary_domain) |
|
canonical_domains_map(primary_domain) |
|
||||||
combine(domains | default({}, true), recursive=True)
|
combine(current_play_domains, recursive=True)
|
||||||
}}
|
}}
|
||||||
|
|
||||||
- name: Merge redirect_domain_mappings
|
- name: Merge redirect_domain_mappings
|
||||||
@ -44,7 +44,7 @@
|
|||||||
redirect_domain_mappings: "{{
|
redirect_domain_mappings: "{{
|
||||||
[] |
|
[] |
|
||||||
add_redirect_if_group('assets-server', domains | get_domain('assets-server'), domains | get_domain('file-server'), group_names) |
|
add_redirect_if_group('assets-server', domains | get_domain('assets-server'), domains | get_domain('file-server'), group_names) |
|
||||||
merge_mapping(redirect_domain_mappings, 'source')
|
merge_mapping(redirect_domain_mappings| default([]), 'source')
|
||||||
}}"
|
}}"
|
||||||
|
|
||||||
- name: Set current play redirect domain mappings
|
- name: Set current play redirect domain mappings
|
||||||
|
45
tests/integration/test_oauth2_acl_mutual_exclusive.py
Normal file
45
tests/integration/test_oauth2_acl_mutual_exclusive.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import os
|
||||||
|
import yaml
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROLES_DIR = Path(__file__).resolve().parent.parent.parent / "roles"
|
||||||
|
|
||||||
|
class TestOauth2AclMutualExclusion(unittest.TestCase):
|
||||||
|
def test_acl_has_either_whitelist_or_blacklist(self):
|
||||||
|
failures = []
|
||||||
|
|
||||||
|
for role_path in ROLES_DIR.iterdir():
|
||||||
|
vars_file = role_path / "vars" / "configuration.yml"
|
||||||
|
if not vars_file.exists():
|
||||||
|
continue
|
||||||
|
|
||||||
|
# open the YAML file instead of passing the Path object
|
||||||
|
try:
|
||||||
|
with open(vars_file) as f:
|
||||||
|
data = yaml.safe_load(f) or {}
|
||||||
|
except yaml.YAMLError as e:
|
||||||
|
failures.append(f"{role_path.name}: failed to parse YAML ({e})")
|
||||||
|
continue
|
||||||
|
|
||||||
|
oauth2 = data.get("oauth2_proxy", {})
|
||||||
|
acl = oauth2.get("acl", None)
|
||||||
|
if acl is None:
|
||||||
|
continue
|
||||||
|
|
||||||
|
has_wl = "whitelist" in acl
|
||||||
|
has_bl = "blacklist" in acl
|
||||||
|
|
||||||
|
if has_wl and has_bl:
|
||||||
|
failures.append(
|
||||||
|
f"{role_path.name}: both 'whitelist' and 'blacklist' are defined"
|
||||||
|
)
|
||||||
|
|
||||||
|
if failures:
|
||||||
|
self.fail(
|
||||||
|
"The following roles define both whitelist and blacklist under oauth2_proxy.acl:\n"
|
||||||
|
+ "\n".join(failures)
|
||||||
|
)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
Loading…
x
Reference in New Issue
Block a user