Git initial commit

This commit is contained in:
Lars Hahn 2023-08-20 10:30:41 +02:00
commit d225f220b5
259 changed files with 7059 additions and 0 deletions

9
LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

21
README.md Executable file
View File

@ -0,0 +1,21 @@
# cloud-environments-example
This repository contains an example environment structure to demonstrate, how the OpenDevChain Cloud repositories can be used.
For each relevant application there is one playbook provided; with
$ ansible-playbook <target-playbook>.yml
you should be able to execute and example playbook.
Please make shure, that at least URLs/DNS entries are correct, or remove the "letsencrypt: true" attribute from website configurations; otherwise runs will fail as letsencrypt is probably not correctly configured to resolve DNS to your server.
The initial roles are kept in this repository; for newer versions of Ansible Roles, please have a look at:
https://git.opendevchain.de/OpenDevChain
For any questions, please do not hesitate to reach out to me:
info@opendevchain.de
Regards

94
cloud-authentik.yml Executable file
View File

@ -0,0 +1,94 @@
- hosts: local
connection: local
roles:
- basis
- backup
- docker
- nginx
- authentik
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
authentik_db:
type: pgsql
name: authentik
user: authentikuser
pass: FancyGiteaDbPasswordVeryLong
authentik_secret_key: LookUpDocumentationForSettingUpKey
authentik_admin_pass: FancyInitialAdminPasswordVeryLong!
authentik_stmp_host: "{{ mail_domain }}"
authentik_stmp_port: "{{ mail_port }}"
authentik_smtp_from: "{{ noreply_mail_address }}"
authentik_smtp_user: "{{ auth_mail_address }}"
authentik_smtp_pass: "{{ auth_mail_pass }}"
authentik_smpt_usessl: "true"
authentik_https_port: 9443
authentik_website:
domain: "idp.{{ domain_external }}"
letsencrypt: true
state: present
owner: root
port: 80
root_setup: false
index: noindex
root: noroot
options:
access_log: "/var/log/nginx/idp.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/idp.{{ domain_external }}-error.log"
pre_options: |
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
locations:
- location: "/"
options: |
proxy_pass https://localhost:{{ authentik_https_port }};
proxy_http_version 1.1;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# This needs to be set inside the location block, very important.
proxy_set_header Host $host;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
authentik_ldaps:
domain: "idp.{{ domain_external }}"
filetag: "ldaps.idp.{{ domain_external }}"
letsencrypt: true
state: present
stream: true
owner: root
port: 3636
root_setup: false
index: noindex
root: noroot
options:
proxy_pass: localhost:389
# Websites
web_sites:
- "{{ authentik_website }}"
- "{{ authentik_ldaps }}"
# Backup
backup_targets:
file:
- "{{ gitea_data_location }}"
- "/etc/letsencrypt"
vars_files:
- "group_vars/environment.yml"

27
cloud-backup.yml Executable file
View File

@ -0,0 +1,27 @@
- hosts: local
connection: local
roles:
- basis
- backup
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
mount_points:
- path: /backup
dev: /dev/sdb
# backup
backup_client: false
backup_hosts:
- name: cloud-example-server
domain: "example-server.{{ domain_external }}"
vars_files:
- "group_vars/environment.yml"

79
cloud-gitea.yml Executable file
View File

@ -0,0 +1,79 @@
- hosts: local
connection: local
roles:
- basis
- backup
- postgres
- nginx
- gitea
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
mount_points:
- path: "{{ gitea_data_location }}"
dev: /dev/sdb
gitea_data_location: "{{ cloud_storage }}/gitea-data"
gitea_db:
type: pgsql
name: gitea
user: giteauser
pass: FancyGiteaDbPasswordVeryLong
gitea_ssh_domain: "git.{{ domain_external }}"
gitea_internal_token: LookUpDocumentationForSettingUpToken
gitea_jwt_secret: LookUpDocumentationForSettingUpSecret
gitea_secret_key: LookUpDocumentationForSettingUpKey
gitea_mail_domain: "{{ mail_domain }}"
gitea_mail_from: "{{ noreply_mail_address }}"
gitea_mail_user: "{{ development_mail_address }}"
gitea_mail_pass: "{{ development_mail_pass }}"
gitea_admin_user: "admin"
gitea_admin_pass: InitialGiteaPasswordPleaseChangeLater
gitea_admin_mail: "{{ gitea_mail_from }}"
gitea_website:
domain: "{{ gitea_ssh_domain }}"
letsencrypt: true
state: present
owner: gitea
port: 80
root_setup: false
index: noindex
root: noroot
options:
access_log: "/var/log/nginx/git.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/git.{{ domain_external }}-error.log"
locations:
- location: '/_/static/assets'
options: "alias /path/to/gitea/public;"
- location: '/'
options: "proxy_pass http://localhost:3000;"
# Websites
web_sites: "{{ gitea_website }}"
# Databases
db_configs:
- "{{ gitea_db }}"
# Backup
backup_dbs:
- "{{ db_configs | json_query('[*].{type: type, name: name}') }}"
backup_targets:
db: "{{ backup_dbs | flatten }}"
file:
- "{{ gitea_data_location }}"
- "/etc/letsencrypt"
vars_files:
- "group_vars/environment.yml"

20
cloud-gocd-agent.yml Executable file
View File

@ -0,0 +1,20 @@
- hosts: local
connection: local
roles:
- basis
- java
- gocd-agent
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
gocd_server: "https://build.{{ domain_external }}/go"
vars_files:
- "group_vars/{{ ansible_local.preferences.ansible.environment }}.yml"

69
cloud-gocd.yml Executable file
View File

@ -0,0 +1,69 @@
- hosts: local
connection: local
roles:
- basis
- backup
- java
- nginx
- gocd
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
mount_points:
- path: "{{ gocd_artifact_location }}"
dev: /dev/sdb
gocd_admin_user: gocd_admin
gocd_admin_pass: VeryCoolAdminPassword!
gocd_artifact_location: "{{ cloud_storage }}/gocd-artifacts"
gocd_website:
domain: "build.{{ domain_external }}"
letsencrypt: true
state: present
owner: jenkins
port: 80
root_setup: false
index: noindex
root: noroot
options:
access_log: "/var/log/nginx/build.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/build.{{ domain_external }}-error.log"
pre_options: |
# Required for GoCD websocket agents
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
locations:
- location: '/'
options: |
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_pass http://localhost:8153/;
client_max_body_size 10000m;
# Websites
web_sites:
- "{{ gocd_website }}"
# Backup
backup_targets:
file:
- "{{ gocd_artifact_location }}"
- "/etc/letsencrypt"
vars_files:
- "group_vars/{{ ansible_local.preferences.ansible.environment }}.yml"

100
cloud-jenkins.yml Executable file
View File

@ -0,0 +1,100 @@
- hosts: local
connection: local
roles:
- basis
- backup
- java
- nginx
- jenkins
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
mount_points:
- path: "{{ jenkins_data_location }}"
dev: /dev/sdb
jenkins_data_location: "{{ cloud_storage }}/jenkins-data"
jenkins_website:
domain: "build.{{ domain_external }}"
letsencrypt: true
state: present
owner: jenkins
port: 80
root_setup: false
index: noindex
root: noroot
options:
access_log: "/var/log/nginx/build.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/build.{{ domain_external }}-error.log"
ignore_invalid_headers: "off"
pre_options: |
upstream jenkins {
keepalive 32; # keepalive connections
server 127.0.0.1:8080; # jenkins ip and port
}
# Required for Jenkins websocket agents
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
locations:
- location: '~ "^/static/[0-9a-fA-F]{8}\/(.*)$"'
options: |
rewrite "^/static/[0-9a-fA-F]{8}\/(.*)" /$1 last;
- location: '/userContent'
options: |
root {{ cloud_apps }}/jenkins/web;
if (!-f $request_filename){
# this file does not exist, might be a directory or a /**view** url
rewrite (.*) /$1 last;
break;
}
sendfile on;
- location: '/'
options: |
sendfile off;
proxy_pass http://jenkins;
proxy_redirect default;
proxy_http_version 1.1;
# Required for Jenkins websocket agents
proxy_set_header Connection $connection_upgrade;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_max_temp_file_size 0;
#this is the maximum upload size
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffering off;
proxy_request_buffering off; # Required for HTTP CLI commands
proxy_set_header Connection ""; # Clear for keepalive
# Websites
web_sites:
- "{{ jenkins_website }}"
# Backup
backup_targets:
file:
- "{{ jenkins_data_location }}"
- "/etc/letsencrypt"
vars_files:
- "group_vars/environment.yml"

36
cloud-mail.yml Executable file
View File

@ -0,0 +1,36 @@
---
- hosts: local
connection: local
roles:
- basis
- backup
- docker
- mailcow
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
# Mailcow
mailcow_db_root_pass: FancyInitialRootPasswordVeryLong
mailcow_db_pass: FancyInitialDBPasswordVeryLong
mailcow_use_sogo: true
mailcow_use_solr: true
mailcow_use_clamav: true
# Backup
backup_client_script_envs:
- var: "MAILCOW_BACKUP_LOCATION"
value: "/tmp"
backup_client_scripts:
- /app/mailcow/helper-scripts/backup_and_restore.sh backup all
- "mv /tmp/mailcow-* {{ backup_folder }}/mail/"
vars_files:
- "group_vars/environment.yml"

55
cloud-monitoring.yml Executable file
View File

@ -0,0 +1,55 @@
- hosts: local
connection: local
roles:
- basis
- nginx
- checkmk
vars:
users_local: []
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
checkmk_is_server: true
checkmk_admin_pass: FancyInitialAdminPasswordVeryLong!
checkmk_website:
domain: "monitoring.{{ domain_external }}"
letsencrypt: true
filetag: "monitoring.{{ domain_external }}"
state: present
port: 80
root: noroot
root_setup: false
index: noindex
options:
access_log: "/var/log/nginx/monitoring.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/monitoring.{{ domain_external }}-error.log"
locations:
- location: '~* /\w+'
options: |
proxy_pass http://127.0.0.1:5000;
proxy_pass_header Authorization;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_buffering off;
proxy_request_buffering off;
client_max_body_size 0;
proxy_read_timeout 36000s;
proxy_ssl_session_reuse off;
proxy_hide_header x-frame-options;
- location: '= /'
options: |
return 444;
web_sites:
- "{{ checkmk_website }}"
vars_files:
- "group_vars/{{ ansible_local.preferences.ansible.environment }}.yml"

227
cloud-nextcloud.yml Executable file
View File

