From ebab5d44f0147a69daa53b6fc683802de102f8c8 Mon Sep 17 00:00:00 2001 From: xbazzi Date: Thu, 10 Jul 2025 21:24:28 -0600 Subject: [PATCH] Initial commit :rocket: :monkey: --- .vscode/settings.json | 5 + README.md | 150 ++++++++++++++++++ ansible.cfg | 5 + inventory/group_vars/all.yml | 96 +++++++++++ inventory/group_vars/cluster_prep.yml | 2 + inventory/host_vars/pve1.yml | 11 ++ inventory/host_vars/pve2.yml | 11 ++ inventory/host_vars/pve3.yml | 11 ++ inventory/hosts.yml | 36 +++++ playbooks/apply-firewalld.yml | 5 + playbooks/backup-pve.yml | 6 + playbooks/backups/pve1.tar.gz | Bin 0 -> 16320 bytes playbooks/backups/pve2.tar.gz | Bin 0 -> 17917 bytes playbooks/backups/pve3.tar.gz | Bin 0 -> 17632 bytes playbooks/configure-pve.yml | 6 + playbooks/deploy-dbgate.yml | 15 ++ playbooks/deploy-postgres.yml | 16 ++ playbooks/example.yml | 6 + playbooks/prep-pve-for-cluster.yml | 5 + playbooks/provision-alma.yml | 13 ++ playbooks/sysprep-alma.yml | 9 ++ roles/app/database/defaults/main.yml | 0 roles/app/database/tasks/main.yml | 20 +++ roles/apps/dbgate/defaults/main.yml | 4 + roles/apps/dbgate/tasks/main.yml | 19 +++ roles/docker/install/defaults/main.yml | 0 roles/docker/install/tasks/main.yml | 40 +++++ roles/docker/install/tasks/main2.yml | 45 ++++++ roles/docker/portainer/defaults/main.yml | 0 roles/docker/portainer/tasks/main.yml | 22 +++ roles/docker/remove/defaults/main.yml | 0 roles/docker/remove/handlers/main.yml | 0 roles/docker/remove/tasks/main.yml | 13 ++ roles/docker/remove/templates/main.yml | 0 roles/docker/stack/defaults/main.yml | 2 + roles/docker/stack/tasks/main.yml | 27 ++++ roles/postgres/database/defaults/main.yml | 0 roles/postgres/database/tasks/main.yml | 10 ++ roles/postgres/priviledges/defaults/main.yml | 1 + roles/postgres/priviledges/tasks/main.yml | 28 ++++ roles/postgres/user/defaults/main.yml | 1 + roles/postgres/user/tasks/main.yml | 11 ++ roles/provision/alma/common/defaults/main.yml | 0 roles/provision/alma/common/handlers/main.yml | 0 roles/provision/alma/common/tasks/main.yml | 56 +++++++ .../provision/alma/common/templates/main.yml | 0 roles/provision/alma/docker/defaults/main.yml | 0 roles/provision/alma/docker/handlers/main.yml | 0 roles/provision/alma/docker/tasks/main.yml | 18 +++ .../provision/alma/docker/templates/main.yml | 0 roles/provision/alma/nfs/defaults/main.yml | 0 roles/provision/alma/nfs/handlers/main.yml | 0 roles/provision/alma/nfs/tasks/main.yml | 23 +++ roles/provision/alma/nfs/templates/main.yml | 0 roles/pve/cluster_prep/defaults/main.yml | 0 roles/pve/cluster_prep/tasks/main.yml | 107 +++++++++++++ roles/pve/cluster_prep/templates/hosts.j2 | 6 + roles/pve/cluster_prep/templates/resolv.j2 | 2 + roles/pve/pve_backup/defaults/main.yml | 0 roles/pve/pve_backup/tasks/main.yml | 26 +++ .../templates/backup_pve_config.sh.j2 | 23 +++ roles/pve/setup_networking/defaults/main.yml | 0 roles/pve/setup_networking/handlers/main.yml | 5 + roles/pve/setup_networking/tasks/main.yml | 46 ++++++ roles/pve/setup_networking/templates/hosts.j2 | 6 + .../templates/interfaces-xbazzi.j2 | 48 ++++++ .../pve/setup_networking/templates/resolv.j2 | 2 + roles/server/firewall/defaults/main.yml | 0 roles/server/firewall/handlers/main.yml | 0 roles/server/firewall/tasks/main.yml | 43 +++++ roles/server/firewall/templates/main.yml | 0 roles/server/ftp/defaults/main.yml | 0 roles/server/ftp/tasks/main.yml | 23 +++ roles/server/network/defaults/main.yml | 0 roles/server/network/handlers/main.yml | 0 roles/server/network/tasks/main.yml | 136 ++++++++++++++++ .../network/templates/ifcfg-template.j2 | 6 + roles/server/network/templates/main.yml | 0 roles/server/reboot/defaults/main.yml | 0 roles/server/reboot/handlers/main.yml | 0 roles/server/reboot/tasks/main.yml | 5 + roles/server/reboot/templates/main.yml | 0 roles/server/sshkey/defaults/main.yml | 0 roles/server/sshkey/tasks/main.yml | 12 ++ roles/server/sysprep/defaults/main.yml | 0 roles/server/sysprep/handlers/main.yml | 0 roles/server/sysprep/tasks/main.yml | 115 ++++++++++++++ roles/server/sysprep/templates/main.yml | 0 roles/server/users/defaults/main.yml | 0 roles/server/users/handlers/main.yml | 0 roles/server/users/tasks/main.yml | 45 ++++++ roles/server/users/templates/main.yml | 0 roles/services/postgres/defaults/main.yml | 5 + roles/services/postgres/tasks/main.yml | 23 +++ roles/util/mount_nfs/defaults/main.yml | 3 + roles/util/mount_nfs/tasks/main.yml | 21 +++ setup.sh | 28 ++++ 97 files changed, 1484 insertions(+) create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 100755 ansible.cfg create mode 100644 inventory/group_vars/all.yml create mode 100644 inventory/group_vars/cluster_prep.yml create mode 100644 inventory/host_vars/pve1.yml create mode 100644 inventory/host_vars/pve2.yml create mode 100644 inventory/host_vars/pve3.yml create mode 100644 inventory/hosts.yml create mode 100644 playbooks/apply-firewalld.yml create mode 100644 playbooks/backup-pve.yml create mode 100644 playbooks/backups/pve1.tar.gz create mode 100644 playbooks/backups/pve2.tar.gz create mode 100644 playbooks/backups/pve3.tar.gz create mode 100644 playbooks/configure-pve.yml create mode 100644 playbooks/deploy-dbgate.yml create mode 100644 playbooks/deploy-postgres.yml create mode 100644 playbooks/example.yml create mode 100644 playbooks/prep-pve-for-cluster.yml create mode 100644 playbooks/provision-alma.yml create mode 100644 playbooks/sysprep-alma.yml create mode 100755 roles/app/database/defaults/main.yml create mode 100755 roles/app/database/tasks/main.yml create mode 100644 roles/apps/dbgate/defaults/main.yml create mode 100644 roles/apps/dbgate/tasks/main.yml create mode 100755 roles/docker/install/defaults/main.yml create mode 100755 roles/docker/install/tasks/main.yml create mode 100644 roles/docker/install/tasks/main2.yml create mode 100755 roles/docker/portainer/defaults/main.yml create mode 100755 roles/docker/portainer/tasks/main.yml create mode 100644 roles/docker/remove/defaults/main.yml create mode 100644 roles/docker/remove/handlers/main.yml create mode 100644 roles/docker/remove/tasks/main.yml create mode 100644 roles/docker/remove/templates/main.yml create mode 100755 roles/docker/stack/defaults/main.yml create mode 100755 roles/docker/stack/tasks/main.yml create mode 100755 roles/postgres/database/defaults/main.yml create mode 100755 roles/postgres/database/tasks/main.yml create mode 100755 roles/postgres/priviledges/defaults/main.yml create mode 100755 roles/postgres/priviledges/tasks/main.yml create mode 100755 roles/postgres/user/defaults/main.yml create mode 100755 roles/postgres/user/tasks/main.yml create mode 100644 roles/provision/alma/common/defaults/main.yml create mode 100644 roles/provision/alma/common/handlers/main.yml create mode 100644 roles/provision/alma/common/tasks/main.yml create mode 100644 roles/provision/alma/common/templates/main.yml create mode 100644 roles/provision/alma/docker/defaults/main.yml create mode 100644 roles/provision/alma/docker/handlers/main.yml create mode 100644 roles/provision/alma/docker/tasks/main.yml create mode 100644 roles/provision/alma/docker/templates/main.yml create mode 100644 roles/provision/alma/nfs/defaults/main.yml create mode 100644 roles/provision/alma/nfs/handlers/main.yml create mode 100644 roles/provision/alma/nfs/tasks/main.yml create mode 100644 roles/provision/alma/nfs/templates/main.yml create mode 100644 roles/pve/cluster_prep/defaults/main.yml create mode 100644 roles/pve/cluster_prep/tasks/main.yml create mode 100644 roles/pve/cluster_prep/templates/hosts.j2 create mode 100644 roles/pve/cluster_prep/templates/resolv.j2 create mode 100644 roles/pve/pve_backup/defaults/main.yml create mode 100644 roles/pve/pve_backup/tasks/main.yml create mode 100644 roles/pve/pve_backup/templates/backup_pve_config.sh.j2 create mode 100644 roles/pve/setup_networking/defaults/main.yml create mode 100644 roles/pve/setup_networking/handlers/main.yml create mode 100644 roles/pve/setup_networking/tasks/main.yml create mode 100644 roles/pve/setup_networking/templates/hosts.j2 create mode 100644 roles/pve/setup_networking/templates/interfaces-xbazzi.j2 create mode 100644 roles/pve/setup_networking/templates/resolv.j2 create mode 100644 roles/server/firewall/defaults/main.yml create mode 100644 roles/server/firewall/handlers/main.yml create mode 100644 roles/server/firewall/tasks/main.yml create mode 100644 roles/server/firewall/templates/main.yml create mode 100755 roles/server/ftp/defaults/main.yml create mode 100755 roles/server/ftp/tasks/main.yml create mode 100644 roles/server/network/defaults/main.yml create mode 100644 roles/server/network/handlers/main.yml create mode 100644 roles/server/network/tasks/main.yml create mode 100644 roles/server/network/templates/ifcfg-template.j2 create mode 100644 roles/server/network/templates/main.yml create mode 100644 roles/server/reboot/defaults/main.yml create mode 100644 roles/server/reboot/handlers/main.yml create mode 100644 roles/server/reboot/tasks/main.yml create mode 100644 roles/server/reboot/templates/main.yml create mode 100755 roles/server/sshkey/defaults/main.yml create mode 100644 roles/server/sshkey/tasks/main.yml create mode 100644 roles/server/sysprep/defaults/main.yml create mode 100644 roles/server/sysprep/handlers/main.yml create mode 100644 roles/server/sysprep/tasks/main.yml create mode 100644 roles/server/sysprep/templates/main.yml create mode 100644 roles/server/users/defaults/main.yml create mode 100644 roles/server/users/handlers/main.yml create mode 100644 roles/server/users/tasks/main.yml create mode 100644 roles/server/users/templates/main.yml create mode 100644 roles/services/postgres/defaults/main.yml create mode 100644 roles/services/postgres/tasks/main.yml create mode 100755 roles/util/mount_nfs/defaults/main.yml create mode 100755 roles/util/mount_nfs/tasks/main.yml create mode 100755 setup.sh diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b1e5280 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "ansible.python.interpreterPath": "/run/current-system/sw/bin/python", + "ansible.validation.lint.path": "", + "ansible.validation.lint.enabled": false +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f6c6df --- /dev/null +++ b/README.md @@ -0,0 +1,150 @@ +# Ansible Starter Kit + +Easy way for my homies to start up an ansible project for their homelab or local machine. + +# Prerequisites + +The ideal setup for a homelab is to have: + +- The same username/password in all vms/hosts so you don't have to type a different password for each host +- SSH key auth on each host so you don't have to type a password at all + +# Ansible basics + +I'll explain the basic units of an ansible project. For this example we're going to assume you want to mount +an NFS share in all your hosts. + +From bottom to top we have: + +## Tasks + +A task is the lowest unit in an ansible project. + +A task could be: + +- Creating a directory +- Installing an os package (curl, docker, nfs-common, etc) +- Starting a docker container + +### Examples + +```yml +- name: Add SSH key for remote user + ansible.posix.authorized_key: + user: javi + state: present + key: "{{ lookup('file', '/home/javi/.ssh/homelab_keypair_ed25519.pub') }}" +``` + +```yml +- name: Ensure NFS client is installed + ansible.builtin.package: + name: nfs-common + state: present + become: true +``` + +## Role + +A role is a self contained, re-usable unit that will give a meaningful result. Think of it like a class in a program. + +Roles have a list of tasks, as well as variables and files associated with those tasks. All contained in a folder. + +A role can look like: + +``` +roles/ + portainer/ + ├── defaults/ + │ └── main.yml # Default variables + ├── files/ + │ └── ... # Static files to be copied (e.g., configs, scripts) + ├── handlers/ + │ └── main.yml # Handlers (e.g., service restart) + ├── meta/ + │ └── main.yml # Role metadata (e.g., dependencies) + ├── tasks/ + │ └── main.yml # Main list of tasks to execute + ├── templates/ + │ └── ... # Jinja2 templates + ├── vars/ + │ └── main.yml # Non-overridable variables + └── README.md # Optional: Document what this role does + sshkey/ + ├── defaults/ + │ └── main.yml # Default variables + ├── files/ + │ └── ... # Static files to be copied (e.g., configs, scripts) + ├── handlers/ + │ └── main.yml # Handlers (e.g., service restart) + ├── meta/ + │ └── main.yml # Role metadata (e.g., dependencies) + ├── tasks/ + │ └── main.yml # Main list of tasks to execute + ├── templates/ + │ └── ... # Jinja2 templates + ├── vars/ + │ └── main.yml # Non-overridable variables + └── README.md # Optional: Document what this role does + +``` + +However, only the `defaults` and `tasks` subfolders and subsequent `main.yml` are required. Everything else is optional. + +A role can be: + +- Mounting a share +- Deploying a docker container with all its requirements like a database and mapped volumes + +# Playbook + +A playbook combines roles and task to create a final state in a host or group of hosts. + +A playbook can be: + +- Make sure all your hosts have sshkey auth, portainer, docker and an nfs share mounted. +- Deploy a suite of apps to a host or multiple hosts + +## Example + +```yml +--- +- name: Deploy apps to apps-1 node + hosts: apps + become: true + roles: + - role: apps/kan + vars: + port: 7070 + - role: apps/memos + vars: + port: 7071 + - role: apps/vaultwarden + vars: + port: 7072 + - role: apps/erugo + vars: + port: 7073 + - role: apps/tianji + vars: + port: 7074 + - role: apps/stirling-pdf o + vars: + port: 7075 + - role: apps/dumbware-todo + vars: + port: 7076 + pin: 8989 + - role: apps/dumbware-drop + vars: + port: 7077 + pin: "8989" +``` + +# Setup + +1. Clone this repo `git clone git@gitgud.foo:javif89/ansible-starter-kit.git [your project name]` +2. Run `setup.sh` to set up the vault password and become password +3. Set up your hosts in `hosts.yml` +4. Start making your roles and playbooks + diff --git a/ansible.cfg b/ansible.cfg new file mode 100755 index 0000000..0b0a949 --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,5 @@ +[defaults] +remote_user = ansible +inventory = inventory/hosts.yml +roles_path = ./roles +vault_password_file = ~/.ansible-vault-key \ No newline at end of file diff --git a/inventory/group_vars/all.yml b/inventory/group_vars/all.yml new file mode 100644 index 0000000..8f7e471 --- /dev/null +++ b/inventory/group_vars/all.yml @@ -0,0 +1,96 @@ +$ANSIBLE_VAULT;1.1;AES256 +38333861353432643165366435353534316564346533666439376631373562366530386636623333 +6130343936376163336432366437623062643161636466640a383232343564636234376330323138 +37393731643030313230613363343639363737393364346231643835613532636530363964383933 +3834343936353965390a313439663463626461376461636462316237366430356437346164393034 +38633331646465666165343365616366623636613264663062613238656466326537373135393234 +38623034306461386132373262666532633562376532303762356663343930623464376661366238 +33373638386366643030366632636138653032633436373932613261656331633663643839306633 +39613136306130626635393333366136646665393932383563373739323730396633363334643639 +36323337336563616165626463306637653865643931613731636233313061616130623662393465 +63366131643135623337313735386566616663343263353561316132343138653761303436386433 +64653736616439623331373865383439343637343737313466363265333033663836633635623732 +30643137633738356665326138363734623766613462323831623931633163373933353661653434 +35343466363132663765623739336136656332333932303332363164366630376638353166316636 +31653133386461323532666661363865383430653230636233616238356431623462316133633239 +34316561333530353166626632653566333966326663383635323165356231386232346263363666 +61366430353239353732663437353165353562313438383063393935306534646165336232333861 +32633138323036323334343866333963353965303536373930336164323565333862353032336566 +39613263303966343337393165633866323233653132626264316238313131663961613037643865 +35376138643934383435636534343231303933396138643231613336613536333961333562343963 +31376438366438346231656364303535336465623237336263383761363630623632356335326231 +61366132613062353833613162623634383134666334366435646238343462396535336534316264 +35326461653331636462366536653430646438626562373635613464313031666434333732616239 +61383536623762653463363031343332393166646264663031656531363761666364653866326230 +33363264663366653930616133363539633463306434653732383435613430626439313935633162 +62323366653639343063353662383265626538646361383030396533366635353830383365636435 +36636433393635633237316131616630383464313535303137376131646566383366333935303830 +34663630613438613836393333626463623466393831303833626666636338356533616436636331 +32393665346538353539633634303161616662366433386139343034333963336630353634346232 +63333561326532336533326333613961643134306264373730346137653962663930326261333763 +32353264616333313263343964663465636235333438343334393963653530663130366133353031 +64626537663362316239643436646236636361656365373232663931613634333465643137313964 +31323464303432346337616530333135346166623561623531313561633533643161363930323265 +32363538323134383434316332383064663437653161316162636339663036316139633636646131 +34343939383935623333613835613431346532323530366331613065666566323731663336623137 +36653165623235343832653438393836353630663063613337346364393439303738656564626432 +64613863376463343433303933656163666532326430383863383636386331643265623963653730 +31666430303666373030343831383436376666346236646231346565643564656339326231383337 +32386239646634643261393531636666666637386633396136653661373835636237323031333434 +31633237633566313131306261613834356139306436393862333533336534383662663837626464 +63653831373235373638303864323531623965333662386239396637636562373632393365663062 +61333934613865626639393236303562643165316466386461636239373336623965333531303335 +63393030326230303537383431663634616133353734353835636565326261386165633730386665 +61363736653762326634316634663530306163366165303464373833633363613338383330353062 +62313331343830323063663363386566373964356566313638653331336366343236356565656331 +61326466653362326337626532353637636535373762383034653464313961353430666132376163 +63323636393331376565343037613631323130646466656531663335373461653063353166346336 +32613564373634663863343036623038656462643532653539396538646532383161333535313164 +66306532393137393736316330383466646265633539326437643039643037393735306136383337 +35353465643762313762653938376331356232356131336131616531303162383737623736363130 +38336634653564363564323964356564313665396461623836633533633534653961323632653766 +39383236663664643666333730623731663438326539346135326564326666396463323661393132 +35343862653264323564343730313938663664663035303332333163633137323661323431343138 +66336666386635643662323431626636636231666561396438336234366331616138323636336664 +36396133323937306463386261363766623366663965623361313264663861626161366166366237 +36393962613135326339623261333635326138336466306132333230643536376334386166346364 +61643231363737656131363935626433373164363161646365633536383563343936653333333832 +33383565346366616365363030646432363633663537316335376333313236616637633066333664 +63313039656664663664393633353466376264356161343532353838373366393835653134353438 +61396164636566313535656533396332316565336664363034353235643635616564663563633338 +32313662666566336437366666376630336466373831343431636662323431393061326139326537 +35303362366338383230643734333533323535303534303637623136613634333436656131376635 +30623736356634616366323563636535633530623435613634636662636436303337373762393734 +63363637323733306532343239303030626135663366333763623933613034333339323636653338 +37646665343632363466383762623763363238633265333166396165633461666662303332373164 +30356231356132323037396231613939353463656333613735376562323837323430623665373364 +63656238356161303462366130636236633238623861373830323237376563353934356239656539 +62346638643263383636666437646466393361366465366362336634663636306230373466366266 +38353133383937336336633239373739663731666162643037623630323739363464623763353163 +36653733663138386432323465383537383137623333333933366232323934623730613139656536 +39623564316135373830316238396664323663663137653130326163356566653630613662613638 +32626261383533393833633539633330383537323534346134366333346438323232336337623861 +35306632356165313063373738303130386436396532616365313633656637373362313639626338 +36616665386663303636323264623839303562303064306139333263343839323436333930393136 +36663531643363643537636437646266643032616437656239666539653163343935633366646534 +36623935356565653831366462653830393465353065386130303065626365663235366530303431 +63353635653163303138383163663931356139626264383331346532663961316261393832626430 +66303435393739303461363731363733646534363766626462333761623537343734343833393634 +31356537653630363563313539356535663032613538303264633864396365613366386366656336 +37643666636436626162636234333938303266393162393933393038366437613165366630386438 +37313634656632653238383134653039323739643366343631343530386237336139313164393133 +64653638363662333461323365333861396266653238306530613064316362663131633461366161 +32633835393832646530623033346238343761393036353137626463613139393839616432626263 +35663232323734333631613139666366666436653566653064393666356165336439303937326637 +36633438623933323964303065313332373762346463343263386439646533306332363136386434 +34363236383733323232306264613137383831633534666337356137316433656238363864646138 +39303661383963313833323330656666373536303931383464343036663035616630343063383139 +63653263323533303933653138666138336530633162653533336466353235366333643835313365 +38303462623430356339323731646238636663393838653466323030653866646435323636343337 +37316336383234323336383061666235663539616631663936613430313138643061393439383636 +31656535366361326566666264656465633337643365393765303732633238653231623735313638 +36303537393038306165393365343334373333393933356133313264396236623936343763366330 +37373262393230326132393237633335353964346434616137636662343635306632373532663830 +66333039613330306231363364323861363964313336666165616635363166623435636366343364 +64356364373832366435656539613238646538623035346434346364386434623461653763656135 +646161643166613037303031663863666465 diff --git a/inventory/group_vars/cluster_prep.yml b/inventory/group_vars/cluster_prep.yml new file mode 100644 index 0000000..96d1b46 --- /dev/null +++ b/inventory/group_vars/cluster_prep.yml @@ -0,0 +1,2 @@ +iscsi_target_ip: nas.lan.xbazzi.com # TrueNAS IP +iscsi_target_iqn: iqn.2005-10.org.freenas.ctl:pve-iscsi \ No newline at end of file diff --git a/inventory/host_vars/pve1.yml b/inventory/host_vars/pve1.yml new file mode 100644 index 0000000..57d1b8d --- /dev/null +++ b/inventory/host_vars/pve1.yml @@ -0,0 +1,11 @@ +$ANSIBLE_VAULT;1.1;AES256 +61636264373765333930663036663164363332363765353836326361383438303065623938353338 +3861383264346132613466666363623562383437643464640a343830356164323732313631666532 +61646636633062333539393266366537613037646137376463343638356562383538376534376533 +6361373233623565310a343466666233623138316439616239376266343932616366636232633735 +32623335633732653637336163666265383066303565386261353539656333656337393530323639 +65313233376434343761653264626563653031623236616362396262643463656535613237383435 +35343439643330343362333362396338646162313063623334326264316235636333376434626535 +34353332653138653765323936346536323038366238323932393335363762623237653962616664 +37653963633936653866656537663435333731343937616237353734383537316361633836363666 +3064366264653335663331383332656638323335633731353531 diff --git a/inventory/host_vars/pve2.yml b/inventory/host_vars/pve2.yml new file mode 100644 index 0000000..4fe1c80 --- /dev/null +++ b/inventory/host_vars/pve2.yml @@ -0,0 +1,11 @@ +$ANSIBLE_VAULT;1.1;AES256 +64366635666462636332636564316263363561326366646531626365633431373934306334373432 +6635396564336238383563613231373339616164326630330a333031643734653738666537386337 +34366264356237613534356330393130376262383361636638316562636463633239643264343564 +6236663764623439360a333165363430373561336334663739353738343364656432363939383234 +32343363373164303130376133633265656564363532663336326263636464623339353966366430 +33313339343534386664663361616438346136643361346264393563633630333562346338366530 +33666261633236363833343931353535366565363733326661626338363030383365383332373837 +62623537396666363265346333366661396139363732666261343132333237636335363338303033 +61376630333263313166356334383931326665383631363961633066396539393963313433373763 +6362323162346164633639623064376265313764353032663434 diff --git a/inventory/host_vars/pve3.yml b/inventory/host_vars/pve3.yml new file mode 100644 index 0000000..39e2b04 --- /dev/null +++ b/inventory/host_vars/pve3.yml @@ -0,0 +1,11 @@ +$ANSIBLE_VAULT;1.1;AES256 +34386433623163393561646137313364663363363138336164363561666533323565653464373961 +3061643566303432623963636530303530306433343666350a663933663935643635366561336630 +37653433666364366431363032633738646436626336323037343730376662363266333038613064 +6131363532623766320a656330613439363562653263666138336639663965303236356139336630 +33663961393438316333333030663236623934666632346566363739316262346538626434393066 +37663563363038393137353336393233316630323734346439663836313065386536326465626632 +30636165626132376138326331663965623965353561616536376266313430373839353230653332 +30653866323231333335313261636336333161363334663734633534343561623764393531386239 +62343136336332666237353863623330336564313130336239323639303766303361616664623331 +3638656138333862366138366539666232376164666239323132 diff --git a/inventory/hosts.yml b/inventory/hosts.yml new file mode 100644 index 0000000..f271aea --- /dev/null +++ b/inventory/hosts.yml @@ -0,0 +1,36 @@ +$ANSIBLE_VAULT;1.1;AES256 +64363164666338376439386465623133383736636361353661303464666164616232366431626333 +3437666365663839343866613537323366333564646234350a363434303639333535643039313039 +61306663306134666139303061316163323033353366386233643039613365386536333336663864 +6463316237376364660a313639623233326634366635313962373830393165343130363337353135 +39616535373561353064373139356362663739363138326237393630326535353961623733323766 +61366665346365626637626531666434336366643061663363323237613065613638353731663834 +63386361646161303339653433316232323135323561363161643833373865366162316465383930 +66346466346433643264633162326665613731383036616437643537383833616262646331356638 +61336331636334343465316366323861326365386136303565363564343438613866326162613930 +35643230316237383865616164653038306339306130316534303230383966353934356366633961 +64623761646138633931356230633961353361376239656364326338646436663831323631346531 +37633261646635633665663037663733313332396666636435383166343262663834383633646335 +39383137383436643865383065613533636132326331303731306465636465613136646462643336 +63386635346534343961626339393330633638633263326131313065353164353833333833326164 +36613462393334333166613765343938393132363165316532396237636137323262616631393930 +32323437316430306532653937613937663963613738323231366565313838656434656532623062 +36633561376536373036323330623539383763306561383136633434623062376266333361306266 +35333431626230316630626663376462653838656330376266396664323238323234306362343633 +66333463646665306561313033313464633231316366633031303863636264333363366666376163 +31663464643331666461353331663936656539616235353530366238326333663966386639353334 +65626330613330303930643835393365383739313831333235633261356331346161333765323335 +39393534393166383161376530623739336635303363393633653666633363656334653961643964 +65373237333338313162626636366264356663616261633734613330626562666538313165663562 +33393336613963353330336238656433613363306535323930623037663463613136643735613337 +63396334626334373737663461386663653865626136353761666531623563643465356366666266 +32393536643638303862353234366233323566623862316636323866323336366434376463306661 +31313133313639313635333335643836373437306535383734373031306539643738326238373366 +31393734383738636333643437393238336365376332643861636435303036653065613164363031 +63373632343634303236653036636134306237663462633861366630633034333832646362303236 +32636166366430343063316333636134616236373866373865316261626239376639366537306461 +33636265313262366264306331313039363734633766323932363465353032633764373332326466 +31363034326161643062343230333435343435623336653163323365363233643231306538373939 +35643338396661356332343431383232376238626434613462306437653537343530643030333735 +38393532303533323430373066343938396533656564663731393738363863663864356462663565 +656438663662326136393134643136663737 diff --git a/playbooks/apply-firewalld.yml b/playbooks/apply-firewalld.yml new file mode 100644 index 0000000..0cac4bb --- /dev/null +++ b/playbooks/apply-firewalld.yml @@ -0,0 +1,5 @@ +- name: Apply firewalld config + hosts: staging-vm + become: yes + roles: + - role: provision/alma/firewall \ No newline at end of file diff --git a/playbooks/backup-pve.yml b/playbooks/backup-pve.yml new file mode 100644 index 0000000..73866bf --- /dev/null +++ b/playbooks/backup-pve.yml @@ -0,0 +1,6 @@ +--- +- name: Backup /etc/pve from all Proxmox nodes + hosts: pve-nodes + become: yes + roles: + - role: utility/pve_backup diff --git a/playbooks/backups/pve1.tar.gz b/playbooks/backups/pve1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..ab4d6f5f0c2ea97bd435051fa70bf165901fd825 GIT binary patch literal 16320 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 literal 0 HcmV?d00001 diff --git a/playbooks/backups/pve2.tar.gz b/playbooks/backups/pve2.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..b1c2430fbcd4a872d23bd1a799a71b2283cbd835 GIT binary patch literal 17917 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

