13

我试图弄清楚如何为 Python 脚本提供以下设施,以便它可以:

  1. 导入 Ansible Python 模块
  2. 打开我定义ansible.cfg和读取的vault_password_file变量
  3. 读取vault_password_file并临时存储在 Python 变量中
  4. 解密引用的 Ansible 保管文件

通过谷歌找到了这段代码,但是当我尝试它时它似乎不起作用:

import ansible.utils

bar = dict()

bar = ansible.utils._load_vars_from_path("secrets.yml", results=bar, vault_password="password")

print bar

引发此错误:

$ python ansible-vault-ex.py
Traceback (most recent call last):
  File "ansible-vault-ex.py", line 5, in <module>
    bar = ansible.utils._load_vars_from_path("credentials.vault", results=bar, vault_password="password")
AttributeError: 'module' object has no attribute '_load_vars_from_path'

当我对此进行调查时,我在任何 Ansible 相关文件中都没有看到此功能的迹象,这使我相信此方法不再适用于某些较新版本的 Ansible。

底线是我想要一些从 Python 脚本导入 Ansible 库/模块的方法,这样我就可以ansible-vault从 Python 以编程方式与托管文件进行交互。

4

7 回答 7

13

考虑使用ansible-vault 包

通过以下方式安装它:

$ pip install ansible-vault

然后它很简单:

from ansible_vault import Vault

vault = Vault('password')
print vault.load(open('/path/to/your/vault.yml').read())

要使用 ansible 代码,请直接查看该包的源代码。最简单的是:

Ansible <= 2.3

from ansible.parsing.vault import VaultLib

vault = VaultLib('password')
print(vault.decrypt(open('/path/to/vault.yml').read()))

Ansible >= 2.4

from ansible.constants import DEFAULT_VAULT_ID_MATCH
from ansible.parsing.vault import VaultLib, VaultSecret

vault = VaultLib([(DEFAULT_VAULT_ID_MATCH, VaultSecret('password'.encode()))])
print(vault.decrypt(open('/path/to/vault.yml').read()))

源代码的数量是相等的,但包提供自动 yaml 解析 + 处理两个 Ansible 版本。

于 2017-06-16T16:28:16.483 回答
4

如果您在 ansible.cfg 中配置了 Vault_password_file,您可以将密码传递给 VaultLib,如下所示

进口 :

from ansible import constants as C
from ansible.parsing.vault import VaultLib
from ansible.cli import CLI
from ansible.parsing.dataloader import DataLoader

然后,您可以致电:

loader = DataLoader()
vault_secret = CLI.setup_vault_secrets(
    loader=loader,
    vault_ids=C.DEFAULT_VAULT_IDENTITY_LIST
)
vault = VaultLib(vault_secret)
vault.decrypt(open('/path/to/vault.yml').read())
于 2019-01-09T16:12:33.290 回答
3

扩展 Kuba 的答案,ansible-vault 是 VaultLib 的包装器。它很好地处理了 Vaultlib 的 Ansible 2.4 前版本以及 2.4 后版本。

ansible-vault load() 方法不仅会解密文件,还会解析文件并将内容作为 dict 返回。如果你想要不解析的内容,最简单的方法可能是扩展 ansible-vault 类似的东西:

from ansible_vault import Vault

class MyVault(Vault):
    def load_raw(self, stream):
        return self.vault.decrypt(stream)

    def dump_raw(self, text, stream=None):
        encrypted = self.vault.encrypt(text)
        if stream:
            stream.write(encrypted)
        else:
            return encrypted
于 2018-06-14T14:13:48.960 回答
3

如果您的整个 yaml 文件已加密,则 broferek 的答案有效。如果您的 yaml 文件未加密但包含加密变量,它会抱怨。这应该以任何一种方式工作:

进口:

from ansible import constants as C
from ansible.cli import CLI
from ansible.parsing.vault import VaultLib
from ansible.parsing.dataloader import DataLoader

然后使用 DataLoader 类将文件读入字典

cfgfile = "/path/to/yaml/file.yml"
loader = DataLoader()
vault_secrets = CLI.setup_vault_secrets(loader=loader,
            vault_ids=C.DEFAULT_VAULT_IDENTITY_LIST)
loader.set_vault_secrets(vault_secrets)
data = loader.load_from_file(cfgfile)
pprint.pprint(data)
于 2019-09-24T01:00:52.423 回答
1

我无法使用上述答案进行解密,但我确实有一个使用子进程并且运行良好的函数:

def vault_decrypt(text, vault_password_file):
    """
    Calls ansible vault and pass the payload via stdin
    :param text: str, text to decode
    :param vault_password_file: str, vault password
    :return: str, decoded text
    """
    cmd = ['ansible-vault', 'decrypt', '--vault-password-file={}'.format(vault_password_file)]
    p = Popen(cmd,
              stdout=PIPE, stdin=PIPE, stderr=PIPE)
    output = p.communicate(input=str.encode(text))
    return output[0].decode("utf-8")

如果我确实更新它以直接使用 ansible python 模块,我会更新。干杯。

于 2020-01-13T15:46:21.110 回答
1

您想通过 Ansible Python API 读取和解密加密文件,对吗?

在 Ansible 2.0 及更高版本中:

def execute_ansible_command(play_source, stdout_callback):
    from ansible.executor.task_queue_manager import TaskQueueManager
    from ansible.inventory import Inventory
    from ansible.parsing.dataloader import DataLoader
    from ansible.playbook import Play
    from ansible.vars import VariableManager

    Options = namedtuple('Options', ['connection', 'module_path', 'forks', 'remote_user',
                                     'private_key_file', 'ssh_common_args', 'ssh_extra_args', 'sftp_extra_args',
                                     'scp_extra_args', 'become', 'become_method', 'become_user', 'verbosity',
                                     'check'])
    variable_manager = VariableManager()
    loader = DataLoader()
    loader.set_vault_password(ANSIBLE_VAULT_PASS)
    options = Options(connection='smart', module_path=None, forks=100,
                      remote_user=None, private_key_file=None, ssh_common_args="-o StrictHostKeyChecking=no",
                      ssh_extra_args=None, sftp_extra_args=None, scp_extra_args=None, become=None,
                      become_method=None, become_user=None, verbosity=None, check=False)
    passwords = dict()
    inventory = Inventory(loader=loader, variable_manager=variable_manager, host_list=ANSIBLE_INVENTORY)
    variable_manager.set_inventory(inventory)

    play = Play().load(play_source, variable_manager=variable_manager, loader=loader)

    tqm = None
    try:
        tqm = TaskQueueManager(
            inventory=inventory,
            variable_manager=variable_manager,
            loader=loader,
            options=options,
            passwords=passwords,
            stdout_callback=stdout_callback,
        )
        tqm.run(play)
    finally:
        if tqm is not None:
            tqm.cleanup()

DataLoader 类用于加载和解析 YAML 或 JSON 内容,它有一个set_vault_password功能,可以发送一个 vault 密码来解密一个 vault 加密的文件

于 2017-08-08T01:32:24.247 回答
0

ansible view <vaultfile>这不完全是我想要的,但通过运行命令来解决我的上述问题subprocess

import subprocess
import yaml

def getCreds():
    cmd = "ansible-vault view credentials.vault"
    process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (result, error) = process.communicate()

    resultYaml = yaml.load(result)

    accesskey = resultYaml['accesskey']
    secretkey = resultYaml['secretkey']

    return(accesskey, secretkey)

直接在 Python 中直接调用 Ansible 方法仍然是最好的。

于 2017-05-23T21:48:49.167 回答