@ -0,0 +1,227 @@
---
- hosts: local
connection: local
roles:
- basis
- backup
- docker
- postgres
- php
- signaling
- nginx
- nextcloud
- checkmk
vars:
users_local: []
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
mount_points:
- path: "{{ ncloud_data_location }}"
dev: /dev/sdb
# NextCloud
ncloud_db:
type: pgsql
name: nextcloud
user: nextclouduser
pass: FancyNextcloudDbPasswordVeryLong
ncloud_admin_user: nextcloudadmin
ncloud_admin_pass: FancyInitialAdminPasswordVeryLong!
ncloud_data_location: "{{ cloud_storage }}/nextcloud-data"
ncloud_npush_port: 7867
ncloud_website:
domain: "{{ ncloud_domain }}"
letsencrypt: true
filetag: "cloud.{{ domain_external }}"
state: present
owner: ncloud
port: 80
port_options: " ipv6only=on"
root: "{{ cloud_apps }}/nextcloud/"
root_setup: false
index:
- index.php
- index.html
- /index.php$request_uri
options:
access_log: "/var/log/nginx/cloud.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/cloud.{{ domain_external }}-error.log"
client_max_body_size: 512M
client_body_timeout: 300s
fastcgi_buffers: 64 4K
gzip: !unsafe on
gzip_vary: !unsafe on
gzip_min_length: 256
gzip_proxied: expired no-cache no-store private no_last_modified no_etag auth
gzip_types: pplication/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/wasm application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy
fastcgi_hide_header: X-Powered-By
add_header:
- Referrer-Policy "no-referrer" always
- X-Content-Type-Options "nosniff" always
- X-Download-Options "noopen" always
- X-Frame-Options "SAMEORIGIN" always
- X-Permitted-Cross-Domain-Policies "none" always
- X-Robots-Tag "none" always
- X-XSS-Protection "1; mode=block" always
- Strict-Transport-Security "max-age=15552000; includeSubDomains" always
- X-Content-Type-Options "nosniff"
- X-XSS-Protection "1; mode=block"
- X-Robots-Tag "noindex, nofollow, nosnippet, noarchive"
- X-Frame-Options "SAMEORIGIN"
- Referrer-Policy "no-referrer"
locations:
- location: '= /'
options: |
if ( $http_user_agent ~ ^DavClnt ) {
return 302 /remote.php/webdav/$is_args$args;
}
- location: '= /robots.txt'
options: |
allow all;
log_not_found off;
access_log off;
- location: '^~ /.well-known'
options: |
location = /.well-known/carddav { return 301 /remote.php/dav/; }
location = /.well-known/caldav { return 301 /remote.php/dav/; }
location /.well-known/acme-challenge { try_files $uri $uri/ =404; }
location /.well-known/pki-validation { try_files $uri $uri/ =404; }
return 301 /index.php$request_uri;
- location: '~ ^/(?:build|tests|config|lib|3rdparty|templates|data)(?:$|/)'
options: return 404;
- location: '~ ^/(?:\.|autotest|occ|issue|indie|db_|console)'
options: return 404;
- location: '~ \.php(?:$|/)'
options: |
rewrite ^/(?!index|remote|public|cron|core\/ajax\/update|status|ocs\/v[12]|updater\/.+|oc[ms]-provider\/.+|.+\/richdocumentscode\/proxy) /index.php$request_uri;
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
set $path_info $fastcgi_path_info;
try_files $fastcgi_script_name =404;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_param HTTPS on;
fastcgi_param modHeadersAvailable true; # Avoid sending the security headers twice
fastcgi_param front_controller_active true; # Enable pretty urls
fastcgi_pass php;
fastcgi_intercept_errors on;
fastcgi_request_buffering off;
fastcgi_max_temp_file_size 0;
- location: '~ \.(?:css|js|svg|gif|png|jpg|ico|wasm|tflite)$'
options: |
try_files $uri /index.php$request_uri;
expires 6M; # Cache-Control policy borrowed from `.htaccess`
access_log off; # Optional: Don't log access to assets
location ~ \.wasm$ {
default_type application/wasm;
}
- location: '~ \.woff2?$'
options: |
try_files $uri /index.php$request_uri;
expires 7d; # Cache-Control policy borrowed from `.htaccess`
access_log off; # Optional: Don't log access to assets
- location: '/remote'
options: return 301 /remote.php$request_uri;
- location: '^~ /push/'
options: |
proxy_pass http://127.0.0.1:{{ ncloud_npush_port }}/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- location: '/'
options: try_files $uri $uri/ /index.php$request_uri;
# Signaling Nextcloud
signaling_listen_host: 127.0.0.1
signaling_listen_port: 8080
signaling_janus_api_key: LookUpDocumentationForSettingUpKey
signaling_hash_key: LookUpDocumentationForSettingUpHashKey
signaling_block_key: LookUpDocumentationForSettingUpBlockKey
signaling_ncloud_secret_key: LookUpDocumentationForSettingUpSecretKey
signaling_backend_name: examplecloud
signaling_website:
domain: "signaling.{{ domain_external }}"
letsencrypt: true
filetag: "signaling.{{ domain_external }}"
state: present
owner: signaling
port: 80
root: noroot
root_setup: false
index: noindex
pre_options: |
upstream signaling {
server {{ signaling_listen_host }}:{{ signaling_listen_port }};
}
options:
access_log: "/var/log/nginx/signaling.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/signaling.{{ domain_external }}-error.log"
locations:
- location: '/standalone-signaling/'
options: |
proxy_pass http://signaling/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- location: '/standalone-signaling/spreed'
options: |
proxy_pass http://signaling/spreed;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Databases
db_configs:
- "{{ ncloud_db }}"
# Websites
web_sites:
- "{{ ncloud_website }}"
- "{{ signaling_website }}"
# Nginx
nginx_conf_http_local:
- |
upstream php {
server unix:/run/php/php{{ php_version }}-fpm.sock;
}
nginx_conf_http: "{{ nginx_conf_http_local }}"
# Backup
backup_dbs:
- "{{ db_configs | json_query('[*].{type: type, name: name}') }}"
backup_targets:
db: "{{ backup_dbs | flatten }}"
file:
- "{{ ncloud_data_location }}"
- "/etc/letsencrypt"
vars_files:
- "group_vars/environment.yml"

60
cloud-nexus.yml Executable file
View File

@ -0,0 +1,60 @@
- hosts: local
connection: local
roles:
- basis
- backup
- java
- nginx
- nexus
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
mount_points:
- path: "{{ nexus_data_location }}"
dev: /dev/sdb
nexus_java_home: "{{ cloud_apps }}/java_jdk/jdk8u322-b06"
nexus_http_port: 8081
nexus_http_host: localhost
nexus_data_location: "{{ cloud_storage }}/sonatype-nexus-data"
nexus_website:
domain: "artifact.{{ domain_external }}"
letsencrypt: true
state: present
owner: sonanexus
port: 80
root_setup: false
index: noindex
root: noroot
options:
access_log: "/var/log/nginx/artifact.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/artifact.{{ domain_external }}-error.log"
client_max_body_size: 1G
locations:
- location: "/"
options: |
proxy_pass http://{{ nexus_http_host }}:{{ nexus_http_port }}/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Websites
web_sites:
- "{{ nexus_website }}"
# Backup
backup_targets:
file:
- "{{ nexus_data_location }}"
- "/etc/letsencrypt"
vars_files:
- "group_vars/environment.yml"

77
cloud-openproject Executable file
View File

@ -0,0 +1,77 @@
- hosts: local
connection: local
roles:
- basis
- backup
- postgres
- nginx
- openproject
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
openproject_db:
type: pgsql
name: openproject
user: openprojectuser
pass: FancyOpenProjectDbPasswordVeryLong
openproject_mail_smtp_host: "{{ mail_domain }}"
openproject_mail_smtp_port: "{{ mail_port }}"
openproject_mail_smtp_user: "{{ development_mail_address }}"
openproject_mail_smtp_pass: "{{ development_mail_pass }}"
openproject_mail_smtp_domain: "{{ openproject_mail_smtp_host }}"
openproject_mail_admin: "{{ noreply_mail_address }}"
openproject_domain: "project.{{ domain_external }}"
openproject_http_port: 6000
openproject_webste:
domain: "project.{{ domain_external }}"
letsencrypt: true
state: present
owner: openproject
port: 80
root_setup: false
index: noindex
root: noroot
options:
access_log: "/var/log/nginx/project.{{ domain_external }}-access.log"
error_log: "/var/log/nginx/project.{{ domain_external }}-error.log"
pre_options: |
upstream openproject {
server 127.0.0.1:{{ openproject_http_port }};
}
locations:
- location: "/"
options: |
proxy_pass_header Server;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto https;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_pass http://openproject/;
# Websites
web_sites:
- "{{ openproject_webste }}"
# Databases
db_configs:
- "{{ openproject_db }}"
# Backup
backup_dbs:
- "{{ db_configs | json_query('[*].{type: type, name: name}') }}"
backup_targets:
db: "{{ backup_dbs | flatten }}"
file:
- "/etc/letsencrypt"
vars_files:
- "group_vars/environment.yml"

49
cloud-vpn.yml Executable file
View File

@ -0,0 +1,49 @@
---
- hosts: local
connection: local
roles:
- basis
- backup
- easy-rsa
- vpn
- checkmk
vars:
users_local: []
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
# easy-rsa
easy_rsa_servers:
- name: "{{ vpn_server }}"
state: present
easy_rsa_vars_conf:
country: "GERMANY"
province: "Niedersachsen"
city: "Wendeburg"
company: "Hühner Cloud"
mail: "{{ admin_mail_address }}"
easy_rsa_clients: "{{ vpn_users + vpn_apps }}"
# OpenVPN
vpn_server: "example-cloud-vpn"
vpn_users: "{{ users | json_query('[?contains(groups, `vpn`)].{name: name, state: state}') }}"
vpn_apps:
- name: admin.exampleapp
state: present
vpn_clients: "{{ vpn_users + vpn_apps }}"
# Backup
backup_targets:
file:
- "/etc/openvpn"
vars_files:
- "group_vars/environment.yml"

48
cloud-wordpress Executable file
View File

