feat: улучшения роли devops и тестирования

- Убрана подстановка значений по умолчанию для devops_password и devops_ssh_public_key
- Добавлена строгая валидация секретов из vault/secrets.yml с детальными сообщениями об ошибках
- Убран подробный вывод установки пакетов в тасках
- Исправлена проблема с созданием симлинков в vault/ при тестировании
- Обновлена логика загрузки vault переменных в molecule тестах
- Добавлена очистка симлинков в destroy.yml для дополнительной безопасности

Автор: Сергей Антропов
Сайт: https://devops.org.ru
This commit is contained in:
Сергей Антропов
2025-10-29 18:53:52 +03:00
parent f6d1182193
commit cb5045fb79
23 changed files with 821 additions and 679 deletions

View File

@@ -13,9 +13,11 @@
vault_targets:
- /workspace/vault/secrets.yml
- /workspace/vault/secret.yml
- /workspace/files/playbooks/group_vars/*/vault.yml
- /workspace/files/playbooks/host_vars/*/vault.yml
- /workspace/roles/**/vars/vault.yml
# - /workspace/files/playbooks/group_vars/*/vault.yml
# - /workspace/files/playbooks/host_vars/*/vault.yml
# - /workspace/roles/**/vars/vault.yml
# - /workspace/roles/*/defaults/*.yml
# - /workspace/files/**/*secret*.yml
tasks:
# =============================================================================
@@ -35,10 +37,6 @@
when: preset_file is file
ignore_errors: true
# - name: Install collections
# community.docker.docker_container_exec:
# container: ansible-controller
# command: bash -lc "ansible-galaxy collection install -r /workspace/requirements.yml --force --no-deps --upgrade >/dev/null 2>&1 || true"
# =============================================================================
# VAULT - Работа с зашифрованными файлами
@@ -52,99 +50,250 @@
Files: {{ vault_targets | length }} targets
================================================================================
- name: Check if vault file is encrypted
community.docker.docker_container_exec:
container: ansible-controller
command: "bash -c 'if [ -f \"/workspace/vault/secrets.yml\" ]; then grep -q \"ANSIBLE_VAULT\" /workspace/vault/secrets.yml && echo \"ENCRYPTED\" || echo \"PLAINTEXT\"; else echo \"NOT_FOUND\"; fi'"
register: vault_status
ignore_errors: true
- name: Encrypt vault file if plaintext
community.docker.docker_container_exec:
container: ansible-controller
command: "bash -c 'VAULT_PASSWORD_FILE=\"/workspace/vault/.vault\"; if [ -f \"$VAULT_PASSWORD_FILE\" ] && [ -f \"/workspace/vault/secrets.yml\" ] && [ \"{{ vault_status.stdout }}\" = \"PLAINTEXT\" ]; then ansible-vault encrypt --encrypt-vault-id default --vault-password-file \"$VAULT_PASSWORD_FILE\" /workspace/vault/secrets.yml; fi'"
when: vault_status.stdout == "PLAINTEXT"
ignore_errors: true
- name: Preflight vault — normalize state (encrypt if plaintext, then decrypt)
community.docker.docker_container_exec:
container: ansible-controller
command: "bash -c 'VAULT_PASSWORD_FILE=\"/workspace/vault/.vault\"; if [ -f \"$VAULT_PASSWORD_FILE\" ] && [ -f \"/workspace/vault/secrets.yml\" ]; then ansible-vault decrypt --vault-password-file \"$VAULT_PASSWORD_FILE\" /workspace/vault/secrets.yml; fi'"
ignore_errors: true
# =============================================================================
# PLAYBOOK - Запуск основного playbook
# =============================================================================
- name: Playbook execution
debug:
msg: |
================================================================================
PLAYBOOK - Запуск основного playbook
================================================================================
File: /workspace/molecule/default/site.yml
================================================================================
- name: Debug - Check files in container
- name: Check vault files encryption status
community.docker.docker_container_exec:
container: ansible-controller
command: |
bash -c '
echo "=== DEBUG INFO ==="
echo "Current directory: $(pwd)"
echo "ANSIBLE_ROLES_PATH: $ANSIBLE_ROLES_PATH"
echo "VAULT_PASSWORD_FILE: $VAULT_PASSWORD_FILE"
echo "VAULT_SECRETS_FILE: $VAULT_SECRETS_FILE"
echo "INVENTORY_FILE: $INVENTORY_FILE"
echo ""
echo "=== FILE CHECKS ==="
echo "Inventory exists: $([ -f "/tmp/molecule_workspace/inventory/hosts.ini" ] && echo "YES" || echo "NO")"
echo "Vault password exists: $([ -f "/workspace/vault/.vault" ] && echo "YES" || echo "NO")"
echo "Vault secrets exists: $([ -f "/workspace/vault/secrets.yml" ] && echo "YES" || echo "NO")"
echo "Site.yml exists: $([ -f "/workspace/molecule/default/site.yml" ] && echo "YES" || echo "NO")"
echo ""
echo "=== DIRECTORY LISTING ==="
ls -la /tmp/molecule_workspace/ || echo "No molecule_workspace dir"
ls -la /workspace/vault/ || echo "No vault dir"
echo ""
echo "=== INVENTORY CONTENT ==="
cat /tmp/molecule_workspace/inventory/hosts.ini || echo "Cannot read inventory"
VAULT_TARGETS_JSON="{{ vault_targets | to_json }}"
VAULT_PASSWORD_FILE="/workspace/vault/.vault"
echo "=== CHECKING VAULT FILES ENCRYPTION STATUS ==="
# Парсим JSON массив и проверяем каждый файл
echo "$VAULT_TARGETS_JSON" | jq -r ".[]" | while read -r target; do
echo "Checking target: $target"
# Если это glob паттерн, находим файлы
if [[ "$target" == *"*"* ]]; then
for file in $target; do
if [ -f "$file" ]; then
echo "Found file: $file"
if grep -q "ANSIBLE_VAULT" "$file"; then
echo "ENCRYPTED: $file"
else
echo "PLAINTEXT: $file"
fi
fi
done
else
# Обычный файл
if [ -f "$target" ]; then
echo "Found file: $target"
if grep -q "ANSIBLE_VAULT" "$target"; then
echo "ENCRYPTED: $target"
else
echo "PLAINTEXT: $target"
fi
else
echo "NOT_FOUND: $target"
fi
fi
done
'
register: vault_status_check
ignore_errors: true
# - name: Run lab playbook
# community.docker.docker_container_exec:
# container: ansible-controller
# command: |
# bash -c '
# set -e
# export ANSIBLE_ROLES_PATH=/workspace/roles
# export VAULT_PASSWORD_FILE="/workspace/vault/.vault"
# export VAULT_SECRETS_FILE="/workspace/vault/secrets.yml"
# export INVENTORY_FILE="/tmp/molecule_workspace/inventory/hosts.ini"
# echo "Starting playbook execution..."
# if [ -f "$VAULT_PASSWORD_FILE" ] && [ -f "$VAULT_SECRETS_FILE" ]; then
# echo "Running with vault..."
# ansible-playbook -i "$INVENTORY_FILE" /workspace/molecule/default/site.yml --vault-password-file "$VAULT_PASSWORD_FILE" -e "vault_file_path=$VAULT_SECRETS_FILE" -v
# else
# echo "Running without vault..."
# ansible-playbook -i "$INVENTORY_FILE" /workspace/molecule/default/site.yml -v
# fi
# echo "Playbook completed successfully"
# '
- name: Encrypt plaintext vault files
community.docker.docker_container_exec:
container: ansible-controller
command: |
bash -c '
VAULT_TARGETS_JSON="{{ vault_targets | to_json }}"
VAULT_PASSWORD_FILE="/workspace/vault/.vault"
echo "=== ENCRYPTING PLAINTEXT VAULT FILES ==="
if [ ! -f "$VAULT_PASSWORD_FILE" ]; then
echo "Vault password file not found: $VAULT_PASSWORD_FILE"
exit 0
fi
# Парсим JSON массив и шифруем каждый plaintext файл
echo "$VAULT_TARGETS_JSON" | jq -r ".[]" | while read -r target; do
echo "Processing target: $target"
# Если это glob паттерн, находим файлы
if [[ "$target" == *"*"* ]]; then
for file in $target; do
if [ -f "$file" ] && ! grep -q "ANSIBLE_VAULT" "$file"; then
echo "Encrypting plaintext file: $file"
ansible-vault encrypt --encrypt-vault-id default --vault-password-file "$VAULT_PASSWORD_FILE" "$file"
fi
done
else
# Обычный файл
if [ -f "$target" ] && ! grep -q "ANSIBLE_VAULT" "$target"; then
echo "Encrypting plaintext file: $target"
ansible-vault encrypt --encrypt-vault-id default --vault-password-file "$VAULT_PASSWORD_FILE" "$target"
fi
fi
done
'
ignore_errors: true
- name: Decrypt vault files for processing
community.docker.docker_container_exec:
container: ansible-controller
command: |
bash -c '
VAULT_TARGETS_JSON="{{ vault_targets | to_json }}"
VAULT_PASSWORD_FILE="/workspace/vault/.vault"
echo "=== DECRYPTING VAULT FILES FOR PROCESSING ==="
if [ ! -f "$VAULT_PASSWORD_FILE" ]; then
echo "Vault password file not found: $VAULT_PASSWORD_FILE"
exit 0
fi
# Парсим JSON массив и расшифровываем каждый зашифрованный файл
echo "$VAULT_TARGETS_JSON" | jq -r ".[]" | while read -r target; do
echo "Processing target: $target"
# Если это glob паттерн, находим файлы
if [[ "$target" == *"*"* ]]; then
for file in $target; do
if [ -f "$file" ] && grep -q "ANSIBLE_VAULT" "$file"; then
echo "Decrypting encrypted file: $file"
ansible-vault decrypt --vault-password-file "$VAULT_PASSWORD_FILE" "$file"
fi
done
else
# Обычный файл
if [ -f "$target" ] && grep -q "ANSIBLE_VAULT" "$target"; then
echo "Decrypting encrypted file: $target"
ansible-vault decrypt --vault-password-file "$VAULT_PASSWORD_FILE" "$target"
fi
fi
done
'
ignore_errors: true
# =============================================================================
# CLEANUP - Перешифровка файлов после выполнения
# VAULT LOADING - Загрузка vault переменных из vault_targets
# =============================================================================
- name: Cleanup operations
- name: Load vault variables from vault_targets
community.docker.docker_container_exec:
container: ansible-controller
command: |
bash -c '
VAULT_PASSWORD_FILE="/workspace/vault/.vault"
# Читаем vault_targets из переменных Ansible
VAULT_TARGETS_JSON="{{ vault_targets | to_json }}"
echo "=== VAULT LOADING ==="
echo "Vault password file: $VAULT_PASSWORD_FILE"
echo "Vault targets from Ansible: $VAULT_TARGETS_JSON"
# Создаем директории для vault файлов
mkdir -p /tmp/vault_files
# Создаем временный файл для объединения всех vault переменных
echo "---" > /tmp/vault_vars.yml
# Счетчик для обработки конфликтов
declare -A variable_sources
# Парсим JSON массив и обрабатываем каждый target
echo "$VAULT_TARGETS_JSON" | jq -r ".[]" | while read -r target; do
echo "Processing target: $target"
# Если это glob паттерн, находим файлы
if [[ "$target" == *"*"* ]]; then
for file in $target; do
if [ -f "$file" ]; then
echo "Found vault file: $file"
# Создаем копию файла в /tmp/vault_files для прямых ссылок
filename=$(basename "$file")
cp "$file" "/tmp/vault_files/$filename"
# Расшифровываем файл если нужно
if [ -f "$VAULT_PASSWORD_FILE" ]; then
echo "Loading encrypted vault file: $file"
ansible-vault view --vault-password-file "$VAULT_PASSWORD_FILE" "$file" > "/tmp/vault_files/${filename}.decrypted"
# Добавляем в объединенный файл с проверкой конфликтов
echo "---" >> /tmp/vault_vars.yml
echo "# From: $file" >> /tmp/vault_vars.yml
ansible-vault view --vault-password-file "$VAULT_PASSWORD_FILE" "$file" >> /tmp/vault_vars.yml
else
echo "Loading plain vault file: $file"
cp "$file" "/tmp/vault_files/${filename}.decrypted"
# Добавляем в объединенный файл с проверкой конфликтов
echo "---" >> /tmp/vault_vars.yml
echo "# From: $file" >> /tmp/vault_vars.yml
cat "$file" >> /tmp/vault_vars.yml
fi
fi
done
else
# Обычный файл
if [ -f "$target" ]; then
echo "Found vault file: $target"
# Создаем копию файла в /tmp/vault_files для прямых ссылок
filename=$(basename "$target")
cp "$target" "/tmp/vault_files/$filename"
# Расшифровываем файл если нужно
if [ -f "$VAULT_PASSWORD_FILE" ]; then
echo "Loading encrypted vault file: $target"
ansible-vault view --vault-password-file "$VAULT_PASSWORD_FILE" "$target" > "/tmp/vault_files/${filename}.decrypted"
# Добавляем в объединенный файл с проверкой конфликтов
echo "---" >> /tmp/vault_vars.yml
echo "# From: $target" >> /tmp/vault_vars.yml
ansible-vault view --vault-password-file "$VAULT_PASSWORD_FILE" "$target" >> /tmp/vault_vars.yml
else
echo "Loading plain vault file: $target"
cp "$target" "/tmp/vault_files/${filename}.decrypted"
# Добавляем в объединенный файл с проверкой конфликтов
echo "---" >> /tmp/vault_vars.yml
echo "# From: $target" >> /tmp/vault_vars.yml
cat "$target" >> /tmp/vault_vars.yml
fi
fi
fi
done
# Символические ссылки не нужны для работы, убираем их создание
echo "=== VAULT VARIABLES LOADED ==="
echo "Combined vault variables:"
cat /tmp/vault_vars.yml
echo ""
echo "Individual vault files available at:"
ls -la /tmp/vault_files/
'
ignore_errors: true
# =============================================================================
# LOAD VAULT VARIABLES - Загрузка vault переменных в Ansible
# =============================================================================
- name: Load vault variables into Ansible
include_vars:
file: /tmp/vault_vars.yml
ignore_errors: true
- name: Set vault files path
set_fact:
vault_files_path: /tmp/vault_files
when: vault_files_path is not defined
# =============================================================================
# CONVERGE ЗАВЕРШЕН - Playbook'и выполняются через Makefile
# =============================================================================
- name: Converge completed
debug:
msg: |
================================================================================
CLEANUP - Перешифровка файлов после выполнения
CONVERGE ЗАВЕРШЕН
================================================================================
Re-encrypting vault files
================================================================================
- name: Post-run — re-encrypt secrets
community.docker.docker_container_exec:
container: ansible-controller
command: "bash -c 'VAULT_PASSWORD_FILE=\"/workspace/vault/.vault\"; if [ -f \"$VAULT_PASSWORD_FILE\" ] && [ -f \"/workspace/vault/secrets.yml\" ]; then ansible-vault encrypt --encrypt-vault-id default --vault-password-file \"$VAULT_PASSWORD_FILE\" /workspace/vault/secrets.yml; fi'"
ignore_errors: true
Vault переменные загружены и готовы к использованию
Playbook'и run.yml и roles/deploy.yml будут выполнены через Makefile
================================================================================