Совместное использование конфиденциальных переменных между ansible и terraform
Простое доказательство концепции, как разделить некоторые конфиденциальные переменные между terraform и ansible таким образом, чтобы это позволяло делать коммиты в git, а также достаточно легко расшифровывалось и использовалось изначально через ansible play.
Ансибль
Давайте создадим несколько чувствительных переменных в ansible play, env-default-secure-vars.yml
:
---
shared_secure_var1: securevalue1
shared_secure_var2: securevalue2
и зашифровать этот файл с помощью ansible-vault encrypt env-default-secure-vars.yml
Давайте проверим, может ли ansible работать с зашифрованными переменными, используя playbook
---
- name: TerraformAnsiblePOC
hosts: localhost
gather_facts: no
pre_tasks:
- include_vars: "env-default-secure-vars.yml"
- include_vars: "env-default-vars.yml"
tasks:
- debug: var="shared_secure_var1"
- debug: var="shared_secure_var2"
PLAY [TerraformAnsiblePOC] *****************
TASK [debug] *******************************
ok: [localhost] => {
"shared_secure_var1": "securevalue1"
}
TASK [debug] *******************************
ok: [localhost] => {
"shared_secure_var2": "securevalue2"
}
PLAY RECAP ******************************************************************
localhost : ok=4 changed=0 unreachable=0 failed=0
Терраформ
Теперь давайте посмотрим, как мы можем использовать те же данные при терраформировании?
К счастью, у нас есть встроенный внешний провайдер, который позволяет использовать json-канал.
возвращается внешней программой
data "external" "ansible" {
program = [ "tf_ansible_vault.sh", "env-default-secure-vars.yml"]
}
output "shared_secure_var1" {
value = "${data.external.ansible.result.shared_secure_var1}"
}
output "shared_secure_var2" {
value = "${data.external.ansible.result.shared_secure_var2}"
}
Давайте напишем процедуру оболочки, которая будет возвращать json-представление зашифрованных переменных.
#!/bin/bash
set -ef -o pipefail
export LC_ALL="C"
readonly TMP_DIR="/tmp"
readonly TMP_OUTPUT="${TMP_DIR}/$$.out"
readonly BASE_DIR="$(dirname "$(realpath "$0")")"
readonly MY_NAME="${0##*/}"
# Cleanup on exit
trap 'rm -rf ${TMP_OUTPUT}' \
EXIT SIGHUP SIGINT SIGQUIT SIGPIPE SIGTERM
if [[ -z "$ANSIBLE_VAULT_IDENTITY_LIST" ]]
then
echo "Please export path to vault id via ANSIBLE_VAULT_IDENTITY_LIST"
exit 1
fi
if [[ -z "$1" ]]
then
echo "Please provide path to secrets file"
exit 1
fi
#echo cp $1 $TMP_OUTPUT
cp $1 $TMP_OUTPUT
ansible-vault decrypt $TMP_OUTPUT > /dev/null
python -c 'import sys, yaml, json; json.dump(yaml.load(sys.stdin), sys.stdout, indent=4)' < $TMP_OUTPUT
rm $TMP_OUTPUT
Проверяем, работает ли скрипт…
./tf_ansible_vault.sh env-default-secure-vars.yml
{
"shared_secure_var2": "securevalue2",
"shared_secure_var1": "securevalue1"
}
а теперь давайте проверим с помощью terraform play:
terraform apply
data.external.ansible: Refreshing state...
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Outputs:
shared_secure_var1 = securevalue1
shared_secure_var2 = securevalue2
Кажется, это работает. Выглядит очень многообещающе, но давайте заглянем в terraform.tfstate.
{
"version": 3,
"terraform_version": "0.11.11",
"serial": 1,
"lineage": "7f589f33-7ef8-7d45-19ab-d053412dd875",
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {
"data.external.ansible": {
"type": "external",
"depends_on": [],
"primary": {
"id": "-",
"attributes": {
"id": "-",
"program.#": "2",
"program.0": "tf_ansible_vault.sh",
"program.1": "env-default-secure-vars.yml",
"result.%": "2",
"result.shared_secure_var1": "securevalue1",
"result.shared_secure_var2": "securevalue2"
},
"meta": {},
"tainted": false
},
"deposed": [],
"provider": "provider.external"
}
},
"depends_on": []
}
]
}
Мы видим там наши расшифрованные безопасные переменные, так что будьте осторожны, как вы их храните. Терраформ имеет
количество обращений по схожим вопросам (за
несколько лет, но до сих пор нет хорошего решения.
Резюме
POC показывает, как вы можете поделиться некоторыми своими переменными подготовки с terraform и обратно (terraform
может генерировать файл переменных yml). Может быть подходящим для некоторых ситуаций, хотя и не идеальным.
Посмотрите пример на