@ -0,0 +1,48 @@
---
- hosts: local
connection: local
roles:
- basis
- backup
- mariadb
- php
- nginx
- wordpress
- checkmk
vars:
users_local: [] #some local users only specific to this node!
users: "{{ users_local + users_admin }}"
fail2ban_activate_modules:
- sshd
- nginx
# Websites
web_sites: "{{ wp_web_sites }}"
# Databases
db_configs: "{{ web_sites | json_query('[*].db') }}"
# Nginx
nginx_conf_http_local:
- |
upstream php {
server unix:/run/php/php{{ php_version }}-fpm.sock;
}
nginx_conf_http: "{{ nginx_conf_http_local }}"
# Backup
backup_dbs:
- "{{ db_configs | json_query('[*].{type: type, name: name}') }}"
backup_targets:
db: "{{ backup_dbs | flatten }}"
file:
- "/app/wordpress"
- "/etc/letsencrypt"
vars_files:
- "group_vars/environments.yml"
- "group_vars/wordpress.yml"

86
group_vars/environment.yml Executable file
View File

@ -0,0 +1,86 @@
---
ansible_python_interpreter: /usr/bin/python3
cloud_name: "example-cloud"
cloud_home: "/{{ cloud_name }}"
cloud_host_group: "example-playbook"
cloud_env: "example_env"
cloud_env_path: "{{ cloud_home }}/{{ cloud_env }}"
cloud_control_name: "cloud-control"
cloud_apps: "/app"
cloud_storage: "/storage"
cloud_stage: "production"
backup_folder: "/backup"
backup_times_hour:
- 20
basis_apps:
- passwd
- python3-jmespath
- python3-psycopg2
- vim
domain_external: "my-domain.tld"
cloud_python_envs: "{{ cloud_apps }}/py-env"
admin_mail_address: "admin@{{ domain_external }}"
noreply_mail_address: "noreply@{{ domain_external }}"
letsencrypt_mail_address: "{{ admin_mail_address }}"
development_mail_address: "development@{{ domain_external }}"
development_mail_pass: MyVeryCoolPassword!
auth_mail_address: "auth@{{ domain_external }}"
auth_mail_pass: MyVeryCoolPassword!
mail_domain: "mail.{{ domain_external }}"
mail_port: 465
mail_ssl: true
shared_group: "cloud"
backup_owner_ssh_key: "ssh-rsa SomeFancyRSAKeyThatIsPreDefined"
users_admin:
- name: admin
displayname: Admin User
shell: /bin/bash
groups:
- admin
- adm
- systemd-journal
- staff
- sudo
- vpn
state: present
ssh_key: "ssh-rsa AdminUserSshKeyThatIsPreDefined"
ssh_port: 22
default_groups:
- ssh
- users
- systemd-journal
- "{{ shared_group }}"
ssh_configs:
- Protocol 2
- "Port {{ ssh_port }}"
- PermitRootLogin prohibit-password
- PubkeyAuthentication yes
- PasswordAuthentication no
- PermitEmptyPasswords no
- ClientAliveInterval 1200
- ClientAliveCountMax 3
fail2ban_bantime: 1h
fail2ban_maxretry: 3
fail2ban_nginx_filter:
- nginx-noscript
- nginx-nohome
- nginx-noproxy
php_version: 8.0
php_upload_max_filesize: 512M
php_post_max_size: 512M
php_memory_limit: 512M

44
group_vars/wordpress Executable file
View File

@ -0,0 +1,44 @@
---
wp_default_locations:
- location: "/favicon.ico"
options: |
log_not_found off;
access_log off;
- location: "/robots.txt"
options: |
allow all;
log_not_found off;
access_log off;
- location: '~ \.php$'
options: |
include fastcgi.conf;
fastcgi_intercept_errors on;
fastcgi_pass php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
- location: '~* \.(js|css|png|jpg|jpeg|gif|ico)$'
options: |
expires max;
log_not_found off;
- location: "/"
options: |
try_files $uri $uri/ /index.php?$args;
wp_web_sites:
- domain: "{{ domain_external }}"
state: present
owner: admin
root: "{{ cloud_apps }}/wordpress/{{ domain_external }}"
root_setup: false
wordpress: true
index:
- index.php
db:
type: mariadb
name: wordpress
user: wordpressuser
pass: FancyGiteaDbPasswordVeryLong
letsencrypt: true
locations: "{{ wp_default_locations }}"
options:
access_log: "/var/log/nginx/{{ domain_external }}-access.log"
error_log: "/var/log/nginx/{{ domain_external }}-error.log"

69
requirements.yml Executable file
View File

@ -0,0 +1,69 @@
---
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-authentik.git
name: authentik
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-backup.git
name: backup
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-basis.git
name: basis
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-checkmk.git
name: checkmk
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-docker.git
name: docker
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-easyrsa.git
name: easy-rsa
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-gitea.git
name: gitea
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-gocd.git
name: gocd
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-gocd-agent.git
name: gocd-agent
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-java.git
name: java
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-jenkins.git
name: jenkins
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-mailcow.git
name: mailcow
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-mariadb.git
name: mariadb
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-nextcloud.git
name: nextcloud
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-nexus.git
name: nexus
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-nginx.git
name: nginx
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-openproject.git
name: openproject
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-php.git
name: php
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-postgresql.git
name: postgres
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-nextcloud-signaling.git
name: signaling
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-vault.git
name: vault
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-vpn.git
name: vpn
- src: git+https://git.opendevchain.de/OpenDevChain/cloud-wordpress.git
name: wordpress

9
roles/authentik/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/authentik/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-authentik
Ansible Role in order to setup go-authentik as a personal identity provider.

View File

@ -0,0 +1,41 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
domain_external: "my-domain.tld"
authentik_dir: "{{ cloud_apps }}/authentik"
authentik_version: 2022.5
authentik_source: https://goauthentik.io/version
authentik_target: docker-compose.yml
authentik_db:
type: pgsql
name: authentik_db
user: authentik_dbu
pass: authentik_dbpw
port: 5432
host: localhost
authentik_http_port: 9080
authentik_https_port: 9443
authentik_secret_key: MyVerySecretKey!
authentik_loglevel: info
authentik_admin_pass: VeryNicePassword!
authentik_admin_token:
authentik_stmp_host: "mail.{{ domain_external }}"
authentik_stmp_port: 25
authentik_smtp_user: "admin@{{ domain_external }}"
authentik_smtp_pass: VeryNicePassword!
authentik_smtp_from: "{{ authentik_smtp_user }}"
authentik_footer:
# - name: Link Name
# href: https://goauthentik.io

View File

@ -0,0 +1,7 @@
---
- name: restart authentik
docker_compose:
project_src: "{{ authentik_link }}"
state: present
restarted: yes
remove_orphans: yes

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:08 '
version: ''

17
roles/authentik/meta/main.yml Executable file
View File

@ -0,0 +1,17 @@
---
galaxy_info:
role_name: authentik
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Role to setup authentik Identity provider
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 11
galaxy_tags:
- authentik
dependencies:
- docker

32
roles/authentik/tasks/main.yml Executable file
View File

@ -0,0 +1,32 @@
---
- name: setup authentik docker dir
file:
state: directory
path: "{{ item }}"
loop:
- "{{ authentik_dir }}"
- "{{ authentik_inst }}"
- name: link installation folder
file:
state: link
src: "{{ authentik_inst }}"
dest: "{{ authentik_link }}"
- name: download authentik compose file
get_url:
url: "{{ authentik_source }}/{{ authentik_version }}/{{ authentik_target }}"
dest: "{{ authentik_link }}/{{ authentik_target }}"
force: yes
owner: root
group: root
notify: restart authentik
- name: template environment
template:
src: opt/authentik/.env.j2
dest: "{{ authentik_link }}/.env"
mode: 0640
owner: root
group: root
notify: restart authentik

View File

@ -0,0 +1,67 @@
### BASIC ###
AUTHENTIK_PORT_HTTP={{ authentik_http_port | default(9080) }}
AUTHENTIK_PORT_HTTPS={{ authentik_https_port | default(9443) }}
AUTHENTIK_SECRET_KEY={{ authentik_secret_key }}
AUTHENTIK_LOG_LEVEL={{ authentik_loglevel }}
AUTHENTIK_OUTPOSTS__DISCOVER={{ authentik_autodiscover | default('true') }}
AUTHENTIK_DEFAULT_USER_CHANGE_NAME={{ authentik_user_change_name | default('true') }}
AUTHENTIK_DEFAULT_USER_CHANGE_MAIL={{ authentik_user_change_mail | default('true') }}
AUTHENTIK_DEFAULT_USER_CHANGE_USERNAME={{ authentik_user_change_username | default('true') }}
AUTHENTIK_GDPR_COMPLIANCE={{ authentik_gdpr_removeondelete | default('true') }}
AUTHENTIK_DISABLE_UPDATE_CHECK={{ authentik_check_update | default('false') }}
AUTHENTIK_ERROR_REPORTING__ENABLED={{ authentik_reporting_error | default('false') }}
AUTHENTIK_ERROR_REPORTING__SEND_PII={{ authentik_reporting_user | default('false') }}
AUTHENTIK_DISABLE_STARTUP_ANALYTICS={{ authentik_disable_analytics | default('true') }}
AUTHENTIK_AVATARS={{ authentik_avatars | default('none') }}
{% if authentik_footer is defined and authentik_footer is not none %}
AUTHENTIK_FOOTER_LINKS='{{ authentik_footer | to_json }}'
{% endif %}
{% if authentik_admin_pass is defined and authentik_admin_pass is not none %}
AK_ADMIN_PASS={{ authentik_admin_pass }}
{% endif %}
{% if authentik_admin_token and authentik_admin_token is not none %}
AK_ADMIN_TOKEN={{ authentik_admin_token }}
{% endif %}
### SMTP ###
# SMTP Host Emails are sent to
AUTHENTIK_EMAIL__HOST={{ authentik_stmp_host }}
AUTHENTIK_EMAIL__PORT={{ authentik_stmp_port }}
# Optionally authentikate (don't add quotation marks to you password)
AUTHENTIK_EMAIL__USERNAME={{ authentik_smtp_user }}
AUTHENTIK_EMAIL__PASSWORD={{ authentik_smtp_pass }}
# Email address authentik will send from, should have a correct @domain
AUTHENTIK_EMAIL__FROM={{ authentik_smtp_from }}
AUTHENTIK_EMAIL__TIMEOUT={{ authentik_smpt_timeout | default('10') }}
# Use StartTLS
AUTHENTIK_EMAIL__USE_TLS={{ authentik_smpt_usetls | default('false') }}
# Use SSL
AUTHENTIK_EMAIL__USE_SSL={{ authentik_smpt_usessl | default('false') }}
{% if authentik_db is not none %}
### POSTGRES ###
PG_PASS={{ authentik_db.pass }}
PG_USER={{ authentik_db.user }}
PG_DB={{ authentik_db.name }}
POSTGRES_PASSWORD={{ authentik_db.pass }}
POSTGRES_USER={{ authentik_db.user }}
POSTGRES_DB={{ authentik_db.name }}
AUTHENTIK_POSTGRESQL__HOST={{ authentik_db.host | default('localhost') }}
AUTHENTIK_POSTGRESQL__PORT={{ authentik_db.post | default(5432) }}
AUTHENTIK_POSTGRESQL__NAME={{ authentik_db.name }}
AUTHENTIK_POSTGRESQL__USER={{ authentik_db.user }}
AUTHENTIK_POSTGRESQL__PASSWORD={{ authentik_db.pass }}
{% endif %}

