diff --git a/.gitignore b/.gitignore index dc35951..73e0622 100644 --- a/.gitignore +++ b/.gitignore @@ -60,7 +60,6 @@ index.txt # Ansible *.retry private/ -hosts.yml group_vars host_vars playbooks @@ -68,29 +67,31 @@ group_vars/ host_vars/ playbooks/ -common.yml -homeservers.yml -hosts-sensors.yml -hosts.yml -letsencrypt.yml -lychener54.yml -monitoring-server.yml -nextcloud.yml -sensors.yml -site.yml -vpnservers.yml -site2.yml -mathom.yml -haproxy.yml -auth.yml -mainframe.yml -nginx.yml -common.yml -turn.yml -sensnet.yml -backup.yml -jenkins.yml -kvm.yml -paperless.yml -vaultwarden.yml -mirrors.yml +/hosts.yml +/common.yml +/homeservers.yml +/hosts-sensors.yml +/hosts.yml +/letsencrypt.yml +/lychener54.yml +/monitoring-server.yml +/nextcloud.yml +/sensors.yml +/site.yml +/vpnservers.yml +/site2.yml +/mathom.yml +/haproxy.yml +/auth.yml +/mainframe.yml +/nginx.yml +/common.yml +/turn.yml +/sensnet.yml +/backup.yml +/jenkins.yml +/kvm.yml +/paperless.yml +/vaultwarden.yml +/mirrors.yml +/lb.yml \ No newline at end of file diff --git a/ansible.cfg b/ansible.cfg deleted file mode 120000 index 48f2d47..0000000 --- a/ansible.cfg +++ /dev/null @@ -1 +0,0 @@ -private/ansible.cfg \ No newline at end of file diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..2d9261e --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,20 @@ + +[defaults] +inventory = hosts.yml +#stdout_callback = json +# unfortunate name, previously named human_log, much less verbose than default +stdout_callback = debug +roles_path = ./roles/:./private/roles/ +playbook_dir = ./private/playbooks/ +forks = 20 +#internal_poll_interval = 0.5 +max_diff_size = 104857600 +ansible_managed = "{{{{ lookup('pipe', 'git rev-parse --show-toplevel')|basename }}}}/roles/{{{{ role_name }}}}/{{{{ template_path }}}}{{{{ lookup('pipe', 'git log -1 ' + template_fullpath|quote) | default(False, True) | ternary("", ",UNCOMITTED") }}}}" + +[diff] +diff_always = False + +[ssh_connection] +ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o PreferredAuthentications=publickey +control_path = /tmp/ansible-ssh-%%h-%%p-%%r +pipelining = true diff --git a/bin/newrole.sh b/bin/newrole.sh index 024c38a..380b16f 100755 --- a/bin/newrole.sh +++ b/bin/newrole.sh @@ -24,12 +24,14 @@ echo " roles:" >> private/playbooks/$1.yml echo " - $1" >> private/playbooks/$1.yml ln -s private/playbooks/$1.yml . -echo "${1}.yml" >> .gitignore +echo "/${1}.yml" >> .gitignore ( cd private/ git st - git add private/site2.yml - git add private/playbooks/$1.yml + git add site2.yml + git add playbooks/$1.yml git commit -m "new role: $1" + git push + git st ) diff --git a/roles/haproxy/tasks/haproxy.yml b/roles/haproxy/tasks/haproxy.yml new file mode 100644 index 0000000..89b30ca --- /dev/null +++ b/roles/haproxy/tasks/haproxy.yml @@ -0,0 +1,123 @@ +--- + +- name: save instacne id + get_url: + url: http://169.254.169.254/hetzner/v1/metadata/instance-id + dest: /usr/local/etc/instance-id + mode: '0755' + ignore_errors: true + +- name: template failover script + template: + src: "{{ item }}.j2" + dest: "/usr/local/bin/{{ item }}" + owner: root + group: root + mode: 0755 + with_items: + - failover.py + +- name: template floating ip config + template: + src: 60-floating-ip.yaml.j2 + dest: /etc/netplan/60-floating-ip.yaml + owner: root + group: root + mode: 0644 + notify: netplan apply + +- name: make sure log dir exists + file: + state: directory + path: /var/log/haproxy + owner: root + group: syslog + mode: 0775 + notify: restart rsyslog + +- name: template rsyslog config + template: + src: 49-haproxy.conf.j2 + dest: /etc/rsyslog.d/49-haproxy.conf + owner: root + group: root + mode: 0644 + notify: restart rsyslog + +- name: install haproxy+keepalived + apt: + name: + - haproxy + - keepalived + - heartbeat + state: latest + update_cache: true + when: not skip_apt|default(false) + tags: + - packages + +- name: tempalte letsencrypt keys with privkey+pubkey in one file + template: + src: ssl-letsencrypt.pem.j2 + dest: /etc/haproxy/ssl-{{ item }}.pem + owner: root + group: root + mode: 0664 + no_log: true + loop_control: + label: "{{ item }}" + tags: + - letsencrypt + notify: reload haproxy + with_items: "{{ letsencrypt_domains }}" + when: haproxy_letsencrypt|default(false) + +- name: tempalte haproxy config + template: + src: haproxy.cfg.j2 + dest: /etc/haproxy/haproxy.cfg + owner: root + group: root + mode: 0644 + tags: + - haproxy.cfg + notify: reload haproxy + + +- name: telegraf file + template: + src: telegraf-haproxy.conf.j2 + dest: /etc/telegraf/telegraf.d/haproxy.conf + notify: + - restart telegraf + tags: + - telegraf + +- name: template filebeat config + template: + src: filebeat-haproxy.yml.j2 + dest: "/etc/filebeat/inputs.d/haproxy.yml" + owner: root + group: root + mode: 0644 + tags: + - filebeat + - filebeat-input + notify: restart filebeat + +- name: enable haproxy and make sure its started + service: + name: haproxy + state: started + enabled: true + +- name: keep pacemaker and keepalived stopped for now + service: + name: "{{ item }}" + state: stopped + enabled: false + loop_control: + label: "{{ item }}" + with_items: + - pacemaker + - keepalived diff --git a/roles/sshd/handlers/main.yml b/roles/sshd/handlers/main.yml new file mode 100644 index 0000000..d73e8e2 --- /dev/null +++ b/roles/sshd/handlers/main.yml @@ -0,0 +1,6 @@ +--- + +- name: reload ssh + service: + name: ssh + state: reloaded diff --git a/roles/sshd/tasks/main.yml b/roles/sshd/tasks/main.yml new file mode 100644 index 0000000..4cee959 --- /dev/null +++ b/roles/sshd/tasks/main.yml @@ -0,0 +1,3 @@ +--- + - import_tasks: sshd.yml + tags: sshd diff --git a/roles/sshd/tasks/sshd.yml b/roles/sshd/tasks/sshd.yml new file mode 100644 index 0000000..6281794 --- /dev/null +++ b/roles/sshd/tasks/sshd.yml @@ -0,0 +1,10 @@ +--- + +- name: template sshd_config + template: + src: sshd_config.j2 + dest: /etc/ssh/sshd_config + owner: root + group: root + mode: '0644' + notify: reload ssh diff --git a/roles/sshd/templates/sshd_config.j2 b/roles/sshd/templates/sshd_config.j2 new file mode 100644 index 0000000..abc193d --- /dev/null +++ b/roles/sshd/templates/sshd_config.j2 @@ -0,0 +1,125 @@ +# {{ ansible_managed }} +# $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. + +Include /etc/ssh/sshd_config.d/*.conf + +#Port 22 +#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 2m +PermitRootLogin {{ sshd_permit_root_login | default('yes') }} +#StrictModes yes +#MaxAuthTries 6 +#MaxSessions 10 + +#PubkeyAuthentication yes + +# 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 no +#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 yes +#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 +PasswordAuthentication no diff --git a/roles/vaultwarden/tasks/vaultwarden.yml b/roles/vaultwarden/tasks/vaultwarden.yml new file mode 100644 index 0000000..1f326d9 --- /dev/null +++ b/roles/vaultwarden/tasks/vaultwarden.yml @@ -0,0 +1,217 @@ +--- + +- name: check if a user is missing mariadb_pass + fail: + msg: "missing: {{ item.username }}.mariadb_pass !" + when: item.mariadb_pass is defined == false + loop_control: + label: "{{ item.username }}" + with_items: "{{ vaultwarden_users }}" + +- name: create mariadb db + mysql_db: + name: "{{ mariadb_db }}" + # utf8mb4 has problems with varchar > 255 and vaultwarden (django) crashes + # https://stackoverflow.com/questions/43483129/does-mariadb-allow-255-character-unique-indexes + encoding: utf8mb4 + collation: utf8mb4_general_ci + login_unix_socket: /run/mysqld/mysqld.sock + with_items: "{{ vw_vaults }}" + loop_control: + label: "{{ mariadb_db }}" + vars: + mariadb_db: "vw_{{ item.name }}" + tags: + - mariadb-users + +- name: mariadb users for vaultwarden user vaults + mysql_user: + state: present + name: "{{ mariadb_username }}" + host: 'localhost' + priv: "{{ mariadb_db }}.*:ALL" + login_unix_socket: /run/mysqld/mysqld.sock + with_items: "{{ vw_vaults }}" + loop_control: + label: "{{ mariadb_username}}@localhost: {{ mariadb_db }}" + vars: + mariadb_db: "ww_{{ item.name }}" + mariadb_username: "{% if item.shared %}{{ mariadb_shared_user }}{% else%}{{ item.name }}{%endif%}" + tags: + - mariadb-users + +- name: mariadb user with password + mysql_user: + state: present + name: "{{ mariadb_username }}" + host: "{{ mariadb_host_allowed }}" + priv: "{{ mariadb_db }}.*:ALL" + password: "{{ mariadb_pass }}" + login_unix_socket: /run/mysqld/mysqld.sock + with_nested: + - "{{ vw_vaults }}" + - - "{{ ansible_default_ipv4.address }}" + - "{{ bridgewithdns_mariadb }}" + loop_control: + label: "{{ mariadb_username}}@{{ mariadb_host_allowed }}: {{ mariadb_db }}" + vars: + mariadb_host_allowed: "{{ item[1] }}" + mariadb_db: "ww_{{ item[0].name }}" + mariadb_username: "{% if item[0].shared %}valutwarden{% else%}{{ item[0].name }}{%endif%}" + mariadb_pass: "{% if item[0].shared %}{{ systemuserlist[mariadb_shared_user].mariadb_pass }}{% else%}{{ userlist[item[0].name].mariadb_pass }}{%endif%}" + tags: + - mariadb-users + +- name: create data dir + file: + path: "{{ systemuserlist.vaultwarden.home }}/{{ item }}" + state: directory + mode: 0770 + owner: "vaultwarden" + group: "vaultwarden" + with_items: + - data + - ldap + tags: + - vaultwarden-dirs + +- name: create data/ dirs dir + file: + path: "{{ item_path }}" + state: directory + mode: 0770 + owner: "{% if item.shared %}vaultwarden{% else %}{{ item.name }}{% endif %}" + group: "{% if item.shared %}vaultwarden{% else %}{{ item.name }}{% endif %}" + tags: + - vaultwarden-dirs + vars: + item_path: "{{ systemuserlist.vaultwarden.home }}/data/{{ item.name }}" + with_items: "{{ vw_vaults }}" + +- name: template config for vaultwarden_ldap + template: + src: ldap-config.toml.j2 + dest: "{{ systemuserlist.vaultwarden.home }}/ldap/config.toml" + owner: vaultwarden + group: vaultwarden + mode: 0640 + tags: + - vaultwarden-ldap + notify: restart vaultwarden_ldap + +- name: start vaultwarden containers + docker_container: + name: "{{ item.container_name }}" + image: "vaultwarden/server:latest" + restart_policy: "unless-stopped" + auto_remove: false + detach: true + pull: true + state: started + container_default_behavior: compatibility + user: "{{ uid }}:{{ gid }}" + networks_cli_compatible: false + network_mode: bridgewithdns + networks: + - name: bridgewithdns + ipv4_address: "{{ bridgewithdns[item.container_name] }}" + mounts: + - type: bind + source: "{{ systemuserlist.vaultwarden.home }}/data/{{ item.name }}" + target: /data + env: + MYSQL_PASSWORD: "{{ mariadb_pass }}" + MYSQL_DATABASE: "{{ mariadb_db }}" + MYSQL_USER: "{{ item.name }}" + ADMIN_TOKEN: "{{ vw_admin_token }}" + DOMAIN: "https://{{ vaultwarden_url }}" + INVITATIONS_ALLOWED: "true" + INVITATION_ORG_NAME: "{{ domain }}" + SIGNUPS_ALLOWED: "false" + SIGNUPS_DOMAINS_WHITELIST: "{{ domain }}" + LOG_FILE: "/data/{{ item.container_name }}.log" + WEBSOCKET_ENABLED: "true" + WEBSOCKET_ADDRESS: "0.0.0.0" + WEBSOCKET_PORT: "3012" + # https://github.com/dani-garcia/vaultwarden/wiki/SMTP-Configuration + SMTP_HOST: "{{ smtp_server }}" + SMTP_USERNAME: "{{ smtp_username }}" + SMTP_PASSWORD: "{{ smtp_passwd }}" + SMTP_PORT: "{{ smtp_port_string }}" + SMTP_SECURITY: "force_tls" + SMTP_FROM: "{{ systems_email }}" + + loop_control: + label: "{{ item.container_name }}" + vars: + uid: "{% if item.shared %}{{ systemuserlist.vaultwarden.uid }}{% else%}{{ userlist[item.name].uid }}{%endif%}" + gid: "{% if item.shared %}{{ systemuserlist.vaultwarden.gid }}{% else%}{{ userlist[item.name].gid }}{%endif%}" + mariadb_db: "ww_{{ item.name }}" + mariadb_username: "{% if item.shared %}valutwarden{% else%}{{ item.name }}{%endif%}" + mariadb_pass: "{% if item.shared %}{{ systemuserlist[mariadb_shared_user].mariadb_pass }}{% else%}{{ userlist[item.name].mariadb_pass }}{%endif%}" + with_items: "{{ vw_vaults }}" + tags: + - vaultwarden-containers + - vaultwarden-container + - vaultwarden-config + - docker-containers + +- name: start vaultwarden_ldap container + docker_container: + name: vaultwarden_ldap + image: vividboarder/vaultwarden_ldap + restart_policy: "unless-stopped" + auto_remove: false + detach: true + pull: true + state: started + container_default_behavior: compatibility + user: "{{ uid }}:{{ gid }}" + networks_cli_compatible: false + network_mode: bridgewithdns + networks: + - name: bridgewithdns + ipv4_address: "{{ bridgewithdns['vaultwarden_ldap'] }}" + mounts: + - type: bind + source: "{{ systemuserlist.vaultwarden.home }}/ldap/config.toml" + target: /config.toml + read_only: true + env: + CONFIG_PATH: "/config.toml" + RUST_BACKTRACE: "full" + vars: + uid: "{{ systemuserlist.vaultwarden.uid }}" + gid: "{{ systemuserlist.vaultwarden.gid }}" + tags: + - vaultwarden-containers + - vaultwarden_ldap-container + - vaultwarden-ldap + - docker-containers + +# - name: install certs +# copy: +# src: "/usr/local/etc/letsencrypt/live/{{ item }}" +# dest: "/usr/local/etc/certs/" +# owner: root +# group: root +# mode: 0755 +# tags: +# - letsencrypt-certs +# notify: reload nginx +# vars: +# prediff_cmd: echo +# with_items: +# - "{{ vaultwarden_url }}" + +- name: template nginx vhost for vaultwarden + template: + src: 01-vaultwarden.j2 + dest: /etc/nginx/sites-enabled/01-{{ vaultwarden_url }} + owner: root + group: root + mode: 0644 + tags: + - nginx + - vaultwarden-nginx + notify: reload nginx