Сообщество - Лига Сисадминов

Лига Сисадминов

2 408 постов 18 930 подписчиков

Популярные теги в сообществе:

7

Ansible для детского сада. Часть 4. Первичная настройка конечного клиента

У меня постоянное ощущение того, что я описываю не велосипед с костылями, а велосипед, который давно изобретен, на котором все катались лет 15 назад, если не 20. Что-то типа «введение в линукс и все вокруг для 10 класса». Что на информатике учат.
Теперь еще и форматирование при оформлении слетает, хотел быстренько выложить, пока обед, а придется потратить полчаса.

Для лиги лени: много примеров, как делать не надо, и как точно не работает
Ansible для детского сада в скольки то частях. Часть 1.Про все сразу
Ansible для детского сада в скольки то частях. Часть 2. Костылируем жалкое подобие WSUS - Linux Server Update Services (LSUS)
Ansible для детского сада. Часть 3. Настраиваем подобие безопасности и все остальное
Подготовка Git

Ansible для детского сада. Часть 4. Первичная настройка конечного клиента
4.1 Теоретически все просто
4.2 Сначала готовим открытую часть сертификата без пароля через Putty в Windows и еще раз вспоминаем что генерирует Putty в Windows, а что нужно в ssh
4.3 Детский скрипт, и как не надо делать
4.4 Отлаживаем SSH, снова и опять
4.5 Проблемы с переносом строки и не только
4.6 Проверяем, что получилось
4.7 Почти переходим к второму Ansible плейбуку
4.8 Воюем с пробелами в Anisble и восстанавливаем пример из первой статьи
4.9 Возвращаемся к основной задаче

Ansible для детского сада в скольки то частях. Часть 5. Приделываем костыли

Ansible для детского сада. Часть 4. Первичная настройка конечного клиента

В предыдущей части оказалось, что в системе есть узкое место – первичная настройка.

4.1 Теоретически все просто:

пишем отдельный плейбук типа такого: Reddit Creating System Users for Ansible Execution

# From a clean system with root ssh access:
# - Install sudo
# - Add the ansible user
# - Enable wheel group for sudo

- name: add wheel group
group:
name: wheel
state: present

- name: add ansible user
user:
name: ansible
groups: wheel
password: "{{ ansible_become_password }}"
createhome: yes
home: /var/local/ansible
state: present
shell: /bin/bash
uid: 20000

- name: install sudo
apt:
name: sudo
state: installed
when: ansible_os_family == 'Debian'

- name: configure sudoers
lineinfile:
dest: /etc/sudoers.d/ansible
line: "%wheel ALL=(ALL) ALL"
state: present
create: yes
validate: 'visudo -cf %s'
owner: root
group: root
mode: 0440

- name: create ansible user authorized_keys file from id_ed25519
authorized_key:
user: ansible
manage_dir: no
path: /etc/ssh/ansible
key: "{{ lookup('file', ansible_ssh_key) }}"

Практически это означает ручную настройку для рута «еще раз». Как раз этого хочется избежать, потому что в том же Debian по умолчанию ssh для root закрыт. Изменить настройку можно. Но не нужно.

4.2 Сначала готовим открытую часть сертификата без пароля через Putty (PUTTYGEN) в Windows и еще раз вспоминаем что генерирует Putty в Windows, а что нужно в ssh

Это все помнят, но необходимо повторить еще раз.

По результатам опытов и вопросов «что ж не работает то» ключ я сделал на целых 4096 бит, а вовсе не по умолчанию в 2048. Вроде бы, должно и так работать, но ведь нет!

Когда PUTTYGEN генерирует пару ключей, открытый и закрытый ключ, то мы получаем два файла.

В моем примере:

ex1_public.pkb – файл с открытым ключем. Можно было сделать без расширения, значения это не имеет
ex1_private.ppk – файл с закрытой частью ключа.
ex1_public выглядит как:

---- BEGIN SSH2 PUBLIC KEY ----

Comment: "key-4-pikabu"

AAAABС(длинный ключ)

---- END SSH2 PUBLIC KEY ----

ex1_private.ppk выглядит как:

PuTTY-User-Key-File-3: ssh-rsa

Encryption: none

Comment: key-4-pikabu

Public-Lines: 6

AAAABС (длинный ключ на 6 строк, он же лежит в ex1_public.pkb)

Private-Lines: 14

AAABAF(длинный ключ)A==

Private-MAC: f(длинная последовательность)

если вы нажимали еще какие-то кнопки и настройки, то могут встречаться строки типа:

Key-Derivation: Argon2id

Argon2-Memory: 8192

Argon2-Passes: 34

В /home/user/.ssh/ authorized_keys лежит только строка из открытого ключа в формате:

ssh-rsa AAAABС.. (и так далее) вплоть до конца строки.

PUTTYGEN так и показывает , КАК НАДО.

4.3 Детский скрипт, и как не надо делать

Перепишу все, что выше, обратно в ssh \ bash:

В процессе отладки выяснилось, что есть такое ограничение, как регистр имени пользователя в Linux, описанное как
User/group names must match [a-z_][a-z0-9_-]*[$],

то есть можно и нужно было посмотреть в тот же chkname.c., и увидеть там

* is_valid_user_name(), is_valid_group_name() - check the new user/group

дебиан сорцы, наведение через ЖЖ - Формат имени пользователя в Linux.

Поэтому, сделать

username=Ansible1

можно, и даже пароль ему поставить можно, но потом разбираться с chmod\chown для \home\ Ansible1\.ssh – это какой-то совсем не очевидный процесс. Хотя при входе с паролем такое имя пользователя работает, но разбираться еще и с этим в рамках статьи было лень, и, значит, пусть все будет строчное.

username=ansible1

/usr/sbin/useradd -m -s /bin/bash "$username"

# как не надо изобретать свои костыли

# Superrandom1=$RANDOM*$RANDOM+$RANDOM-$RANDOM*$RANDOM

# это строка, и математика так не сработает. Это и не важно

# PASS1=$(echo -n $Superrandom1 | sha256sum)

# echo $PASS > ps1.txt

# echo ${PASS:0:64} > ps2.txt

# PASS2=`date`

# PASS3=${PASS2:0:3}-${PASS:0:60}

#PASS2=${PASS:0:61}

# echo -e $PASS2\n$PASS2 | passwd "$username"

