From 16af4d1fd1a76c5f2f759712760847da6ddad1a1 Mon Sep 17 00:00:00 2001 From: Badanin Maksim Date: Mon, 1 Apr 2024 19:35:30 +0300 Subject: [PATCH] add playbook --- ansible.cfg | 7 + docspace_recover_password.md | 59 ++++++ group_vars/all.yml | 5 + install.md | 20 ++ inventory/hosts.yml | 15 ++ play.yml | 355 +++++++++++++++++++++++++++++++++++ 6 files changed, 461 insertions(+) create mode 100644 ansible.cfg create mode 100644 docspace_recover_password.md create mode 100644 group_vars/all.yml create mode 100644 install.md create mode 100644 inventory/hosts.yml create mode 100644 play.yml diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..02684cb --- /dev/null +++ b/ansible.cfg @@ -0,0 +1,7 @@ +[defaults] +ask_pass = false +host_key_checking = false +inventory = ./inventory + +[ssh_connection] +ssh_args = -o UserKnownHostsFile=/dev/null diff --git a/docspace_recover_password.md b/docspace_recover_password.md new file mode 100644 index 0000000..b6bcc45 --- /dev/null +++ b/docspace_recover_password.md @@ -0,0 +1,59 @@ +5/pKuJ+2FDOksnA2EcFgH416mluIKBu0BcZKDU65WimvcR4u/bBMw8S/r3v1MYSeXbt/cviqRcxsXMsnLK8WVQ== +Base64(unhex(SHA-512($plaintext))) + + +echo -n $PASS | base64 --decode | hexdump -ve '/1 "%02X"' + +E7FA4AB89FB61433A4B2703611C1601F8D7A9A5B88281BB405C64A0D4EB95A29AF711E2EFDB04CC3C4BFAF7BF531849E5DBB7F72F8AA45CC6C5CCB272CAF1655 +e7fa4ab89fb61433a4b2703611c1601f8d7a9a5b88281bb405c64a0d4eb95a29af711e2efdb04cc3c4bfaf7bf531849e5dbb7f72f8aa45cc6c5ccb272caf1655 + + + + +Hasher.Base64Hash(password + userId + Encoding.UTF8.GetString(_machinePseudoKeys.GetMachineConstant()), HashAlg.SHA512) + +password = +11111111 +userId = +66faa6e4-f133-11ea-b126-00ffeec8b4ef +machineid = +qFlL10hN9HFe + ++++ = +1111111166faa6e4-f133-11ea-b126-00ffeec8b4efqFlL10hN9HFe + +SHA512 = +6979b3330c8dbfcc8fcffc1751582eb6c14befa6dc27b4c62a24c87a306a108d1f535e1f59790de75cc2b8b09c2fac509bbe6ccbdaf0109a776888af5c7072e1 + +Base64 = +Njk3OWIzMzMwYzhkYmZjYzhmY2ZmYzE3NTE1ODJlYjZjMTRiZWZhNmRjMjdiNGM2MmEyNGM4N2EzMDZhMTA4ZDFmNTM1ZTFmNTk3OTBkZTc1Y2MyYjhiMDljMmZhYzUwOWJiZTZjY2JkYWYwMTA5YTc3Njg4OGFmNWM3MDcyZTE= + + + + + +default salt = +{9450BEF7-7D9F-4E4F-A18A-971D8681722D} +sha256 = +64ef7c70accbdd465543105d8d714f9c11ec3bb2052348a38d76df3a42088f5d + + + +pbkdf2_sha256.using(salt=b'64ef7c70accbdd465543105d8d714f9c11ec3bb2052348a38d76df3a42088f5d', rounds=100000, salt_size=256).hash("11111111") +'$pbkdf2-sha256$100000$NjRlZjdjNzBhY2NiZGQ0NjU1NDMxMDVkOGQ3MTRmOWMxMWVjM2JiMjA1MjM0OGEzOGQ3NmRmM2E0MjA4OGY1ZA$It1CiqperI2orr1phXptnkZS1spPhQ0eiO4BPe9XB2g' + + +JHBia2RmMi1zaGEyNTYkMTAwMDAwJE5qUmxaamRqTnpCaFkyTmlaR1EwTmpVMU5ETXhNRFZrT0dRM01UUm1PV014TVdWak0ySmlNakExTWpNME9HRXpPR1EzTm1SbU0yRTBNakE0T0dZMVpBJEl0MUNpcXBlckkyb3JyMXBoWHB0bmtaUzFzcFBoUTBlaU80QlBlOVhCMmc= + + + + + + + +UPDATE docspace.core_user SET email='bms@badms.ru' WHERE id='66faa6e4-f133-11ea-b126-00ffeec8b4ef'; +UPDATE docspace.tenants_tenants SET statuschanged='2024-03-31 13:43:06',timezone='Europe/Moscow',`language`='ru',version_changed='0001-01-01 00:00:00' WHERE id=1; +UPDATE docspace.core_usersecurity SET pwdhash='5/pKuJ+2FDOksnA2EcFgH416mluIKBu0BcZKDU65WimvcR4u/bBMw8S/r3v1MYSeXbt/cviqRcxsXMsnLK8WVQ==' WHERE userid='66faa6e4-f133-11ea-b126-00ffeec8b4ef'; +DELETE FROM docspace.webstudio_settings WHERE TenantID=1 AND ID='9a925891-1f92-4ed7-b277-d6f649739f06' AND UserID='00000000-0000-0000-0000-000000000000'; +INSERT INTO docspace.webstudio_settings (TenantID, ID, UserID, `Data`) VALUES(1, '03b382bd-3c20-4f03-8ab9-5a33f016316e', '66faa6e4-f133-11ea-b126-00ffeec8b4ef', '{"EnableThirdpartySettings":true,"FastDelete":false,"StoreOriginalFiles":true,"KeepNewFileName":false,"UpdateIfExist":false,"ConvertNotify":true,"DefaultSortedBy":0,"DefaultSortedAsc":false,"HideConfirmConvertSave":false,"HideConfirmConvertOpen":false,"Forcesave":true,"StoreForcesave":false,"HideRecent":false,"HideFavorites":false,"HideTemplates":false,"DownloadZip":false,"ShareLink":false,"ShareLinkSocialMedia":false,"AutomaticallyCleanUp":{"IsAutoCleanUp":true,"Gap":4},"DefaultSharingAccessRights":null}'); +INSERT INTO docspace.webstudio_settings (TenantID, ID, UserID, `Data`) VALUES(1, 'ee139f6c-8821-4011-8444-fd87882cd5f5', '00000000-0000-0000-0000-000000000000', '{"IsFirst":true}'); diff --git a/group_vars/all.yml b/group_vars/all.yml new file mode 100644 index 0000000..e6394c5 --- /dev/null +++ b/group_vars/all.yml @@ -0,0 +1,5 @@ +--- +step_ca_fqdn: ca.badms.ru +admin_email: bms@badms.ru +admin_password: "1" +ds_jwt_secret: WE4Cf0INl7zERb3GzG95XO9fmOq44h76 diff --git a/install.md b/install.md new file mode 100644 index 0000000..7bf59ed --- /dev/null +++ b/install.md @@ -0,0 +1,20 @@ +1. Запускаем виртуальные машины, настраиваем hostname и IP-адреса: + - ca.example.com - 10.0.0.CCC + - npm.example.com - 10.0.0.NNN + - docs.example.com - 10.0.0.DDD + - office.example.com - 10.0.0.OOO + - auth.example.com - 10.0.0.AAA +2. Устанавливаем на виртуальные машины docker: https://git.badms.ru/bms/debian_prepare +3. Создаем DNS записи: + - ca.example.com - 10.0.0.CCC + - npm.example.com - 10.0.0.NNN + - docs.example.com - 10.0.0.NNN + - office.example.com - 10.0.0.NNN + - auth.example.com - 10.0.0.NNN +4. Запускаем playbook - docspace_stack +5. Заходим на http://npm.example.com:81, меняем пароль администратора, добавляем хосты и выпускаем сертификаты для них: + - docs.example.com - 10.0.0.DDD - 80 + - office.example.com - 10.0.0.OOO - 80 + - auth.example.com - 10.0.0.AAA - 80 +6. Заходим на https://auth.example.com, меняем пароль администратора, настраиваем связи, провайдера, приложение и соединение: https://git.badms.ru/bms/authentik +7. Заходим на https://office.example.com, создаем учетную запись, diff --git a/inventory/hosts.yml b/inventory/hosts.yml new file mode 100644 index 0000000..bd045ad --- /dev/null +++ b/inventory/hosts.yml @@ -0,0 +1,15 @@ +all: + vars: + # ansible_password: 111111 + ansible_user: root + hosts: + ca: + ansible_host: 192.168.1.216 + npm: + ansible_host: 192.168.1.200 + docs: + ansible_host: 192.168.1.211 + office: + ansible_host: 192.168.1.212 + auth: + ansible_host: 192.168.1.210 diff --git a/play.yml b/play.yml new file mode 100644 index 0000000..27955e9 --- /dev/null +++ b/play.yml @@ -0,0 +1,355 @@ +--- +- name: run ca + gather_facts: false + hosts: ca + tasks: + + - name: create docker directory + ansible.builtin.file: + path: /docker + state: directory + + - name: clone repository + ansible.builtin.git: + repo: https://git.badms.ru/bms/step-ca.git + dest: /docker/step-ca + register: git_clone_result + failed_when: (git_clone_result.failed == true) and ("Local modifications" not in git_clone_result.msg) + + - name: create data directory + ansible.builtin.file: + path: /docker/step-ca/data + state: directory + owner: 1000 + group: 1000 + + - name: change fqdn + ansible.builtin.lineinfile: + name: /docker/step-ca/.env + regexp: 'STEP_CA_FQDN=ca.example.com' + line: 'STEP_CA_FQDN={{step_ca_fqdn}}' + + - name: start service + community.docker.docker_compose_v2: + project_src: /docker/step-ca + + - name: check configured + ansible.builtin.lineinfile: + name: /docker/step-ca/data/config/ca.json + regexp: '"forceCN": true' + line: '' + check_mode: yes + register: ca_config + changed_when: false + + - block: + - name: check started + community.docker.docker_container_exec: + container: step-ca + command: step ca provisioner update acme --force-cn + + - name: restart service + community.docker.docker_compose_v2: + project_src: /docker/step-ca + state: restarted + when: 'ca_config.msg == "line added"' + +- name: run npm + gather_facts: false + hosts: npm + tasks: + + - name: create docker directory + ansible.builtin.file: + path: /docker + state: directory + + - name: clone repository + ansible.builtin.git: + repo: https://git.badms.ru/bms/npm-step-ca.git + dest: /docker/npm-step-ca + register: git_clone_result + failed_when: (git_clone_result.failed == true) and ("Local modifications" not in git_clone_result.msg) + + - name: change fqdn + ansible.builtin.lineinfile: + name: /docker/npm-step-ca/.env + regexp: 'STEP_CA_FQDN=ca.example.com' + line: 'STEP_CA_FQDN={{step_ca_fqdn}}' + + - name: start service + community.docker.docker_compose_v2: + project_src: /docker/npm-step-ca + + - name: install packages + ansible.builtin.apt: + update_cache: yes + pkg: + - sqlite3 + # - python3-passlib + + - name: wait database created + ansible.builtin.wait_for: + path: /docker/npm-step-ca/data/npm-data/database.sqlite + state: present + + - name: change admin email + ansible.builtin.command: + cmd: sqlite3 /docker/npm-step-ca/data/npm-data/database.sqlite "UPDATE user SET email='{{admin_email}}' WHERE id=1;" + + - name: get password hash + ansible.builtin.set_fact: + admin_password_hashed: "{{ admin_password | ansible.builtin.password_hash(hashtype=\"blowfish\") }}" + + - name: change admin password + ansible.builtin.command: + cmd: sqlite3 /docker/npm-step-ca/data/npm-data/database.sqlite "UPDATE auth SET secret='{{ admin_password_hashed }}' WHERE id=1;" + + +- name: run documentserver + gather_facts: false + hosts: docs + tasks: + + - name: create docker directory + ansible.builtin.file: + path: /docker + state: directory + + - name: clone repository + ansible.builtin.git: + repo: '{{item.repo}}' + dest: '{{item.dest}}' + register: git_clone_result + failed_when: (git_clone_result.failed == true) and ("Local modifications" not in git_clone_result.msg) + loop: + - repo: https://git.badms.ru/bms/documentserver.git + dest: /docker/documentserver + - repo: https://git.badms.ru/bms/oo-unlim.git + dest: /docker/oo-unlim + + - name: create ca docker directory + ansible.builtin.file: + path: /docker/documentserver/data/step_ca + state: directory + + - name: download ca certificate + ansible.builtin.get_url: + validate_certs: false + url: https://{{step_ca_fqdn}}/roots.pem + dest: /docker/documentserver/data/step_ca/{{step_ca_fqdn}}.crt + + - name: uncomment and replace + ansible.builtin.replace: + path: /docker/documentserver/{{item.file}} + regexp: '{{item.regexp}}' + replace: '{{item.replace}}' + loop: + - file: .env + regexp: 'JWT_SECRET=' + replace: 'JWT_SECRET={{ds_jwt_secret}}' + - file: .env + regexp: 'ca.example.com' + replace: '{{step_ca_fqdn}}' + - file: config/supervisord.conf + regexp: 'ca.example.com' + replace: '{{step_ca_fqdn}}' + - file: .env + regexp: '# STEP_CA_FQDN' + replace: ' STEP_CA_FQDN' + - file: docker-compose.yml + regexp: '# - STEP_CA_FQDN' + replace: ' - STEP_CA_FQDN' + - file: docker-compose.yml + regexp: '#volumes' + replace: 'volumes' + - file: docker-compose.yml + regexp: '# - ./data/step_ca' + replace: ' - ./data/step_ca' + - file: docker-compose.yml + regexp: '# - ./config/supervisord.conf' + replace: ' - ./config/supervisord.conf' + + - name: start service (long task) + community.docker.docker_compose_v2: + project_src: /docker/documentserver + + +- name: run docspace + gather_facts: false + hosts: office + tasks: + + - name: create docker directory + ansible.builtin.file: + path: /docker + state: directory + + - name: clone repository + ansible.builtin.git: + repo: https://git.badms.ru/bms/docspace.git + dest: /docker/docspace + register: git_clone_result + failed_when: (git_clone_result.failed == true) and ("Local modifications" not in git_clone_result.msg) + + - name: create directories + ansible.builtin.file: + path: /docker/docspace/{{item}} + state: directory + loop: + - data + - data/app_data + - data/es_data + - data/files_data + - data/mysql_data + - data/people_data + - data/proxy_log + - data/router_log + - data/webroot_path + - data/step_ca + + - name: create special directories + ansible.builtin.file: + path: /docker/docspace/{{item.path}} + owner: '{{item.owner}}' + group: '{{item.group}}' + state: directory + loop: + - path: data/es_data + owner: 1000 + group: 1000 + - path: data/mysql_data + owner: 999 + group: 999 + + - name: uncomment and replace + ansible.builtin.replace: + path: /docker/docspace/{{item.file}} + regexp: '{{item.regexp}}' + replace: '{{item.replace}}' + loop: + - file: .env + regexp: 'APP_URL_PORTAL=' + replace: 'APP_URL_PORTAL=https://office.{{ step_ca_fqdn | regex_replace("^\w*\.(.*)$", "\1") }}' + - file: .env + regexp: 'DOCUMENT_SERVER_URL_EXTERNAL=' + replace: 'DOCUMENT_SERVER_URL_EXTERNAL=https://docs.{{ step_ca_fqdn | regex_replace("^\w*\.(.*)$", "\1") }}' + - file: .env + regexp: 'APP_CORE_MACHINEKEY=' + replace: 'APP_CORE_MACHINEKEY={{ lookup("community.general.random_string", length=12, special=false) }}' + - file: .env + regexp: 'MYSQL_ROOT_PASSWORD=' + replace: 'MYSQL_ROOT_PASSWORD={{ lookup("community.general.random_string", length=20, special=false) }}' + - file: .env + regexp: 'MYSQL_PASSWORD=' + replace: 'MYSQL_PASSWORD={{ lookup("community.general.random_string", length=20, special=false) }}' + - file: .env + regexp: 'DOCUMENT_SERVER_JWT_SECRET=' + replace: 'DOCUMENT_SERVER_JWT_SECRET={{ds_jwt_secret}}' + - file: .env + regexp: '# STEP_CA_FQDN=ca.example.com' + replace: 'STEP_CA_FQDN={{step_ca_fqdn}}' + - file: .env + regexp: '# NODE_EXTRA_CA_CERTS' + replace: 'NODE_EXTRA_CA_CERTS' + - file: docker-compose.yml + regexp: '# STEP_CA_FQDN' + replace: 'STEP_CA_FQDN' + - file: docker-compose.yml + regexp: '# NODE_EXTRA_CA_CERTS' + replace: 'NODE_EXTRA_CA_CERTS' + - file: docker-compose.yml + regexp: '# - /etc/ssl' + replace: '- /etc/ssl' + - file: docker-compose.yml + regexp: '# - ./data/step_ca' + replace: '- ./data/step_ca' + + - name: download ca certificate + ansible.builtin.get_url: + validate_certs: false + url: https://{{step_ca_fqdn}}/roots.pem + dest: '{{item}}' + loop: + - /docker/docspace/data/step_ca/{{step_ca_fqdn}}.crt + - /usr/local/share/ca-certificates/{{step_ca_fqdn}}.crt + + - name: update ca certificates + ansible.builtin.command: + cmd: update-ca-certificates + register: updata_ca_result + changed_when: '"1 added" in updata_ca_result.stdout' + + - name: start service (long task) + community.docker.docker_compose_v2: + project_src: /docker/docspace + + +# UPDATE docspace.core_user SET email='bms@badms.ru' WHERE id='66faa6e4-f133-11ea-b126-00ffeec8b4ef'; +# UPDATE docspace.tenants_tenants SET statuschanged='2024-03-31 13:43:06',timezone='Europe/Moscow',`language`='ru',version_changed='0001-01-01 00:00:00' WHERE id=1; +# UPDATE docspace.core_usersecurity SET pwdhash='5/pKuJ+2FDOksnA2EcFgH416mluIKBu0BcZKDU65WimvcR4u/bBMw8S/r3v1MYSeXbt/cviqRcxsXMsnLK8WVQ==' WHERE userid='66faa6e4-f133-11ea-b126-00ffeec8b4ef'; +# DELETE FROM docspace.webstudio_settings WHERE TenantID=1 AND ID='9a925891-1f92-4ed7-b277-d6f649739f06' AND UserID='00000000-0000-0000-0000-000000000000'; +# INSERT INTO docspace.webstudio_settings (TenantID, ID, UserID, `Data`) VALUES(1, '03b382bd-3c20-4f03-8ab9-5a33f016316e', '66faa6e4-f133-11ea-b126-00ffeec8b4ef', '{"EnableThirdpartySettings":true,"FastDelete":false,"StoreOriginalFiles":true,"KeepNewFileName":false,"UpdateIfExist":false,"ConvertNotify":true,"DefaultSortedBy":0,"DefaultSortedAsc":false,"HideConfirmConvertSave":false,"HideConfirmConvertOpen":false,"Forcesave":true,"StoreForcesave":false,"HideRecent":false,"HideFavorites":false,"HideTemplates":false,"DownloadZip":false,"ShareLink":false,"ShareLinkSocialMedia":false,"AutomaticallyCleanUp":{"IsAutoCleanUp":true,"Gap":4},"DefaultSharingAccessRights":null}'); +# INSERT INTO docspace.webstudio_settings (TenantID, ID, UserID, `Data`) VALUES(1, 'ee139f6c-8821-4011-8444-fd87882cd5f5', '00000000-0000-0000-0000-000000000000', '{"IsFirst":true}'); + + + +- name: run authentik + gather_facts: false + hosts: auth + tasks: + + - name: create docker directory + ansible.builtin.file: + path: /docker + state: directory + + - name: clone repository + ansible.builtin.git: + repo: https://git.badms.ru/bms/authentik.git + dest: /docker/authentik + register: git_clone_result + failed_when: (git_clone_result.failed == true) and ("Local modifications" not in git_clone_result.msg) + + - name: replace veriables + ansible.builtin.replace: + path: /docker/authentik/.env + regexp: '{{item.regexp}}' + replace: '{{item.replace}}' + loop: + - regexp: 'PG_PASS=' + replace: 'PG_PASS={{ lookup("community.general.random_string", length=20, special=false) }}' + - regexp: 'AUTHENTIK_SECRET_KEY=' + replace: 'AUTHENTIK_SECRET_KEY={{ lookup("community.general.random_string", length=20, special=false) }}' + + - name: start service (long task) + community.docker.docker_compose_v2: + project_src: /docker/authentik + + - name: install packages + ansible.builtin.apt: + name: python3-passlib + update_cache: yes + state: present + + - name: generate password hash + ansible.builtin.shell: + cmd: python3 -c 'from passlib.hash import django_pbkdf2_sha256; print(django_pbkdf2_sha256.hash("{{admin_password}}"))' + register: password_hash + changed_when: false + + - name: wait for page is up + ansible.builtin.uri: + url: 'https://auth.{{ step_ca_fqdn | regex_replace("^\w*\.(.*)$", "\1") }}' + validate_certs: false + register: uri_result + until: uri_result.status == 200 + retries: 24 + delay: 10 + + - name: set admin password and email + community.docker.docker_container_exec: + container: authentik-postgresql-1 + command: psql -d authentik -U authentik -c "UPDATE public.authentik_core_user SET password='{{password_hash.stdout}}',email='{{admin_email}}' WHERE username='akadmin'" + +