Skip to content

Commit 85c2a41

Browse files
committed
Fix FIPS enabled cluster operations
Make sure host system is FIPS enabled and proper installer is downloaded
1 parent 5452052 commit 85c2a41

File tree

4 files changed

+506
-478
lines changed

4 files changed

+506
-478
lines changed

Diff for: osia/cli.py

+42-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
openshift"""
1818
import argparse
1919
import logging
20-
from typing import List
20+
from typing import List, Tuple, Optional
21+
from subprocess import Popen
22+
from semantic_version import Version, SimpleSpec
2123
import coloredlogs
24+
import distro
2225

2326
from .config.config import ARCH_AMD, ARCH_ARM, ARCH_X86_64, ARCH_AARCH64, ARCH_S390X, ARCH_PPC
2427
from .installer import install_cluster, delete_cluster, storage, download_installer
@@ -84,16 +87,50 @@ def _read_list(in_str: str) -> List[str]:
8487
a['proc'] = _identity
8588

8689

90+
def _check_fips_compatible() -> Tuple[bool, Optional[str]]:
91+
rhel_version = None
92+
if distro.id() == "rhel":
93+
rhel_version = distro.major_version()
94+
95+
if not rhel_version:
96+
return False, "FIPS installs are supported only from RHEL systems"
97+
try:
98+
with Popen(["fips-mode-setup", "--check"]) as proc:
99+
proc.wait()
100+
if proc.returncode != 0:
101+
return False, "FIPS is not enabled on the system"
102+
except FileNotFoundError:
103+
return False, "fips-mode-setup must be installed on the system"
104+
105+
return True, None
106+
107+
87108
def _resolve_installer(from_args):
88109
if from_args.installer is None and from_args.installer_version is None:
89110
raise Exception('Either installer or installer-version must be passed')
90111
if from_args.installer:
91112
return from_args.installer
92113

114+
rhel_version = None
115+
if distro.id() == "rhel":
116+
rhel_version = distro.major_version()
117+
118+
if from_args.enable_fips:
119+
supported, msg = _check_fips_compatible()
120+
if not supported:
121+
raise Exception(msg)
122+
123+
if Version.coerce(from_args.installer_version.split("-")[-1]) in SimpleSpec("<4.16"):
124+
# ocp <4.16 does not have dedicated openshift-install-fips, it is
125+
# fine to run normal installer on FIPS enabled RHEL
126+
from_args.enable_fips = False
127+
93128
return download_installer(from_args.installer_version,
94129
from_args.installer_arch,
95130
from_args.installers_dir,
96-
from_args.installer_source)
131+
from_args.installer_source,
132+
rhel_version=rhel_version,
133+
fips=from_args.enable_fips)
97134

98135

99136
def _merge_dictionaries(from_args):
@@ -122,6 +159,9 @@ def _exec_install_cluster(args):
122159

123160

124161
def _exec_delete_cluster(args):
162+
# cleanup of fips cluster can be done from anywhere
163+
args.enable_fips = None
164+
125165
conf = _merge_dictionaries(args)
126166

127167
if not args.skip_git:

Diff for: osia/installer/downloader/install.py

+48-21
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,12 @@
3535
BUILD_ROOT = "https://openshift-release-artifacts.svc.ci.openshift.org/"
3636
PREVIEW_ROOT = "http://mirror.openshift.com/pub/openshift-v4/{}/clients/ocp-dev-preview/"
3737

38-
VERSION_RE = re.compile(r"^openshift-install-(?P<platform>\w+)"
39-
r"(-(?P<architecture>\w+))?-(?P<version>\d+.*)\.tar\.gz")
38+
VERSION_RE = re.compile(r"^openshift-install(-rhel(?P<rhel>\d+))?(-(?P<platform>(linux|mac)))?"
39+
r"(-(?P<architecture>\w+))?(-(?P<version>\d+.*))?\.tar\.gz")
4040
EXTRACTION_RE = re.compile(r'.*Extracting tools for .*, may take up to a minute.*')
4141

4242

43-
def _current_platform():
43+
def _current_platform() -> Tuple[str, str]:
4444
if platform.system() == "Linux" and platform.machine() == "x86_64":
4545
return "linux", "amd64"
4646
if platform.system() == "Linux" and platform.machine() == "arm64":
@@ -53,10 +53,14 @@ def _current_platform():
5353
raise Exception(f"Unrecognized platform {platform.system()} {platform.machine()}")
5454

5555

56-
def get_url(directory: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
56+
def get_url(directory: str, arch: str, fips: bool = False,
57+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
5758
"""Searches the http directory and returns both url to installer
5859
and version.
5960
"""
61+
if fips and not rhel_version:
62+
raise Exception("Rhel version was not detected. Please download installer separatly.")
63+
6064
logging.debug('Url for installers look-up %s', directory)
6165
lst = requests.get(directory, allow_redirects=True)
6266
tree = BeautifulSoup(lst.content, 'html.parser')
@@ -66,16 +70,29 @@ def get_url(directory: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
6670
for k in links:
6771
logging.debug('Parsing link: %s', k.get('href'))
6872
match = VERSION_RE.match(k.get('href'))
69-
if match and match.group('platform') == os_name:
70-
if (local_arch == match.group('architecture')) \
71-
or (local_arch == arch and not match.group('architecture')):
72-
installer = lst.url + k.get('href')
73+
74+
if match:
75+
if match.group("version"):
7376
version = match.group('version')
77+
78+
if fips and match.group("rhel") == rhel_version:
79+
installer = lst.url + k.get('href')
7480
break
81+
82+
if not fips and match.group('platform') == os_name:
83+
if (local_arch == match.group('architecture')) \
84+
or (local_arch == arch and not match.group('architecture')):
85+
installer = lst.url + k.get('href')
86+
break
87+
else:
88+
if fips:
89+
raise Exception(f"FIPS Installer not found for {rhel_version=}")
90+
raise Exception("Installer not found")
7591
return installer, version
7692

7793

78-
def get_devel_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
94+
def get_devel_url(version: str, arch: str, fips: bool = False,
95+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
7996
"""
8097
Searches developement sources and returns url to installer
8198
"""
@@ -88,17 +105,19 @@ def get_devel_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]
88105
req = requests.get(BUILD_ROOT + version, allow_redirects=True)
89106
ast = BeautifulSoup(req.content, 'html.parser')
90107
logging.debug('Installer found on page, continuing')
91-
return get_url(req.url, arch)
108+
return get_url(req.url, arch, fips, rhel_version)
92109

93110

94-
def get_prev_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
111+
def get_prev_url(version: str, arch: str, fips: bool = False,
112+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
95113
"""Returns installer url from dev-preview sources"""
96-
return get_url(PREVIEW_ROOT.format(arch) + version + "/", arch)
114+
return get_url(PREVIEW_ROOT.format(arch) + version + "/", arch, fips, rhel_version)
97115

98116

99-
def get_prod_url(version: str, arch: str) -> Tuple[Optional[str], Optional[str]]:
117+
def get_prod_url(version: str, arch: str, fips: bool = False,
118+
rhel_version: str = None) -> Tuple[Optional[str], Optional[str]]:
100119
"""Returns installer url from production sources"""
101-
return get_url(PROD_ROOT.format(arch) + version + "/", arch)
120+
return get_url(PROD_ROOT.format(arch) + version + "/", arch, fips, rhel_version)
102121

103122

104123
def _get_storage_path(version: str, install_base: str) -> str:
@@ -114,12 +133,12 @@ def _extract_tar(buffer: NamedTemporaryFile, target: str) -> Path:
114133
with tarfile.open(buffer.name) as tar:
115134
inst_info = None
116135
for i in tar.getmembers():
117-
if i.name == 'openshift-install':
136+
if i.name in ['openshift-install', 'openshift-install-fips']:
118137
inst_info = i
119138
if inst_info is None:
120139
raise Exception("error")
121140
stream = tar.extractfile(inst_info)
122-
result = Path(target).joinpath('openshift-install')
141+
result = Path(target).joinpath(inst_info.name)
123142
with result.open('wb') as output:
124143
copyfileobj(stream, output)
125144
result.chmod(result.stat().st_mode | stat.S_IXUSR)
@@ -131,10 +150,13 @@ def get_installer(tar_url: str, target: str):
131150
return get_data(tar_url, target, _extract_tar)
132151

133152

153+
# pylint: disable=too-many-arguments
134154
def download_installer(installer_version: str,
135155
installer_arch: str,
136156
dest_directory: str,
137-
source: str) -> str:
157+
source: str,
158+
fips: bool = False,
159+
rhel_version: str = None) -> str:
138160
"""Starts search and extraction of installer"""
139161
logging.debug("Getting version %s of %s, storing to directory %s and devel is %r",
140162
installer_version, installer_arch, dest_directory, source)
@@ -149,12 +171,17 @@ def download_installer(installer_version: str,
149171
else:
150172
raise Exception("Error for source profile " + source)
151173

152-
url, version = downloader(installer_version, installer_arch)
174+
url, version = downloader(installer_version, installer_arch, fips, rhel_version)
153175
logging.debug('Installer\'s URL is %s and full version is %s', url, version)
154176
root = Path(dest_directory).joinpath(version)
155177

156-
if root.exists() and root.joinpath('openshift-install').exists():
178+
installer_exe_name = 'openshift-install'
179+
180+
if fips:
181+
installer_exe_name = 'openshift-install-fips'
182+
183+
if root.exists() and root.joinpath(installer_exe_name).exists():
157184
logging.info('Found installer at %s', root.as_posix())
158-
return root.joinpath('openshift-install').as_posix()
159-
root.mkdir(parents=True)
185+
return root.joinpath(installer_exe_name).as_posix()
186+
root.mkdir(parents=True, exist_ok=True)
160187
return get_installer(url, root.as_posix())

0 commit comments

Comments
 (0)