From 5c56d43f64f0310f2d9db5da937e386e604cc836 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Tue, 18 Oct 2022 13:01:02 +0200 Subject: [PATCH 1/4] Add support for globally disabling repo_gpgcheck While developing and/or installing from an already-verified ISO, yum's repo_gpgcheck just gets in the way. This provides a general kill-switch for checking repomd.xml.asc, through commandline or answerfile. Signed-off-by: Yann Dirson --- answerfile.py | 1 + backend.py | 4 ++++ doc/answerfile.txt | 15 +++++++++++++++ doc/parameters.txt | 5 +++++ install.py | 3 +++ repository.py | 8 ++++++-- 6 files changed, 34 insertions(+), 2 deletions(-) diff --git a/answerfile.py b/answerfile.py index 490b49ec..62b0615c 100644 --- a/answerfile.py +++ b/answerfile.py @@ -92,6 +92,7 @@ def processAnswerfile(self): else: raise AnswerfileException("Unknown mode, %s" % install_type) + results['repo-gpgcheck'] = getBoolAttribute(self.top_node, ['repo-gpgcheck'], default=True) results.update(self.parseCommon()) elif self.operation == 'restore': results = self.parseRestore() diff --git a/backend.py b/backend.py index 1788db74..0132885e 100644 --- a/backend.py +++ b/backend.py @@ -395,6 +395,10 @@ def add_repos(main_repositories, update_repositories, repos): for i in answers_pristine['sources']: repos = repository.repositoriesFromDefinition(i['media'], i['address']) add_repos(main_repositories, update_repositories, repos) + repo_gpgcheck = answers.get('repo-gpgcheck', True) + for repo in repos: + if repo in main_repositories: + repo.setRepoGpgCheck(repo_gpgcheck) # A single source coming from an interactive install if 'source-media' in answers_pristine and 'source-address' in answers_pristine: diff --git a/doc/answerfile.txt b/doc/answerfile.txt index 1e1d41d4..8309ef71 100644 --- a/doc/answerfile.txt +++ b/doc/answerfile.txt @@ -34,6 +34,21 @@ Restore: ... + +Common Attributes +----------------- + + repo-gpgcheck="false" + + Disable check of repodata signature (`repo_gpgcheck=0` in + `yum.conf`), for all yum repositories that are not Supplemental + Packs (none of which are checked). Don't use this for a network + install of a production server, and make sure to verify the + authenticity of your install media through other means. + + Validity: any operation. + + Elements common to all answerfiles, both 'installation' and 'restore' --------------------------------------------------------------------- diff --git a/doc/parameters.txt b/doc/parameters.txt index c0f78819..5a2294ca 100644 --- a/doc/parameters.txt +++ b/doc/parameters.txt @@ -220,3 +220,8 @@ Installer --cc-preparations Prepare configuration for common criteria security. + + + --no-repo-gpgcheck + + Disable check of repodata signature, for all yum repositories. diff --git a/install.py b/install.py index 825b569e..e090ea48 100755 --- a/install.py +++ b/install.py @@ -128,6 +128,9 @@ def go(ui, args, answerfile_address, answerfile_script): elif opt == "--cc-preparations": constants.CC_PREPARATIONS = True results['network-backend'] = constants.NETWORK_BACKEND_BRIDGE + elif opt == "--no-repo-gpgcheck": + results['repo-gpgcheck'] = False + logger.log("Yum gpg check of repository disabled on command-line") if boot_console and not serial_console: serial_console = boot_console diff --git a/repository.py b/repository.py index b0fb9716..10e8e5a7 100644 --- a/repository.py +++ b/repository.py @@ -242,6 +242,7 @@ def __init__(self, accessor): super(MainYumRepository, self).__init__(accessor) self._identifier = MAIN_REPOSITORY_NAME self.keyfiles = [] + self._repo_gpg_check = True def get_name_version(config_parser, section, name_key, vesion_key): name, version = None, None @@ -313,9 +314,9 @@ def _repo_config(self): outfh.write(infh.read()) return """ gpgcheck=1 -repo_gpgcheck=1 +repo_gpgcheck=%s gpgkey=file://%s -""" % (key_path) +""" % (int(self._repo_gpg_check), key_path) finally: if infh: infh.close() @@ -351,6 +352,9 @@ def getBranding(self, mounts, branding): branding['product-build'] = self._build_number return branding + def setRepoGpgCheck(self, value): + logger.log("%s: setRepoGpgCheck(%s)" % (self, value)) + self._repo_gpg_check = value class UpdateYumRepository(YumRepositoryWithInfo): """Represents a Yum repository containing packages and associated meta data for an update.""" From afdbe029b9ea253972c79e8090f58576fb5fb6c9 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Tue, 18 Oct 2022 15:58:23 +0200 Subject: [PATCH 2/4] Add support for globally disabling gpgcheck Similar to no-repo-gpgcheck but for RPM sigs. Signed-off-by: Yann Dirson --- answerfile.py | 1 + backend.py | 2 ++ doc/answerfile.txt | 8 ++++++++ doc/parameters.txt | 5 +++++ install.py | 3 +++ repository.py | 9 +++++++-- 6 files changed, 26 insertions(+), 2 deletions(-) diff --git a/answerfile.py b/answerfile.py index 62b0615c..370b928e 100644 --- a/answerfile.py +++ b/answerfile.py @@ -93,6 +93,7 @@ def processAnswerfile(self): raise AnswerfileException("Unknown mode, %s" % install_type) results['repo-gpgcheck'] = getBoolAttribute(self.top_node, ['repo-gpgcheck'], default=True) + results['gpgcheck'] = getBoolAttribute(self.top_node, ['gpgcheck'], default=True) results.update(self.parseCommon()) elif self.operation == 'restore': results = self.parseRestore() diff --git a/backend.py b/backend.py index 0132885e..4d886ccb 100644 --- a/backend.py +++ b/backend.py @@ -396,9 +396,11 @@ def add_repos(main_repositories, update_repositories, repos): repos = repository.repositoriesFromDefinition(i['media'], i['address']) add_repos(main_repositories, update_repositories, repos) repo_gpgcheck = answers.get('repo-gpgcheck', True) + gpgcheck = answers.get('gpgcheck', True) for repo in repos: if repo in main_repositories: repo.setRepoGpgCheck(repo_gpgcheck) + repo.setGpgCheck(gpgcheck) # A single source coming from an interactive install if 'source-media' in answers_pristine and 'source-address' in answers_pristine: diff --git a/doc/answerfile.txt b/doc/answerfile.txt index 8309ef71..23a7a8d1 100644 --- a/doc/answerfile.txt +++ b/doc/answerfile.txt @@ -48,6 +48,14 @@ Common Attributes Validity: any operation. + gpgcheck="false" + + Disable check of rpm signature (`gpgcheck=0` in `yum.conf`), for + all yum repositories that are not Supplemental Packs (none of + which are checked). Don't use this for a production server. + + Validity: any operation. + Elements common to all answerfiles, both 'installation' and 'restore' --------------------------------------------------------------------- diff --git a/doc/parameters.txt b/doc/parameters.txt index 5a2294ca..3f5f3ed3 100644 --- a/doc/parameters.txt +++ b/doc/parameters.txt @@ -225,3 +225,8 @@ Installer --no-repo-gpgcheck Disable check of repodata signature, for all yum repositories. + + + --no-gpgcheck + + Disable check of rpm signature, for all yum repositories. diff --git a/install.py b/install.py index e090ea48..5afb9c8f 100755 --- a/install.py +++ b/install.py @@ -131,6 +131,9 @@ def go(ui, args, answerfile_address, answerfile_script): elif opt == "--no-repo-gpgcheck": results['repo-gpgcheck'] = False logger.log("Yum gpg check of repository disabled on command-line") + elif opt == "--no-gpgcheck": + results['gpgcheck'] = False + logger.log("Yum gpg check of RPMs disabled on command-line") if boot_console and not serial_console: serial_console = boot_console diff --git a/repository.py b/repository.py index 10e8e5a7..13a20818 100644 --- a/repository.py +++ b/repository.py @@ -243,6 +243,7 @@ def __init__(self, accessor): self._identifier = MAIN_REPOSITORY_NAME self.keyfiles = [] self._repo_gpg_check = True + self._gpg_check = True def get_name_version(config_parser, section, name_key, vesion_key): name, version = None, None @@ -313,10 +314,10 @@ def _repo_config(self): outfh = open(key_path, "w") outfh.write(infh.read()) return """ -gpgcheck=1 +gpgcheck=%s repo_gpgcheck=%s gpgkey=file://%s -""" % (int(self._repo_gpg_check), key_path) +""" % (int(self._gpg_check), int(self._repo_gpg_check), key_path) finally: if infh: infh.close() @@ -356,6 +357,10 @@ def setRepoGpgCheck(self, value): logger.log("%s: setRepoGpgCheck(%s)" % (self, value)) self._repo_gpg_check = value + def setGpgCheck(self, value): + logger.log("%s: setGpgCheck(%s)" % (self, value)) + self._gpg_check = value + class UpdateYumRepository(YumRepositoryWithInfo): """Represents a Yum repository containing packages and associated meta data for an update.""" From 22c5b0b119c1835ed1a253b0a8f2f96c551357ff Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Mon, 24 Oct 2022 17:42:21 +0200 Subject: [PATCH 3/4] answerfile: support *gpgcheck override for each Global *gpgcheck flag can change the default from True to False, and these new flags allow to override this default on a per-source basis. Signed-off-by: Yann Dirson --- answerfile.py | 16 +++++++++++++++- backend.py | 6 ++++-- doc/answerfile.txt | 9 +++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/answerfile.py b/answerfile.py index 370b928e..742bf701 100644 --- a/answerfile.py +++ b/answerfile.py @@ -268,7 +268,21 @@ def parseSource(self): if rtype == 'url': address = util.URL(address) - results['sources'].append({'media': rtype, 'address': address}) + # workaround getBoolAttribute() not allowing "None" as + # default, by using a getStrAttribute() call first to + # handle the default situation where the attribute is not + # specified + repo_gpgcheck = (None if getStrAttribute(i, ['repo-gpgcheck'], default=None) is None + else getBoolAttribute(i, ['repo-gpgcheck'])) + gpgcheck = (None if getStrAttribute(i, ['gpgcheck'], default=None) is None + else getBoolAttribute(i, ['gpgcheck'])) + + results['sources'].append({ + 'media': rtype, 'address': address, + 'repo_gpgcheck': repo_gpgcheck, + 'gpgcheck': gpgcheck, + }) + logger.log("parsed source %s" % results['sources'][-1]) return results diff --git a/backend.py b/backend.py index 4d886ccb..d5a2e39a 100644 --- a/backend.py +++ b/backend.py @@ -395,8 +395,10 @@ def add_repos(main_repositories, update_repositories, repos): for i in answers_pristine['sources']: repos = repository.repositoriesFromDefinition(i['media'], i['address']) add_repos(main_repositories, update_repositories, repos) - repo_gpgcheck = answers.get('repo-gpgcheck', True) - gpgcheck = answers.get('gpgcheck', True) + repo_gpgcheck = (answers.get('repo-gpgcheck', True) if i['repo_gpgcheck'] is None + else i['repo_gpgcheck']) + gpgcheck = (answers.get('gpgcheck', True) if i['gpgcheck'] is None + else i['gpgcheck']) for repo in repos: if repo in main_repositories: repo.setRepoGpgCheck(repo_gpgcheck) diff --git a/doc/answerfile.txt b/doc/answerfile.txt index 23a7a8d1..3c86e48e 100644 --- a/doc/answerfile.txt +++ b/doc/answerfile.txt @@ -123,6 +123,15 @@ Elements for 'installation' modes The location of the installation repository or a Supplemental Pack. There may be multiple 'source' elements. + Optional attributes for only: + + repo-gpgcheck=bool + gpgcheck=bool + + Override the global yum gpgcheck setting, respectively for + repodata and RPMs, for this source only. Only applies to + repositories that are not Supplemental Packs (none of which + are checked). grub2|extlinux[D]|grub[D]? From 9c07411cfe8a18bec328f156ce71dc484dc91570 Mon Sep 17 00:00:00 2001 From: Yann Dirson Date: Mon, 14 Nov 2022 11:15:43 +0100 Subject: [PATCH 4/4] Fix interactive install to honor no-*gpgcheck from commandline When originally implementing the per-source gpgcheck flags in answerfile[1], the full code was moved to an anwerfile-only location, breaking the original interactive-install implementation (and then following code review[2] the working code for interactive install disappeared further from the patch series). This moves the Repository flag-setting to `add_repos()` common code, while leaving the flag computation to the caller, since only the answerfile case has to do any non-trivial logic. - [1] https://github.com/xcp-ng/host-installer/commit/06b700789f2c22d1c78285f9583937511e4d3c07 - [2] https://github.com/xcp-ng/host-installer/pull/2#discussion_r1012080594 Signed-off-by: Yann Dirson --- backend.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/backend.py b/backend.py index d5a2e39a..6ffe79bb 100644 --- a/backend.py +++ b/backend.py @@ -373,7 +373,7 @@ def handleRepos(repos, ans): main_repositories = [] update_repositories = [] - def add_repos(main_repositories, update_repositories, repos): + def add_repos(main_repositories, update_repositories, repos, repo_gpgcheck, gpgcheck): """Add repositories to the appropriate list, ensuring no duplicates, that the main repository is at the beginning, and that the order of the rest is maintained.""" @@ -390,28 +390,28 @@ def add_repos(main_repositories, update_repositories, repos): else: repo_list.append(repo) + if repo_list is main_repositories: # i.e., if repo is a "main repository" + repo.setRepoGpgCheck(repo_gpgcheck) + repo.setGpgCheck(gpgcheck) + + default_repo_gpgcheck = answers.get('repo-gpgcheck', True) + default_gpgcheck = answers.get('gpgcheck', True) # A list of sources coming from the answerfile if 'sources' in answers_pristine: for i in answers_pristine['sources']: repos = repository.repositoriesFromDefinition(i['media'], i['address']) - add_repos(main_repositories, update_repositories, repos) - repo_gpgcheck = (answers.get('repo-gpgcheck', True) if i['repo_gpgcheck'] is None - else i['repo_gpgcheck']) - gpgcheck = (answers.get('gpgcheck', True) if i['gpgcheck'] is None - else i['gpgcheck']) - for repo in repos: - if repo in main_repositories: - repo.setRepoGpgCheck(repo_gpgcheck) - repo.setGpgCheck(gpgcheck) + repo_gpgcheck = default_repo_gpgcheck if i['repo_gpgcheck'] is None else i['repo_gpgcheck'] + gpgcheck = default_gpgcheck if i['gpgcheck'] is None else i['gpgcheck'] + add_repos(main_repositories, update_repositories, repos, repo_gpgcheck, gpgcheck) # A single source coming from an interactive install if 'source-media' in answers_pristine and 'source-address' in answers_pristine: repos = repository.repositoriesFromDefinition(answers_pristine['source-media'], answers_pristine['source-address']) - add_repos(main_repositories, update_repositories, repos) + add_repos(main_repositories, update_repositories, repos, default_repo_gpgcheck, default_gpgcheck) for media, address in answers_pristine['extra-repos']: repos = repository.repositoriesFromDefinition(media, address) - add_repos(main_repositories, update_repositories, repos) + add_repos(main_repositories, update_repositories, repos, default_repo_gpgcheck, default_gpgcheck) if not main_repositories or main_repositories[0].identifier() != MAIN_REPOSITORY_NAME: raise RuntimeError("No main repository found")