3
roles/authentik/vars/main.yml Executable file
View File

@ -0,0 +1,3 @@
---
authentik_inst: "{{ authentik_dir }}/authentik_{{ authentik_version }}"
authentik_link: "{{ authentik_dir }}/inst"

9
roles/backup/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/backup/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-backup
Ansible role repository in order to setup backup clientside tasks (what should be backuped) and masterside tasks (where should be backuped from where).

69
roles/backup/defaults/main.yml Executable file
View File

@ -0,0 +1,69 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
ssh_port: 1802
# clients push only daily backup
# server (!= client) will then pull daily backups
backup_client: true
# Server should pull 1 hour later the backups.
backup_hour_shift: 1
backup_times_weekday: "*"
backup_times_hour:
- 6
- 10
- 14
- 18
- 22
backup_times_minute: 0
backup_keep_days: 7
backup_owner: backup
backup_owner_ssh_key: "ssh-rsa THEREISSUCHRSAKEYYET"
backup_group: "{{ backup_owner }}"
backup_permission: 0770
backup_hosts:
- name: server1-name
domain: host1.my-domain.tld
ip: 001.112.223.123
- name: server2-name
domain: host2.my-domain.tld
backup_folder: "{{ cloud_apps }}/backup"
#backup_client_scripts:
# - /path/to/script -param
backup_client_scripts: []
#backup_client_script_envs:
# - var: VAR_NAME
# path: /some/path
# - var: VAR_NAME
# value: some_value
backup_client_script_envs: []
backup_lock: "{{ backup_folder }}/backup.lock"
#backup_targets:
# db:
# - type: mariadb
# name: db_name_mdb
# - type: pgsql
# name: db_name_pg
# mail:
# - type: file
# path: /path/to/some/file
# - type: mariadb
# name: db_name_mdb_mail
# file:
# - /path/to/some/file
# - /path/to/some/dir
backup_targets:
db: []
mail: []
file: []

1
roles/backup/handlers/main.yml Executable file
View File

@ -0,0 +1 @@
---

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:09 '
version: ''

16
roles/backup/meta/main.yml Executable file
View File

@ -0,0 +1,16 @@
---
galaxy_info:
role_name: backup
namespace: hahn-cloud
author: Lars Hahn
company: Data Learning
license: MIT
description: Role to setup a backup system + configuration.
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 10
galaxy_tags:
- backup
dependencies: []

38
roles/backup/tasks/client.yml Executable file
View File

@ -0,0 +1,38 @@
---
- name: generate backup ssh user
user:
name: "{{ backup_owner }}"
group: "{{ backup_group }}"
comment: Backup user
shell: /bin/sh
- name: Setup User ssh_key
authorized_key:
user: "{{ backup_owner }}"
key: "{{ backup_owner_ssh_key }}"
- name: generate config lists
template:
src: backup/conf/{{ conf }}.list.j2
dest: "{{ backup_conf }}/{{ conf }}.list"
loop:
- filedir
- db
- mail
loop_control:
loop_var: conf
label: "{{ conf }}.list"
- name: setup backup script
template:
src: backup/backup_on_client.sh.j2
dest: "{{ backup_folder }}/backup.sh"
mode: 0740
- name: setup cronjob for client backup generation
cron:
name: "backup"
weekday: "{{ backup_times_weekday }}"
hour: "{{ backup_times_hour | join(',') }}"
minute: "{{ backup_times_minute }}"
job: "{{ backup_folder }}/backup.sh"

34
roles/backup/tasks/main.yml Executable file
View File

@ -0,0 +1,34 @@
---
# Basics
- name: install requirements for backup system
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- rsync
- name: setup storage folders for backup
file:
state: directory
path: "{{ dir.value.path }}"
owner: "{{ backup_owner }}"
group: "{{ backup_group }}"
mode: "{{ backup_permission }}"
with_dict: "{{ backup_storage }}"
loop_control:
loop_var: dir
label: "{{ dir.key }}"
- name: setup conf folder
file:
state: directory
path: "{{ backup_folder }}/conf"
- name: setup client backup structure
include_tasks: client.yml
when: backup_client
- name: setup server backup structure
include_tasks: server.yml
when: not backup_client

27
roles/backup/tasks/server.yml Executable file
View File

@ -0,0 +1,27 @@
---
- name: analyse backup hours for pulling server
set_fact:
backup_times_server_hour: "{{ backup_times_server_hour | default([]) + [item + backup_hour_shift] }}"
loop: "{{ backup_times_hour }}"
- name: generate backup user ssh key
user:
name: "{{ backup_owner }}"
generate_ssh_key: yes
ssh_key_type: rsa
ssh_key_bits: 4096
home: "{{ backup_folder }}"
- name: template main server backup pull script
template:
src: backup/backup_from_clients.sh.j2
dest: "{{ backup_folder }}/pull-backup.sh"
mode: 0740
- name: setup cronjob for server backup pull
cron:
name: "pull backups"
weekday: "{{ backup_times_weekday }}"
hour: "{{ backup_times_server_hour | join(',') }}"
minute: "{{ backup_times_minute }}"
job: "{{ backup_folder }}/pull-backup.sh"

View File

