Packer mit Ansible und HashiCorp Vault as Vault


Bicycle

Der Schutz von Daten ist ein entscheidender Bestandteil jeder Infrastruktur. In diesem Artikel zeigen wir, wie man HashiCorp Vault als sichere Quelle von Secrets für HashiCorp Packer in Kombination mit Ansible-Provisionern verwendet. Wir werden die HCP Packer Pipelines verwenden, um unsere Images zu erstellen.

Wir verwenden in dem Provisionierungsprozess weiterhin ansible um das bereits gewonnen Wissen zu Konfiguration als Code weiterhin nutzen zu können. Außerdem ermöglicht uns das auch, Day 2 Operations mit dem gleichen Prozess - per ansible - zu warten. Wir müssen hier also dann nicht wieder auf manuelle Konfigurationsänderungen zurückgreifen. Dies ist besonders nützlich, wenn wir die Images für einen längeren Zeitraum ausführen müssen und diese warten müssen, z.B. in einem On-Premise-Rechenzentrum oder wenn wir die gleiche Konfiguration als Code für Bare-Metal-Bereitstellungen verwenden.

HashiCorp Vault

HasiCorp Vault ist ein System um sicher sensitive Daten zu verwalten und zu speichern. Es kann zum Speichern von Secrets wie Passwörtern, Zertifikaten, Token usw. verwendet werden. Vault kann zum Speichern von Daten für Anwendungen, aber auch für die Infrastruktur verwendet werden. Vault kann zum Speichern von Geheimnissen für Packer, Terraform, Kubernetes usw. verwendet werden. Dies ist also der nächste Schritt auf dem Weg zur Generierung von Images mit Packer, um diese Daten aus Vault zu erhalten.

Ansible Vault und HashiCorp Vault

Innerhalb von Ansible gibt es eine Funktion namens Ansible Vault. Diese Funktion kann zum Verschlüsseln vertraulicher Daten in Ansible-Playbooks verwendet werden. Dies ist eine gute Möglichkeit, senstive Daten in Ansible-Playbooks zu speichern. Es ist jedoch keine gute Möglichkeit, Daten in Packer-Vorlagen zu verwenden. Der Grund dafür ist, dass Ansible Vault kein gute Secrets-Store ist. Es ist eine Möglichkeit, Daten zu verschlüsseln. Und hier kommt HashiCorp Vault ins Spiel.

Mit HashiCorp Vault können wir Daten sicher speichern. Und wir können diese Daten in unseren Packer-Vorlagen verwenden. Ansible ist in Python geschrieben und es gibt einen HashiCorp Vault Python-Client. Und dieser Client wird als Kern innerhalb der hashi_vault-Collection verwendet. Diese Collection kann verwendet werden, um Daten aus HashiCorp Vault in Ansible-Playbooks abzurufen. Wir brauchen nur eine andere Möglichkeit, diese Daten in unsere Ansible-Playbooks einzuschleusen.

HashiCorp Packer mit HashiCorp Vault und Ansible

Wir möchten einen Task mit Ansible schreiben, der mehrmals eingebunden werden kann, um Daten aus dem HashiCorp Vault in unser Playbook zu laden. Wir werden eine Key/Value Secrets-Engine verwenden, um unsere Daten zu speichern, und gehen im folgenden Beispiel davon aus, dass diese Engine im Pfad ansible gemountet ist. Wir werden die folgende Struktur verwenden, um auf ein dediziertes Geheimnis zuzugreifen:

 1---
 2# snippets/get_vault_extra_vars.yml
 3- name: "load extra vars {{ vault_vars }}"
 4  when: vault_vars is defined
 5  register: vault_data
 6  ignore_errors: true
 7  delegate_to: localhost
 8  become: false
 9  no_log: "{{ lookup('ansible.builtin.env', 'CI') | length > 0 }}"    
10  community.hashi_vault.vault_kv2_get:
11    retry_action: ignore
12    engine_mount_point: 'ansible'
13    path: "{{vault_vars}}"
14    token: "{{ vault_token }}"
15
16- name: "update extra host facts {{ vault_vars }}"
17  when: vault_data is defined and vault_data.failed == false
18  loop: "{{ vault_data.secret | dict2items }}"
19  no_log: "{{ lookup('ansible.builtin.env', 'CI') | length > 0 }}"
20  set_fact:
21    "{{ item.key }}": "{{ item.value }}"

