encrypt-file : role to encrypt a file
This is a role that takes some ASCII gpg keys, and encrypts a file with them. Change-Id: If2fe7921ff051a1c5d0589f5e32fba26d30ae96c
This commit is contained in:
parent
e3b7e0dcf6
commit
ad7093c17b
@ -15,6 +15,7 @@ General Purpose Roles
|
||||
.. zuul:autorole:: emit-job-header
|
||||
.. zuul:autorole:: enable-fips
|
||||
.. zuul:autorole:: enable-netconsole
|
||||
.. zuul:autorole:: encrypt-file
|
||||
.. zuul:autorole:: ensure-bazelisk
|
||||
.. zuul:autorole:: ensure-dhall
|
||||
.. zuul:autorole:: ensure-dstat-graph
|
||||
|
34
roles/encrypt-file/README.rst
Normal file
34
roles/encrypt-file/README.rst
Normal file
@ -0,0 +1,34 @@
|
||||
encrypt-file
|
||||
|
||||
Import GPG keys and encrypt a file
|
||||
|
||||
**Role Variables**
|
||||
|
||||
.. zuul:rolevar:: encrypt_file
|
||||
:default: *undefined*
|
||||
|
||||
A *string* with the full path to a log file to encrypt, or a *list*
|
||||
of *string* values of full paths to encrypt. Must be defined.
|
||||
Resulting file(s) will have ``.gpg`` added.
|
||||
|
||||
.. zuul:rolevar:: encrypt_file_recipients
|
||||
:default: []
|
||||
|
||||
List of recipients who will be able to decrypt the file(s). This
|
||||
should be a list of ``name`` keys that exist in
|
||||
``encrypt_file_keys``.
|
||||
|
||||
.. zuul:rolevar:: encrypt_file_keys
|
||||
:default: []
|
||||
|
||||
Keys available to encrypt the file with. Each entry is a
|
||||
dictionary with keys
|
||||
|
||||
* ``name`` : a freeform string identifier
|
||||
* ``key_id``: the GPG key ID
|
||||
* ``gpg_asc``: the GPG ASCII-armored public key. If the public-key
|
||||
is not already available, it will be imported to GPG.
|
||||
|
||||
It is intended that this is a global-variable, and specific files
|
||||
to be encrypted then choose a subset of keys in this variable for
|
||||
encryption.
|
1
roles/encrypt-file/defaults/main.yaml
Normal file
1
roles/encrypt-file/defaults/main.yaml
Normal file
@ -0,0 +1 @@
|
||||
encrypt_file_keys: []
|
38
roles/encrypt-file/tasks/import-key.yaml
Normal file
38
roles/encrypt-file/tasks/import-key.yaml
Normal file
@ -0,0 +1,38 @@
|
||||
- name: Check for existing key
|
||||
command: |
|
||||
gpg --list-keys {{ zj_encrypt_file.key_id }}
|
||||
register: _key_exists
|
||||
# A found key returns 0, a missing key returns 2
|
||||
failed_when: _key_exists.rc != 0 and _key_exists.rc != 2
|
||||
|
||||
- name: Install key
|
||||
when: _key_exists.rc != 0
|
||||
block:
|
||||
- name: Create temporary keyfile
|
||||
tempfile:
|
||||
state: file
|
||||
register: _keyfile
|
||||
|
||||
- name: Copy keyfile material # noqa risky-file-permissions
|
||||
copy:
|
||||
content: '{{ zj_encrypt_file.gpg_asc }}'
|
||||
dest: '{{ _keyfile.path }}'
|
||||
|
||||
- name: Import key
|
||||
command: |
|
||||
gpg --import {{ _keyfile.path }}
|
||||
|
||||
# Strip all whitespace and take the second line of output, which
|
||||
# is the fingerprint, then import this at "I trust fully" level.
|
||||
# This was a pain to figure out as gpg really wants to communicate
|
||||
# with a tty if you do something obvious like "gpg --edit-key <id>
|
||||
# ...". And what is menu option number "5" is actually "6" in the
|
||||
# ownertrust db!
|
||||
- name: Trust key
|
||||
shell: |
|
||||
echo $(gpg --fingerprint {{ zj_encrypt_file.key_id }} | sed -n "s/ //g;2 p"):6: | gpg --import-ownertrust
|
||||
|
||||
- name: Remove temporary keyfile
|
||||
file:
|
||||
path: '{{ _keyfile.path }}'
|
||||
state: absent
|
37
roles/encrypt-file/tasks/main.yaml
Normal file
37
roles/encrypt-file/tasks/main.yaml
Normal file
@ -0,0 +1,37 @@
|
||||
- name: Validate input file
|
||||
fail:
|
||||
msg: 'Must define "encrypt_file"'
|
||||
when: encrypt_file is undefined
|
||||
|
||||
- name: Ensure gpg2 installed
|
||||
package:
|
||||
name: gnupg2
|
||||
state: present
|
||||
|
||||
- name: Check for required keys
|
||||
fail:
|
||||
msg: 'Name {{ zj_recipient_name }} not in encrypt_file_keys'
|
||||
when: zj_recipient_name not in encrypt_file_keys | map(attribute="name")
|
||||
loop: '{{ encrypt_file_recipients }}'
|
||||
loop_control:
|
||||
loop_var: zj_recipient_name
|
||||
|
||||
- name: Build recipient list
|
||||
set_fact:
|
||||
_recipients: '{{ encrypt_file_keys | selectattr("name", "in", encrypt_file_recipients) | list }}'
|
||||
|
||||
- name: Install keys
|
||||
include_tasks: import-key.yaml
|
||||
loop: '{{ _recipients }}'
|
||||
loop_control:
|
||||
loop_var: zj_encrypt_file
|
||||
|
||||
- name: Build recipient list
|
||||
set_fact:
|
||||
_recipients_cmd: '--recipient={{ _recipients | map(attribute="key_id") | join(" --recipient=") }}'
|
||||
|
||||
- name: Encrypt file
|
||||
command: 'gpg2 --encrypt --output {{ zj_encrypt_file }}.gpg {{ _recipients_cmd }} {{ zj_encrypt_file }}'
|
||||
loop: '{{ [ encrypt_file ] if encrypt_file is string else encrypt_file }}'
|
||||
loop_control:
|
||||
loop_var: zj_encrypt_file
|
114
test-playbooks/encrypt-file.yaml
Normal file
114
test-playbooks/encrypt-file.yaml
Normal file
@ -0,0 +1,114 @@
|
||||
- hosts: all
|
||||
tasks:
|
||||
|
||||
- name: Make a fake file
|
||||
tempfile:
|
||||
state: file
|
||||
register: _tempfile
|
||||
|
||||
- name: Add some data
|
||||
copy:
|
||||
content: 'Hello, I am encrypted'
|
||||
dest: '{{ _tempfile.path }}'
|
||||
|
||||
- name: Setup encryption variables
|
||||
set_fact:
|
||||
encrypt_file_keys:
|
||||
- name: 'zuul-jobs-test-1'
|
||||
key_id: '0xD0A3C69F209B3B8E'
|
||||
gpg_asc: |
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEYgxZHhYJKwYBBAHaRw8BAQdAl9ZJaMvAc4kcO2mWFCZ5Em0xl7kRc3QYgtg0
|
||||
+98sqoO0EHp1dWwtam9icy10ZXN0LTGIlAQTFgoAPBYhBKNWMSQoy8kXXIv/T9Cj
|
||||
xp8gmzuOBQJiDFkeAhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgAAKCRDQ
|
||||
o8afIJs7jqlUAQCVxaINjS5/rd1oCAp19lHrscMhFmQBOtxyU7CTDoCrCAEAh9mH
|
||||
scfOGRWhxiwg0+dXe6RE/C3Kk13kdN8pfTOIGA24OARiDFkeEgorBgEEAZdVAQUB
|
||||
AQdAl53uFFzrhnTTmq0YbDRtQ5KrMJYYNahImPzzrvVajW4DAQgHiHgEGBYKACAW
|
||||
IQSjVjEkKMvJF1yL/0/Qo8afIJs7jgUCYgxZHgIbDAAKCRDQo8afIJs7jqE7AP9M
|
||||
LRe/tJ+SeHexDI1m9tmo6xcID7UOJW8eIuuwi3kjZgEAl+WqJfqjBxJmBWIjTZcV
|
||||
zA2T4i8ViORhXLo0oohQVwE=
|
||||
=/liI
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
- name: 'zuul-jobs-test-2'
|
||||
key_id: '0x4E1BA7A3AB674E6F'
|
||||
gpg_asc: |
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEYgxZkRYJKwYBBAHaRw8BAQdA1/5ta4i1G+NGqRWtlFuzZUmDHZP5uMt1gguX
|
||||
WcXfoGW0EHp1dWwtam9icy10ZXN0LTKIlAQTFgoAPBYhBN0G/+apoMfgIYAX404b
|
||||
p6OrZ05vBQJiDFmRAhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgAAKCRBO
|
||||
G6ejq2dOb4BkAQDoHczJaUH0LRgZUE+tkxhyqYY7kevX65vxe6vAqFci1gD/VvtA
|
||||
lYrnQPqGG1GqRqy7cIsCfnI5lzAlL2Q2tYdO6A24OARiDFmREgorBgEEAZdVAQUB
|
||||
AQdAZsFeMnJ7FGzNXf2SbGrVvYjgX397PaY6xAQoFWe4IQQDAQgHiHgEGBYKACAW
|
||||
IQTdBv/mqaDH4CGAF+NOG6ejq2dObwUCYgxZkQIbDAAKCRBOG6ejq2dOb0t2AP9b
|
||||
6Lv4BKjblZOhxJbsB9qvQbeyYunCLP07lSHBEhggNQEA+Luzhn3uitf4lyNbv6cS
|
||||
9p2BPtxrLR4Ab20opteZ7w0=
|
||||
=is5k
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
- name: 'zuul-jobs-test-3'
|
||||
key_id: '0FDF4D29F272F75A'
|
||||
gpg_asc: |
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
mDMEYgxZmxYJKwYBBAHaRw8BAQdAVUbvG30ucCb6ztQ/iuis7fX5FXssxSfbl/n8
|
||||
vl/gyse0EHp1dWwtam9icy10ZXN0LTOIlAQTFgoAPBYhBHfjn1eq18PQIZ3qNA/f
|
||||
TSnycvdaBQJiDFmbAhsDBQsJCAcCAyICAQYVCgkICwIEFgIDAQIeBwIXgAAKCRAP
|
||||
300p8nL3WqgFAQCNhAEx7yC7UMV81IhiWMCDLK66eeHF16CiqPMabwlOEAD/V1cQ
|
||||
NYCJekbq8GEcB3i36yIMPJokrPmXf6mkebs6vA24OARiDFmbEgorBgEEAZdVAQUB
|
||||
AQdAPGKpDC3HpbRCJYkMzwY2NybY+/+G1beIjlDjpaxf/mIDAQgHiHgEGBYKACAW
|
||||
IQR3459XqtfD0CGd6jQP300p8nL3WgUCYgxZmwIbDAAKCRAP300p8nL3WlQpAQC1
|
||||
qwAAr63kwKKszAN+J32EGSaXp+dsR04367XacSJ3aQD/Tu6q45tF0t4G0dQIpzxT
|
||||
jnHN/zEM7eyW45Jf/V8migI=
|
||||
=CRYD
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
|
||||
- name: Encrypt file
|
||||
include_role:
|
||||
name: encrypt-file
|
||||
vars:
|
||||
encrypt_file: '{{ _tempfile.path }}'
|
||||
encrypt_file_recipients:
|
||||
- zuul-jobs-test-2
|
||||
- zuul-jobs-test-3
|
||||
|
||||
- name: Remove temporary file
|
||||
file:
|
||||
path: '{{ _tempfile.path }}'
|
||||
state: absent
|
||||
when: _tempfile.path is defined
|
||||
|
||||
- name: Check output file
|
||||
stat:
|
||||
path: '{{ _tempfile.path }}.gpg'
|
||||
register: _output
|
||||
|
||||
- name: Ensure exists
|
||||
fail:
|
||||
msg: 'Output file not found'
|
||||
when: not _output.stat.exists
|
||||
|
||||
- name: Dump gpg packets
|
||||
command: gpg --list-packets '{{ _tempfile.path }}.gpg'
|
||||
register: _gpg_output
|
||||
# Because it can't decrypt, gpg give an error. But we're
|
||||
# interested in the encryption packets so expect this.
|
||||
failed_when: _gpg_output.rc != 2
|
||||
|
||||
- name: Show gpg command output
|
||||
debug:
|
||||
var: _gpg_output
|
||||
|
||||
- name: Validate packets
|
||||
assert:
|
||||
that:
|
||||
- "'zuul-jobs-test-1' not in _gpg_output.stdout"
|
||||
- "'zuul-jobs-test-2' in _gpg_output.stdout"
|
||||
- "'zuul-jobs-test-3' in _gpg_output.stdout"
|
||||
|
||||
- name: Remove output file
|
||||
file:
|
||||
path: '{{ _tempfile.path }}.gpg'
|
||||
state: absent
|
@ -95,6 +95,14 @@
|
||||
A+tEIZhDiZh2NZoXXAKqV3pH6nOF9kPgRymy7de7BCoQx3rB7YgXpOk=
|
||||
-----END RSA PRIVATE KEY-----
|
||||
|
||||
- job:
|
||||
name: zuul-jobs-test-encrypt-file
|
||||
description: |
|
||||
Test encrypt-file role
|
||||
files:
|
||||
- roles/encrypt-file/.*
|
||||
run: test-playbooks/encrypt-file.yaml
|
||||
|
||||
- job:
|
||||
name: zuul-jobs-test-base-roles
|
||||
description: |
|
||||
@ -749,6 +757,7 @@
|
||||
- zuul-jobs-test-add-authorized-keys
|
||||
- zuul-jobs-test-add-gpgkey
|
||||
- zuul-jobs-test-add-sshkey
|
||||
- zuul-jobs-test-encrypt-file
|
||||
- zuul-jobs-test-base-roles-centos-7
|
||||
- zuul-jobs-test-base-roles-centos-8-stream
|
||||
- zuul-jobs-test-base-roles-centos-9-stream
|
||||
|
Loading…
Reference in New Issue
Block a user