@ -0,0 +1,68 @@
#!/bin/bash
set -e -o pipefail
cd {{ backup_folder }}
if [ -f {{ backup_lock }} ]; then
echo "Backup lock! Cannot procceed as lock '{{ backup_lock }}' exist."
echo "Associated PID is $(cat {{ backup_lock }})"
exit 1
fi
echo "$$" > {{ backup_lock }}
BKPTIMESTAMP=$(date +"%y-%m-%d.%H")
BKP=$BKPTIMESTAMP"_backup"
# generate rolling folder
{% for target in backup_targets %}
{% for host in backup_hosts %}
{% if 'domain' in host %}
mkdir -p {{ target }}/{{ host.name + '_' + host.domain }}/$BKP
{% elif 'ip' in host %}
mkdir -p {{ target }}/{{ host.name + '_' + host.ip }}/$BKP
{% endif %}
{% endfor %}
{% endfor %}
# pull backups
{% for target in backup_targets %}
{% for host in backup_hosts %}
{% if 'domain' in host %}
rsync --rsh='ssh -p{{ ssh_port }} -i ~{{ backup_owner }}/.ssh/id_rsa' -chav --stats --ignore-missing-args {{ backup_owner }}@{{ host.domain }}:{{ backup_folder }}/{{ target }}.tgz {{ target }}/{{ host.name + '_' + host.domain }}/$BKP
{% elif 'ip' in host %}
rsync --rsh='ssh -p{{ ssh_port }} -i ~{{ backup_owner }}/.ssh/id_rsa' -chav --stats --ignore-missing-args {{ backup_owner }}@{{ host.ip }}:{{ backup_folder }}/{{ target }}.tgz {{ target }}/{{ host.name + '_' + host.ip }}/$BKP
{% endif %}
{% endfor %}
{% endfor %}
# link to latest
{% for target in backup_targets %}
{% for host in backup_hosts %}
{% if 'domain' in host %}
ln -sf {{ backup_folder }}/{{ target }}/{{ host.name + '_' + host.domain }}/$BKP {{ backup_folder }}/{{ target }}/{{ host.name + '_' + host.domain }}/LATEST
{% elif 'ip' in host %}
ln -sf {{ backup_folder }}/{{ target }}/{{ host.name + '_' + host.ip }}/$BKP {{ backup_folder }}/{{ target }}/{{ host.name + '_' + host.ip }}/LATEST
{% endif %}
{% endfor %}
{% endfor %}
# keep only last {{ backup_keep_days * ( backup_times_hour | length ) }}
{% for target in backup_targets %}
{% for host in backup_hosts %}
{% if 'domain' in host %}
DELETE_LIST=$(ls -1dtr {{ target }}/{{ host.name + '_' + host.domain }}/* | head -n -{{ backup_keep_days * ( backup_times_hour | length ) }})
{% elif 'ip' in host %}
DELETE_LIST=$(ls -1dtr {{ target }}/{{ host.name + '_' + host.ip }}/* | head -n -{{ backup_keep_days * ( backup_times_hour | length ) }})
{% endif %}
if (( $( echo $DELETE_LIST | wc -w ) > 0 )); then
rm -rf $DELETE_LIST
fi
{% endfor %}
{% endfor %}
rm {{ backup_lock }}

View File

@ -0,0 +1,72 @@
#!/bin/bash
set -e -o pipefail
if [ -f {{ backup_lock }} ]; then
echo "Backup lock! Cannot procceed as lock '{{ backup_lock }}' exist."
echo "Associated PID is $(cat {{ backup_lock }})"
exit 1
fi
echo "$$" > {{ backup_lock }}
cd {{ backup_folder }}
# Load script envs
echo "Load script environment variables"
{% for scr_env in backup_client_script_envs %}
{% if 'path' in scr_env %}
export {{ scr_env.var }}={{ scr_env.path }}:${{ scr_env.var }}
{% else %}
export {{ scr_env.var }}={{ scr_env.value }}
{% endif %}
{% endfor %}
# Perform client pre backup scripts for
echo "Perform pre-backup scripts"
{% for cmd in backup_client_scripts %}
{{ cmd }};
{% endfor %}
# Backup files and directories
echo "Copy files and directories"
while read DIRFILE; do
echo " - Copy $DIRFILE"
BACKUP_SUBDIR=$(dirname $DIRFILE)
mkdir -p "{{ backup_storage.file.path }}/$BACKUP_SUBDIR"
cp -r -u $DIRFILE "{{ backup_storage.file.path }}/$DIRFILE"
done < {{ backup_conf }}/filedir.list
rm -f file.tgz #remove old backup
tar czfv file.tgz file
rm -rf file/*
# Backup databases
echo "Generate DB dumps"
while read DBS; do
DBTYPE=$(echo $DBS | cut -f 1 -d "{{ backup_conf_db_sep }}" );
DBNAME=$(echo $DBS | cut -f 2 -d "{{ backup_conf_db_sep }}" );
if [ $DBTYPE == "mariadb" ] || [ $DBTYPE == "mysql" ]; then
echo "- dump to {{ backup_storage.db.path }}/$DBTYPE/$DBNAME.sql"
mkdir -p {{ backup_storage.db.path }}/$DBTYPE;
mysqldump $DBNAME | gzip -c > {{ backup_storage.db.path }}/$DBTYPE/$DBNAME.sql.gz;
elif [ $DBTYPE == "pgsql" ]; then
echo "- dump to {{ backup_storage.db.path }}/$DBTYPE/$DBNAME.sql"
mkdir -p {{ backup_storage.db.path }}/$DBTYPE;
sudo -u postgres bash -c "pg_dump $DBNAME | gzip -c > /tmp/$DBNAME.sql.gz";
mv /tmp/$DBNAME.sql.gz /backup/db/$DBTYPE/$DBNAME.sql.gz;
else
echo "- ERROR! DB type '$DBTYPE' for '$DBNAME' is unknown to backup."
fi
done < {{ backup_conf }}/db.list
rm -f db.tgz #remove old backup
tar czfv db.tgz db
rm -rf db/*
#Mail
rm -f mail.tgz #remove old backup
tar czfv mail.tgz mail
rm -rf mail/*
rm {{ backup_lock }}
chown {{ backup_owner }}:{{ backup_group }} {{ backup_folder }}/*.tgz

View File

@ -0,0 +1,5 @@
{% if 'db' in backup_targets %}
{% for db in backup_targets.db %}
{{ db.type }}{{ backup_conf_db_sep }}{{ db.name }}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,5 @@
{% if 'file' in backup_targets %}
{% for filedir in backup_targets.file %}
{{ filedir }}
{% endfor %}
{% endif %}

View File

@ -0,0 +1,5 @@
{% if 'mail' in backup_targets %}
{% for mail in backup_targets.mail %}
{{ mail }}
{% endfor %}
{% endif %}

12
roles/backup/vars/main.yml Executable file
View File

@ -0,0 +1,12 @@
---
backup_conf: "{{ backup_folder }}/conf"
backup_conf_db_sep: ":"
backup_storage:
mail:
path: "{{ backup_folder }}/mail"
db:
path: "{{ backup_folder }}/db"
file:
path: "{{ backup_folder }}/file"

9
roles/basis/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

4
roles/basis/README.md Executable file
View File

@ -0,0 +1,4 @@
# cloud-basis
Ansible role to setup basic cloud configuration for a cloud node.
E.g.: mount volumes, setup user, install basic software and so on.

78
roles/basis/defaults/main.yml Executable file
View File

@ -0,0 +1,78 @@
---
cloud_update: false
cloud_name: cloud
cloud_home: "/opt/{{ cloud_name }}"
cloud_type: "cloud"
cloud_env: production
cloud_env_path: "{{ cloud_home }}/{{ cloud_env }}"
cloud_host_group: server
cloud_control_version: 1.0.0
cloud_control_name: cloud-control
cloud_git_branch_main: main
cloud_stage: prod
cloud_tzdata: Europe/Berlin
cloud_apps: /opt
cloud_storage: /srv
cloud_python_envs: "{{ cloud_apps }}/pyenv"
shared_group: "{{ cloud_name }}"
users:
- name: username
displayname: User Name
shell: /bin/bash
groups:
- sudo
- username
state: present
ssh_key: "ssh-rsa ABCDEF"
default_groups:
- "ssh"
- "users"
- "cdrom"
- "{{ cloud_shared_group }}"
ssh_port: 22
ssh_configs:
- Protocol 2
- "Port {{ cloud_ssh_port }}"
- PermitRootLogin no
- PubkeyAuthentication yes
- PasswordAuthentication no
- PermitEmptyPasswords no
fail2ban_bantime: 1h
fail2ban_maxretry: 3
fail2ban_nginx_selfmade_filter:
- nginx-noscript
- nginx-nohome
- nginx-noproxy
fail2ban_nginx_default_filter:
- nginx-limit-req
- nginx-botsearch
fail2ban_activate_modules:
- sshd
- nginx
basis_apps:
- passwd
- vim
- unzip
#mount_points:
# - path: /some/path
# dev: /dev/sdb
# fstype: ext4
# opts: noatime
# state: mounted
mount_points: []
swap_on: true
swap_file: /swapfile
#block size * block count = swap size (Bytes)
swap_block_size: 1024
swap_block_count: 1048576

12
roles/basis/handlers/main.yml Executable file
View File

@ -0,0 +1,12 @@
---
- name: restart sshd service
service:
name: sshd
state: restarted
enabled: yes
- name: restart fail2ban service
service:
name: fail2ban
state: restarted
enabled: yes

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:09 '
version: ''

16
roles/basis/meta/main.yml Executable file
View File

@ -0,0 +1,16 @@
---
galaxy_info:
role_name: basis
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Basis role to setup a basic system with ansible; e.g. Users, Fail2Ban, SSHD
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 10
galaxy_tags:
- basis
dependencies: []

View File

@ -0,0 +1,8 @@
---
- name: setup Cloud Control script
template:
src: "templates{{ cloud_control_path }}/cloud-control.j2"
dest: "{{ cloud_control_path }}/{{ cloud_control_name }}"
owner: root
group: root
mode: 0754

30
roles/basis/tasks/fail2ban.yml Executable file
View File

@ -0,0 +1,30 @@
---
- name: install fail2ban service
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg: fail2ban
- name: setup fail2ban config jail.local
template:
backup: yes
src: "templates{{ fail2ban_jail_conf }}.j2"
dest: "{{ fail2ban_jail_conf }}"
owner: root
group: root
mode: 0644
notify: restart fail2ban service
- name: Install fail2ban filter plugins nginx
template:
src: "templates{{ fail2ban_path }}/filter.d/{{ filter }}.local.j2"
dest: "{{ fail2ban_path }}/filter.d/{{ filter }}.local"
owner: root
group: root
mode: 0644
loop: "{{ fail2ban_nginx_filter }}"
loop_control:
label: "{{ filter }}"
loop_var: filter
notify: restart fail2ban service

60
roles/basis/tasks/main.yml Executable file
View File

@ -0,0 +1,60 @@
---
- name: Limit access to cloude home only for root
file:
state: directory
path: "{{ cloud_home }}"
owner: root
group: root
mode: 0700
recurse: yes
- name: Install basic apps via apt
apt:
update_cache: yes
autoclean: yes
autoremove: yes
state: latest
install_recommends: yes
pkg: "{{ basis_apps }}"
- name: set timezone
timezone:
name: "{{ cloud_tzdata }}"
- name: Setup hahn-cloud users
import_tasks: users.yml
- name: Setup and configure sshd service
import_tasks: sshd.yml
- name: Setup and configure fail2ban service
import_tasks: fail2ban.yml
- name: Setup and configure cloud control script
import_tasks: cloud_control.yml
- name: Setup mount points
import_tasks: mount.yml
- name: Setup swap
import_tasks: swap.yml
when: swap_on
- name: Setup basic cloud folders for apps and storage
file:
state: directory
path: "{{ item }}"
mode: 0755
owner: root
group: "{{ shared_group }}"
loop:
- "{{ cloud_apps }}"
- "{{ cloud_storage }}"
- name: Setup shared python environment for all cloud users
file:
state: directory
path: "{{ cloud_python_envs }}"
mode: 0755
owner: root
group: "{{ shared_group }}"

20
roles/basis/tasks/mount.yml Executable file
View File

@ -0,0 +1,20 @@
- name: generate filesystem on mounts if not defined
filesystem:
fstype: "{{ mnt.fstype | default('ext4') }}"
dev: "{{ mnt.dev }}"
loop: "{{ mount_points }}"
loop_control:
loop_var: mnt
label: "{{ mnt.dev }}: {{ mnt.fstype | default('ext4') }}"
- name: mount required points
mount:
path: "{{ mnt.path }}"
src: "{{ mnt.dev }}"
state: "{{ mnt.state | default('mounted') }}"
fstype: "{{ mnt.fstype | default('ext4') }}"
opts: "{{ mnt.opts | default('defaults') }}"
loop: "{{ mount_points }}"
loop_control:
loop_var: mnt
label: "{{ mnt.dev }}: {{ mnt.path }}"

21
roles/basis/tasks/sshd.yml Executable file
View File

@ -0,0 +1,21 @@
---
- name: install OpenSSH server
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg: openssh-server
- name: setup sshd_config
lineinfile:
path: "{{ sshd_conf }}"
regexp: '^#?{{ configline.split(" ")[0] }}{% if configline.split(" ") | length > 1 %} {% endif %}'
line: "{{ configline }}"
owner: root
group: root
mode: 0644
loop: "{{ ssh_configs }}"
loop_control:
loop_var: configline
label: "{{ configline }}"
notify: restart sshd service

35
roles/basis/tasks/swap.yml Executable file
View File

@ -0,0 +1,35 @@
---
- name: generate file for swapping
command:
cmd: "dd if=/dev/zero of={{ swap_file }} bs={{ swap_block_size }} count={{ swap_block_count }}"
chdir: "/"
creates: "{{ swap_file }}"
register: swapfile_setup
- name: prepare swap file
command:
cmd: "mkswap {{ swap_file }}"
chdir: "/"
when: swapfile_setup.changed
register: swapfile_creation
- name: set swap permission
file:
path: "{{ swap_file }}"
mode: 0600
- name: activate swap
command:
cmd: "swapon {{ swap_file }}"
chdir: "/"
when: swapfile_creation.changed
- name: mount swap on boot
mount:
path: none
src: "{{ swap_file }}"
fstype: swap
opts: sw
passno: 0
dump: 0
state: present

47
roles/basis/tasks/users.yml Executable file
View File

@ -0,0 +1,47 @@
---
- name: list active users
shell: cat /etc/passwd | grep -v "nologin" | cut -f 1 -d ":"
changed_when: false
register: active_users
- name: Setup required groups of users
group:
name: "{{ group }}"
state: present
loop: "{{ ((users | json_query('[*].groups') | flatten) + default_groups) | unique }}"
loop_control:
loop_var: group
label: "{{ group }}"
- name: Setup users
user:
name: "{{ user.name }}"
state: "{{ user.state }}"
comment: "{{ user.displayname }}"
group: "{{ user.name }}"
groups: "{{ default_groups | default([]) + user.groups }}"
append: yes
shell: "{{ user.shell }}"
loop: "{{ users }}"
loop_control:
loop_var: user
label: "{{ user.name }}"
register: new_user_setup
- name: Setup User ssh_key
authorized_key:
user: "{{ user.name }}"
state: "{{ user.state | default('present') }}"
key: "{{ user.ssh_key }}"
loop: "{{ users | selectattr('ssh_key', 'defined') | list }}"
loop_control:
label: "{{ user.name }}"
loop_var: user
- name: Activate password setup for newly created users
shell: " set -e pipefail; passwd -d {{ user }}; chage -d0 {{ user }}"
loop: "{{ new_user_setup | json_query('results[?changed==`true`].name') | difference(active_users.stdout_lines) }}"
loop_control:
label: "{{ user }}"
loop_var: user
when: new_user_setup.changed

View File

@ -0,0 +1,5 @@
[Definition]
failregex = ^<HOST> -.*GET .*/~.*
ignoreregex =

View File

@ -0,0 +1,5 @@
[Definition]
failregex = ^<HOST> -.*GET http.*
ignoreregex =

View File

@ -0,0 +1,5 @@
[Definition]
failregex = ^<HOST> -.*GET.*(\.asp|\.exe|\.pl|\.cgi|\.scgi)
ignoreregex =

View File

@ -0,0 +1,34 @@
[DEFAULT]
bantime = {{ fail2ban_bantime }}
findtime = {{ fail2ban_bantime }}
maxretry = {{ fail2ban_maxretry }}
[sshd]
enabled = true
port = 22,{{ ssh_port }},ssh
[nginx-http-auth]
enabled = {{ 'nginx' in fail2ban_activate_modules }}
port = http,https
filter = nginx-noscript
logpath = %(nginx_error_log)s
maxretry = 6
{% for filter in fail2ban_nginx_default_filter %}
[{{ filter }}]
enabled = {{ 'nginx' in fail2ban_activate_modules }}
port = http,https
filter = {{ filter }}
logpath = %(nginx_access_log)s
maxretry = 2
{% endfor %}
{% for filter in fail2ban_nginx_selfmade_filter %}
[{{ filter }}]
enabled = {{ 'nginx' in fail2ban_activate_modules }}
port = http,https
filter = {{ filter }}
logpath = %(nginx_access_log)s
maxretry = 2
{% endfor %}

View File

@ -0,0 +1,121 @@
# $OpenBSD: sshd_config,v 1.103 2018/04/09 20:41:22 tj Exp $
# This is the sshd server system-wide configuration file. See
# sshd_config(5) for more information.
# This sshd was compiled with PATH=/usr/bin:/bin:/usr/sbin:/sbin
# The strategy used for options in the default sshd_config shipped with
# OpenSSH is to specify options with their default value where
# possible, but leave them commented. Uncommented options override the
# default value.
Protocol {{ ssh_protocol_version }}
Port {{ ssh_port }}
#AddressFamily any
#ListenAddress 0.0.0.0
#ListenAddress ::
#HostKey /etc/ssh/ssh_host_rsa_key
#HostKey /etc/ssh/ssh_host_ecdsa_key
#HostKey /etc/ssh/ssh_host_ed25519_key
# Ciphers and keying
#RekeyLimit default none
# Logging
#SyslogFacility AUTH
#LogLevel INFO
# Authentication:
#LoginGraceTime 10m
PermitRootLogin {{ ssh_login_root }}
#StrictModes yes
#MaxAuthTries 6
#MaxSessions 10
PubkeyAuthentication {{ ssh_use_key }}
# Expect .ssh/authorized_keys2 to be disregarded by default in future.
#AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2
#AuthorizedPrincipalsFile none
#AuthorizedKeysCommand none
#AuthorizedKeysCommandUser nobody
# For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
#HostbasedAuthentication no
# Change to yes if you don't trust ~/.ssh/known_hosts for
# HostbasedAuthentication
#IgnoreUserKnownHosts no
# Don't read the user's ~/.rhosts and ~/.shosts files
#IgnoreRhosts yes
# To disable tunneled clear text passwords, change to no here!
PasswordAuthentication {{ ssh_use_password }}
PermitEmptyPasswords no
# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication no
# Kerberos options
#KerberosAuthentication no
#KerberosOrLocalPasswd yes
#KerberosTicketCleanup yes
#KerberosGetAFSToken no
# GSSAPI options
#GSSAPIAuthentication no
#GSSAPICleanupCredentials yes
#GSSAPIStrictAcceptorCheck yes
#GSSAPIKeyExchange no
# Set this to 'yes' to enable PAM authentication, account processing,
# and session processing. If this is enabled, PAM authentication will
# be allowed through the ChallengeResponseAuthentication and
# PasswordAuthentication. Depending on your PAM configuration,
# PAM authentication via ChallengeResponseAuthentication may bypass
# the setting of "PermitRootLogin without-password".
# If you just want the PAM account and session checks to run without
# PAM authentication, then enable this but set PasswordAuthentication
# and ChallengeResponseAuthentication to 'no'.
UsePAM yes
#AllowAgentForwarding yes
#AllowTcpForwarding yes
#GatewayPorts no
X11Forwarding no
#X11DisplayOffset 10
#X11UseLocalhost yes
#PermitTTY yes
PrintMotd no
#PrintLastLog yes
#TCPKeepAlive yes
#PermitUserEnvironment no
#Compression delayed
#ClientAliveInterval 0
#ClientAliveCountMax 3
#UseDNS no
#PidFile /var/run/sshd.pid
#MaxStartups 10:30:100
#PermitTunnel no
#ChrootDirectory none
#VersionAddendum none
# no default banner path
#Banner none
# Allow client to pass locale environment variables
AcceptEnv LANG LC_*
# override default of no subsystems
Subsystem sftp /usr/lib/openssh/sftp-server
# Example of overriding settings on a per-user basis
#Match User anoncvs
# X11Forwarding no
# AllowTcpForwarding no
# PermitTTY no
# ForceCommand cvs server

View File

@ -0,0 +1,155 @@
#!/bin/bash
set -e
### VARIABLE ###################################################################
environment_folder={{ cloud_env_path }}
environment="{{ cloud_env }}"
host_type="{{ cloud_host_group }}"
script_name=$(basename $0)
cloud_name="{{ cloud_name }}"
cloud_type="{{ cloud_type }}"
version="{{ cloud_control_version }}"
branch_main="{{ cloud_git_branch_main }}"
################################################################################
### FUNCTION ###################################################################
to_working_directory() {
if [ ! -d $environment_folder/.git ] || [ ! -d $environment_folder ]; then
echo "Environment '$environment' in '$environment_folder' not available or folder not a git repository! Abort."
exit 1
fi
cd $environment_folder/$environment
}
help() {
echo "$script_name, version $version by L.Hahn"
echo ""
echo " $cloud_name script for cloud control"
echo " You can checkout environment (branches), rollout configurations,"
echo " run ansible and restore entire configurations."
echo ""
echo "Usage: $script_name [command] [options]"
echo ""
echo "commands:"
echo " - help print this help"
echo " - maintenance setup local server into maintenance mode; no automatic ansible call"
echo " - environment"
echo " download <branch> checkout <branch> from remote repository"
echo " update load latest remote changes for current branch"
echo " reset stash changes and reset current branch from remote repository with latest changes"
echo " restore checkout latest $branch_main branch from remote repository"
echo " - update get latest roles according to environment requirements.yml"
echo " - play play current loaded ansible playbooks"
echo " - reset perform 1. environment restore, 2. update, 3. execute"
echo ""
echo ""
echo "example:"
echo "~# $script_name environment update"
echo " this will download changes from the currently active remote branch"
}
environment() {
to_working_directory
current_branch=$(git branch | grep "^\*" | cut -d " " -f 2)
current_upstream=$(git rev-parse $current_branch@{upstream})
env_option=$1
case $env_option in
"update")
echo "### Updating branch '$current_branch' in $environment_folder ###"
git pull
;;
"reset")
echo "### Resetting branch '$current_branch' in $environment_folder ###"
git reset --hard $current_branch
git pull
;;
"restore")
echo "### Restoring branch '$branch_main' in $environment_folder ###"
git reset --hard HEAD
git clean -f
git checkout $branch_main
git pull
;;
"download")
if [ $# -lt 2 ]; then
echo "Missing branch name for environment downloading"
exit 1
fi
echo "### Stashing branch '$current_branch' & downloading branch '$2' in $environment_folder ###"
git stash
git checkout -b $2 origin/$2
git pull
;;
*)
echo "Unknown environments option '$env_option', abort!"
exit 1
;;
esac
}
maintenance() {
to_working_directory
echo "maint"
}
update() {
to_working_directory
ansible-galaxy install -f -p roles/ -r requirements.yml
}
play() {
to_working_directory
ansible-playbook $cloud_type"-"$host_type".yml"
}
################################################################################
### MAIN #######################################################################
if [ $# -eq 0 ]; then
help
exit 1
fi
script_command=$1
case $script_command in
"help")
help
;;
"maintenance")
maintenance
;;
"environment")
if [ $# -lt 2 ]; then
echo "ERROR! environment command needs options! None provided."
echo "Call '~# $script_name help' for more information."
exit 1
fi
environment $2 $3
;;
"update")
update
;;
"play")
play
;;
"reset")
echo "#=== restore environment ===#"
environment restore
echo ""
echo "#=== update roles ===#"
update
echo ""
echo "#=== play playbook ===#"
play
echo ""
;;
*)
echo "Unknown command '$script_command', abort!"
echo "Call '~# $script_name help' for more information."
;;
esac
################################################################################