8dYv^ 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' + backrefs: yes + state: present + loop: "{{ list_files.files }}" + +- name: Overwrite sources.list with Proxmox-recommended repos + copy: + dest: /etc/apt/sources.list + content: | + deb http://ftp.debian.org/debian bookworm main contrib + deb http://ftp.debian.org/debian bookworm-updates main contrib + + # Proxmox VE pve-no-subscription repository provided by proxmox.com, + # NOT recommended for production use + deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription + + # security updates + deb http://security.debian.org/debian-security bookworm-security main contrib + mode: '0644' + +- name: Add Proxmox no-subscription repo to sources.list.d + copy: + dest: /etc/apt/sources.list.d/pve-no-subscription.list + content: | + deb http://download.proxmox.com/debian/pve bullseye pve-no-subscription + owner: root + group: root + mode: '0644' + + +- name: Update apt cache + apt: + update_cache: yes + +- name: Update /etc/hosts with all PVE nodes + template: + src: hosts.j2 + dest: /etc/hosts + mode: "0644" + +- name: Ensure search domain and nameserver set properly + template: + src: resolv.j2 + dest: /etc/resolv.conf + mode: "0644" + +- name: Ensure chrony is installed + apt: + name: chrony + state: present + update_cache: yes + +- name: Enable and start chronyd + service: + name: chrony + state: started + enabled: yes + +- name: Discover iSCSI targets from TrueNAS + shell: | + iscsiadm -m discovery -t st -p {{ iscsi_target_ip }} + register: iscsi_discovery + changed_when: false + +- name: Login to discovered iSCSI target (unauthenticated) + shell: | + iscsiadm -m node -T {{ iscsi_target_iqn }} -p {{ iscsi_target_ip }} --login + register: iscsi_login + changed_when: "'Login to' in iscsi_login.stdout or 'already present' in iscsi_login.stdout" + +- name: Make iSCSI login persistent across reboots + shell: | + iscsiadm -m node -T {{ iscsi_target_iqn }} -p {{ iscsi_target_ip }} --op update -n node.startup -v automatic + changed_when: false + +# - name: Ensure vg_ha exists +# command: vgs vg_ha +# register: vg_result +# failed_when: vg_result.rc != 0 +# changed_when: false + +# - name: Debug VG presence +# debug: +# msg: "VG 'vg_ha' found on {{ inventory_hostname }}" diff --git a/roles/pve/cluster_prep/templates/hosts.j2 b/roles/pve/cluster_prep/templates/hosts.j2 new file mode 100644 index 0000000..a65756c --- /dev/null +++ b/roles/pve/cluster_prep/templates/hosts.j2 @@ -0,0 +1,6 @@ +127.0.0.1 localhost +{% for host in groups['pve-nodes'] %} +{{ hostvars[host]['ansible_default_ipv4']['address'] }} {{ host }} {{ host }}.lan.xbazzi.com +{{ hostvars[host]['cluster_ip'] }} {{ host }}-cluster +{% endfor %} + diff --git a/roles/pve/cluster_prep/templates/resolv.j2 b/roles/pve/cluster_prep/templates/resolv.j2 new file mode 100644 index 0000000..e2b3300 --- /dev/null +++ b/roles/pve/cluster_prep/templates/resolv.j2 @@ -0,0 +1,2 @@ +search lan.xbazzi.com +nameserver 10.133.7.1 \ No newline at end of file diff --git a/roles/pve/pve_backup/defaults/main.yml b/roles/pve/pve_backup/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/pve/pve_backup/tasks/main.yml b/roles/pve/pve_backup/tasks/main.yml new file mode 100644 index 0000000..20a1bab --- /dev/null +++ b/roles/pve/pve_backup/tasks/main.yml @@ -0,0 +1,26 @@ +--- +- name: Copy /etc/ backup script to PVE node + template: + src: backup_pve_config.sh.j2 + dest: /home/xbazzi/backup_pve.sh + mode: '0755' + +- name: Run backup script + shell: /home/xbazzi/backup_pve.sh + +- name: Find most recent backup directory + shell: "ls -td /home/xbazzi/pve_backup_* | head -1" + register: latest_backup_dir + changed_when: false + +- name: Archive backup folder + archive: + path: "{{ latest_backup_dir.stdout }}" + dest: "{{ latest_backup_dir.stdout }}.tar.gz" + format: gz + +- name: Fetch backup archive to control machine + fetch: + src: "{{ latest_backup_dir.stdout }}.tar.gz" + dest: "backups/{{ inventory_hostname }}.tar.gz" + flat: yes diff --git a/roles/pve/pve_backup/templates/backup_pve_config.sh.j2 b/roles/pve/pve_backup/templates/backup_pve_config.sh.j2 new file mode 100644 index 0000000..0e1d96e --- /dev/null +++ b/roles/pve/pve_backup/templates/backup_pve_config.sh.j2 @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") +BACKUP_DIR="/home/xbazzi/pve_backup_${TIMESTAMP}" +NODE_NAME=$(hostname) + +echo "🔒 Creating backup directory at $BACKUP_DIR..." +mkdir -p "$BACKUP_DIR" + +echo "📁 Backing up /etc/pve..." +cp -a /etc/pve "$BACKUP_DIR/etc_pve" + +echo "📄 Saving VM and container config files..." +mkdir -p "$BACKUP_DIR/qemu-server" "$BACKUP_DIR/lxc" +cp -a /etc/pve/qemu-server/*.conf "$BACKUP_DIR/qemu-server/" 2>/dev/null || true +cp -a /etc/pve/lxc/*.conf "$BACKUP_DIR/lxc/" 2>/dev/null || true + +echo "💽 Saving storage.cfg..." +cp -a /etc/pve/storage.cfg "$BACKUP_DIR/" 2>/dev/null || true + +echo "📦 Backup complete on $NODE_NAME." +echo "🗃️ Location: $BACKUP_DIR" diff --git a/roles/pve/setup_networking/defaults/main.yml b/roles/pve/setup_networking/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/pve/setup_networking/handlers/main.yml b/roles/pve/setup_networking/handlers/main.yml new file mode 100644 index 0000000..eb3f4ff --- /dev/null +++ b/roles/pve/setup_networking/handlers/main.yml @@ -0,0 +1,5 @@ +# - name: Restart networking +# ansible.builtin.systemd: +# name: networking +# state: restarted + \ No newline at end of file diff --git a/roles/pve/setup_networking/tasks/main.yml b/roles/pve/setup_networking/tasks/main.yml new file mode 100644 index 0000000..91d62bc --- /dev/null +++ b/roles/pve/setup_networking/tasks/main.yml @@ -0,0 +1,46 @@ +--- +- name: Set up network interfaces for new PVE node + template: + src: interfaces-xbazzi.j2 + # dest: /etc/network/interfaces.d/interfaces-xbazzi + dest: /etc/network/interfaces + owner: root + group: root + mode: "0644" + +- name: Apply correct permissions to interfaces.d + file: + path: "/etc/network/interfaces.d" + owner: root + group: root + mode: '0644' + +- name: Find all files in the directory + ansible.builtin.find: + paths: /etc/network/interfaces.d/ + file_type: file + register: files_to_delete + +- name: Delete all files + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + loop: "{{ files_to_delete.files }}" + +- name: Update /etc/hosts with all PVE nodes + template: + src: hosts.j2 + dest: /etc/hosts + mode: "0644" + +- name: Ensure search domain and nameserver set properly + template: + src: resolv.j2 + dest: /etc/resolv.conf + mode: "0644" + + +- name: Restart networking + ansible.builtin.systemd: + name: networking + state: restarted diff --git a/roles/pve/setup_networking/templates/hosts.j2 b/roles/pve/setup_networking/templates/hosts.j2 new file mode 100644 index 0000000..a65756c --- /dev/null +++ b/roles/pve/setup_networking/templates/hosts.j2 @@ -0,0 +1,6 @@ +127.0.0.1 localhost +{% for host in groups['pve-nodes'] %} +{{ hostvars[host]['ansible_default_ipv4']['address'] }} {{ host }} {{ host }}.lan.xbazzi.com +{{ hostvars[host]['cluster_ip'] }} {{ host }}-cluster +{% endfor %} + diff --git a/roles/pve/setup_networking/templates/interfaces-xbazzi.j2 b/roles/pve/setup_networking/templates/interfaces-xbazzi.j2 new file mode 100644 index 0000000..e3f38ff --- /dev/null +++ b/roles/pve/setup_networking/templates/interfaces-xbazzi.j2 @@ -0,0 +1,48 @@ +auto eno1 +iface eno1 inet manual + mtu 1500 + +auto enp1s0f0 +iface enp1s0f0 inet manual + mtu 9000 + +iface enp1s0f1 inet manual + mtu 9000 + +# Mgmt interface +auto vmbr0 +iface vmbr0 inet static + address {{ vmbr0_ip }}/22 + bridge-ports eno1 + bridge-stp off + bridge-fd 0 + mtu 1500 + +auto vmbr1 +iface vmbr1 inet manual + bridge-ports enp1s0f0 + bridge-stp off + bridge-fd 0 + bridge-vlan-aware yes + bridge-vids 2-4094 + mtu 9000 + +# Prod interface +auto vmbr1.1337 +iface vmbr1.1337 inet static + address {{ vmbr1_1337_ip }}/22 + gateway 10.133.7.1 + mtu 9000 + +# DMZ interface +auto vmbr1.666 +iface vmbr1.666 inet static + address {{ vmbr1_666_ip }}/22 + mtu 1500 + +# Cluster network +auto {{ cluster_iface }} +iface {{ cluster_iface }} inet static + address {{ cluster_ip }}/28 + mtu 1500 + diff --git a/roles/pve/setup_networking/templates/resolv.j2 b/roles/pve/setup_networking/templates/resolv.j2 new file mode 100644 index 0000000..e2b3300 --- /dev/null +++ b/roles/pve/setup_networking/templates/resolv.j2 @@ -0,0 +1,2 @@ +search lan.xbazzi.com +nameserver 10.133.7.1 \ No newline at end of file diff --git a/roles/server/firewall/defaults/main.yml b/roles/server/firewall/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/firewall/handlers/main.yml b/roles/server/firewall/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/firewall/tasks/main.yml b/roles/server/firewall/tasks/main.yml new file mode 100644 index 0000000..a742df0 --- /dev/null +++ b/roles/server/firewall/tasks/main.yml @@ -0,0 +1,43 @@ +--- +- name: Enable and start firewalld + ansible.builtin.systemd: + name: firewalld + enabled: yes + state: started + +- name: Assign interface ens18 to core zone + ansible.posix.firewalld: + interface: ens18 + zone: core + state: enabled + permanent: true + +- name: Assign interface ens19 to mgmt zone + ansible.posix.firewalld: + interface: ens19 + zone: mgmt + state: enabled + permanent: true + +- name: Assign interface ens20 to dmz zone + ansible.posix.firewalld: + interface: ens20 + zone: dmz + state: enabled + permanent: true + +- name: Set core to default + ansible.builtin.command: firewall-cmd --set-default-zone=core + +# - name: Remove ens18 from public +# ansible.builtin.command: firewall-cmd --zone=public --remove-interface=ens18 + +# - name: Assign interface ens18 to "internal" zone +# ansible.posix.firewalld: +# interface: ens18 +# zone: internal +# state: enabled +# permanent: true + +- name: Reload firewalld to apply changes + ansible.builtin.command: firewall-cmd --reload diff --git a/roles/server/firewall/templates/main.yml b/roles/server/firewall/templates/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/ftp/defaults/main.yml b/roles/server/ftp/defaults/main.yml new file mode 100755 index 0000000..e69de29 diff --git a/roles/server/ftp/tasks/main.yml b/roles/server/ftp/tasks/main.yml new file mode 100755 index 0000000..a710115 --- /dev/null +++ b/roles/server/ftp/tasks/main.yml @@ -0,0 +1,23 @@ +--- +- name: Update apt cache + ansible.builtin.apt: + update_cache: true + +- name: Install proftpd package + ansible.builtin.apt: + name: proftpd + state: present + +- name: Ensure proftpd is enabled and started + ansible.builtin.service: + name: proftpd + state: started + enabled: true + become: true + +- name: Allow FTP through UFW firewall (if UFW is enabled) + community.general.ufw: + rule: allow + port: 21 + proto: tcp + ignore_errors: false \ No newline at end of file diff --git a/roles/server/network/defaults/main.yml b/roles/server/network/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/network/handlers/main.yml b/roles/server/network/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/network/tasks/main.yml b/roles/server/network/tasks/main.yml new file mode 100644 index 0000000..05daa35 --- /dev/null +++ b/roles/server/network/tasks/main.yml @@ -0,0 +1,136 @@ +--- +- name: Enable and start firewalld + ansible.builtin.systemd: + name: firewalld + enabled: yes + state: started + +- name: Enable and start NetworkManager + ansible.builtin.systemd: + name: NetworkManager + enabled: yes + state: started + +- name: Check existing zones + ansible.builtin.command: firewall-cmd --get-zones + register: firewalld_zones + +- name: Debug output + ansible.builtin.debug: + var: firewalld_zones.stdout + +# - name: Create zone "core" +# ansible.builtin.command: firewall-cmd --permanent --new-zone="{{ item }}" +# loop: ["core", "mgmt"] +# # loop: "{{ firewalld_zones.stdout | split }}" +# when: item in firewalld_zones.stdout.split() + # (item != "core" and + # item != "dmz") + +- name: Create firewalld core zone + ansible.posix.firewalld: + zone: core + state: present + permanent: true + +- name: Create firewalld mgmt zone + ansible.posix.firewalld: + zone: mgmt + state: present + permanent: true + +- name: Create firewalld dmz zone + ansible.posix.firewalld: + zone: dmz + state: present + permanent: true + +- name: Reload firewalld to apply changes + ansible.builtin.command: firewall-cmd --reload + +- name: Enable ssh rule in core for initial ansible config + ansible.posix.firewalld: + zone: core + service: ssh + state: enabled + permanent: true + +# - name: Ensure all other zones are disabled +# ansible.posix.firewalld: +# zone: "{{ item }}" +# state: disabled +# permanent: true +# when: item not in zones +# loop: "{{ firewalld_zones.stdout | split }}" + +- name: Set up CORE interface manually + nmcli: + conn_name: CORE + zone: core + type: ethernet + ip4: "{{ provision_core_ip4 }}" + gw4: "{{ core_gw4 }}" + dns4: "{{ core_gw4 }}" + method4: "manual" + ifname: ens18 + dns4_search: lan.xbazzi.com + state: present + # delegate_to: "{{ provision_core_ip4_no_subnet }}" + +- name: Set up mgmt interface manually + nmcli: + conn_name: MGMT + zone: mgmt + type: ethernet + ip4: "{{ provision_mgmt_ip4 }}" + routes4: "0.0.0.0/0 {{ mgmt_gw4 }}" + routing_rules4: + - "priority 2 from {{ mgmt_net }} table 200" + route_metric4: 102 + dns4: "{{ mgmt_gw4 }}" + method4: "manual" + ifname: "ens19" + dns4_search: "lan.xbazzi.com" + state: present + # delegate_to: "{{ provision_core_ip4_no_subnet }}" + +- name: Set up dmz interface manually + nmcli: + conn_name: DMZ + zone: dmz + type: ethernet + ip4: "{{ provision_dmz_ip4 }}" + routes4: "0.0.0.0/0 {{ dmz_gw4 }}" + routing_rules4: + - "priority 3 from {{ dmz_net }} table 300" + route_metric4: 103 + dns4: "{{ dmz_gw4 }}" + method4: "manual" + ifname: "ens20" + dns4_search: "lan.xbazzi.com" + state: present + # delegate_to: "{{ provision_core_ip4_no_subnet }}" + +- name: Remove ens18 default connection + nmcli: + conn_name: ens18 + state: absent + # delegate_to: "{{ provision_core_ip4_no_subnet }}" + +- name: Remove ens19 default connection + nmcli: + conn_name: ens19 + state: absent + # delegate_to: "{{ provision_core_ip4_no_subnet }}" + +- name: Remove ens20 default connection + nmcli: + conn_name: ens20 + state: absent + # delegate_to: "{{ provision_core_ip4_no_subnet }}" + +- name: Remove "Wired connection 1" + nmcli: + conn_name: Wired connection 1 + state: absent + # delegate_to: "{{ provision_core_ip4_no_subnet }}" diff --git a/roles/server/network/templates/ifcfg-template.j2 b/roles/server/network/templates/ifcfg-template.j2 new file mode 100644 index 0000000..89715b7 --- /dev/null +++ b/roles/server/network/templates/ifcfg-template.j2 @@ -0,0 +1,6 @@ +DEVICE={{ network_config.interface }} +BOOTPROTO=none +ONBOOT=yes +IPADDR={{ network_config.address }} +NETMASK={{ network_config.netmask }} +GATEWAY={{ network_config.gateway }} diff --git a/roles/server/network/templates/main.yml b/roles/server/network/templates/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/reboot/defaults/main.yml b/roles/server/reboot/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/reboot/handlers/main.yml b/roles/server/reboot/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/reboot/tasks/main.yml b/roles/server/reboot/tasks/main.yml new file mode 100644 index 0000000..f814796 --- /dev/null +++ b/roles/server/reboot/tasks/main.yml @@ -0,0 +1,5 @@ +--- +- name: Reboot machine and send a message + ansible.builtin.shell: "reboot" + async: 1 + poll: 0 \ No newline at end of file diff --git a/roles/server/reboot/templates/main.yml b/roles/server/reboot/templates/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/sshkey/defaults/main.yml b/roles/server/sshkey/defaults/main.yml new file mode 100755 index 0000000..e69de29 diff --git a/roles/server/sshkey/tasks/main.yml b/roles/server/sshkey/tasks/main.yml new file mode 100644 index 0000000..f2484c4 --- /dev/null +++ b/roles/server/sshkey/tasks/main.yml @@ -0,0 +1,12 @@ +--- +- name: Add ansible user SSH public key + ansible.posix.authorized_key: + user: ansible + key: "{{ lookup('file', '/home/xbazzi/.ssh/ansible_ed25519.pub') }}" + state: present + +- name: Add xbazzi user SSH public key + ansible.posix.authorized_key: + user: xbazzi + key: "{{ lookup('file', '/home/xbazzi/.ssh/lan_id_ed25519.pub') }}" + state: present \ No newline at end of file diff --git a/roles/server/sysprep/defaults/main.yml b/roles/server/sysprep/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/sysprep/handlers/main.yml b/roles/server/sysprep/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/sysprep/tasks/main.yml b/roles/server/sysprep/tasks/main.yml new file mode 100644 index 0000000..b3f8f0e --- /dev/null +++ b/roles/server/sysprep/tasks/main.yml @@ -0,0 +1,115 @@ +--- +- name: Set hostname to generic localhost + ansible.builtin.hostname: + name: localhost.localdomain + # use: systemd + +- name: Ensure IPv4 localhost entry exists in /etc/hosts + ansible.builtin.lineinfile: + path: /etc/hosts + line: "127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4" + state: present + create: yes + regexp: '^127\.0\.0\.1\s+localhost' + +- name: Remove IPv6 localhost entry (::1) from /etc/hosts + ansible.builtin.lineinfile: + path: /etc/hosts + regexp: '^::1\s+localhost' + state: absent + +# - name: Remove xbazzi user +# ansible.builtin.user: +# name: xbazzi +# state: absent +# remove: true + +# - name: Truncate machine-id +# ansible.builtin.command: truncate -s 0 /etc/machine-id + +- name: Remove DBus machine-id if exists + ansible.builtin.file: + path: /var/lib/dbus/machine-id + state: absent + +- name: Remove root SSH folder + ansible.builtin.file: + path: /root/.ssh + state: absent + +- name: Remove anaconda kickstart config + ansible.builtin.file: + path: /root/anaconda-ks.cfg + state: absent + +- name: Clear logs + ansible.builtin.file: + path: "{{ item }}" + state: absent + loop: + - /var/log/boot.log + - /var/log/cron + - /var/log/dmesg + - /var/log/grubby + - /var/log/lastlog + - /var/log/maillog + - /var/log/messages + - /var/log/secure + - /var/log/spooler + - /var/log/tallylog + - /var/log/wtmp + - /var/log/yum.log + - /var/log/audit/audit.log + - /var/log/tuned/tuned.log + - /var/log/wpa_supplicant.log + - /var/log/ovirt-guest-agent/ovirt-guest-agent.log + +- name: Rotate and vacuum journal logs + ansible.builtin.shell: | + journalctl --rotate + journalctl --vacuum-time=1s + when: ansible_facts['distribution_major_version'] is version('8', '>=') + +- name: Clear shell history + ansible.builtin.copy: + content: "" + dest: /root/.bash_history + force: true + +- name: Find all SSH keys + ansible.builtin.find: + paths: + - /etc/ssh + - /home/ + patterns: + - "ssh_host*" + - "id_*" + - "authorized_keys" + - "known_hosts" + - "config" + use_regex: false + recurse: true + file_type: file + register: ssh_files + +- name: Debug found SSH keys + debug: + msg: "{{ item.path }}" + loop: "{{ ssh_files.files }}" + +- name: Remove SSH keys + ansible.builtin.file: + path: "{{ item.path }}" + state: absent + loop: "{{ ssh_files.files }}" + # loop: "{{ ssh_keys.results | map(attribute='files') | flatten }}" + +- name: Sync changes to disk + ansible.builtin.command: sync + +- name: Remove old local SSH known_hosts entry (necessary to avoid fingerprint warning) + become_user: xbazzi + local_action: + module: command + args: + cmd: ssh-keygen -R "{{ hostvars['staging-vm'].ansible_host }}" diff --git a/roles/server/sysprep/templates/main.yml b/roles/server/sysprep/templates/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/users/defaults/main.yml b/roles/server/users/defaults/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/users/handlers/main.yml b/roles/server/users/handlers/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/server/users/tasks/main.yml b/roles/server/users/tasks/main.yml new file mode 100644 index 0000000..365b9cf --- /dev/null +++ b/roles/server/users/tasks/main.yml @@ -0,0 +1,45 @@ +--- +- name: Add xbazzi group + ansible.builtin.group: + name: xbazzi + state: present + gid: 1337 + +- name: Add xbazzi user + ansible.builtin.user: + name: xbazzi + create_home: true + shell: /bin/bash + groups: wheel,xbazzi + uid: 1337 + state: present + +# - name: Add ansible group +# ansible.builtin.group: +# name: ansible +# state: present +# gid: 1001 + +# - name: Add ansible user +# ansible.builtin.user: +# name: ansible +# create_home: true +# shell: /bin/bash +# groups: wheel,ansible +# state: present +# uid: 1001 + +- name: Add nfsuser group + ansible.builtin.group: + name: nfsuser + state: present + gid: 3005 + +- name: Add nfsuser user + ansible.builtin.user: + name: nfsuser + create_home: true + shell: /bin/bash + groups: wheel + state: present + uid: 3005 diff --git a/roles/server/users/templates/main.yml b/roles/server/users/templates/main.yml new file mode 100644 index 0000000..e69de29 diff --git a/roles/services/postgres/defaults/main.yml b/roles/services/postgres/defaults/main.yml new file mode 100644 index 0000000..8ca4c28 --- /dev/null +++ b/roles/services/postgres/defaults/main.yml @@ -0,0 +1,5 @@ +directory: "postgres" +default_user: "postgres" +default_password: "password" +port: "5432" +container_name: "postgres" \ No newline at end of file diff --git a/roles/services/postgres/tasks/main.yml b/roles/services/postgres/tasks/main.yml new file mode 100644 index 0000000..7df3f06 --- /dev/null +++ b/roles/services/postgres/tasks/main.yml @@ -0,0 +1,23 @@ +- name: Create data folder + ansible.builtin.file: + dest: "{{ docker_dir }}/{{ directory }}" + state: directory + owner: root + group: docker + mode: '0770' + recurse: yes + +- name: Put up the postgres container + community.docker.docker_container: + name: "{{container_name}}" + image: postgres:17.4 + restart_policy: always + state: started + pull: true + ports: + - "{{ port }}:5432" + env: + POSTGRES_USER: "{{ default_user }}" + POSTGRES_PASSWORD: "{{ default_password }}" + volumes: + - "{{ docker_dir }}/{{ directory }}/data:/var/lib/postgresql/data/" \ No newline at end of file diff --git a/roles/util/mount_nfs/defaults/main.yml b/roles/util/mount_nfs/defaults/main.yml new file mode 100755 index 0000000..771dc8d --- /dev/null +++ b/roles/util/mount_nfs/defaults/main.yml @@ -0,0 +1,3 @@ +mount_host: "{{ hostvars['nas'].ansible_host }}" +share: "/mnt/ALEXANDRIA/" +mount_path: "/mnt/unspecifiedshare" \ No newline at end of file diff --git a/roles/util/mount_nfs/tasks/main.yml b/roles/util/mount_nfs/tasks/main.yml new file mode 100755 index 0000000..9173c44 --- /dev/null +++ b/roles/util/mount_nfs/tasks/main.yml @@ -0,0 +1,21 @@ +--- +- name: Ensure NFS client is installed + ansible.builtin.package: + name: nfs-common + state: present + become: true + +- name: Create mount point directory + ansible.builtin.file: + path: "{{ mount_path }}" + state: directory + mode: '0777' + become: true + +- name: Mount share + ansible.posix.mount: + src: "{{ mount_host }}:{{ share }}" + path: "{{ mount_path }}" + fstype: nfs + state: mounted + become: true \ No newline at end of file diff --git a/setup.sh b/setup.sh new file mode 100755 index 0000000..bd30ef7 --- /dev/null +++ b/setup.sh @@ -0,0 +1,28 @@ +echo "**Deleting .git so you can start your own repo" +rm -rf .git +echo "***Ansible vault password***" +echo "This is used to encrypt/descrypt secrets in your vault" +echo "We'll save it to a file in ~/.[file name] so it doesn't have to be typed every time" +echo +read -p "File name (no . prefix): " ansible_vault_pass_filename +read -s -p "Password: " ansible_vault_pass + +echo $ansible_vault_pass > ~/.$ansible_vault_pass_filename +echo "vault_password_file = ~/.$ansible_vault_pass_filename" >>ansible.cfg + +echo +echo + +echo "***Ansible become password***" +echo "A lot of actions need sudo. This password will be stored in group_vars/all.yml encrypted" +read -s -p "Password: " ansible_become_pass +echo "# Sudo password for your servers" >>./group_vars/all.yml +ansible-vault encrypt_string "$ansible_become_pass" --name 'ansible_become_pass' >>./group_vars/all.yml + +echo +echo + +echo "Setup complete" +echo "You can delete setup.sh since running it again would cause issues" +echo "Config for vault password was output to ./ansible.cfg" +echo "Config for sudo (become) password was output to ./group_vars/all.yml"