不使用文件系统临时读写数据

不使用文件系统临时读写数据

我在管理 debian 盒子的 vagrant 环境中使用 ansible。由于多个 ansible 配置程序具有保管库加密数据(例如数据库根密码),我必须由第一个配置程序输入一次保管库密码。目前,此密码存储在 中/tmp,由每个 ansible 配置程序中的脚本读取,并由/dev/null最后一个配置程序覆盖并删除。

Ansible 能够调用返回保管库密码的脚本。所以这个脚本将在单独的 shell 中运行。

如果攻击者成功侵入虚拟机,他就有机会恢复任何临时文件并获得保管库密码。

虽然这些流浪环境将在生产中使用,但我正在寻找一种更安全的方法。我首先想到的是以某种方式读取和写入内存。因此,虚拟机重新启动会擦除内存。我知道上述数据可以以某种方式在磁盘上交换。但我认为获取这些数据比临时文件方法更困难。

编辑

我忘记提及如果配置程序失败会带来安全风险。然后最后一个配置程序将不会被执行,并且临时文件保留在文件系统上。


我提供了一个额外的答案,展示了集成解决方案,仅供对导致此问题的起源问题的解决方案感兴趣的任何人使用。

答案1

要使用以下命令创建 1 MB RAM 磁盘tmpfs

mkdir /tmp/ramdisk
mount -t tmpfs -o size=1m myramdisk /tmp/ramdisk

RAM盘不进行交换,但如果需要确保在使用 RAM 盘期间没有发生交换,则可以在使用RAM 盘ramfs时分别关闭和打开交换tmpfsswapoff -a和。卸载:swapon -atmpfs

umount /tmp/ramdisk

也许我错过了一些东西,但我没有看到在 中描述 RAM 磁盘的好处/etc/fstab;但是,如果需要的话,如下所示的内容应该足以使 RAM 磁盘仅对用户可用root( mode=0700):

tmpfs /tmp/ramdisk tmpfs rw,mode=0700,size=1m

答案2

除了 @Christopher 的回答之外,我还想展示如何将解决方案集成到我的 Vagrantfile 中,以便让它与我的 ansible 配置一起工作。

可能有人会偶然发现这一点。

流浪文件

Vagrant.configure("2") do |config|

    class AnsibleVaultPassword
        def to_s
            begin
                system 'stty -echo'
                print "Enter ansible vault password: "
                pass = STDIN.gets.chomp
                ensure
                system 'stty echo'
            end
            pass
        end
    end

    config.vm.box = "vendor/box-name"
    config.vm.box_version = ">=1.0"
    config.vm.box_url = "https://vagrant.example.com/vendor/box-name.json"
    config.vm.box_download_insecure = true

    config.vm.define "vendor-server-name"
    config.vm.provider "virtualbox" do |provider|
        provider.name = "vendor-server-name"
    end

    config.vm.network "private_network", ip: "192.168.0.42"

    config.vm.synced_folder ".", "/vagrant", type: "nfs"

    config.vm.provision "Provisioning the server `server-name` with the playbook `ansible`", type: "ansible_local" do |provisioner|
        provisioner.compatibility_mode = "2.0"
        provisioner.playbook = "/vagrant/ansible/ansible.yml"
        provisioner.inventory_path = "/vagrant/ansible/inv/integration/hosts"
        provisioner.limit = "localhost"
    end

    config.vm.provision "Requesting the ansible vault password", type: "shell" do |provisioner|
        provisioner.env = { "ansibleVaultPassword" => AnsibleVaultPassword.new }
        provisioner.inline = <<-END
            [[ ! -d "/mnt/ansible-tmp" ]] \
            && mkdir "/mnt/ansible-tmp"
            mountpoint -q "/mnt/ansible-tmp" \
            || mount -t tmpfs -o size=512 ansible-tmp "/mnt/ansible-tmp"
            /vagrant/env/ansible/scripts/vault-password.sh --save "${ansibleVaultPassword}"
        END
    end

    config.vm.provision "Provisioning the server `server-name` with the playbook `environment`", type: "ansible_local" do |provisioner|
        provisioner.compatibility_mode = "2.0"
        provisioner.playbook = "/vagrant/ansible/environment.yml"
        provisioner.raw_arguments = [ "--vault-id /vagrant/ansible/scripts/vault-password.sh" ]
        provisioner.inventory_path = "/vagrant/ansible/inv/integration/hosts"
        provisioner.limit = "localhost"
    end

    config.vm.provision "Provisioning the server `server-name` with the playbook `users`", type: "ansible_local" do |provisioner|
        provisioner.compatibility_mode = "2.0"
        provisioner.playbook = "/vagrant/ansible/users.yml"
        provisioner.raw_arguments = [ "--vault-id /vagrant/ansible/scripts/vault-password.sh" ]
        provisioner.inventory_path = "/vagrant/ansible/inv/integration/hosts"
        provisioner.limit = "localhost"
    end

    config.vm.provision "Deleting the ansible vault password", type: "shell" do |provisioner|
        provisioner.inline = <<-END
            /vagrant/env/ansible/scripts/vault-password.sh --delete
            mountpoint -q "/mnt/ansible-tmp" \
            && umount "/mnt/ansible-tmp"
            [[ -d "/mnt/ansible-tmp" ]] \
            && rm -r "/mnt/ansible-tmp"
        END
    end

end

/vagrant/ansible/scripts/vault-password.sh

#!/usr/bin/env bash

passwordFile="/mnt/ansible-tmp/vault-password"
case "${1}" in
    "-s" | "--save" )
        echo "${2}" > "${passwordFile}"
        ;;
    "-d" | "--delete" )
        unlink "${passwordFile}"
        ;;
    * )
        cat "${passwordFile}"
        ;;
esac

虽然它是 Debian VM,但我首先运行 playbook ansible,添加来自 Ubuntu 的 ansible 存储库,然后安装最新的ansible.这至少--vault-id对于为 Vagrant 的调用提供参数是必要的ansible-playbook。 (在这篇文章Debian Stretch发表时,ansible 2.2它并不支持这一论点。)

然后通过 class 请求保管库密码AnsibleVaultPassword。随后将创建密码tmpfs,并将密码传递给脚本vault-password.sh以将其存储在tmpfs安装上。

vault-password.sh然后,ansible 将通过每个提供保管库加密数据的 playbook 中的脚本请求密码。

最后会先删除密码,然后tmpfs再卸载挂载。

我认为这是一个非常安全可靠的解决方案,可以通过临时可擦除内存存储提供 ansible 保险库密码。因此,可以配置正在运行的系统,并且不再需要重新启动。

相关内容