Changeset - c6f217756635
[Not reviewed]
0 6 0
Branko Majic (branko) - 8 years ago 2016-01-11 00:05:52
branko@majic.rs
MAR-44: Redesigned handling of private keys by the backup_client role. Keys are now provided directly, not as key identifiers to be looked-up in the backup keyring.
6 files changed with 48 insertions and 67 deletions:
0 comments (0 inline, 0 general)
docs/rolereference.rst
Show inline comments
 
@@ -1488,15 +1488,16 @@ Backup clients utilise duplicity (via the duply convenience wrapper) for
 
performing the backups to a backup server via *SFTP* protocol.
 

	
 
The role itself will take care of deploying the necessary software,
 
configuration files, and encryption/signing keys to the backup client in order
 
to be able to perform backup.
 
configuration files, and encryption/signing private key to the backup client in
 
order to be able to perform backup.
 

	
 
The role implements the following:
 

	
 
* Installs backup software (Duplicity, Duply).
 
* Sets-up Duply configuration under directory ``/etc/duply/main/``.
 
* Extracts the encryption public key and signing private key from a
 
  locally-available keyring, deploys them to the server, and imports them.
 
* Deploys encryption/signing private key (usually host-specific), as well as
 
  additional encryption public keys to the server, and imports them into local
 
  GnuPG keyring used by backup software.
 
* Deploys private SSH key for logging-in into the backup server over SFTP.
 
* Deploys ``known_hosts`` file for SFTP fingerprint verification.
 
* Sets-up pre-backup task that creates LDAP database dump in location
 
@@ -1515,38 +1516,42 @@ Duply is configured as follows:
 
  directory ``/etc/duply/main/patterns/``. It is recommended to name such a file
 
  after the role name. Include pattern file is assembled from these snippets and
 
  stored in location ``/etc/duply/main/include``.
 
* Backups are encrypted with specified encryption keys. If signing key has been
 
  provided, it will be used for signing the backups.
 
* Backups are encrypted and signed with the specified encryption key.
 
* Maximum age for old backups is set to 6 months.
 
* Maximum age for full backups is set to 1 month.
 
* Volume size is set to 1GB.
 

	
 
.. note::
 
   Since at time of this writing there are no lookup plugins for extracting key
 
   material/information from GnuPG keyring, you may want to resort to extraction
 
   of keys on the controller machine via lookups similar to::
 

	
 
     lookup('pipe', 'gpg2 --homedir /path/to/your/keyring --armor --export some_identifier')
 
     lookup('pipe', 'gpg2 --homedir /path/to/your/keyring --armor --export-secret-keys some_identifier')
 

	
 
   This may not be the most elegant solution, but for now it offers better
 
   flexibility (theoretically, you could store all those keys etc as plaintext
 
   files instead).
 

	
 

	
 
Parameters
 
~~~~~~~~~~
 

	
 
**backup_additional_encryption_keys** (list, optional, ``[]``)
 
  List of additional identifiers of encryption keys used for backup
 
  operation. Listed encryption keys must be present in the backup keyring - only
 
  the public key is used. These additional keys are useful in cases where the
 
  backups should be decryptable with some master key in addition to
 
  server-specific key.
 
  List of additional public encryption keys used for backup operation. Each item
 
  in the list should be an ASCII armour-encoded public key exported from a GnuPG
 
  keyring. These additional public keys are useful in cases where the backups
 
  should be decryptable with some master key in addition to server-specific key.
 

	
 
**backup_client_username** (string, optional, ``bak-{{ ansible_fqdn | replace('.', '_') }}``)
 
  Username for connecting to the backup server via SFTP.
 

	
 
**backup_encryption_key** (string, optional, ``{{ ansible_fqdn }}``)
 
  Identifier of encryption key used for the backup operations. Specified key
 
  must be present in the backup keyring, both private and public
 
  counterpart. This is normally host-specified encryption key that is
 
  distributed to destination server and that can be also used for the restore
 
  operations (for data decryption).
 

	
 
**backup_gnupg_keyring** (string, optional, ``{{ inventory_dir }}/backup_keyring``)
 
  Path to the directory on *controller* machine (where Ansible is executed)
 
  where the GnuPG keyring can be found. The keyring contains encryption and
 
  signing keys for backup clients, and is used for deploying those keys to the
 
  backup clients.
 