7
roles/basis/vars/main.yml Executable file
View File

@ -0,0 +1,7 @@
---
sshd_path: "/etc/ssh"
sshd_conf: "{{ sshd_path }}/sshd_config"
fail2ban_path: "/etc/fail2ban"
fail2ban_jail_conf: "{{ fail2ban_path }}/jail.local"
cloud_control_path: "/usr/local/bin"

9
roles/checkmk/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/checkmk/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-checkmk
Ansible role in order to setup a checkmk node for monitoring.

28
roles/checkmk/defaults/main.yml Executable file
View File

@ -0,0 +1,28 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
domain_external: my-domain.tld
checkmk_edition: free
checkmk_version: 2.0.0p22
checkmk_server_arch: _0.bullseye_amd64.deb
checkmk_server_source: "https://download.checkmk.com/checkmk/{{ checkmk_version }}/check-mk-{{ checkmk_edition }}-{{ checkmk_version }}{{ checkmk_server_arch }}"
checkmk_server_sites:
- monitoring
checkmk_server_host: "{{ domain_external }}"
checkmk_server_scheme: https
# allow requests only from that ip (server), otherwise
# metrics are available from the entire world
checkmk_server_ip: 12.34.56.78
checkmk_agent_arch: "-1_all.deb"
checkmk_agent_site: "{{ checkmk_server_sites[0] }}"
checkmk_agent_source: "{{ checkmk_server_scheme }}://{{ checkmk_server_host }}/{{ checkmk_agent_site }}/check_mk/agents/check-mk-agent_{{ checkmk_version }}{{ checkmk_agent_arch }}"
checkmk_admin_pass: VeryStrongAdminPass
checkmk_is_server: false

