-
Notifications
You must be signed in to change notification settings - Fork 24.1k
rpm_key: support multiple siging keys #83493
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: devel
Are you sure you want to change the base?
Conversation
Google makes a RPM key file containing multiple public keys publicly avaiable which is great for making sure ansible's rpm_key module can handle multiple keys being present in a single file.
Multiple keys can be concatenated into a single file however. This aims to make the module check for multiple key fingerprints beng present in a single file. This also allows for a list of fingerprints to be passed to module arguments for verification. If there's any mismatch, then the module throws an error.
…ible/ansible/pull/75251/files#r670746523) restore normalize_keyid() for unit testing (https://github.com/ansible/ansible/pull/75251/files#r670747283)
|
The test The test |
|
I would like to remove the RHEL9 SHA1 deprecation from /test/integration/targets/rpm_key/tasks/rpm_key.yaml To be able to do that i guess a GPG key file would need to be added to https://ci-files.testing.ansible.com/test/integration/targets/ That file needs to contain keys with at least two different fingerprints and those keys have to comply with the SHA-1 deprecation in RHEL 9. The example ('Google GPG keys') from the original PR will result in
|
|
|
||
| - name: Issue 83493 - Verify key fingerprints. This should fail due to multiple key signatures | ||
| rpm_key: | ||
| key: /tmp/KEY_83493 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this. You should be able to swap this out for https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/rpm_key/linux_signing_key.pub now and remove the few tasks preceding this one.
| @@ -0,0 +1,7 @@ | |||
| minor_changes: | |||
| - > | |||
| rpm_key - Check for multiple signing keys in a single GPG key file. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you rephrase this in non-imperative mood? The writing style is inconsistent with the following entry (and likely many other changelog fragments).
This is going to show up in the aggregated change log document on release. That document refers to the changes that have already happened since the previous release, so it's natural to describe things as if they are already merged. Imperative mood is a better fit for Git commit summary lines and TODO entries, but change logs have different style, purpose and audience.
| self.rpm = self.module.get_bin_path('rpm', True) | ||
| state = module.params['state'] | ||
| key = module.params['key'] | ||
| fingerprint = module.params['fingerprint'] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is now a list, seeing code iterating over a variable called as a single item reads somewhat counterintuitive.
May I suggest renaming the variable to fingerprints? Even if you keep the public interface with the original name. This will make the code easier to reason about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or even expected_fingerprints?
| if not keyfile: | ||
| self.module.fail_json(msg="When importing a key, a valid file must be given") | ||
| if fingerprint: | ||
| has_fingerprint = self.getfingerprint(keyfile) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This var should probably be called differently. Currently, set(has_fingerprint) looks as if a boolean is passed to the set() constructor. Perhaps, computed_fingerprint?
| if fingerprint: | ||
| has_fingerprint = self.getfingerprint(keyfile) | ||
| if fingerprint != has_fingerprint: | ||
| if set(fingerprint) != set(has_fingerprint): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be something along the lines of
| if set(fingerprint) != set(has_fingerprint): | |
| if any(fgrprnt not in computed_fingerprint for fgrprnt in fingerprints): |
?
Perhaps, this entire expression could be assigned to a variable, so its intended purpose could be labeled via a variable name?
| """Ensure a keyid doesn't have a leading 0x, has leading or trailing whitespace, and make sure is uppercase""" | ||
| ret = keyid.strip().upper() | ||
| if ret.startswith('0x'): | ||
| if ret.startswith("0x"): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pro tip: mixing formatting changes with functional ones is discouraged because it makes it harder for the reviewers to identify which places in the patch are useful payload. These should always be separated.
| return line.split(':')[4] | ||
| keyids.append(line.split(':')[4]) | ||
|
|
||
| if keyids == []: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what people usually expect in Python:
| if keyids == []: | |
| if not keyids: |
| imported_ids.add(keyid) | ||
|
|
||
| missing_keys = set(keyids).difference(imported_ids) | ||
| return len(missing_keys) == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this could be
| return len(missing_keys) == 0 | |
| return not missing_keys |
| missing_keys = set(keyids).difference(imported_ids) | ||
| return len(missing_keys) == 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though, I'd probably label the expression with what it intends to compute and return that:
| missing_keys = set(keyids).difference(imported_ids) | |
| return len(missing_keys) == 0 | |
| some_gpg_keys_missing = bool(set(keyids) - imported_ids) | |
| return some_gpg_keys_missing |
(I think that “return whether the length of a set of missing keys is zero” might be more difficult to parse vs. “return whether some GPG keys are missing” — it's low level vs. high level)
| - name: Issue 83493 - Verify key fingerprints. This should fail due to multiple key signatures | ||
| rpm_key: | ||
| key: https://ansible-ci-files.s3.amazonaws.com/test/integration/targets/rpm_key/linux_signing_key.pub | ||
| fingerprint: 1B09 0CE4 7562 66D7 1203 13F6 3BAC 309A 6EB4 25D5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I'm wrong, but isn't this a breaking change?
I think the current case is that users would only need to list one of the keys which appears in the import, and this test suggests that all keys would need to be listed for verification. I can imagine scenarios where users upload all their signing keys to a single file and then check for different keys in different modules. This change would break that usage if I have how it currently works right.
SUMMARY
Fixes # #83394
Took the changes from #75251 (for #50615) - which implement checking for multiple key ids when importing keys with the rpm_key module (see #75251 (comment)):
Make rpm_key module use lists for key ids since a single key file can contain multiple keys.
I also made the fingerprint option accept lists of fingerprints since they correspond with key ids. All fingerprints in a keyfile should be present when the fingerprints option is set for task success.
ISSUE TYPE
COMPONENT NAME
rpm_key
ADDITIONAL INFORMATION
Fixed the concerns from @sivel regarding # #75251:
comparing the keys against the actual content of keyids instead of asserting the lengths are equal (Make rpm_key aware of multiple keys in a keyfile #75251 (comment))
keeping the normalize_keyid function and creating a normalize_keyids funtion that calls the singular version for unit testing (Make rpm_key aware of multiple keys in a keyfile #75251 (comment))
Additional Info from #75251
Example:
The rpm_key module only checked for the presence of the first key in a file when importing keys from files. This meant that in cases where a single file contained multiple keys it was possible for later keys to not be imported if the first key in a key file was already installed. It could also mean that multiple keys could be installed even when only expecting a single key in a file.