**backup_encryption_key** (string, mandatory)
 
  Private GnuPG key, encoded using ASCII armor, used for encryption and signing
 
  operations when running the backup on the client server. This *must* be a
 
  private key! This is normally host-specific encryption key that is distributed
 
  to destination server and that can be also used for the restore operations
 
  (for data decryption). The key must not be password-protected.
 

	
 
**backup_server** (string, mandatory)
 
  Backup server to connect to.
 
@@ -1562,12 +1567,6 @@ Parameters
 
**backup_server_port** (int, optional, ``2222``)
 
  Port on the backup server to connect to for accessing the SFTP service.
 

	
 
**backup_signing_key** (string, optional, ``None``)
 
  Key identifier of a key to use for signing the backups. The specified key
 
  needs to be present in backup keyring, both private and public counterpart. If
 
  there are multiple keys with the same ID present, the most recent one will be
 
  used.
 

	
 
**backup_ssh_key** (string, mandatory)
 
  SSH private key for logging-in into the backup server.
 

	
 
@@ -1581,10 +1580,9 @@ plugin is quite useful here for fetching key values from some local directory):
 
.. code-block:: yaml
 

	
 
  - role: backup_client
 
    backup_additional_encryption_keys: "my_key"
 
    backup_additional_encryption_keys: "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"
 
    backup_client_username: "user"
 
    backup_encryption_key: "host_enc_key"
 
    backup_gnupg_keyring: "/home/admin/.gnupg"
 
    backup_encryption_key: "-----BEGIN PGP PRIVATE KEY BLOCK-----\n...\n-----END PGP PRIVATE KEY BLOCK-----"
 
    backup_server: "backup.example.com"
 
    backup_server_destination: "//example/host"
 
    backup_server_host_ssh_public_keys:
 
@@ -1593,5 +1591,4 @@ plugin is quite useful here for fetching key values from some local directory):
 
      - "{{ lookup('file', inventory_dir + '/ssh/backup_server_ed25519_key.pub') }}"
 
      - "{{ lookup('file', inventory_dir + '/ssh/backup_server_rsa_key.pub') }}"
 
    backup_server_port: 22
 
    backup_signing_key: "host_enc_key"
 
    backup_ssh_key: "{{ lookup('file', inventory_dir + '/ssh/web.example.com') }}"
roles/backup_client/defaults/main.yml
Show inline comments
 
@@ -2,8 +2,5 @@
 

	
 
backup_additional_encryption_keys: []
 
backup_client_username: "bak-{{ ansible_fqdn | replace('.', '_') }}"
 
backup_encryption_key: "{{ ansible_fqdn }}"
 
backup_gnupg_keyring: "{{ inventory_dir }}/backup_keyring"
 
backup_server_destination: //duplicity
 
backup_server_port: 2222
 
backup_signing_key: ""
roles/backup_client/tasks/main.yml
Show inline comments
 
@@ -17,28 +17,8 @@
 
    - "/var/cache/duply"
 
    - "/var/cache/duply/main"
 

	
 
- name: Extract private keys used for encryption and signing
 
  local_action: "command gpg2 --homedir '{{ backup_gnupg_keyring }}' --armor --export-secret-keys {{ backup_encryption_key }} {{ backup_signing_key }}"
 
  become: no
 
  register: private_keys
 
  changed_when: False
 

	
 
- name: Extract public keys used for encryption only
 
  local_action: "command gpg2 --homedir '{{ backup_gnupg_keyring }}' --armor --export {{ backup_additional_encryption_keys | join(' ') }}"
 
  become: no
 
  register: public_keys
 
  changed_when: False
 
  when: backup_additional_encryption_keys
 

	
 
- name: Extract signing key ID (duplicity accepts 8-char hex code only)
 
  local_action: shell gpg2 --homedir "{{ backup_gnupg_keyring }}" --with-colons --list-secret-keys "{{ backup_signing_key }}" | grep '^sec' | sort -n -k 6 -t ":"  | cut -f 5 -d ':' | grep -o '[A-F0-9]\{8\}$'
 
  become: no
 
  when: backup_signing_key is defined
 
  register: signing_key_id
 
  changed_when: False
 

	
 