10
roles/checkmk/handlers/main.yml Executable file
View File

@ -0,0 +1,10 @@
---
- name: restart omd
systemd:
name: omd
state: restarted
- name: restart xinetd
systemd:
name: xinetd
state: restarted

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:09 '
version: ''

16
roles/checkmk/meta/main.yml Executable file
View File

@ -0,0 +1,16 @@
---
galaxy_info:
role_name: checkmk
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Role to setup CheckMK as server or agent.
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 11
galaxy_tags:
- checkmk
dependencies: []

29
roles/checkmk/tasks/main.yml Executable file
View File

@ -0,0 +1,29 @@
---
- name: install checkmk server
include_tasks: server.yml
when: checkmk_is_server | bool
- name: install requirements for checkmk agents
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- xinetd
- name: install agent from monitoring server
apt:
deb: "{{ checkmk_agent_source }}"
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
ignore_errors: yes
# if the monitoring server is not fast enough online...
- name: restrict metrics access via xinetd only for montoring server
lineinfile:
path: "/etc/xinetd.d/check_mk"
regexp: '^\s*#?only_from\s*='
line: "\tonly_from = {{ checkmk_server_ip }}"
ignore_errors: yes # if the monitoring server is not fast enough online...
notify: restart xinetd

45
roles/checkmk/tasks/server.yml Executable file
View File

@ -0,0 +1,45 @@
---
- name: install requirements for checkmk
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- python3-passlib
- name: install checkmk from deb file
apt:
deb: "{{ checkmk_server_source }}"
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
# apache2 is default installed via e.g. deb file
# in order to run e.g. nginx as webserver, we should disable it
- name: adjust apache2 systemd unit state
systemd:
name: apache2
enabled: "{{ checkmk_system_apache2 | default('no') | bool }}"
daemon_reload: yes
- name: generate checkmk sites
command:
cmd: "omd create {{ item }}"
creates: "/omd/sites/{{ item }}"
notify: restart omd
loop: "{{ checkmk_server_sites }}"
- name: setup admin password for sites
htpasswd:
path: "/omd/sites/{{ cmk_site }}/etc/htpasswd"
name: "{{ checkmk_admin_user }}"
password: "{{ checkmk_admin_pass }}"
owner: "{{ cmk_site }}"
group: "{{ cmk_site }}"
mode: 0660
become: yes
become_user: "{{ cmk_site }}"
loop: "{{ checkmk_server_sites }}"
loop_control:
loop_var: cmk_site
label: "site: {{ cmk_site }}"

2
roles/checkmk/vars/main.yml Executable file
View File

@ -0,0 +1,2 @@
---
checkmk_admin_user: cmkadmin

9
roles/docker/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/docker/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-docker
Ansible role to setup basic docker and docker compose.

7
roles/docker/defaults/main.yml Executable file
View File

@ -0,0 +1,7 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
docker_compose_version: 1.29.2

1
roles/docker/handlers/main.yml Executable file
View File

@ -0,0 +1 @@
---

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:09 '
version: ''

16
roles/docker/meta/main.yml Executable file
View File

@ -0,0 +1,16 @@
---
galaxy_info:
role_name: docker
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Role to setup docker.
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 10
galaxy_tags:
- docker
dependencies: []

41
roles/docker/tasks/main.yml Executable file
View File

@ -0,0 +1,41 @@
---
# Basics
- name: install requirements for docker
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- apt-transport-https
- ca-certificates
- gnupg2
- software-properties-common
- curl
# Docker
- name: install docker repository key
apt_key:
url: https://download.docker.com/linux/debian/gpg
state: present
- name: install docker repository
apt_repository:
repo: "deb [arch={{ ansible_kernel.split('-')[-1] }}] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable"
state: present
- name: install docker (docker-ce + docker-ce-cli)
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- docker-ce
- docker-ce-cli
- python3-docker
# Docker Compose
- name: download latest docker
get_url:
url: "https://github.com/docker/compose/releases/download/{{ docker_compose_version }}/docker-compose-linux-{{ ansible_architecture }}"
dest: /usr/local/bin/docker-compose
mode: 0755

1
roles/docker/vars/main.yml Executable file
View File

@ -0,0 +1 @@
---

9
roles/easy-rsa/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/easy-rsa/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-easyrsa
Ansible role to provide easyrsa for VPN CA setup. Can be used standalone aswell.

View File

@ -0,0 +1,23 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
easy_rsa_ca: "{{ ansible_hostname }}"
easy_rsa_servers:
- name: some_server
state: present
easy_rsa_clients:
- name: username
state: present
- name: username.app
state: absent
easy_rsa_vars_conf:
country: "COUNTRY"
province: "PROVINCE"
city: "CITY"
company: "YOUR COMPANY"
mail: "admin@your-company.com"

View File

@ -0,0 +1 @@
---

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:10 '
version: ''

16
roles/easy-rsa/meta/main.yml Executable file
View File

@ -0,0 +1,16 @@
---
galaxy_info:
role_name: easy-rsa
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Role to setup an easy-rsa for PKI, CA and certificates.
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 10
galaxy_tags:
- easy-rsa
dependencies: []

107
roles/easy-rsa/tasks/main.yml Executable file
View File

@ -0,0 +1,107 @@
---
- name: install openvpn, easy-rsa and recommendations
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- "easy-rsa"
- name: Setup easy-rsa variables
template:
src: "templates{{ easy_rsa_home }}/vars.j2"
dest: "{{ easy_rsa_home }}/vars"
mode: 0644
owner: root
group: root
- name: initialise PKI
shell:
creates: "{{ easy_rsa_home }}/pki"
chdir: "{{ easy_rsa_home }}"
cmd: ./easyrsa init-pki
- name: setup certificate authority
shell:
creates: "{{ easy_rsa_home }}/pki/ca.crt"
chdir: "{{ easy_rsa_home }}"
cmd: "echo '{{ easy_rsa_ca }}' | ./easyrsa build-ca nopass"
- name: setup diffie-hellman key-pair for key exchange
shell:
creates: "{{ easy_rsa_home }}/pki/dh.pem"
chdir: "{{ easy_rsa_home }}"
cmd: ./easyrsa gen-dh
- name: setup server certificates
shell:
cmd: |
echo '{{ srvr }}' | ./easyrsa gen-req {{ srvr }} nopass
echo 'yes' | ./easyrsa sign-req server {{ srvr }}
chdir: "{{ easy_rsa_home }}"
creates: "{{ easy_rsa_home }}/pki/issued/{{ srvr }}.crt"
loop: "{{ easy_rsa_servers_active }}"
loop_control:
loop_var: srvr
label: "{{ srvr }}"
- name: setup client certificates
shell:
cmd: |
echo '{{ client }}' | ./easyrsa gen-req {{ client }} nopass
echo 'yes' | ./easyrsa sign-req client {{ client }}
chdir: "{{ easy_rsa_home }}"
creates: "{{ easy_rsa_home }}/pki/issued/{{ client }}.crt"
loop: "{{ easy_rsa_clients_active }}"
loop_control:
loop_var: client
label: "{{ client }}"
- name: verify certificate integrety
command: "openssl verify -CAfile {{ easy_rsa_home }}/pki/ca.crt {{ easy_rsa_home }}/pki/issued/{{ cert }}.crt"
register: easy_rsa_cert_check
changed_when: ((easy_rsa_cert_check.stdout.split(' ') | length) > 1) and (easy_rsa_cert_check.stdout.split(' ')[1] != "OK")
loop: "{{ easy_rsa_entities_active }}"
loop_control:
loop_var: cert
label: "{{ cert }}"
- name: find abstent easy-rsa certifcates
find:
paths: "{{ easy_rsa_home }}/pki/issued/"
pattern: "{{ cert }}.crt"
loop: "{{ easy_rsa_entities_passive }}"
loop_control:
loop_var: cert
label: "{{ cert }}"
register: easy_rsa_absent_certs
- name: remove absent easy-rsa clients certs
file:
state: absent
path: "{{ client }}"
loop: "{{ easy_rsa_absent_certs.results | json_query('[*].files[*].path') | flatten }}"
loop_control:
loop_var: client
label: "{{ client | basename }}"
when: easy_rsa_absent_certs.results | length > 0
- name: find abstent easy-rsa keys
find:
paths: "{{ easy_rsa_home }}/pki/private/"
pattern: "{{ cert }}.key"
loop: "{{ easy_rsa_entities_passive }}"
loop_control:
loop_var: cert
label: "{{ cert }}"
register: easy_rsa_absent_keys
- name: remove absent easy-rsa clients keys
file:
state: absent
path: "{{ client }}"
loop: "{{ easy_rsa_absent_keys.results | json_query('[*].files[*].path') | flatten }}"
loop_control:
loop_var: client
label: "{{ client | basename }}"
when: easy_rsa_absent_keys.results | length > 0

View File

@ -0,0 +1,18 @@
set_var EASYRSA "$PWD"
set_var EASYRSA_PKI "$EASYRSA/pki"
set_var EASYRSA_DN "cn_only"
set_var EASYRSA_REQ_COUNTRY "{{ easy_rsa_vars_conf.country }}"
set_var EASYRSA_REQ_PROVINCE "{{ easy_rsa_vars_conf.province }}"
set_var EASYRSA_REQ_CITY "{{ easy_rsa_vars_conf.city }}"
set_var EASYRSA_REQ_ORG "{{ easy_rsa_vars_conf.company }} CERTIFICATE AUTHORITY"
set_var EASYRSA_REQ_EMAIL "{{ easy_rsa_vars_conf.mail }}"
set_var EASYRSA_REQ_OU "{{ easy_rsa_vars_conf.company }} EASY CA"
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 7500
set_var EASYRSA_CERT_EXPIRE 365
set_var EASYRSA_NS_SUPPORT "no"
set_var EASYRSA_NS_COMMENT "{{ easy_rsa_vars_conf.company }} CERTIFICATE AUTHORITY"
set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types"
set_var EASYRSA_SSL_CONF "$EASYRSA/openssl-easyrsa.cnf"
set_var EASYRSA_DIGEST "sha256"

