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:
@@ -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
|
||||
================================================================================
|
||||
Reference in New Issue
Block a user