# так не работает, потому что в sha256sum попадаются простые сочетания.# echo $PASS3

# echo $username:$PASS3 | /usr/sbin/chpasswd #тут почему-то denied

PASS4=`cat /dev/urandom | fold -w 32 | head -n 1`

echo $username:$PASS4 | /usr/sbin/chpasswd

Пароль поставили. Но он не нужен, потому что вход будет по сертификату. Пока переделывал оформление, вспомнил, что не отключил вход по паролю.

Добавлю группу и юзера в группу

groupname=ans_demo1

/usr/sbin/groupadd $groupname

/usr/sbin/usermod --append --groups $groupname $username

Теперь sudoers для группы:

mkdir -p /etc/sudoers.d

и дальше

curl --header "PRIVATE-TOKEN: glpat-norDQhvwoTxyAtM9ANhV" http://192.168.1111.2222/api/v4/projects/2/repository/files/ansible/raw?ref=main -o /etc/sudoers.d/ansible

где 2 – ID проекта, а токен ваш токен. Токен в примере выше я сменил, и это токен из домашней лабы, и с этим токеном не так много можно увидеть даже в домашней лабе. Можно увидеть открытую часть ключа, и метод генерации случайного пароля.

Содержание sudoers.d/ansible

## Allow root to run any commands anywhere

root ALL=(ALL) ALL

## Allows people in group wheel to run all commands

%ans_demo1 ALL=(ALL) ALL

## Same thing without a password

%ans_demo1 ALL=(ALL) NOPASSWD: ALL

и остается сделать только

curl --header "PRIVATE-TOKEN: glpat-norDQhvwoTxyAtM9ANhV" http://192.168.1111.2222/api/v4/projects/2/repository/files/authorized_keys/raw?ref=main -o /home/$username/.ssh/authorized_keys --create-dirs

Думали все так просто? Ничего подобного. Так работать без дополнительной магии не будет.

4.4 Отлаживаем SSH, снова и опять

Эти пара абзацев написаны после того, как в разделе 4.9 ничего не заработало, потому что я попросту забыл настроить права на файл. Вроде, столько раз делал, и опять забыл.

По результатам перегенерации всех паролей и настроек я имею:

Локально, на ПК с Windows,
Было ex1_public.pkb, стало pikabu_part4_public – файл с открытым ключем. Расширение значения не имеет
Было ex1_private.ppk, стало pikabu_part4_private.ppk - файл с закрытой частью ключа.

Это два текстовых файла. Конечно, лучше бы файл с закрытой частью ключа хранить на зашифрованном разделе, или в волте, или как-то еще, «закрыто».

Файл pikabu_part4_export4ssh. Это экспорт файла для ssh, потом будет нужен.
В гите, в файле authorized_keys, лежит, в одну строку, длинная строка с началом

ssh-rsa AAAAB… и окончанием == и какой-то комментарий, который вы сами пропишете при создании ключа.

Поскольку дело происходит в Debian, то речь про
tail -f /var/log/auth.log – не идет, а в
journalctl -ru ssh | grep 'Could not open user' -
будет
Could not open user 'Ansible1' authorized keys '/home/Ansible1/.ssh/authorized_keys': Permission denied

В интернетах пишут: сделайте chmod да chown, и будет вам радость да счастье. Возьму да сделаю!

chmod 600 /home/ansible1/.ssh/authorized_keys
chmod 700 /home/ansible1/.ssh/
chown ansible1 /home/ansible1/.ssh/ -R
systemctl restart ssh.service

Про вот такое еще пишут знающие люди в интернетах, но я пожалуй, воздержусь.

chown ansible1:ans_demo1 /home/ansible1/.ssh –R

И вот замечу я, что когда все буковки в имени пользователя стали маленькие, то волшебным образом все заработало. А пока user был Ansible1, то есть с большой буквы, то сделав

passwd Ansible1

все работало, а через ssh – нет. И магия это мне не понятна, поскольку и ключи я переделал, и все переписал, и три раза перегрузил, а ишь ты – не работало, и хоть ты что делай.

Потому делал я всякое непотребное,
pkill -KILL -u ansible1
и
/usr/sbin/deluser ansible1

и неоднократно.

4.5 Проблемы с переносом строки и не только

Если вы копипастите из винды \ текстового файла (в формате винды с переносом строки и возвратом каретки), и потом тащите этот файл в git, и потом на Linux машину, не забудьте сменить формат переноса строки через

sed -i 's/\r$//' filename

Потому что иногда так получается, что скрипт в две строки, из примера в третьей части, работает нормально. Вот такой еще работает,

#!/bin/bash
date