7
roles/easy-rsa/vars/main.yml Executable file
View File

@ -0,0 +1,7 @@
---
easy_rsa_home: "/usr/share/easy-rsa"
easy_rsa_servers_active: "{{ easy_rsa_servers | json_query('[?state==`present`].name') }}"
easy_rsa_clients_active: "{{ easy_rsa_clients | json_query('[?state==`present`].name') }}"
easy_rsa_entities_active: "{{ (easy_rsa_servers + easy_rsa_clients) | json_query('[?state==`present`].name') }}"
easy_rsa_entities_passive: "{{ (easy_rsa_servers + easy_rsa_clients) | json_query('[?state!=`present`].name') }}"

9
roles/gitea/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/gitea/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-gitea
Ansible role to setup gitea.

42
roles/gitea/defaults/main.yml Executable file
View File

@ -0,0 +1,42 @@
---
cloud_apps: /opt
cloud_storage: /opt/storage
cloud_stage: prod
cloud_update: false
gitea_data_location: "{{ cloud_storage }}/gitea-data"
gitea_db:
type: pgsql
name: gitea_db
user: gitea_dbu
pass: gitea_dbpw
port: 5432
host: localhost
gitea_version: 1.16.7
gitea_source: https://dl.gitea.io/gitea
gitea_arch: linux-amd64
gitea_domain: localhost
gitea_domain_protocol: https
gitea_port: 3000
gitea_ssh_domain: localhost
gitea_internal_token: INTERNAL_TOKEN
gitea_jwt_secret: JWT_SECRET
gitea_secret_key: SECRET_KEY
gitea_mail: true
gitea_mail_type: smtp
gitea_mail_tls: true
gitea_mail_domain: mail.my-domain.tld
gitea_mail_port: 465
gitea_mail_user: user@my-domain.tld
gitea_mail_from: "{{ gitea_mail_user }}"
gitea_mail_pass: ThisCouldBeYourAdd
gitea_admin_user: gitea_adm
gitea_admin_pass: gitea_fancy_adm_password!
gitea_admin_mail: "{{ gitea_mail_user }}"

18
roles/gitea/handlers/main.yml Executable file
View File

@ -0,0 +1,18 @@
---
- name: restart gitea
systemd:
name: gitea
state: restarted
- name: generate admin user
command:
cmd: |
{{ gitea_link }}/gitea admin user create
--admin
--username {{ gitea_admin_user }}
--password '{{ gitea_admin_pass }}'
--email {{ gitea_admin_mail }}
--config {{ gitea_home }}/app.ini
--work-path {{ gitea_data_location }}
become: yes
become_user: "{{ gitea_usr }}"

View File

@ -0,0 +1,2 @@
install_date: 'So 29 Mai 2022 13:55:10 '
version: ''

17
roles/gitea/meta/main.yml Executable file
View File

@ -0,0 +1,17 @@
---
galaxy_info:
role_name: gitea
namespace: hahn-cloud
author: Lars Hahn
company: OpenDevChain
license: MIT
description: Role to setup gitea Git Server
min_ansible_version: 2.7
platforms:
- name: Debian
versions:
- 11
galaxy_tags:
- gitea
dependencies:
- postgres

90
roles/gitea/tasks/main.yml Executable file
View File

@ -0,0 +1,90 @@
---
- name: install Gitea recommendations
apt:
update_cache: yes
state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}"
install_recommends: yes
pkg:
- "git"
- name: setup gitea group
group:
name: "{{ gitea_usr }}"
state: "present"
- name: setup gitea user
user:
name: "{{ gitea_usr }}"
home: "{{ gitea_home }}"
group: "{{ gitea_grp }}"
groups:
- "{{ gitea_grp }}"
comment: Virtual Gitea User
shell: /bin/bash
state: present
system: yes
- name: setup gitea directories
file:
state: directory
path: "{{ item }}"
owner: "{{ gitea_usr }}"
group: "{{ gitea_grp }}"
mode: 0750
loop:
- "{{ gitea_inst }}"
- "{{ gitea_home }}"
- "{{ gitea_data_location }}"
- "{{ gitea_data_location }}/custom"
- "{{ gitea_data_location }}/data"
- "{{ gitea_data_location }}/log"
- name: setup gitea config directories
file:
state: directory
path: "{{ item }}"
owner: "root"
group: "{{ gitea_grp }}"
mode: 0770
loop:
- "/etc/gitea"
- name: setup gitea installation link
file:
state: link
src: "{{ gitea_inst }}"
dest: "{{ gitea_link }}"
owner: "{{ gitea_usr }}"
group: "{{ gitea_grp }}"
mode: 0750
- name: download gitea
get_url:
url: "{{ gitea_source }}/{{ gitea_version }}/gitea-{{ gitea_version }}-{{ gitea_arch }}"
dest: "{{ gitea_link }}/gitea"
owner: "{{ gitea_usr }}"
group: "{{ gitea_grp }}"
mode: 0775
notify: generate admin user
- name: setup gitea application ini
template:
src: opt/gitea/home/app.ini.j2
dest: "{{ gitea_home }}/app.ini"
owner: root
group: "{{ gitea_grp }}"
mode: 0640
notify: restart gitea
- name: setup gitea systemd unit
template:
src: etc/systemd/system/gitea.service.j2
dest: /etc/systemd/system/gitea.service
notify: restart gitea
- name: enable gitea systemd unit
systemd:
name: gitea
enabled: yes
daemon_reload: yes
state: started

View File

@ -0,0 +1,27 @@
[Unit]
Description=Gitea (Git with a cup of tea)
After=syslog.target
After=network.target
Wants=postgresql.service
After=postgresql.service
#Wants=memcached.service
#After=memcached.service
#Wants=redis.service
#After=redis.service
[Service]
#LimitMEMLOCK=infinity
#LimitNOFILE=65535
RestartSec=2s
Type=simple
User={{ gitea_usr }}
Group={{ gitea_grp }}
WorkingDirectory={{ gitea_data_location }}
ExecStart={{ gitea_link }}/gitea web --config {{ gitea_home }}/app.ini
Restart=always
Environment=USER={{ gitea_usr }} HOME={{ gitea_home }} GITEA_WORK_DIR={{ gitea_data_location }}
#Environment=PATH=/path/to/git/bin:/bin:/sbin:/usr/bin:/usr/sbin
[Install]
WantedBy=multi-user.target

View File

@ -0,0 +1,80 @@
APP_NAME = gitea@{{ gitea_ssh_domain }}
RUN_USER = {{ gitea_usr }}
RUN_MODE = {{ cloud_stage }}
[database]
DB_TYPE = postgres
HOST = {{ gitea_db.host | default('localhost') }}:{{ gitea_db.port | default(5432) }}
NAME = {{ gitea_db.name }}
USER = {{ gitea_db.user }}
PASSWD = `{{ gitea_db.pass }}`
SCHEMA =
SSL_MODE = disable
CHARSET = utf8
PATH = {{ gitea_data_location }}/data/gitea.db
LOG_SQL = false
[repository]
ROOT = {{ gitea_data_location }}/data/gitea-repositories
[server]
SSH_DOMAIN = {{ gitea_ssh_domain }}
DOMAIN = {{ gitea_domain }}
HTTP_PORT = {{ gitea_port | default(3000) }}
ROOT_URL = {{ gitea_domain_protocol }}://{{ gitea_ssh_domain }}/
DISABLE_SSH = {{ gitea_ssh | default('false') }}
SSH_PORT = {{ ssh_port | default(22) }}
LFS_START_SERVER = {{ gitea_lfs | default('true') }}
LFS_CONTENT_PATH = {{ gitea_data_location }}/data/lfs
LFS_JWT_SECRET = `{{ gitea_jwt_secret }}`
OFFLINE_MODE = {{ gitea_is_offline | default('false') }}
LANDING_PAGE = {{ gitea_landing_page | default('explore') }}
[mailer]
ENABLED = {{ gitea_mail }}
FROM = {{ gitea_mail_from }}
MAILER_TYPE = {{ gitea_mail_type }}
HOST = {{ gitea_mail_domain }}:{{ gitea_mail_port }}
IS_TLS_ENABLED = {% if gitea_mail_tls is defined and gitea_mail_tls%}true{% else %}false{% endif %}
USER = {{ gitea_mail_user }}
PASSWD = `{{ gitea_mail_pass }}`
[service]
REGISTER_EMAIL_CONFIRM = true
ENABLE_NOTIFY_MAIL = true
DISABLE_REGISTRATION = true
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
ENABLE_CAPTCHA = false
REQUIRE_SIGNIN_VIEW = false
DEFAULT_KEEP_EMAIL_PRIVATE = true
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
DEFAULT_ENABLE_TIMETRACKING = true
NO_REPLY_ADDRESS = noreply.{{ gitea_ssh_domain }}
[picture]
DISABLE_GRAVATAR = false
ENABLE_FEDERATED_AVATAR = true
[openid]
ENABLE_OPENID_SIGNIN = false
ENABLE_OPENID_SIGNUP = false
[oauth2_client]
ENABLE_AUTO_REGISTRATION = true
UPDATE_AVATAR = true
ACCOUNT_LINKING = auto
[session]
PROVIDER = file
[log]
MODE = file
LEVEL = info
ROOT_PATH = {{ gitea_data_location }}/log
ROUTER = file
[security]
INSTALL_LOCK = true
INTERNAL_TOKEN = `{{ gitea_internal_token }}`
SECRET_KEY = `{{ gitea_secret_key }}`
PASSWORD_HASH_ALGO = pbkdf2

7
roles/gitea/vars/main.yml Executable file
View File

@ -0,0 +1,7 @@
---
gitea_usr: gitea
gitea_grp: "{{ gitea_usr }}"
gitea_link: "{{ cloud_apps }}/gitea/inst"
gitea_inst: "{{ cloud_apps }}/gitea/gitea-{{ gitea_version }}"
gitea_home: "{{ cloud_apps }}/gitea/home"

9
roles/gocd-agent/LICENSE Executable file
View File

@ -0,0 +1,9 @@
MIT License
Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

3
roles/gocd-agent/README.md Executable file
View File

@ -0,0 +1,3 @@
# cloud-gocd-agent
Ansible role to provide an GoCD agent for an existing GoCD server; does not necessarly have to on the GoCD server node.

Some files were not shown because too many files have changed in this diff Show More