Allow requesting secrets by a different name
There are some cases, such as the artifact upload job, where the job can
take a dict parameter and where it could be advantageous to allow other
people to re-use the job but passing in their own local secret data by
supplying variables to a variant. However, currently secrets carry with
them a name, which is used as the variable name in ansible.
Make a secret in a job config be able to be given as a string or a
dict. In the dict case, the name of the secret and the name it should be
added to ansible as are required. This allows someone to have a named
secret but to pass it to a job under a different name.
Change-Id: I27a82c6ee1cf7399353509f98a0a52536ebbc19a
diff --git a/doc/source/user/config.rst b/doc/source/user/config.rst
index 7ff7106..e356d44 100644
--- a/doc/source/user/config.rst
+++ b/doc/source/user/config.rst
@@ -684,6 +684,42 @@
appear here must be defined in the same project as this job
definition.
+ Each item in the list may may be supplied either as a string,
+ in which case it references the name of a :ref:`secret` definition,
+ or as a dict. If an element in this list is given as a dict, it
+ must have the following fields.
+
+ .. attr:: name
+
+ The name to use for the Ansible variable into which the secret
+ content will be placed.
+
+ .. attr:: secret
+
+ The name to use to find the secret's definition in the configuration.
+
+ For example:
+
+ .. code-block:: yaml
+
+ - secret:
+ important-secret:
+ key: encrypted-secret-key-data
+
+ - job:
+ name: amazing-job:
+ secrets:
+ - name: ssh_key
+ secret: important-secret
+
+ will result in the following being passed as a variable to the playbooks
+ in ``amazing-job``:
+
+ .. code-block:: yaml
+
+ ssh_key:
+ key: descrypted-secret-key-data
+
.. attr:: nodes
A list of nodes which should be supplied to the job. This
diff --git a/tests/fixtures/config/ansible/git/common-config/playbooks/check-secret-names.yaml b/tests/fixtures/config/ansible/git/common-config/playbooks/check-secret-names.yaml
new file mode 100644
index 0000000..13eaf56
--- /dev/null
+++ b/tests/fixtures/config/ansible/git/common-config/playbooks/check-secret-names.yaml
@@ -0,0 +1,10 @@
+- hosts: ubuntu-xenial
+ tasks:
+
+ - debug:
+ msg: "renamed secret {{ renamed_secret }}"
+
+ - name: Assert variable precedence.
+ assert:
+ that:
+ - renamed_secret.value == 'vartest_secret'
diff --git a/tests/fixtures/config/ansible/git/common-config/zuul.yaml b/tests/fixtures/config/ansible/git/common-config/zuul.yaml
index d90f5e2..d34d5c4 100644
--- a/tests/fixtures/config/ansible/git/common-config/zuul.yaml
+++ b/tests/fixtures/config/ansible/git/common-config/zuul.yaml
@@ -110,6 +110,16 @@
- vartest_secret
- job:
+ parent: python27
+ name: check-secret-names
+ nodes:
+ - name: ubuntu-xenial
+ label: ubuntu-xenial
+ secrets:
+ - secret: vartest_secret
+ name: renamed_secret
+
+- job:
parent: base-urls
name: hello
post-run: playbooks/hello-post
diff --git a/tests/fixtures/config/ansible/git/org_project/.zuul.yaml b/tests/fixtures/config/ansible/git/org_project/.zuul.yaml
index e87d988..e144325 100644
--- a/tests/fixtures/config/ansible/git/org_project/.zuul.yaml
+++ b/tests/fixtures/config/ansible/git/org_project/.zuul.yaml
@@ -13,6 +13,7 @@
- python27
- faillocal
- check-vars
+ - check-secret-names
- timeout
- hello-world
- failpost
diff --git a/tests/unit/test_v3.py b/tests/unit/test_v3.py
index 2293ca0..adb6bed 100755
--- a/tests/unit/test_v3.py
+++ b/tests/unit/test_v3.py
@@ -799,6 +799,9 @@
build_check_vars = self.getJobFromHistory('check-vars')
with self.jobLog(build_check_vars):
self.assertEqual(build_check_vars.result, 'SUCCESS')
+ build_check_secret_names = self.getJobFromHistory('check-secret-names')
+ with self.jobLog(build_check_secret_names):
+ self.assertEqual(build_check_secret_names.result, 'SUCCESS')
build_hello = self.getJobFromHistory('hello-world')
with self.jobLog(build_hello):
self.assertEqual(build_hello.result, 'SUCCESS')
diff --git a/zuul/configloader.py b/zuul/configloader.py
index 8b459b3..aead0d8 100644
--- a/zuul/configloader.py
+++ b/zuul/configloader.py
@@ -339,6 +339,9 @@
job_project = {vs.Required('name'): str,
'override-branch': str}
+ secret = {vs.Required('name'): str,
+ vs.Required('secret'): str}
+
job = {vs.Required('name'): str,
'parent': vs.Any(str, None),
'final': bool,
@@ -352,7 +355,7 @@
'tags': to_list(str),
'branches': to_list(str),
'files': to_list(str),
- 'secrets': to_list(str),
+ 'secrets': to_list(vs.Any(secret, str)),
'irrelevant-files': to_list(str),
'nodes': vs.Any([node], str),
'timeout': int,
@@ -450,15 +453,24 @@
# Secrets are part of the playbook context so we must establish
# them earlier than playbooks.
secrets = []
- for secret_name in conf.get('secrets', []):
- secret = layout.secrets[secret_name]
+ for secret_config in conf.get('secrets', []):
+ if isinstance(secret_config, str):
+ secret_name = secret_config
+ secret = layout.secrets[secret_name]
+ else:
+ secret_name = secret_config['name']
+ secret = layout.secrets[secret_config['secret']]
if secret.source_context != job.source_context:
raise Exception(
"Unable to use secret %s. Secrets must be "
"defined in the same project in which they "
"are used" % secret_name)
- secrets.append(secret.decrypt(
- job.source_context.project.private_key))
+ # If the secret declares a different name, set it on the decrypted
+ # copy of the secret object
+ decrypted_secret = secret.decrypt(
+ job.source_context.project.private_key)
+ decrypted_secret.name = secret_name
+ secrets.append(decrypted_secret)
# A job in an untrusted repo that uses secrets requires
# special care. We must note this, and carry this flag