А что-то длиннее начинает ругаться на
command not found
или
unexpected token `newline

Прям печаль и беда. Что остается? Костыли.

curl --header "PRIVATE-TOKEN: glpat-norDQhvwoTxyAtM9ANhV" http://192.168.1111.2222/api/v4/projects/2/repository/files/second.sh/raw?ref=main -o ansible4.txt && sed -i 's/\r$//' ansible4.txt && bash ansible4.txt

Конечно, правильнее хранить токены не в коде, а в vault. Но если у этого токена доступ только к этому проекту, то .. и так сойдет.
И, конечно токен не стоит хранить в коде, а имеет смысл передавать как параметр в командной строке. Или нет.

4.6 Проверяем, что получилось

Во первых. Оказалось, что я забыл установить пакет sudo. Нет его в Debian12 и Debian 13 by Proxmox. Не забудьте дописать
Во вторых. Оказалось, что я на одном из хостов не прописал Nexus в /etc/apt/sources.list, отчего обновления не шли. Тоже не забывайте.
В третьих. На одном хосте словил: bash: curl: command not found
Потому что curl там лежит, почему-то, только в:
/usr/share/bash-completion/completions/curl
/usr/lib/python3/dist-packages/curl

как это в одном дебиане работает, в другом нет, я даже не пытаюсь понять. Поэтому:
сначала nano /etc/resolv.conf (где у меня с времен тестов SSSD прописан DNS от AD DC), потом

apt install curl -y

Итого я забыл:

apt install curl -y
apt install sudo -y

заменить или исправить /etc/resolv.conf
заменить или исправить /etc/apt/sources.list. Причем, при использовании Nexus, это будут разные sources.list.

Или нет ? Прописать то я могу что угодно.
Отредактировать /etc/ssh/sshd_config – для входа только по сертификату, сделать PasswordAuthentication no

И про велосипед.

Вопрос «что лучше, исправить или заменить» - мне не ясен. И та и другая операция приводит к одному виду, а что «правильнее» ?

В скрипте выше в строке
PASS4=`cat /dev/urandom | fold -w 32 | head -n 1`
возникают ошибки
ansible4.txt: line 17: warning: command substitution: ignored null byte in input
Да и путь -o ansible4.txt правильнее переписать как -o ~/ansible4.txt, но опять же, если это все работает не от рута, потому что у рута домашняя директория (~) вовсе не /home/user.

И что с этим делать, мне тоже не понятно. То есть, мне то понятно, ничего не делать.
Осталось удалить созданную в ходе опытов директорию ''$'\r'?. Оказалось, что проще всего ее сначала переименовать, иначе удаление делает некоторые фокусы, особенно если сделать rm $'*

Еще от влияния переноса строки образовалась не только \home\Ansible1, но и:
'Ansible1'$'\r' и 'Ansible1'$'\r\r'
И в скрипт можно бы и дописать, rm ansible5.txt.
Или даже и apt update && apt upgrade -y, вдруг забыл кто-то, кто систему ставил, сделать сразу же после настройки /etc/apt/sources.list.

4.7 Почти переходим к второму Ansible плейбуку

Вначале было слово, потом был вообще не плейбук, а команда
ansible proxmox -m setup -a "filter=ansible_uptime_seconds" --ask-pass

Первый плейбук, /home/user/uptime_report.yml, описан в первой статье, как и перечень хостов к нему,/home/user/1st_hosts.ini.
Итоговая команда была:

ansible-playbook uptime_report.yml --ask-pass --user root --inventory /home/user/1st_hosts.ini

При этом, я еще и умудрился файл uptime_report.yml сломать. Точнее, случайно удалить, и при переписывании получить:

[ERROR]: YAML parsing failed: This may be an issue with missing quotes around a template block.
Origin: /home/user/uptime_report.yml:11:19
9 msg:
10 Hostname: {{ inventory_hostname }}
11 Uptime: {{ (ansible_uptime_seconds / 86400) | int }} days,
^ column 19

Вот она, проблема vibe кода. Какой запрос был, я, конечно, не помню. Почему сломалось – не знаю, и написано не понять. Починить? Могу, но.
Но я так люблю возню с пробелами, кавычками, и даже со скобками, вы не представляете насколько.

4.8 Воюем с пробелами в Anisble и восстанавливаем пример из первой статьи

В статье Slurm: Примеры Ansible-Playbook есть максимально простой пример (пробелы в начале строки заменены на ! для лучшей считаемости числа пробелов). Файл: example01.yml

- hosts: all

!!tasks:

!!!!- name: Проверить доступность

!!!!!!ping:

Такой сценарий работает, и ему, кстати, безразлична возня с переносами строки.

Если же я пойду в справочник Ansible ansible.builtin.debug module – Print statements during execution, и сделаю

---

- name: Print the gateway for each host when defined

ansible.builtin.debug:

msg: System {{ inventory_hostname }} has gateway {{ ansible_default_ipv4.gateway }}

when: ansible_default_ipv4.gateway is defined

То я получу новую ошибку:

[ERROR]: 'ansible.builtin.debug' is not a valid attribute for a Play

То есть, пример Simple Ansible playbook to get the Linux host uptime – работает, а пример из документации – не работает, то есть не совсем не работает, но это очередной случай «в документации забыли прописать очевидное тем, кто ее пишет, и не очевидное тем, кто ее читает первый раз».

Возьму часть примера из статьи Simple Ansible playbook to get the Linux host uptime и продолжу с ним

Пример 2 (файл: example2) «Не работает!!!!!111111». Пробелы заменены на 1234.

Ошибка: [ERROR]: YAML parsing failed: Colons in unquoted values must be followed by a non-space character.

- name: Print the gateway for each host when defined

12hosts: all

12gather_facts: true # Ensure facts are gathered to get ansible_uptime_seconds

12tasks:

12- name: Display uptime for each host

123456debug:

12345678msg: " Examlpe test 2 "

123456when: (uptime_days | int) > 30

Пример 3 (файл: example3) так работает проверка синтаксиса, но не исполнение yml. Пробелы заменены на 1234

- name: Print the gateway for each host when defined

12hosts: all

12gather_facts: true # Ensure facts are gathered to get ansible_uptime_seconds

12tasks:

1234- name: Display uptime for each host

123456debug:

12345678msg: " Examlpe test 3 "

123456when: (uptime_days | int) > 30

Как легко заметить (не легко, но можно):
Не работающий пример:
12- name: Display uptime for each host
Пример с работающей проверкой синтаксиса:
1234- name: Display uptime for each host

Пример 3 (выше), хотя и проходит проверку, но не будет работать с ошибкой:
[ERROR]: Task failed: Error while evaluating conditional: 'uptime_days' is undefined

Еще раз читаем статью Simple Ansible playbook to get the Linux host uptime, и пытаемся сделать так же. Можно найти статью Отладка плэйбуков ansible.

Пример «НЕ Работает #21 ». Пробелы заменены на 1234
Точнее, не проходит проверку синтаксиса командой
ansible-playbook --syntax-check report21.yml, с ошибкой
YAML parsing failed: This may be an issue with missing quotes around a template block.

---

- name: Get and display system uptimes 21

12hosts: all

12gather_facts: true # Ensure facts are gathered to get ansible_uptime_seconds

12tasks:

1234- name: Display uptime for each host

123456ansible.builtin.debug:

12345678msg:

1234567890Hostname: {{ inventory_hostname }}

1234567890Uptime: {{ (ansible_uptime_seconds / 86400) | int }} days,

1234567890{{ ((ansible_uptime_seconds % 86400) / 3600) | int }} hours,

1234567890{{ (((ansible_uptime_seconds % 86400) % 3600) / 60) | int }} minutes,

1234567890{{ (((ansible_uptime_seconds % 86400) % 3600) % 60) | int }} seconds

123456when: ansible_uptime_seconds is defined

Пример «Работает #22». Пробелы заменены на 1234

Это то, что генерит google AI для примеров, и оно даже работает. Пока не надо отлаживать.

---

- name: Show uptime for each host in seconds

12hosts: all

12gather_facts: true # Ensure facts are gathered

12tasks:

1234- name: Display uptime in seconds

123456ansible.builtin.debug:

12345678msg: "Host {{ inventory_hostname }} has been up for {{ ansible_uptime_seconds }} seconds."

Пример «Работает #23».

Только картинкой, отличия от #21 очевидны – кавычки открыли, кавычки закрыли.

12345678msg:
и
12345678msg: "

4.9 Возвращаемся к основной задаче

Для следующего подхода нам потребуется два, а лучше три файла.
первый - second_inventory.ini

В комментариях мне в файл с настройками ткнули, все правильно сделали, но еще не время переходить к такой конфигурации.
Поэтому сначала:
cp /etc/ansible/hosts /home/user/second_inventory.ini.

Не забыв прочитать Ansible How to build your inventory, и вписав в конфигурацию секцию для закрытой части ssh ключа.

[ansible4]

192.168.1111.2222 ansible_user= ansible1

192.168.1111.3333 ansible_user= ansible1

192.168.1111.4444 ansible_user= ansible1

# compare with: files/second.sh

[all:vars]

ansible_python_interpreter=/usr/bin/python3

[defaults]

private_key_file = /home/ansible1/.ssh/ansible_key

Какой-то странный хардкод получается. Потому что при смене имени я должен прописать новое имя и в скрипте настройки, и в коде для Ansible. Если бы я вел документацию, то подумал бы, как сделать иначе, и прописал бы это где-то в ридми.

Не забываем, что закрытый ключ из Puttygen в Windows нужно экспортировать в другой формат. Как это сделать, знает даже AI,

To copy a private key generated by PuTTYgen for use with Ansible, which typically expects OpenSSH format keys, you need to convert it and then copy the resulting OpenSSH-formatted private key.

Steps to Convert and Copy the Private Key:

Open PuTTYgen: Launch the PuTTY Key Generator application.

Load the Private Key: Click the "Load" button and navigate to your existing private key file (usually with a .ppk extension) generated by PuTTYgen. Enter the passphrase if prompted.

Export as OpenSSH Key:

Go to the "Conversions" menu.

Select "Export OpenSSH key."

You will likely be prompted to save it without a passphrase; choose "Yes" if you want to use it without a password in Ansible (which is common for automated tasks).

Save the OpenSSH Key: Choose a location and filename for the exported OpenSSH-formatted private key (e.g., id_rsa or ansible_key). This file will not have a .ppk extension.

Copy the Key to your Ansible Control Machine: Transfer this newly exported OpenSSH private key file to your Ansible control machine. A common location for private keys on Linux-based systems is ~/.ssh/.

Set Permissions (on Ansible Control Machine): Ensure the private key file has appropriate permissions, typically read-only for the owner to prevent unauthorized access.

chmod 400 ~/.ssh/ansible_key

Не забываем настроить WinSCP,

Open WinSCP: and navigate to the main menu.

Select Options > Preferences.

In the Preferences dialog box, go to the Panels tab.

Locate the option "Show hidden files" and check the box next to it.

Click OK to apply the changes.

Работать так все равно не будет, если вы, конечно, не пошли от рута. Поэтому положим куда попало и переложим от рута локально
переложим файл pikabu_part4_export4ssh в /home/user и сделаем
mv pikabu_part4_export4ssh /home/ansible1/.ssh/ansible_key

Проверим что получилось.
ansible-playbook report23.yml --inventory /home/user/second_inventory.ini

и получим

Failed to parse inventory with 'ini' plugin: Failed to parse inventory: Expected key=value host variable assignment, got: Ansible1

Кто нашел ошибку сам – тот молодец.

кто не нашел, может сравнить

192.168.1111.2222 ansible_user= ansible1
192.168.1111.2222 ansible_user=ansible1

Отдельно надо сказать про ошибку с блоком [defaults]

[defaults]
private_key_file

потому что достаточно прочитать обсуждение ошибки private_key_file vs ansible_ssh_private_key_file #79186 , связанную с определение порядка переменных - Understanding variable precedence, но это уже другая история.

Поэтому, этот блок из конфигурации я пока удалю, и сделаю ручную проверку,

ansible-playbook report23.yml --inventory /home/user/1st_hosts.ini --user ansible1 --private-key /home/ansible1/.ssh/ansible_key

Которая не сработает, и поэтому переходить дальше, к команде

ansible-playbook report23.yml --inventory /home/user/second_inventory.ini --private-key /home/ansible1/.ssh/ansible_key

еще рано.

Потому что команда может и не сработает, с сообщением Server refused our key.
Потому что после копирования ключа, атрибуты на файл /.ssh/ansible_key никто не перепроверил.
Потому что все, что выше, было написано до появления раздела 4.4 Отлаживаем SSH, снова и опять

Потому что 192.168.1111.2222 настроен на порт 2424, а на порту 22 висит ssh до одного из контейнеров, и надо прописать не

192.168.1111.2222 ansible_user=ansible1
а
192.168.1111.2222 ansible_user=ansible1 ansible_port=2424

С чем еще пришлось столкнуться.

С недостатком памяти на VM. Я, в ходе опытов, снизил оперативную память VM с 5000 до 4750 мегабайт. Как оказалось, 4750 МАЛОВАТО.

В остальном поздравляю, вы великолепны, и можете сделать то, ради чего все затевалось, но про это будет уже в пятой части.

Литература

stackexchange Proper way to add a user account via bash script
stackexchange Why is this random password flagged saying it is too simplistic/systematic?
stackoverflow Change user password with one Bash command line
S/KEY
Ansible Connection methods and details
Ansible How to build your inventory
Ansible ansible.builtin.debug module – Print statements during execution
Статья: Отладка плэйбуков ansible

Перевод: Как убить вашу сеть с помощью Ansible. Оригинал: How to kill your network with Ansible
Перевод: Плейбуки Ansible — советы и примеры. Оригинал: Working with Ansible Playbooks — Tips & Tricks with Examples
slurm: Примеры Ansible-Playbook
пример Simple Ansible playbook to get the Linux host uptime

Тег Ansible не добавляется, ну что тут сделать.

@editors, как теги то добавлять??

Показать полностью 3
10

Неделю назад вышла Windows 11 25h2

Для лиги лени: пока ничего нового

Как многие в курсе, вышла Windows 11 25h2
Если у кого-то система не обновилась, то ничего страшного – в настоящее время у 24h2 и 25h2 одна кодовая база. Как нам пишут в статье 10 interesting facts about Windows 11 version 25H2, пока ничего нового и стоящего внимания не появилось.

Если кто-то хочет обновиться с 24h2, то можно вручную скачать x64 - Enablement Package Update:

Размер 166 KB (170,885 bytes)
MD5  CB181B744C3DD608B76A2E13D08CF773 
SHA256  92EDDA7EEAA19B60D15CCDF777556BF0662EE9FEA1DCC9AEC281FCF12068044C
SHA384: 4e65535f2a667702b6a7cad036679e3c4715aea4c2f252f4200c1d099613018db2750c80f2fdeec04af85bf9796489bd
SHA512: 91c5c513966131c12b5abc372c4311f4dcbc64606ac0011e10c38add69e721cace5c5935666fa498a08878302d1a0237fc21d4693b70c4ee2449f3f260dc25f2

SHA3-256: 59932f8f2dc2100cdd2198f914fc9568a23ff2d1a0771373ad3820585ec642a4
(этого алгоритма нет в get-filehash)


Для тех, кто сидит на старых версиях, напоминаю, что через полтора месяца заканчивается поддержка на Windows 11 Home and Pro Version 23H2

Windows 11 Home and Pro
Version Start Date  End Date
Version 24H2  Oct 1, 2024  Oct 13, 2026
Version 23H2  Oct 31, 2023  Nov 11, 2025
Version 22H2  Sep 20, 2022  Oct 8, 2024
Version 21H2  Oct 4, 2021  Oct 10, 2023

И тогда же, через полтора месяца, заканчивается поддержка на Windows 11 Enterprise and Education 22h2

Version 24H2  Oct 1, 2024  Oct 12, 2027
Version 23H2  Oct 31, 2023  Nov 10, 2026
Version 22H2  Sep 20, 2022  Oct 14, 2025
Version 21H2  Oct 4, 2021  Oct 8, 2024

Список взят на сайте Microsoft.
Статьи: Search Product and Services Lifecycle Information, Windows 11 Home and Pro, Windows 11 Enterprise and Education.

Показать полностью
9

Как сделать мультиязычный сайт на поддоменах в WordPress. Полное руководство для разработчиков

Дисклеймер.
1. В статье упрощены некоторые понятия. Я сделал это, чтобы не загружать статью лишними терминами. Вы можете дополнить и поправить меня в комментариях.
2. Я знаю про плагины. Моя задача - показать, как можно настроить всю мультиязычность руками.
3. На пикабу нет редактора кода - поэтому код в картинках. Но я дам ссылки на гитхаб, чтобы вы могли скачать готовый код.

Мультиязычный сайт, расположенный на разных поддоменах (например, en.site.com, es.site.com, fr.site.com), работает как несколько (по числу языков) независимых сайтов. Вы можете управлять им отдельно, настраивать уникальные метатеги, подключать региональные CDN, собирать точную аналитику по географическим сегментам и даже распределять нагрузку между разными серверами. Кроме того, поисковые системы воспринимают такие версии как отдельные ресурсы, что улучшает SEO: каждая языковая версия индексируется независимо и может занимать высокие позиции в локальных поисковых результатах.

Примеры поддоменов:

У этого подхода есть неоспоримые преимущества: каждая языковая версия изолирована и обновляется отдельно. Поддомены можно обслуживать на отдельных серверах или использовать разные настройки кэширования, что повышает производительность сайта. Отдельные поддомены позволяют точно собирать статистику по пользователям из разных стран и языковых сегментов. Поддомены упрощают настройку CDN и кэширования для каждой языковой версии, благодаря чему страницы загружаются быстрее. Поисковые системы воспринимают поддомены как отдельные сайты, что позволяет показывать контент на нужном языке и регионе.

Для работы поддоменов необходимо настроить DNS, хостинг и SSL. Мы разберёмся с этим шаг за шагом.

Часть 1. DNS, хостинг и SSL

Для работы мультиязычного сайта через поддомены нужно настроить внешний уровень: домен, сервер и сертификат безопасности.

Основные понятия:

  • DNS (Domain Name System) — система, которая переводит удобный для человека адрес сайта (например, mysite.com) в числовой IP-адрес сервера (например, 123.45.67.89). Это работает как телефонная книга интернета.

  • NS-сервер (Nameserver) — хранит все DNS-записи для вашего домена. На запрос «какой IP у mysite.com?» возвращает: 123.45.67.89.

  • Хостинг — это физический сервер, на котором хранятся файлы и база данных вашего сайта.

  • SSL — это сертификат, который шифрует соединение между браузером пользователя и вашим сайтом, обеспечивая безопасную передачу данных (HTTPS).

Шаг 1. Настройка DNS

Чтобы браузер понял, куда вести пользователя, когда тот вводит ru.mysite.com, мы настраиваем DNS-записи.

Как найти панель управления DNS?
DNS управляется там, где указаны NS-серверы вашего домена.

  1. Войдите в личный кабинет вашего регистратора домена (компании, где вы купили mysite.com, например, reg.ru, GoDaddy).

  2. Найдите раздел «Управление доменом» или «NS-серверы» (Nameservers).

  3. Посмотрите на указанные адреса:

    • Если указаны адреса вашего хостинга (например, ns1.myhosting.com) — мы настраиваем DNS в панели управления хостингом.

    • Если указаны адреса, похожие на wilson.ns.cloudflare.com или dalary.ns.cloudflare.com — значит, DNS управляется через сервис Cloudflare, и все изменения мы делаем в его личном кабинете.

    • Если указаны адреса самого регистратора (например, ns1.reg.ru) — мы настраиваем DNS прямо в кабинете регистратора.

    • Если вы знаете другие настройки — напишите в комментариях.

Настройка поддоменов вручную
Если вам нужно создать несколько конкретных поддоменов (например, только для русского и немецкого), вы можете добавить для каждого отдельную запись.

  • Тип A: Прямо связывает поддомен с IP-адресом вашего сервера.

  • Имя: Название поддомена без основного домена (ru, de).

  • Значение: IP-адрес вашего хостинга.

Альтернативный вариант — запись типа CNAME, которая связывает поддомен с другим доменным именем.

Неудобство ручного подхода в том, что для каждого нового языка вам придётся создавать новую запись. Для масштабируемости лучше использовать Wildcard.

Настройка Wildcard-поддоменов
Wildcard-запись покрывает все возможные поддомены, которые вы захотите создать в будущем. Это избавляет от необходимости вручную добавлять записи для каждого языка.

  • Имя: Символ звёздочки * означает «любой поддомен».

Рекомендация: Для Wildcard предпочтительнее использовать A-запись, так как она надёжнее и работает напрямую с IP-адресом. CNAME для Wildcard поддерживается не всеми провайдерами и может создавать лишние перенаправления.

После сохранения записей подождите обновления DNS (от нескольких минут до 24 часов).

Шаг 2. Настройка хостинга

Теперь нужно научить сервер правильно реагировать на запросы ко всем поддоменам. Задача — чтобы ru.mysite.com, de.mysite.com и т.д. загружали файлы из одной корневой папки (где установлен WordPress).

  1. Войдите в панель управления вашим хостингом (например, cPanel, Plesk).

  2. Найдите раздел «Поддомены» (Subdomains).

  3. Создайте новый поддомен со следующими параметрами:

    • Имя поддомена: * (символ звёздочки).

    • Домен: Ваш основной домен (например, mysite.com).

    • Корневая папка (Document Root): Критически важно указать ту же папку, где лежит ваш основной сайт (обычно public_html или www). Не позволяйте системе создать новую папку типа public_html/*.

Если в вашей панели нет опции создания Wildcard-поддомена, обратитесь в техническую поддержку хостинга с запросом: «Пожалуйста, настройте обработку wildcard-поддоменов для домена mysite.com, чтобы все они указывали на корневую папку public_html«.

Шаг 3. Настройка SSL-сертификата

Для безопасной работы (HTTPS) каждому поддомену нужен действительный SSL-сертификат. Есть два подхода:

Вариант 1: Wildcard SSL-сертификат (рекомендуется)
Сертификат покрывает все поддомены вида *.mysite.com одним файлом.

  1. В панели хостинга найдите раздел «SSL/TLS» или «Безопасность».

  2. Найдите управление сертификатами для вашего домена.

  3. Убедитесь, что активен сертификат с пометкой Wildcard (в его данных должно быть указано *.mysite.com).

  4. Если у вас обычный сертификат, перевыпустите его, обязательно выбрав опцию «Включить Wildcard» или «Защитить все поддомены».

Вариант 2: Отдельные сертификаты для каждого поддомена
Можно выпускать отдельные сертификаты для ru.mysite.com, de.mysite.com и т.д.

  1. В разделе SSL/TLS выберите «Добавить сертификат» или «Выпустить».

  2. В качестве домена укажите конкретный поддомен (например, ru.mysite.com).

  3. Повторите для каждого языкового поддомена.

Когда использовать отдельные сертификаты:

  • Если хостинг не поддерживает Wildcard SSL

  • Для поддоменов на разных серверах

  • При особых требованиях безопасности

Почти все современные хостинги предоставляют бесплатные Wildcard SSL-сертификаты (например, от Let’s Encrypt) по умолчанию или в несколько кликов.

Итог Части 1

Мы выполнили всю необходимую серверную подготовку:

  • DNS настроен для автоматического направления любых поддоменов на наш сервер.

  • Хостинг обучен обрабатывать запросы ко всем поддоменам и отдавать файлы из единой корневой папки.

  • SSL обеспечивает безопасное HTTPS-соединение для всех текущих и будущих языковых версий.

Технический фундамент заложен. В следующей части мы перейдём к настройке WordPress — активируем сеть сайтов (Multisite) и подключим мультиязычность.

Понравилось — ставь «+»
Полезно? Подпишись.
Задавай вопросы в комментариях 👇👇👇
Удачи! 🚀

UPD:

Следующая публикация: Как сделать мультиязычный сайт на поддоменах в WordPress. Часть 2. Включение и настройка режима WordPress Multisite

Показать полностью 3
9

Странное с логон скриптом (иногда не работает - в 2% случаев примерно)

Логон скрипт на powershell содержит следующyю строчку:
`Invoke-RestMethod -Method Post -Uri $uri -Body $data -ContentType 'application/json' -UseDefaultCredentials -TimeoutSec 10`

$uri это просто айпишник, $data это просто джейсон

Именно эта строчка иногда зависает по таймауту в 10 секунд и вылетает в catch блок.
Все остальные строки скрипта отрабатывают нормально. Если бы это не работало в 100% случаев то было бы гораздо проще, но это происходит в 2-3% случаев, без какого либо паттерна (по пользователям или по компьютерам). К серверу который этот запрос принимает ничего не доходит.

Есть подозрение что одна из подсистем безопасности: анти-вирус или smartscreen или AMSI, блокирует запрос опираясь на какие-то эвристики - например может посчитать передачу NTLM credentials по не зашифрованному каналу в логон скрипте кражой кредсов. Это могло бы объяснить не постоянную природу блокировок запроса.

Что было рассмотрено/сделано:
- Фаервол - был всегда отключен и фаервол бы блокировал всегда а не иногда
- Сайт был добавлен в Trusted Sites - и это не помогло
- Прокси или DNS - прокси отсутствует (WPAD отключен), DNS не участвует поскольку uri это айпи адрес
- Сервер нагружен и не может 10 секунд прийти в себя - Сервер не нагружен к нему вообще ничего не дошло даже
- Компьютеры и Сервер находятся все в одном домене, в одном L3 сегменте, пинг 1 мс
- Пробовал включить логи WinHTTP, WinInet, Powershell в режиме Analytic, Debug - по ним особо ничего не поймешь даже когда все отрабатывает
- Стоит Eset Antivirus - в антивирусе нет никаких логов что он что-то заблокировал
- Procmon и прочие утилиты глубинного анализа не расматриваю потому что я узнаю пост-фактум о проблеме, не могу это воспроизвести по желанию.

Как можно добраться до первопричины? Спасибо
П.С.
Есть еще логофф скрипт который содержит такую же строчку и он с той же периодичностью не отрабатывает.

Показать полностью

Мониторинг действий юзеров

Доброго всем времени суток
Есть сервак под Win 2022. Без доступа в интернет. На сервере поднят RDP, установлен офис и т.д.

Есть куча юзеров (около 50) которые подключаются к серваку по RDP и работают (создают, редактируют, копируют, удаляют) там с файлами офиса.

Нужно:
а) какую-нибудь программу, для записи действий каждого пользователя. Родной журнал событий показывает только параметры сессий. То есть время подключения\отключения и т.д. Но не показывает какие действия и с какими НЕсистемными файлами производил пользователь. А нужно, именно знать с какими конкретно документами, что, сколько раз, когда (по дате и времени) делал каждый пользователь.
б) поскольку число файлов плавно перевалило за тысячу, понадобилось что-то вроде СУБД для хранения, разграничения доступа и номинального редактирования офисных документов.
Доступа к интернету - нет, поэтому никакие онлайн или облачные решения, тут не годятся.

Прошу совета опытных и знающих.
Заранее всем благодарен за подсказки и помощь.

Показать полностью
9

Ansible для детского сада. Часть 3. Настраиваем подобие безопасности и все остальное

Почему я вообще пишу эту статью? Почему нет готового решения «делайте хорошо, плохо не делайте»?
Как жесток и несправедлив этот мир!
У меня постоянное ощущение того, что я описываю не велосипед с костылями, а велосипед, который давно изобретен, на котором все катались лет 15 назад, если не 20. Что-то типа «введение в линукс и все вокруг для 10 класса». Что на информатике учат.
Серия «Кудахтеры: Ansible»

Ansible для детского сада в скольки то частях. Часть 1.Про все сразу
Ansible для детского сада в скольки то частях. Часть 2. Костылируем жалкое подобие WSUS - Linux Server Update Services (LSUS)
Ansible для детского сада. Часть 3. Настраиваем подобие безопасности и все остальное
Подготовка Git
Ansible для детского сада. Часть 4. Первичная настройка конечного клиента
Ansible для детского сада в скольки то частях. Часть 5. Приделываем костыли

Еще раз объясняю принципы СПО.
Видишь голую жопу - сшей трусы и отдай владельцу жопы.
Не умеешь шить - сообщи владельцу жопы, где трусы можно купить.
Не знаешь где купить - просто скажи владельцу жопы "А у вас жопа голая!".
Не хочешь делать ничего из предложенного - заткнись, не твое дело.

Интересно разделился ИТ мир

В одном отделе (у соседей) n8n подняли и тыкают в него палкой. В другом, у бывших коллег на новом месте работы, оказывается, нет инструмента для сбора статистики обновлений. И вообще ничего нет, кроме папки с сотнями Excel файлов. И те не актуальны.

Ничего против Excel не имею. Инструмент удобный, и внутри можно сделать много чего на VBA – но нужно ли? Но, текст не про философию.

Для того, чтобы Ansible отработал задачу на хосте, необходимо:

Чтобы на целевом (target) хосте существовал нужный пользователь, с нужными правами на исполнение
Чтобы целевой пользователь имел права на вход по ssh
Чтобы (если требуется) на целевом хосте были прописаны, или стали прописаны, нужные репозитории
Чтобы Ansible доверял ssh сертификату целевого хоста. Потому что до первого входа, по умолчанию, и так далее, ничего подобного не будет, никакого доверия.

Дальше мы переходим к вопросу регулярной смены или пароля, или сертификата, или и пароля и сертификата для служебного пользователя.

Становится очевидно, что, чем больше пользователей имеет доступ к Ansible серверу, тем желательнее (скорее, обязательно) заводить отдельный сервер для инфраструктурных задач, в отдельной подсети, с серьезными ограничениями по доступу к серверу, и отдельный сервер для dev\test окружений, с своими правилами и задачами. В идеальной среде, где все профессионалы и друг друга уважают, и думают, что делают.. В идеальном мире можно сразу дать всем пароль от рута. В реальном мире необходим баланс между ограничениями всеми и всего.

Придется начинать с установки и настройки fail2ban и настройкой полуторафакторной авторизации (сертификат с паролем) для серверов с git и ansible. При этом к git нужен будет доступ «от всех серверов локальной сети», а к ansible, без pull модели, не со всех.

Видимо, придется потом сесть и писать длинную статью «я так вижу про безопасность в Linux».

Будет еще одна недописанная статья, кроме «Инвентаризация инфраструктуры и сети. Пометки для начинающих». Что-то такое один дьяк писал в 1415, со словами «житие мое..» , будет «10 лет спустя».

Пока думаю, и пока коллеги думают, сделаю в стиле «для домашней лаборатории сойдет» -

В гите есть public repo, в котором лежит:
1 ssh файл для прописывания первичных настроек и юзера для Ansible.
2 открытая часть сертификата юзера для Ansible, при этом сертификат генерируется с паролем
3 Остальные преднастройки для работы Kerberos + AD

Подготовка Git

Что в наличии: Бесплатный Gitlab в контейнере, Version v18.2.1 (gitlab/gitlab-ce; latest).

Создам там юзера из GUI - (панель админки внизу слева, рядом с help)
Admin > Users > New user > Name: Preset; mail: firstname.lastname@example.com
Admin > Users > Preset > Password: Pa$$word1234
Создам токен; Name: Token01
Через : Admin – Users - Preset Impersonation Tokens for preset с правами:
read_repository: Grants read-only access to repositories on private projects using Git-over-HTTP or the Repository Files API.

Получу токен. Токен выглядит вот так:
glpat-MFuiWVjB1BTngs-6wyHj

Там же, в управлении токенами, сразу сделаю ему rotate.

Создам группу: Linuxpregoup2.
тип: Private (The group and its projects can only be viewed by members.)
Почему так: просто так, потому что все равно токен сделал.

Создам в Gitlab проект:
имя и все прочее: linuxpreset01
Тип: Private (Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group.
Можно делать и Internal, и Public (The project can be accessed without any authentication.), но зачем ?

Создам в проекте файл first.sh
С текстом

#!/bin/bash
date

И сделаю copy permalink. Получу, поскольку у меня не настроен DNS и мне не хочется прописывать что-то в /etc/host -
http://192.168.1111.2222/linuxpregoup2/linuxpreset01/-/blob/какойтодлинныйтокен/first.sh

Добавление пользователя preset к проекту linuxpreset01

Gitlab содержит 7 ролей из коробки: Guest (This role applies to private and internal projects only.) ; Planner; Reporter ; Developer;  Maintainer;  Owner; Minimal Access (available for the top-level group only)

Дам права Guest и попробую зайти.
При входе получу предупреждение:
Update password for Preset . Чтож, сменю пароль и зайду уже с новым паролем, и увижу проект, и в проекте увижу ничего.
По прямой ссылке тоже увижу то самое ничего. И с правами reporter то же самое, то есть ничего. Только роль Reporter (и выше) имеет права на чтение файлов. Ничуть не удивлюсь, если при аудите окажется, что всем подряд выданы роли Maintainer.
Понять это из документации, наверно, можно. Но я не смог.
Хорошие новости: отредактировать файл все равно нельзя.
Новости так себе: можно сделать fork и получить две ветки. Можно почитать Default branch file and directory locks, и все равно задуматься.
Что еще интереснее, я, как user Preset вижу ветку patch-1, а как админ – не вижу. И это несколько странно, как и то ,что создался новый проект - Preset/linuxpreset01
Но, на данном этапе не важно.

Токен к проекту (Project access tokens) я не создавал, а, наверное, зря. Судя по теме How to curl single file using deploy token, я не один такой тупенький.
Создам . User – Preferences – access tokens - Personal access tokens
Add a project access token
Name: Token02Personal; read_repository
Замечу, что эти злые люди переделали (опять) интерфейс, и теперо Project ID живет не там, где раньше

Что я забыл?

практика показала, что, раз я сделал только read_repository, но не сделал в токене:
read_user (Grants read-only access to your profile through the /user API endpoint, which includes username, public email, and full name. Also grants access to read-only API endpoints under /users. )
read_api (Grants read access to the API, including all groups and projects, the container registry, and the package registry.)

То получу {"message":"401 Unauthorized"}

Это еще ничего. Потому что если адрес совсем неправильный, то я получу
<html><body>You are being <a href="http://192.168.1111.2222/users/sign_in">redirected</a

Управление токенами в бесплатной версии поначалу вызывает того самого кота

Потому что выглядит вот так.

Токен можно посмотреть один раз при перевыпуске, и все, давайте досвиданья.
Посмотреть значение уже выпущенного токена нельзя.
Можно перевыпустить или отозвать
Можно посмотреть сразу после выпуска. Все.

Токен

Токен

Теперь понятно, почему на управление токенами тоже могут забивать. Потому что это надо 5 минут потратить, разобраться.

Если почти все правильно, кроме токена, то будет ошибка:
{"error":"invalid_token","error_description":"Token was revoked. You have to re-authorize from the user."}

Если токен корректен, но что-то не то с путем, то получим:
{"message":"404 Commit Not Found"}

Итого

Неправильно: использовать токен с недостаточными правами, или выписанный «не там». Роль «вон того токена» надо изучить отдельно.

Неправильно: использовать путь из WEB, например
curl --header "PRIVATE-TOKEN: glft-h5DSfGmqiVESDZ7kQJMz" http://192.168.1111.2222/linuxpregoup2/linuxpreset01/-/raw/main/first.sh

Неправильно: прописывать master, хотя у тебя ветка main, например:
curl --header "PRIVATE-TOKEN: glpat-norDQhvwoTxyAtM9ANhV" http://192.168.1111.2222/api/v4/projects/2/repository/files/first.sh/raw?ref=master -o ot05.txt

Работает:
прописывать токен с нужными правами, прописывать путь через API и project ID, использовать нужную ветку (main):
curl --header "PRIVATE-TOKEN: glpat-norDQhvwoTxyAtM9ANhV" http://192.168.1111.2222/api/v4/projects/2/repository/files/first.sh/raw?ref=main -o ot08.txt

И, конечно, неправильно публиковать любые токены в статьях. Вдруг они еще рабочие.
но я не очень беспокоюсь за мою домашнюю виртуальную машину, и перевыпустил токен еще до того, как дописал это предложение.

Дальше проще. Изян: stackoverflow

curl --header "PRIVATE-TOKEN: glpat-norDQhvwoTxyAtM9ANhV" http://192.168.1111.2222/api/v4/projects/2/repository/files/first.sh/raw?ref=main -o

http://192.168.1111.2222/linuxpregoup2/linuxpreset01/-/blob/(какой-то UUID)/ansible

и остается только положить нужные файлы (открытую часть сертификата) в gitlab, и переписать стартовый скрипт.

Итоговый скрипт у меня на домашнем стенде у меня будет выглядеть так, что оказалось что проще написать отдельную статью:

Ansible для детского сада. Часть 4. Первичная настройка конечного клиента

Заключение

У меня постоянное ощущение того, что я описываю не велосипед с костылями, а велосипед, который давно изобретен, на котором все катались лет 15 назад, если не 20. Что-то типа «введение в линукс и все вокруг для 10 класса». Что на информатике учат.
Потому что тут коллеги n8n крутят, а я описываю, как с гита файл скачать с токеном.

Костыли и велосипеды

Костыли и велосипеды

Литература

Основы Ansible для сетевых инженеров
Etckeeper - ставим под контроль изменения конфигурации сервера
Ansible Community Documentation Managing vault passwords
Ansible Community Documentation 2.8 Using Vault in playbooks > The documentation regarding Ansible Vault has moved. Encrypting content with Ansible Vault

RBAC Ansible Tower
RBAC Ansible AWX
RBAC Red Hat Ansible Automation Platform

gitlab signup users without email confirmation

Gitlab docs Roles and permissions
Перевод из 2017 года от ruvds Bash-скрипты: начало. Оригинал: Shell scripting step by step tutorial
Gitlab forum How to curl single file using deploy token
Gitlab forum Curling raw file fails
Medium How to curl single file using access token in gitlab
digitalocean How to Download Files with cURL
Reddit Creating System Users for Ansible Execution

@editors, мне бы тег Ansible, выдайте пожалуйста

Показать полностью 5
44

Закручивание гаек

На крупном предприятии произошло закручивание гаек со стороны безопасности. Усложнение и урезание закупок оборудования, ограничение перемещения по предприятию, ограничение на внос/вынос инструмента/оборудования. И еще много всего влияющего на работу.

IT отдел сильно пострадал из-за этого. 90% заявок теперь не выполняется в срок по куче причин, которые никак не зависят от обслуживающего персонала.

Вопрос: Почем обслуживающий персонал начали наказывать (лишинием премии) за невыполнение задач в срок и абсолютно никого не волнуют причины? Многочисленных начальников почему то не трогают.

Отличная работа, все прочитано!