Der erste Task lädt Daten aus HashiCorp Vault und der zweite Task legt die Daten als Fakten fest. Wenn wir in unseren Vault strukturen komplexe Daten speichern, müssen wir diese später bei der Verwendung der tatsächlichen Daten berücksichtigen. Die folgende Datenstruktur, die als ansible/group_vars/consul_nodes gespeichert und mit der ansible-Rolle ansible-consul verwendet werden kann, zeigt, wie Ihre Daten aussehen könnten. In diesem Beispiel müssen wir den Wert consul_config_custom`` als consul_config_custom | to_nice_json` verarbeiten.

 1{
 2  "consul_bind_address": "0.0.0.0",
 3  "consul_client_address": "0.0.0.0",
 4  "consul_config_custom": {
 5    "telemetry": {
 6      "disable_hostname": true,
 7      "prometheus_retention_time": "1h"
 8    }
 9  },
10  "consul_datacenter": "home",
11  "consul_domain": "consul",
12  "consul_group_name": "consul_nodes",
13  "consul_ports_grpc": "8502",
14  "consul_version": "1.17.0"
15}

Diese Tasks können mehrfach eingebunden werden, um Daten aus unterschiedlichen Pfaden zu laden. Mit der Aufgabe können Daten für alle Hosts, alle Gruppen, den aktuellen Host und die aktuellen Gruppen des Hosts geladen werden. Das folgende Snippet zeigt, wie Sie die Aufgabe verwenden, um Daten auf diese Weise zu laden:

 1---
 2# snippets/get_vault_secrets.yml
 3- name: "vault - load host_vars for all hosts"
 4  include_tasks: snippets/get_vault_extra_vars.yml
 5  vars:
 6    vault_vars: "host_vars/all"
 7
 8- name: "vault - load host_vars for {{ inventory_hostname }}"
 9  include_tasks: snippets/get_vault_extra_vars.yml
10  vars:
11    vault_vars: "host_vars/{{ inventory_hostname }}"
12
13- name: "vault - load group data for all hosts"
14  include_tasks: snippets/get_vault_extra_vars.yml
15  vars:
16    vault_vars: "group_vars/all"
17
18- name: "vault - load group for {{ inventory_hostname }}"
19  include_tasks: snippets/get_vault_extra_vars.yml
20  loop: "{{ ['group_vars']| product(group_names) | map('join','/') | list }}"
21  vars:
22    vault_vars: "{{ item }}"

Und nun können wir innerhalb der pre_task Sektion mittels include_tasks Daten für alle Hosts und Gruppen aus HashiCorp Vault laden, die für ein Playbook relevant sind:

 1---
 2# docker.yaml playbook
 3- hosts: all
 4  gather_facts: true
 5  pre_tasks:
 6    - include_tasks: snippet/get_vault_secrets.yml
 7
 8  roles:
 9    - role: "base"
10
11    - role: "customize"
12
13    - role: "docker"

HashiCorp Vault Auhtenfitizierung

Es bleibt übrig, wie Sie Ihr Pipeline-Automatisierungs- oder Konfigurationstool einrichten, um ein gültiges VAULT_TOKEN zu erhalten. Dies kann entweder durch den Einsatz eines Vault Agenten mithilfe einer Vault AppRole erfolgen, es kann aber auch mit hvac und Ansible umgesetzt werden:

 1- name: "vault - get environment data"
 2  set_fact:
 3    vault_token: "{{ lookup('ansible.builtin.env', 'VAULT_TOKEN') }}"
 4    role_id: "{{ lookup('ansible.builtin.env', 'VAULT_ROLE_ID') }}"
 5    secret_id: "{{ lookup('ansible.builtin.env', 'VAULT_SECRET_ID') }}"
 6
 7- name: "vault - check vault authentication credentials"
 8  when: vault_token is not defined and ( role_id is not defined or secret_id is not defined )
 9  fail: 
10    msg: please check your vault credentials 
11
12- name: "vault - verify token information"
13  when: vault_token is defined and vault_token | length > 0
14  delegate_to: localhost
15  become: false
16  community.hashi_vault.vault_login:
17    auth_method: token
18    token: "{{ vault_token }}"
19
20- name: "vault - use approle to login"
21  when: secret_id is defined and role_id is defined and secret_id | length > 0 and role_id | length > 0
22  block:
23  - name: "vault - login by approle"
24    delegate_to: localhost
25    become: false
26    register: login_data
27    community.hashi_vault.vault_login:
28      auth_method: approle
29      mount_point: pipeline_approle
30      role_id: "{{ role_id }}"
31      secret_id: "{{ secret_id }}"
32
33  - name: "vault - set vault token fact"
34    set_fact:
35      vault_token: '{{ login_data | community.hashi_vault.vault_login_token }}'

Fazit

Wir haben gezeigt, wie man HashiCorp Vault als Datenquelle für die HashiCorp Packer Provisionierung in Kombination mit Ansible verwendet. Wir haben gezeigt, wie Sie die hashi_vault Collection verwenden, um mithilfe von hashi_vault Daten aus HashiCorp Vault in Ansible-Playbooks abzurufen.

Dieses Setup ermöglicht die Verwaltung von Geheimnissen außerhalb eines Git-Repositorys mit einem Tool für diese Aufgabe, das darauf ausgelegt ist, Daten auf sichere Weise zu verteilen. Außerdem können wir die tatsächlichen Daten in ihren eigenen Iterationen verwalten, da die Key/Value-Secret Engine Version 2 die Iteration durch die Daten ermöglicht. So kann das Sicherheitsteam die Rotation der Daten überwachen und das Betriebsteam die Daten verwenden.

Zurück Unsere Trainings entdecken

Wir sind für Sie da

Sie interessieren sich für unsere Trainings oder haben einfach eine Frage, die beantwortet werden muss? Sie können uns jederzeit kontaktieren! Wir werden unser Bestes tun, um alle Ihre Fragen zu beantworten.

Hier kontaktieren