- name: Deploy GnuPG private keys
 
  copy: content="{{ private_keys.stdout }}" dest="/etc/duply/main/private_keys.asc"
 
  copy: content="{{ backup_encryption_key }}" dest="/etc/duply/main/private_keys.asc"
 
        owner=root group=root mode=600
 
  notify:
 
    - Clean-up GnuPG keyring for import of new keys
 
@@ -46,13 +26,24 @@
 
    - Import public keys
 

	
 
- name: Deploy GnuPG public keys
 
  copy: content="{{ public_keys.stdout | default("") }}" dest="/etc/duply/main/public_keys.asc"
 
  copy: content="{{ backup_additional_encryption_keys | join('\n') }}" dest="/etc/duply/main/public_keys.asc"
 
        owner=root group=root mode=600
 
  notify:
 
    - Clean-up GnuPG keyring for import of new keys
 
    - Import private keys
 
    - Import public keys
 

	
 
- name: Extract encryption key identifier (Duplicty requires key ID in hexadecimal format)
 
  shell: "gpg2 --list-packets /etc/duply/main/private_keys.asc | grep keyid: | head -n1 | sed -e 's/.*: //' | sed -re 's/^.{8}//'"
 
  register: backup_encryption_key_id
 
  changed_when: False
 

	
 
- name: Extract additional encryption keys identifiers (Duplicty requires key ID in hexadecimal format)
 
  shell: "gpg2 --list-packets /etc/duply/main/private_keys.asc | grep keyid: | head -n1 | sed -e 's/.*: //' | sort -u | sed -re 's/^.{8}//' | tr '\n' ',' | sed -e 's/,$//'"
 
  register: backup_additional_encryption_keys_ids
 
  when: backup_additional_encryption_keys
 
  changed_when: False
 

	
 
- name: Deploy private SSH key for logging-in into backup server
 
  copy: content="{{ backup_ssh_key }}" dest="/etc/duply/main/ssh/identity"
 
        owner="root" group="root" mode="600"
roles/backup_client/templates/duply_main_conf.j2
Show inline comments
 
# GnuPG keys that should be used for encryption. Normally the encryption key is
 
# not available locally.
 
GPG_KEYS_ENC='{{ backup_encryption_key}}{% if backup_additional_encryption_keys %},{{ backup_additional_encryption_keys | join(',') }}{% endif %}'
 
GPG_KEYS_ENC='{{ backup_encryption_key_id.stdout }}{% if backup_additional_encryption_keys %},{{ backup_additional_encryption_keys_ids.stdout }}{% endif %}'
 

	
 
{% if backup_signing_key is defined -%}
 
# GnuPG keys that should be used for signing. Normally the signing key should be
 
# available locally.
 
GPG_KEY_SIGN='{{ signing_key_id.stdout }}'
 
{% endif -%}
 
# GnuPG key used for signing.
 
GPG_KEY_SIGN='{{backup_encryption_key_id.stdout }}'
 

	
 
# Trust all keys available in the GnuPG keyring.
 
GPG_OPTS="--homedir /etc/duply/main/gnupg/ --trust-model always"
testsite/group_vars/all.yml
Show inline comments
 
@@ -66,9 +66,9 @@ ldap_client_config:
 
enable_backup: yes
 

	
 
backup_additional_encryption_keys:
 
  - "backup.{{ testsite_domain }}"
 
  - "{{ lookup('pipe', 'gpg2 --homedir \"' + inventory_dir + '/backup_keyring' + '\" --armor --export backup.' + testsite_domain ) }}"
 

	
 
backup_signing_key: "{{ ansible_fqdn }}"
 
backup_encryption_key: "{{ lookup('pipe', 'gpg2 --homedir \"' + inventory_dir + '/backup_keyring' + '\" --armor --export-secret-keys ' + ansible_fqdn ) }}"
 

	
 
backup_server: "backup.{{ testsite_domain }}"
 

	
testsite/playbooks/web.yml
Show inline comments
 
@@ -11,4 +11,3 @@
 
    - web_server
 
    - phpinfo
 
    - wsgihello
 
    - backup_client
 
\ No newline at end of file
0 comments (0 inline, 0 general)