From 923312b782e2c7d954919cf8cb14172d267a7216 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christer=20War=C3=A9n?= Date: Sun, 5 May 2024 18:10:54 +0300 Subject: [PATCH] Initial Commit --- .gitignore | 4 + .vscode/settings.json | 6 + LICENSE | 21 ++++ ansible.cfg | 16 +++ files/certbot/nginx.sh | 5 + files/nginx/conf/000-default.conf | 81 +++++++++++++ files/nginx/config.conf | 31 +++++ install.sh | 50 ++++++++ inventories/mkj/host_vars/mkj | 14 +++ inventories/mkj/hosts | 7 ++ protect.sh | 57 +++++++++ requirements.yml | 3 + tasks.yml | 25 ++++ tasks/deployer.yml | 152 ++++++++++++++++++++++++ tasks/installer.yml | 184 ++++++++++++++++++++++++++++++ tasks/maintenance.yml | 37 ++++++ 16 files changed, 693 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/settings.json create mode 100644 LICENSE create mode 100644 ansible.cfg create mode 100644 files/certbot/nginx.sh create mode 100644 files/nginx/conf/000-default.conf create mode 100644 files/nginx/config.conf create mode 100644 install.sh create mode 100644 inventories/mkj/host_vars/mkj create mode 100644 inventories/mkj/hosts create mode 100755 protect.sh create mode 100644 requirements.yml create mode 100644 tasks.yml create mode 100644 tasks/deployer.yml create mode 100644 tasks/installer.yml create mode 100644 tasks/maintenance.yml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..51fab92 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +!/collections/.gitkeep +/collections +/vault +__pycache__ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..247bf3e --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "editor.renderFinalNewline": false +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d5ea22a --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Warén Group + +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. diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..7187313 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,16 @@ +[defaults] +inventory = inventories/mkj +hash_behaviour = merge +gathering = smart +transport = local +display_skipped_hosts = false +interpreter_python = auto_silent +localhost_warning = false +collections_path = collections +inject_facts_as_vars = false +force_handlers = true +action_warnings = false +inventory_unparsed_warning = false + +[inventory] +host_pattern_mismatch = ignore diff --git a/files/certbot/nginx.sh b/files/certbot/nginx.sh new file mode 100644 index 0000000..4c28ff8 --- /dev/null +++ b/files/certbot/nginx.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +echo -n "$CERTBOT_VALIDATION" > /root/nginx/html/.well-known/acme-challenge/$CERTBOT_TOKEN +mkdir -p /root/nginx/html/.well-known/acme-challenge +/opt/ansible/bin/ansible-pull -U ssh://git@github.com/MatteZ02/mkj-infra --vault-password-file ~/.ansible/vault.yml --private-key ~/.ssh/id_rsa tasks.yml -t nginx &> /dev/null diff --git a/files/nginx/conf/000-default.conf b/files/nginx/conf/000-default.conf new file mode 100644 index 0000000..7993281 --- /dev/null +++ b/files/nginx/conf/000-default.conf @@ -0,0 +1,81 @@ +server { + + listen 80 default_server; + listen [::]:80 default_server; + + server_name _; + + expires off; + etag off; + if_modified_since off; + + gzip on; + gzip_min_length 1000; + gzip_proxied any; + gzip_types *; + gunzip on; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + + return 301 https://$host$request_uri; + } + + location /.well-known/acme-challenge/ { + root /usr/share/nginx/html; + index index.html index.htm; + } + + if ($request_method !~ ^(GET|HEAD|POST)$ ) + { + return 405; + } +} + +server { + + listen 443 ssl default_server; + listen [::]:443 ssl default_server; + + server_name _; + + http2 on; + + ssl_certificate /etc/nginx/certs/mkj/fullchain.pem; + ssl_certificate_key /etc/nginx/certs/mkj/privkey.pem; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-CCM8:DHE-RSA-AES256-CCM:ECDHE-ARIA256-GCM-SHA384:DHE-RSA-ARIA256-GCM-SHA384:ECDHE-ARIA128-GCM-SHA256:DHE-RSA-ARIA128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-CCM8:DHE-RSA-AES128-CCM'; + ssl_prefer_server_ciphers on; + ssl_session_cache shared:SSL:20m; + ssl_session_timeout 180m; + + ssl_stapling on; + ssl_stapling_verify on; + ssl_trusted_certificate /etc/nginx/certs/mkj/chain.pem; + + expires off; + etag off; + if_modified_since off; + + gzip on; + gzip_min_length 1000; + gzip_proxied any; + gzip_types *; + gunzip on; + + client_max_body_size 256M; + + location / { + proxy_pass http://127.0.0.1:8080/; + proxy_set_header Host $http_host; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + if ($request_method !~ ^(GET|HEAD|POST|PUT|DELETE)$ ) + { + return 405; + } +} diff --git a/files/nginx/config.conf b/files/nginx/config.conf new file mode 100644 index 0000000..c3c0a8f --- /dev/null +++ b/files/nginx/config.conf @@ -0,0 +1,31 @@ +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log error; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '[$time_local] $host - $remote_addr - $remote_user "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + server_tokens off; + + sendfile off; + #tcp_nopush on; + + keepalive_timeout 65; + + resolver 1.1.1.1; + + include /etc/nginx/conf.d/*.conf; +} diff --git a/install.sh b/install.sh new file mode 100644 index 0000000..c6aa135 --- /dev/null +++ b/install.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +if [ ! "$BASH_VERSION" ] ; then + exit 1 +fi + +echo " +============================== + +MKJ - Infra +Install Script + +------------------------------ +" + +stop () { + +echo " +============================== +" + +exit 1 + +} + +mkdir -p ~/.ssh &> /dev/null + +apt-get install -y python3-pip python3-venv jq git curl &> /dev/null +python3 -m venv /opt/ansible &> /dev/null +/opt/ansible/bin/pip3 install ansible hvac netaddr jmespath pexpect &> /dev/null + +/opt/ansible/bin/ansible-galaxy collection install -r requirements.yml --upgrade &> /dev/null + +mkdir -p ~/.ansible &> /dev/null + +if [[ ! -f ~/.ansible/vault.yml ]] +then + echo -n "Vault Password: " + read PASSWORD + echo "$PASSWORD" > ~/.ansible/vault.yml +fi + +ssh-keyscan github.com 1> ~/.ssh/known_hosts 2> /dev/null + +/opt/ansible/bin/ansible-pull -U ssh://git@github.com/MatteZ02/mkj-ansible --vault-password-file ~/.ansible/vault.yml --private-key ~/.ssh/id_rsa tasks.yml -t installer + + +echo " +============================== +" diff --git a/inventories/mkj/host_vars/mkj b/inventories/mkj/host_vars/mkj new file mode 100644 index 0000000..7b4f9ee --- /dev/null +++ b/inventories/mkj/host_vars/mkj @@ -0,0 +1,14 @@ +$ANSIBLE_VAULT;1.1;AES256 +34366533383537636563363238346530306364323437633062363834363738613462666632653730 +3231376531356466333161643535353433633834633765300a343462663562663065326131663765 +33356238666332326130643662386265666665303566643330326466353334366635626232386465 +3937366161663038340a386134616234653635313339663031366137343362663262616166376262 +36666461326634376262613362393139623230326238363736643133656537303332393234616566 +31646338313832663462656638313833336135663336316634616332636663386230306665623337 +30666131393732356337613530393238633733653162313631323766643563366134326265376163 +37666564656664323035343132336564343861643030396266616538353165376230393636663134 +62313063336538636464396134666134336662633534376435656363633632623964343338663866 +35623832633033363532303831366530363834393363333333623832616461323464393761333664 +34386262343338306164353539363230613562633231386436653134333235336638646334643332 +31663430333230663363316437336332303633633263336437313761396164656564666539393264 +3632 diff --git a/inventories/mkj/hosts b/inventories/mkj/hosts new file mode 100644 index 0000000..704409c --- /dev/null +++ b/inventories/mkj/hosts @@ -0,0 +1,7 @@ +--- +all: + hosts: + mkj: + vars: + ansible_connection: local + ansible_python_interpreter: "{{ansible_playbook_python}}" diff --git a/protect.sh b/protect.sh new file mode 100755 index 0000000..673556a --- /dev/null +++ b/protect.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +underline=`tput smul` +nounderline=`tput rmul` +bold=$(tput bold) +normal=$(tput sgr0) + +echo "${bold}MKJ / Infra / Protect${normal}" +action=$1 + +encrypt() { + echo "${underline}Encrypting...${nounderline}" + execute "ansible-vault encrypt --vault-id default@vault/mkj" +} + +decrypt() { + echo "${underline}Decrypting...${nounderline}" + execute "ansible-vault decrypt --vault-id default@vault/mkj" +} + +list() { + echo "${underline}Listing...${nounderline}" + i=0 + for file in inventories/*/group_vars/* inventories/*/host_vars/*; + do + i=$((i + 1)) + echo $i")"$file + done +} + +execute() { +for file in inventories/*/group_vars/* inventories/*/host_vars/*; + do + i=$((i + 1)) + echo $i")"$file + $1 $file + done +} + + +case $action in + encrypt) + encrypt + ;; + decrypt) + decrypt + ;; + list) + list + ;; + help) + echo "encrypt, decrypt, list" + ;; + *) + echo "..." + ;; +esac diff --git a/requirements.yml b/requirements.yml new file mode 100644 index 0000000..68b4a8e --- /dev/null +++ b/requirements.yml @@ -0,0 +1,3 @@ +--- +collections: + - containers.podman diff --git a/tasks.yml b/tasks.yml new file mode 100644 index 0000000..62bee9d --- /dev/null +++ b/tasks.yml @@ -0,0 +1,25 @@ +--- +- name: "Tasks" + hosts: all + module_defaults: + ansible.builtin.gather_facts: + gather_timeout: 10 + + tasks: + - name: "Installer" + import_tasks: tasks/installer.yml + tags: + - installer + - never + + - name: "Maintenance" + import_tasks: tasks/maintenance.yml + tags: + - maintenance + - never + + - name: "Deployer" + import_tasks: tasks/deployer.yml + tags: + - deployer + - never diff --git a/tasks/deployer.yml b/tasks/deployer.yml new file mode 100644 index 0000000..f75a2e5 --- /dev/null +++ b/tasks/deployer.yml @@ -0,0 +1,152 @@ +--- +- name: "Deployer - Certbot - Renew Certificates" + command: "certbot renew" + register: task + changed_when: task.stdout.find("No renewals were attempted.") == -1 + tags: + - certbot + - tls + +- name: "Deployer - Certbot - Copy Certificates" + copy: + src: "/etc/letsencrypt/live/mkj/" + dest: "/root/certs/mkj/" + follow: true + register: task + tags: + - certbot + - tls + +- name: "Deployer - MariaDB - Pull Image" + containers.podman.podman_image: + name: docker.io/mariadb + tag: latest + force: on + register: deployerTask101 + +- name: "Deployer - MariaDB - Run Container" + containers.podman.podman_container: + name: mariadb + image: docker.io/mariadb:latest + state: started + restart: on + network: host + volumes: + - "/root/mariadb:/var/lib/mysql" + restart_policy: always + env: + MYSQL_ROOT_PASSWORD: "{{ secrets.mariadb.root.password }}" + register: deployerTask102 + when: + - (deployerTask101 is defined and deployerTask101.changed) or deployerTask101 is undefined + tags: + - mariadb + +- name: "Deployer - MariaDB - Wait" + wait_for: + host: "127.0.0.1" + port: "3306" + delay: 10 + when: + - (deployerTask102 is defined and deployerTask102.changed) or deployerTask102 is undefined + tags: + - mariadb + +- name: "Deployer - MariaDB - Upgrade" + containers.podman.podman_container_exec: + name: mariadb + command: "mariadb-upgrade --host=127.0.0.1 --user=root --password={{ secrets.mariadb.root.password }}" + register: task + ignore_errors: yes + changed_when: + - task.stdout is defined + - task.stdout.find("This installation of MariaDB is already upgraded") == -1 + when: + - (deployerTask102 is defined and deployerTask102.changed) or deployerTask102 is undefined + tags: + - mariadb + +- name: "Deployer - MariaDB - Create Users" + mysql_user: + login_host: "127.0.0.1" + login_user: root + login_password: "{{ secrets.mariadb.root.password }}" + name: "mkj" + host: "%" + password: "{{ secrets.mariadb.mkj.password }}" + priv: "mkj.*:ALL" + vars: + ansible_python_interpreter: "/opt/ansible/bin/python3" + when: + - (deployerTask102 is defined and deployerTask102.changed) or deployerTask102 is undefined + tags: + - mariadb + +- name: "Deployer - MariaDB - Create Database" + mysql_db: + login_host: "127.0.0.1" + login_user: "mkj" + login_password: "{{ secrets.mariadb.mkj.password }}" + name: "mkj" + vars: + ansible_python_interpreter: "/opt/ansible/bin/python3" + when: + - (deployerTask102 is defined and deployerTask102.changed) or deployerTask102 is undefined + tags: + - mariadb + +- name: "Deployer - Nginx - Configure - Create Folder" + file: + path: "/root/nginx/" + state: directory + tags: + - nginx + +- name: "Deployer - Nginx - Configure - Create Subfolders" + file: + dest: '/root/nginx/{{ item.path }}' + state: directory + with_filetree: './files/nginx/' + loop_control: + label: "{{ item.path }}" + when: + - item.state == 'directory' + tags: + - nginx + +- name: "Deployer - Nginx - Configure - Generating & Transferring Files" + template: + src: '{{ item.src }}' + dest: '/root/nginx/{{ item.path }}' + with_filetree: './files/nginx/' + loop_control: + label: "{{ item.path }}" + when: + - item.state == 'file' + tags: + - nginx + +- name: "Deployer - Nginx - Pull Image" + containers.podman.podman_image: + name: docker.io/nginx + tag: latest + force: on + register: deployerTask3 + +- name: "Deployer - Nginx - Run Container" + containers.podman.podman_container: + name: nginx + image: docker.io/nginx + state: started + recreate: on + network: host + volumes: + - "/root/nginx/html:/usr/share/nginx/html:ro" + - "/root/nginx/config.conf:/etc/nginx/nginx.conf:ro" + - "/root/nginx/conf/:/etc/nginx/conf.d/:ro" + - "/root/certs/:/etc/nginx/certs/:ro" + restart_policy: always + when: + - (deployerTask3 is defined and deployerTask3.changed) or deployerTask3 is undefined + tags: + - nginx diff --git a/tasks/installer.yml b/tasks/installer.yml new file mode 100644 index 0000000..a8b17ba --- /dev/null +++ b/tasks/installer.yml @@ -0,0 +1,184 @@ +--- +- name: "Installer - Ansible - Python Library" + pip: + name: ansible + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - ansible + +- name: "Installer - Ansible - Create Symbolic Links" + ansible.builtin.file: + src: /opt/ansible/bin/{{ binary }} + dest: /usr/bin/{{ binary }} + state: link + vars: + binaries: + - ansible + - ansible-community + - ansible-config + - ansible-connection + - ansible-console + - ansible-doc + - ansible-galaxy + - ansible-inventory + - ansible-playbook + - ansible-pull + - ansible-test + - ansible-vault + loop: "{{ binaries }}" + loop_control: + label: "{{ binary }}" + loop_var: "binary" + tags: + - ansible + +- name: "Installer - Ansible - Dependencies / Python Library : hvac" + pip: + name: hvac + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - ansible + +- name: "Installer - Ansible - Dependencies / Python Library : netaddr" + pip: + name: netaddr + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - ansible + +- name: "Installer - Ansible - Dependencies / Python Library : jmespath" + pip: + name: jmespath + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - ansible + +- name: "Installer - Ansible - Dependencies / Python Library : pexpect" + pip: + name: pexpect + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - ansible + +- name: "Installer - Podman" + apt: + name: podman + state: latest + tags: + - podman + +- name: "Installer : Podman : Configure - Subordinate Ids : Users : root" + lineinfile: + path: /etc/subuid + regexp: "^root" + line: "root:100000:65536" + +- name: "Installer : Podman : Configure - Subordinate Ids : Groups : root" + lineinfile: + path: /etc/subgid + regexp: "^root" + line: "root:100000:65536" + +- name: "Installer - Certbot - Python Library" + pip: + name: certbot + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - certbot + +- name: "Installer - Certbot - Create Symbolic Links" + ansible.builtin.file: + src: /opt/ansible/bin/{{ binary }} + dest: /usr/bin/{{ binary }} + state: link + vars: + binaries: + - certbot + loop: "{{ binaries }}" + loop_control: + label: "{{ binary }}" + loop_var: "binary" + tags: + - certbot + +- name: "Installer - Certbot - Auth Hook" + copy: + src: "../files/certbot/nginx.sh" + dest: "/etc/letsencrypt/renewal-hooks/pre/nginx.sh" + mode: '700' + force: true + tags: + - certbot + +- name: "Installer - Certbot - Create Certificates" + command: "certbot certonly --cert-name {{ cert.name }} --manual --preferred-challenges http-01 --email {{ cert.email }} --server https://acme-v02.api.letsencrypt.org/directory --agree-tos -n --manual-auth-hook /etc/letsencrypt/renewal-hooks/pre/nginx.sh --debug-challenges --preferred-chain='ISRG Root X1' --key-type rsa -d {{ cert.domains | join(' -d ') }}" + register: task + changed_when: task.stdout.find("Certificate not yet due for renewal; no action taken.") == -1 + vars: + cert: + name: mkj + email: "{{ config.certbot.email }}" + domains: + - "{{ ansible_facts.fqdn }}" + tags: + - certbot + +- name: "Installer - MariaDB - Dependencies / Python Library : pymysql" + pip: + name: pymysql + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + tags: + - mariadb + +- name: "Installer - MariaDB - Dependencies / Package : mariadb-client" + apt: + name: "mariadb-client" + state: latest + when: + - ansible_facts.distribution == "Debian" or ansible_facts.distribution == "Ubuntu" or ansible_facts.distribution == "Linux Mint" + tags: + - mariadb + +- name: "Installer - Schedule - Setup" + cron: + name: PATH + env: yes + value: "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +- name: "Installer - Schedule - Maintenance" + cron: + name: Maintenance + hour: "*/3" + minute: "0" + job: "/opt/ansible/bin/ansible-pull -U ssh://git@github.com/MatteZ02/mkj-infra --accept-host-key --vault-password-file ~/.ansible/vault.yml --private-key ~/.ssh/id_rsa tasks.yml -t maintenance" + tags: + - cron + +- name: "Installer - Schedule - Deployer" + cron: + name: Deployer + minute: "*/5" + job: "/opt/ansible/bin/ansible-pull -U ssh://git@github.com/MatteZ02/mkj-infra --accept-host-key --vault-password-file ~/.ansible/vault.yml --private-key ~/.ssh/id_rsa tasks.yml -t deployer" + tags: + - cron diff --git a/tasks/maintenance.yml b/tasks/maintenance.yml new file mode 100644 index 0000000..0c8839a --- /dev/null +++ b/tasks/maintenance.yml @@ -0,0 +1,37 @@ +--- +- name: "Maintenance - OS Update" + apt: + upgrade: dist + update_cache: yes + +- name: "Maintenance - Ansible : Dependencies - Python Library : hvac" + pip: + name: hvac + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + +- name: "Maintenance - Ansible : Dependencies - Python Library : netaddr" + pip: + name: netaddr + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + +- name: "Maintenance - Ansible : Dependencies - Python Library : jmespath" + pip: + name: jmespath + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv" + +- name: "Maintenance - Ansible : Dependencies - Python Library : pexpect" + pip: + name: pexpect + state: latest + extra_args: --upgrade + virtualenv: /opt/ansible + virtualenv_command: "python3 -m venv"