Merge ~ahasenack/ubuntu/+source/ubuntu-advantage-tools:v17-fips-updates into ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel
- Git
- lp:~ahasenack/ubuntu/+source/ubuntu-advantage-tools
- v17-fips-updates
- Merge into ubuntu/devel
Status: | Merged |
---|---|
Merge reported by: | Andreas Hasenack |
Merged at revision: | 25878f5d7e4c18e97cf7118be3440f030fc9adbe |
Proposed branch: | ~ahasenack/ubuntu/+source/ubuntu-advantage-tools:v17-fips-updates |
Merge into: | ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel |
Diff against target: |
779 lines (+437/-49) 14 files modified
.gitignore (+4/-0) debian/changelog (+12/-0) modules/apt.sh (+14/-2) modules/service-esm.sh (+2/-2) modules/service-fips.sh (+110/-17) modules/service-livepatch.sh (+1/-1) modules/service.sh (+6/-6) modules/utils.sh (+20/-0) tests/test_esm.py (+2/-2) tests/test_fips.py (+172/-1) tests/test_script.py (+12/-0) tests/testing.py (+16/-3) ubuntu-advantage (+47/-15) ubuntu-advantage.1 (+19/-0) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Christian Ehrhardt (community) | Approve | ||
Steve Langasek (community) | Approve | ||
Canonical Server Core Reviewers | Pending | ||
Canonical Server | Pending | ||
Review via email: mp+342208@code.launchpad.net |
Commit message
Description of the change
ubuntu-
The bug this is fixing is a Feature Freeze Exception request, which was granted provided there are no new package relations introduced, which is correct.
PPA with bionic test packages: https:/
sudo add-apt-repository ppa:ahasenack/
Andreas Hasenack (ahasenack) wrote : | # |
Andreas Hasenack (ahasenack) wrote : | # |
That is boiling down to a manual mirroring from github from the landed pull requests. The commits and individual pull requests can be seen in https:/
Steve Langasek (vorlon) wrote : | # |
Reviewing with respect to archive and feature freeze only. Comments inline.
Christian Ehrhardt (paelzer) wrote : | # |
Some potential improvements inline, but could as well be on the next version being uploaded.
I'll set need info and leave it to you if you want to address now or later.
Andreas Hasenack (ahasenack) wrote : | # |
Replied to commends from Steve and Christian inline. Thanks guys!
Andreas Hasenack (ahasenack) wrote : | # |
Upstream issues opened.
Christian Ehrhardt (paelzer) wrote : | # |
All that was asked was explained and I agree to those you opened new bugs for.
As I said none of these has to be in this upload.
Approve +1
Joy Latten (j-latten) wrote : | # |
We were not able to anticipate which fips modules a customer wants, so the enable-fips installs all the certified fips modules. Thus naturally assumed the update-fips should update all of them. Manual install instructions are published and provided for customers that prefer to "customize" their fips installations. See, https:/
Given that after initial installation, whether done manually or via enable-fips, a customer may have removed fips modules not desired or only installed those desired, the update-fips perhaps should loop thru and see which fips modules are installed, and only update those. In the special case of an update-fips being called where no fips modules have been installed, the script can just install all the updated fips modules similar to the enable-fips.
If that sounds good, then I can open an issue in github to do that.
In regards to fips updates, both potential and existing customers have indicated they would like "updated" fips modules, that is, they want fips modules with bugfixes and CVEs applied and is ok if these "updated" fips modules are not re-certified. They want the fips code paths and fips approved algorithms. For example, not all the fips approved algorithms are in the corresponding, regular version of ssl. We also found this is what several other major Linux distros do as well. So we are giving customers choice of strict fips compliance with fips certified modules from fips ppa and|or the ability to run in "fips mode" with CVEs+bugfixes on top of the fips-certified modules from fips-update ppa. We decided to include that warning or info message in update-fips to do just that, provide info and warn, just in case. Thus absolving us of any potential liability or misunderstanding. Hopefully, that all seems ok. We are learning as we go.
Andreas Hasenack (ahasenack) wrote : | # |
Thanks Christian.
I need sponsoring for this package, if you could please push the upload tag and dput the package, thanks.
Christian Ehrhardt (paelzer) wrote : | # |
Tag push and sponsoring done as requested
Preview Diff
1 | diff --git a/.gitignore b/.gitignore |
2 | new file mode 100644 |
3 | index 0000000..34972a2 |
4 | --- /dev/null |
5 | +++ b/.gitignore |
6 | @@ -0,0 +1,4 @@ |
7 | +*.pyc |
8 | +*.pyo |
9 | +__pycache__ |
10 | +.tox |
11 | diff --git a/debian/changelog b/debian/changelog |
12 | index bb95c3d..39ea084 100644 |
13 | --- a/debian/changelog |
14 | +++ b/debian/changelog |
15 | @@ -1,3 +1,15 @@ |
16 | +ubuntu-advantage-tools (17) bionic; urgency=medium |
17 | + |
18 | + * New upstream release (LP: #1759280): |
19 | + - Added enable-fips-updates command. This command enables the fips-updates |
20 | + repository to install updates to FIPS modules. The updated modules from |
21 | + fips-updates repository are non-certified. |
22 | + - Add repository pinning for FIPS packages |
23 | + - Check that all prerequisite packages are installed when enabling FIPS |
24 | + - Support returning the status for a single service |
25 | + |
26 | + -- Andreas Hasenack <andreas@canonical.com> Wed, 21 Mar 2018 14:20:04 -0300 |
27 | + |
28 | ubuntu-advantage-tools (16) bionic; urgency=medium |
29 | |
30 | * d/t/update-motd-run: fix path to the esm motd (LP: #1757490) |
31 | diff --git a/keyrings/ubuntu-fips-updates-keyring.gpg b/keyrings/ubuntu-fips-updates-keyring.gpg |
32 | new file mode 100644 |
33 | index 0000000..d00f63f |
34 | Binary files /dev/null and b/keyrings/ubuntu-fips-updates-keyring.gpg differ |
35 | diff --git a/modules/apt.sh b/modules/apt.sh |
36 | index 8a9a2ab..3d73d12 100644 |
37 | --- a/modules/apt.sh |
38 | +++ b/modules/apt.sh |
39 | @@ -35,19 +35,31 @@ apt_remove_repo() { |
40 | _apt_remove_auth "$repo_url" |
41 | } |
42 | |
43 | +apt_add_repo_pinning() { |
44 | + local repo_file="$1" |
45 | + local origin="$2" |
46 | + local priority="$3" |
47 | + |
48 | + cat <<EOF >"$repo_file" |
49 | +Package: * |
50 | +Pin: release o=${origin}, n=${SERIES} |
51 | +Pin-Priority: ${priority} |
52 | +EOF |
53 | +} |
54 | + |
55 | apt_get() { |
56 | DEBIAN_FRONTEND=noninteractive \ |
57 | apt-get -y -o Dpkg::Options::='--force-confold' "$@" |
58 | } |
59 | |
60 | -is_package_installed() { |
61 | +apt_is_package_installed() { |
62 | local package="$1" |
63 | |
64 | dpkg-query -s "$package" >/dev/null 2>&1 |
65 | } |
66 | |
67 | # Install a package if the specified file doesn't exist |
68 | -install_package_if_missing_file() { |
69 | +apt_install_package_if_missing_file() { |
70 | local file="$1" |
71 | local package="$2" |
72 | |
73 | diff --git a/modules/service-esm.sh b/modules/service-esm.sh |
74 | index 0bbfaa2..de281f8 100644 |
75 | --- a/modules/service-esm.sh |
76 | +++ b/modules/service-esm.sh |
77 | @@ -14,8 +14,8 @@ esm_enable() { |
78 | check_token "$ESM_REPO_URL" "$token" |
79 | apt_add_repo "$ESM_REPO_LIST" "$ESM_REPO_URL" "$token" \ |
80 | "${KEYRINGS_DIR}/${ESM_REPO_KEY_FILE}" |
81 | - install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https |
82 | - install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates |
83 | + apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https |
84 | + apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates |
85 | echo -n 'Running apt-get update... ' |
86 | check_result apt_get update |
87 | echo 'Ubuntu ESM repository enabled.' |
88 | diff --git a/modules/service-fips.sh b/modules/service-fips.sh |
89 | index 38c2c6d..4df3872 100644 |
90 | --- a/modules/service-fips.sh |
91 | +++ b/modules/service-fips.sh |
92 | @@ -7,6 +7,11 @@ FIPS_SUPPORTED_ARCHS="x86_64 ppc64le s390x" |
93 | FIPS_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/fips" |
94 | FIPS_REPO_KEY_FILE="ubuntu-fips-keyring.gpg" |
95 | FIPS_REPO_LIST=${FIPS_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-fips-${SERIES}.list"} |
96 | +FIPS_REPO_PREFERENCES=${FIPS_REPO_PREFERENCES:-"/etc/apt/preferences.d/ubuntu-fips-${SERIES}"} |
97 | +FIPS_UPDATES_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/fips-updates" |
98 | +FIPS_UPDATES_REPO_KEY_FILE="ubuntu-fips-updates-keyring.gpg" |
99 | +FIPS_UPDATES_REPO_LIST=${FIPS_UPDATES_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-fips-updates-${SERIES}.list"} |
100 | +FIPS_UPDATES_REPO_PREFERENCES=${FIPS_UPDATES_REPO_PREFERENCES:-"/etc/apt/preferences.d/ubuntu-fips-updates-${SERIES}"} |
101 | FIPS_ENABLED_FILE=${FIPS_ENABLED_FILE:-"/proc/sys/crypto/fips_enabled"} |
102 | if [ "$ARCH" = "s390x" ]; then |
103 | FIPS_BOOT_CFG=${FIPS_BOOT_CFG:-"/etc/zipl.conf"} |
104 | @@ -15,28 +20,30 @@ else |
105 | FIPS_BOOT_CFG=${FIPS_BOOT_CFG:-"${FIPS_BOOT_CFG_DIR}/99-fips.cfg"} |
106 | fi |
107 | FIPS_HMAC_PACKAGES="openssh-client-hmac openssh-server-hmac libssl1.0.0-hmac \ |
108 | - linux-fips strongswan-hmac" |
109 | + linux-fips strongswan-hmac" |
110 | +FIPS_OTHER_PACKAGES="openssh-client openssh-server openssl libssl1.0.0 \ |
111 | + fips-initramfs strongswan" |
112 | |
113 | fips_enable() { |
114 | local token="$1" |
115 | |
116 | - _fips_check_packages_installed || error_exit service_already_enabled |
117 | + _fips_check_installed || error_exit service_already_enabled |
118 | |
119 | check_token "$FIPS_REPO_URL" "$token" |
120 | apt_add_repo "$FIPS_REPO_LIST" "$FIPS_REPO_URL" "$token" \ |
121 | "${KEYRINGS_DIR}/${FIPS_REPO_KEY_FILE}" |
122 | - install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https |
123 | - install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates |
124 | + apt_add_repo_pinning "$FIPS_REPO_PREFERENCES" \ |
125 | + LP-PPA-ubuntu-advantage-fips 1001 |
126 | + apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https |
127 | + apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates |
128 | echo -n 'Running apt-get update... ' |
129 | check_result apt_get update |
130 | echo 'Ubuntu FIPS PPA repository enabled.' |
131 | |
132 | # install all the fips packages |
133 | echo -n 'Installing FIPS packages (this may take a while)... ' |
134 | - check_result apt_get install openssh-client openssh-client-hmac \ |
135 | - openssh-server openssh-server-hmac openssl libssl1.0.0 \ |
136 | - libssl1.0.0-hmac fips-initramfs linux-fips \ |
137 | - strongswan strongswan-hmac |
138 | + # shellcheck disable=SC2086 |
139 | + check_result apt_get install $FIPS_HMAC_PACKAGES $FIPS_OTHER_PACKAGES |
140 | |
141 | echo "Configuring FIPS... " |
142 | _fips_configure |
143 | @@ -47,8 +54,73 @@ fips_disable() { |
144 | not_supported 'Disabling FIPS' |
145 | } |
146 | |
147 | +fips_updates_enable() { |
148 | + local token="$1" |
149 | + local bypass_prompt="$2" |
150 | + |
151 | + local fips_configured=0 |
152 | + local fips_kernel_version=0 |
153 | + local result=0 |
154 | + |
155 | + _fips_updates_is_enabled || result=$? |
156 | + if [ $result -eq 0 ]; then |
157 | + error_msg "FIPS-UPDATES repository is already enabled." |
158 | + error_exit service_already_enabled |
159 | + fi |
160 | + |
161 | + check_token "$FIPS_UPDATES_REPO_URL" "$token" |
162 | + |
163 | + echo "Installing updates from FIPS-UPDATES repository will take the system out of FIPS compliance." |
164 | + if [ "$bypass_prompt" -ne 1 ]; then |
165 | + if ! prompt_user 'Do you want to proceed?'; then |
166 | + error_msg "Aborting updating FIPS packages..." |
167 | + return |
168 | + fi |
169 | + fi |
170 | + |
171 | + # add the fips-updates repo if the system is undergoing updates the first time |
172 | + if [ ! -f "$FIPS_UPDATES_REPO_LIST" ]; then |
173 | + apt_add_repo "$FIPS_UPDATES_REPO_LIST" "$FIPS_UPDATES_REPO_URL" "$token" \ |
174 | + "${KEYRINGS_DIR}/${FIPS_UPDATES_REPO_KEY_FILE}" |
175 | + apt_add_repo_pinning "$FIPS_UPDATES_REPO_PREFERENCES" \ |
176 | + LP-PPA-ubuntu-advantage-fips-updates 1001 |
177 | + apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https |
178 | + apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates |
179 | + echo -n 'Running apt-get update... ' |
180 | + check_result apt_get update |
181 | + echo 'Ubuntu FIPS-UPDATES PPA repository enabled.' |
182 | + fi |
183 | + |
184 | + # if a fips package is found on the system, assume fips was configured before |
185 | + # users could be running with fips=0 or fips=1, so just checking package here |
186 | + if apt_is_package_installed fips-initramfs; then |
187 | + fips_configured=1 |
188 | + # get the fips kernel version installed here |
189 | + fips_kernel_version=$(package_version linux-fips) |
190 | + fi |
191 | + |
192 | + # update all the fips packages |
193 | + echo -n 'Updating FIPS packages (this may take a while)... ' |
194 | + # shellcheck disable=SC2086 |
195 | + check_result apt_get install $FIPS_HMAC_PACKAGES $FIPS_OTHER_PACKAGES |
196 | + |
197 | + # if fips was never configured before and is enabled for the |
198 | + # first time, configure fips |
199 | + if [ "$fips_configured" -eq 0 ]; then |
200 | + echo "Configuring FIPS... " |
201 | + _fips_configure |
202 | + fi |
203 | + echo "Successfully updated FIPS packages." |
204 | + |
205 | + # show the message to reboot only if fips kernel has undergone an upgrade or fips is |
206 | + # being configured the first time |
207 | + if [ "$fips_kernel_version" != "$(package_version linux-fips)" ] || [ "$fips_configured" -eq 0 ]; then |
208 | + echo "Please reboot into the new FIPS kernel." |
209 | + fi |
210 | +} |
211 | + |
212 | fips_is_enabled() { |
213 | - is_package_installed fips-initramfs && [ "$(_fips_enabled_check)" -eq 1 ] |
214 | + apt_is_package_installed fips-initramfs && [ "$(_fips_enabled_check)" -eq 1 ] |
215 | } |
216 | |
217 | fips_validate_token() { |
218 | @@ -80,6 +152,21 @@ fips_check_support() { |
219 | esac |
220 | } |
221 | |
222 | +fips_print_status() { |
223 | + local result=0 |
224 | + |
225 | + _fips_updates_is_enabled || result=$? |
226 | + if [ $result -eq 0 ]; then |
227 | + echo "fips-updates (uncertified): enabled" |
228 | + else |
229 | + echo "fips-updates (uncertified): disabled" |
230 | + fi |
231 | +} |
232 | + |
233 | +_fips_updates_is_enabled() { |
234 | + apt-cache policy | grep -Fq "$FIPS_UPDATES_REPO_URL" |
235 | +} |
236 | + |
237 | _fips_configure() { |
238 | local bootdev fips_params result |
239 | |
240 | @@ -118,16 +205,22 @@ _fips_enabled_check() { |
241 | echo 0 |
242 | } |
243 | |
244 | +_fips_check_installed() { |
245 | + if ! _fips_check_packages_installed; then |
246 | + return |
247 | + fi |
248 | + |
249 | + if fips_is_enabled; then |
250 | + error_msg "FIPS is already enabled." |
251 | + else |
252 | + error_msg "FIPS is already installed. Please reboot into the FIPS kernel to enable it." |
253 | + fi |
254 | + return 1 |
255 | +} |
256 | + |
257 | _fips_check_packages_installed() { |
258 | local pkg |
259 | for pkg in $FIPS_HMAC_PACKAGES; do |
260 | - if is_package_installed "$pkg"; then |
261 | - if fips_is_enabled; then |
262 | - error_msg "FIPS is already enabled." |
263 | - else |
264 | - error_msg "FIPS is already installed. Please reboot into the FIPS kernel to enable it." |
265 | - fi |
266 | - return 1 |
267 | - fi |
268 | + apt_is_package_installed "$pkg" || return 1 |
269 | done |
270 | } |
271 | diff --git a/modules/service-livepatch.sh b/modules/service-livepatch.sh |
272 | index 7b3a5ad..0e35020 100644 |
273 | --- a/modules/service-livepatch.sh |
274 | +++ b/modules/service-livepatch.sh |
275 | @@ -81,7 +81,7 @@ _livepatch_validate_token() { |
276 | } |
277 | |
278 | _livepatch_install_prereqs() { |
279 | - install_package_if_missing_file "$SNAPD" snapd |
280 | + apt_install_package_if_missing_file "$SNAPD" snapd |
281 | if ! snap list canonical-livepatch >/dev/null 2>&1; then |
282 | echo 'Installing the canonical-livepatch snap.' |
283 | echo 'This may take a few minutes depending on your bandwidth.' |
284 | diff --git a/modules/service.sh b/modules/service.sh |
285 | index 1ac3243..26dc63e 100644 |
286 | --- a/modules/service.sh |
287 | +++ b/modules/service.sh |
288 | @@ -12,8 +12,8 @@ service_enable() { |
289 | local service="$1" |
290 | local token="$2" |
291 | |
292 | - _service_check_user |
293 | - _service_check_support "$service" |
294 | + service_check_user |
295 | + service_check_support "$service" |
296 | _service_check_enabled "$service" || error_exit service_already_enabled |
297 | "${service}_validate_token" "$token" || error_exit invalid_token |
298 | "${service}_enable" "$token" |
299 | @@ -22,8 +22,8 @@ service_enable() { |
300 | service_disable() { |
301 | local service="$1" |
302 | |
303 | - _service_check_user |
304 | - _service_check_support "$service" |
305 | + service_check_user |
306 | + service_check_support "$service" |
307 | _service_check_disabled "$service" || error_exit service_already_disabled |
308 | shift 1 |
309 | "${service}_disable" "$@" |
310 | @@ -58,14 +58,14 @@ service_print_status() { |
311 | fi |
312 | } |
313 | |
314 | -_service_check_user() { |
315 | +service_check_user() { |
316 | if [ "$(id -u)" -ne 0 ]; then |
317 | error_msg "This command must be run as root (try using sudo)" |
318 | error_exit not_root |
319 | fi |
320 | } |
321 | |
322 | -_service_check_support() { |
323 | +service_check_support() { |
324 | local service="$1" |
325 | |
326 | check_series_arch_supported "$service" |
327 | diff --git a/modules/utils.sh b/modules/utils.sh |
328 | index 1862fb4..5d13057 100644 |
329 | --- a/modules/utils.sh |
330 | +++ b/modules/utils.sh |
331 | @@ -20,6 +20,26 @@ error_exit() { |
332 | exit "${codes[$code]}" |
333 | } |
334 | |
335 | +# prompt the user to confirm |
336 | +# |
337 | +prompt_user() { |
338 | + local answer |
339 | + |
340 | + while true; do |
341 | + read -r -p "$* [N/y] " answer 2>&1 |
342 | + case "$answer" in |
343 | + y|Y) |
344 | + return 0 |
345 | + ;; |
346 | + ''|n|N) |
347 | + return 1 |
348 | + ;; |
349 | + *) echo "Please answer y or n." |
350 | + ;; |
351 | + esac |
352 | + done |
353 | +} |
354 | + |
355 | check_result() { |
356 | local result output |
357 | result=0 |
358 | diff --git a/tests/test_esm.py b/tests/test_esm.py |
359 | index 04f73e9..acd0707 100644 |
360 | --- a/tests/test_esm.py |
361 | +++ b/tests/test_esm.py |
362 | @@ -20,7 +20,7 @@ class ESMTest(UbuntuAdvantageTest): |
363 | expected = ( |
364 | 'deb https://esm.ubuntu.com/ubuntu precise main\n' |
365 | '# deb-src https://esm.ubuntu.com/ubuntu precise main\n') |
366 | - self.assertEqual(expected, self.repo_list.read_text()) |
367 | + self.assertEqual(expected, self.esm_repo_list.read_text()) |
368 | self.assertEqual( |
369 | self.apt_auth_file.read_text(), |
370 | 'machine esm.ubuntu.com/ubuntu/ login user password pass\n') |
371 | @@ -198,7 +198,7 @@ class ESMTest(UbuntuAdvantageTest): |
372 | process = self.script('disable-esm') |
373 | self.assertEqual(0, process.returncode) |
374 | self.assertIn('Ubuntu ESM repository disabled', process.stdout) |
375 | - self.assertFalse(self.repo_list.exists()) |
376 | + self.assertFalse(self.esm_repo_list.exists()) |
377 | # the keyring file is removed |
378 | keyring_file = self.trusted_gpg_dir / 'ubuntu-esm-keyring.gpg' |
379 | self.assertFalse(keyring_file.exists()) |
380 | diff --git a/tests/test_fips.py b/tests/test_fips.py |
381 | index 5efe325..433c0bf 100644 |
382 | --- a/tests/test_fips.py |
383 | +++ b/tests/test_fips.py |
384 | @@ -23,7 +23,12 @@ class FIPSTest(UbuntuAdvantageTest): |
385 | 'fips/ubuntu xenial main\n' |
386 | '# deb-src https://private-ppa.launchpad.net/' |
387 | 'ubuntu-advantage/fips/ubuntu xenial main\n') |
388 | - self.assertEqual(expected, self.repo_list.read_text()) |
389 | + self.assertEqual(expected, self.fips_repo_list.read_text()) |
390 | + expected = ( |
391 | + 'Package: *\n' |
392 | + 'Pin: release o=LP-PPA-ubuntu-advantage-fips, n=xenial\n' |
393 | + 'Pin-Priority: 1001\n') |
394 | + self.assertEqual(self.fips_repo_preferences.read_text(), expected) |
395 | self.assertEqual( |
396 | self.apt_auth_file.read_text(), |
397 | 'machine private-ppa.launchpad.net/ubuntu-advantage/fips/ubuntu/' |
398 | @@ -67,6 +72,15 @@ class FIPSTest(UbuntuAdvantageTest): |
399 | 'Please reboot into the FIPS kernel to enable it.', |
400 | process.stderr.strip()) |
401 | |
402 | + def test_enable_fips_not_all_packages_installed(self): |
403 | + # one of the packages is not installed |
404 | + self.make_fake_binary( |
405 | + 'dpkg-query', command='[ $2 != openssh-client-hmac ]') |
406 | + process = self.script('enable-fips', 'user:pass') |
407 | + self.assertEqual(process.returncode, 0) |
408 | + self.assertIn('Installing FIPS packages', process.stdout) |
409 | + self.assertIn('Successfully configured FIPS', process.stdout) |
410 | + |
411 | def test_enable_fips_writes_config(self): |
412 | """The enable-fips option writes fips configuration.""" |
413 | self.script('enable-fips', 'user:pass') |
414 | @@ -249,3 +263,160 @@ class FIPSTest(UbuntuAdvantageTest): |
415 | self.assertIn( |
416 | 'Canonical FIPS 140-2 Modules is not enabled', |
417 | process.stderr) |
418 | + |
419 | + def test_update_fips(self): |
420 | + """The enable-fips-updates option enables FIPS-UPDATES repository.""" |
421 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
422 | + self.assertEqual(0, process.returncode) |
423 | + self.assertIn('Ubuntu FIPS-UPDATES PPA repository enabled.', |
424 | + process.stdout) |
425 | + expected = ( |
426 | + 'deb https://private-ppa.launchpad.net/ubuntu-advantage/' |
427 | + 'fips-updates/ubuntu xenial main\n' |
428 | + '# deb-src https://private-ppa.launchpad.net/' |
429 | + 'ubuntu-advantage/fips-updates/ubuntu xenial main\n') |
430 | + self.assertEqual(expected, self.fips_updates_repo_list.read_text()) |
431 | + expected = ( |
432 | + 'Package: *\n' |
433 | + 'Pin: release o=LP-PPA-ubuntu-advantage-fips-updates, n=xenial\n' |
434 | + 'Pin-Priority: 1001\n') |
435 | + self.assertEqual(self.fips_updates_repo_preferences.read_text(), |
436 | + expected) |
437 | + self.assertEqual( |
438 | + self.apt_auth_file.read_text(), |
439 | + 'machine private-ppa.launchpad.net/ubuntu-advantage/' |
440 | + 'fips-updates/ubuntu/' |
441 | + ' login user password pass\n') |
442 | + self.assertEqual(self.apt_auth_file.stat().st_mode, 0o100600) |
443 | + keyring_file = self.trusted_gpg_dir / 'ubuntu-fips-updates-keyring.gpg' |
444 | + self.assertEqual('GPG key', keyring_file.read_text()) |
445 | + self.assertIn( |
446 | + 'Configuring FIPS...', |
447 | + process.stdout) |
448 | + self.assertIn( |
449 | + 'Successfully updated FIPS packages.\n' |
450 | + 'Please reboot into the new FIPS kernel', |
451 | + process.stdout) |
452 | + |
453 | + def test_update_fips_auth_if_other_entries(self): |
454 | + """Existing auth.conf entries are preserved.""" |
455 | + auth = 'machine example.com login user password pass\n' |
456 | + self.apt_auth_file.write_text(auth) |
457 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
458 | + self.assertEqual(0, process.returncode) |
459 | + self.assertIn(auth, self.apt_auth_file.read_text()) |
460 | + |
461 | + def test_update_fips_writes_config(self): |
462 | + """The enable-fips-updates option writes fips configuration.""" |
463 | + self.script('enable-fips-updates', 'user:pass', '-y') |
464 | + self.assertEqual( |
465 | + 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT fips=1"', |
466 | + self.boot_cfg.read_text().strip()) |
467 | + |
468 | + def test_update_fips_writes_config_with_boot_partition(self): |
469 | + """The fips configuration includes the /boot partition.""" |
470 | + self.fstab.write_text('/dev/sda1 /boot ext2 defaults 0 1\n') |
471 | + self.script('enable-fips-updates', 'user:pass', '-y') |
472 | + self.assertIn('bootdev=/dev/sda1', self.boot_cfg.read_text()) |
473 | + |
474 | + def test_update_fips_writes_config_s390x_parameters(self): |
475 | + """On S390x, FIPS parameters are appended to the config file.""" |
476 | + self.ARCH = 's390x' |
477 | + self.boot_cfg.write_text('parameters=foo\n') |
478 | + self.script('enable-fips-updates', 'user:pass', '-y') |
479 | + self.assertEqual('parameters=foo fips=1\n', self.boot_cfg.read_text()) |
480 | + |
481 | + def test_update_unsupported_on_i686(self): |
482 | + """FIPS is unsupported on i686 arch.""" |
483 | + self.ARCH = 'i686' |
484 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
485 | + self.assertEqual(7, process.returncode) |
486 | + self.assertIn( |
487 | + 'Sorry, but Canonical FIPS 140-2 Modules is not supported on i686', |
488 | + process.stderr) |
489 | + |
490 | + def test_update_fips_missing_token(self): |
491 | + """The token must be specified when using enable-fips-updates.""" |
492 | + process = self.script('enable-fips-updates') |
493 | + self.assertEqual(3, process.returncode) |
494 | + self.assertIn( |
495 | + 'Invalid token, it must be in the form "user:password"', |
496 | + process.stderr) |
497 | + |
498 | + def test_update_fips_invalid_token_format(self): |
499 | + """The FIPS token must be specified as "user:password".""" |
500 | + process = self.script('enable-fips-updates', 'foo-bar', '-y') |
501 | + self.assertEqual(3, process.returncode) |
502 | + self.assertIn( |
503 | + 'Invalid token, it must be in the form "user:password"', |
504 | + process.stderr) |
505 | + |
506 | + def test_update_fips_invalid_token(self): |
507 | + """If token is invalid, an error is returned.""" |
508 | + message = ( |
509 | + 'E: Failed to fetch https://esm.ubuntu.com/' |
510 | + ' 401 Unauthorized [IP: 1.2.3.4]') |
511 | + self.make_fake_binary( |
512 | + 'apt-helper', command='echo "{}"; exit 1'.format(message)) |
513 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
514 | + self.assertEqual(3, process.returncode) |
515 | + self.assertIn('Checking token... ERROR', process.stdout) |
516 | + self.assertIn('Invalid token', process.stderr) |
517 | + |
518 | + def test_update_fips_invalid_token_trusty(self): |
519 | + """Invalid token error is caught with apt-helper in trusty.""" |
520 | + message = 'E: Failed to fetch https://esm.ubuntu.com/ HttpError401' |
521 | + self.make_fake_binary( |
522 | + 'apt-helper', command='echo "{}"; exit 1'.format(message)) |
523 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
524 | + self.assertEqual(3, process.returncode) |
525 | + self.assertIn('Checking token... ERROR', process.stdout) |
526 | + self.assertIn('Invalid token', process.stderr) |
527 | + |
528 | + def test_update_fips_error_checking_token(self): |
529 | + """If token check fails, an error is returned.""" |
530 | + message = ( |
531 | + 'E: Failed to fetch https://esm.ubuntu.com/' |
532 | + ' 404 Not Found [IP: 1.2.3.4]') |
533 | + self.make_fake_binary( |
534 | + 'apt-helper', command='echo "{}"; exit 1'.format(message)) |
535 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
536 | + self.assertEqual(3, process.returncode) |
537 | + self.assertIn('Checking token... ERROR', process.stdout) |
538 | + self.assertIn( |
539 | + 'Failed checking token (404 Not Found [IP: 1.2.3.4])', |
540 | + process.stderr) |
541 | + |
542 | + def test_update_fips_only_supported_on_xenial(self): |
543 | + """The enable-fips-updates option fails if not on Xenial.""" |
544 | + self.SERIES = 'zesty' |
545 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
546 | + self.assertEqual(4, process.returncode) |
547 | + self.assertIn( |
548 | + 'Canonical FIPS 140-2 Modules is not supported on zesty', |
549 | + process.stderr) |
550 | + |
551 | + def test_update_fips_x86_64_aes_not_available(self): |
552 | + """The enable-fips-updates command fails if AESNI is not available.""" |
553 | + self.cpuinfo.write_text('flags\t\t: fpu tsc') |
554 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
555 | + self.assertEqual(7, process.returncode) |
556 | + self.assertEqual( |
557 | + 'FIPS requires AES CPU extensions', process.stderr.strip()) |
558 | + |
559 | + def test_update_fips_ppc64le_power8(self): |
560 | + """POWER8 processors are supported by FIPS.""" |
561 | + self.ARCH = 'ppc64le' |
562 | + self.cpuinfo.write_text('cpu\t\t: POWER8 (raw), altivec supported') |
563 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
564 | + self.assertEqual(0, process.returncode) |
565 | + self.assertIn('Successfully updated FIPS packages', process.stdout) |
566 | + |
567 | + def test_update_fips_ppc64le_older_power(self): |
568 | + """processors older than POWER8 are not supported by FIPS.""" |
569 | + self.ARCH = 'ppc64le' |
570 | + self.cpuinfo.write_text('cpu\t\t: POWER7') |
571 | + process = self.script('enable-fips-updates', 'user:pass', '-y') |
572 | + self.assertEqual(7, process.returncode) |
573 | + self.assertEqual( |
574 | + 'FIPS requires POWER8 or later', process.stderr.strip()) |
575 | diff --git a/tests/test_script.py b/tests/test_script.py |
576 | index 1feb400..4e7da93 100644 |
577 | --- a/tests/test_script.py |
578 | +++ b/tests/test_script.py |
579 | @@ -79,6 +79,18 @@ class UbuntuAdvantageScriptTest(UbuntuAdvantageTest): |
580 | process = self.script('status') |
581 | self.assertIn("livepatch: disabled (not available)", process.stdout) |
582 | |
583 | + def test_status_with_one_service(self): |
584 | + """The status for a single service can be returned.""" |
585 | + self.SERIES = 'precise' |
586 | + process = self.script('status', 'fips') |
587 | + self.assertEqual(process.returncode, 0) |
588 | + self.assertEqual(process.stdout, 'fips: disabled (not available)\n') |
589 | + |
590 | + def test_status_with_one_service_unknown(self): |
591 | + """The script exits with error on unknown service status name.""" |
592 | + process = self.script('status', 'unknown') |
593 | + self.assertEqual(process.returncode, 1) |
594 | + |
595 | def test_version(self): |
596 | """The version command shows the package version.""" |
597 | self.make_fake_binary('dpkg-query', command='echo 123') |
598 | diff --git a/tests/testing.py b/tests/testing.py |
599 | index a26eb6c..c684f48 100644 |
600 | --- a/tests/testing.py |
601 | +++ b/tests/testing.py |
602 | @@ -50,10 +50,17 @@ class UbuntuAdvantageTest(TestWithFixtures): |
603 | def setUp(self): |
604 | super(UbuntuAdvantageTest, self).setUp() |
605 | self.tempdir = self.useFixture(TempDir()) |
606 | - self.repo_list = Path(self.tempdir.join('repo.list')) |
607 | self.boot_cfg = Path(self.tempdir.join('boot.cfg')) |
608 | self.fstab = Path(self.tempdir.join('fstab')) |
609 | self.cpuinfo = Path(self.tempdir.join('cpuinfo')) |
610 | + self.esm_repo_list = Path(self.tempdir.join('esm-repo.list')) |
611 | + self.fips_repo_list = Path(self.tempdir.join('fips-repo.list')) |
612 | + self.fips_updates_repo_list = Path( |
613 | + self.tempdir.join('fips-updates-repo.list')) |
614 | + self.fips_repo_preferences = Path( |
615 | + self.tempdir.join('preferences-fips')) |
616 | + self.fips_updates_repo_preferences = Path( |
617 | + self.tempdir.join('preferences-fips-updates')) |
618 | self.fips_enabled_file = Path(self.tempdir.join('fips_enabled_file')) |
619 | self.bin_dir = Path(self.tempdir.join('bin')) |
620 | self.etc_dir = Path(self.tempdir.join('etc')) |
621 | @@ -73,6 +80,8 @@ class UbuntuAdvantageTest(TestWithFixtures): |
622 | self.trusted_gpg_dir.mkdir() |
623 | (self.keyrings_dir / 'ubuntu-esm-keyring.gpg').write_text('GPG key') |
624 | (self.keyrings_dir / 'ubuntu-fips-keyring.gpg').write_text('GPG key') |
625 | + (self.keyrings_dir / 'ubuntu-fips-updates-keyring.gpg').write_text( |
626 | + 'GPG key') |
627 | self.cpuinfo.write_text('flags\t\t: fpu apic') |
628 | self.make_fake_binary('apt-get') |
629 | self.make_fake_binary('apt-helper') |
630 | @@ -105,11 +114,15 @@ class UbuntuAdvantageTest(TestWithFixtures): |
631 | 'PATH': path, |
632 | 'FSTAB': str(self.fstab), |
633 | 'CPUINFO': str(self.cpuinfo), |
634 | - 'ESM_REPO_LIST': str(self.repo_list), |
635 | - 'FIPS_REPO_LIST': str(self.repo_list), |
636 | + 'ESM_REPO_LIST': str(self.esm_repo_list), |
637 | + 'FIPS_REPO_LIST': str(self.fips_repo_list), |
638 | + 'FIPS_UPDATES_REPO_LIST': str(self.fips_updates_repo_list), |
639 | 'FIPS_BOOT_CFG': str(self.boot_cfg), |
640 | 'FIPS_BOOT_CFG_DIR': str(self.etc_dir), |
641 | 'FIPS_ENABLED_FILE': str(self.fips_enabled_file), |
642 | + 'FIPS_REPO_PREFERENCES': str(self.fips_repo_preferences), |
643 | + 'FIPS_UPDATES_REPO_PREFERENCES': str( |
644 | + self.fips_updates_repo_preferences), |
645 | 'KEYRINGS_DIR': str(self.keyrings_dir), |
646 | 'APT_HELPER': str(self.apt_helper), |
647 | 'APT_AUTH_FILE': str(self.apt_auth_file), |
648 | diff --git a/ubuntu-advantage b/ubuntu-advantage |
649 | index 451e060..1ad03a5 100755 |
650 | --- a/ubuntu-advantage |
651 | +++ b/ubuntu-advantage |
652 | @@ -38,8 +38,15 @@ load_modules() { |
653 | } |
654 | |
655 | print_status() { |
656 | - local service |
657 | - for service in $SERVICES; do |
658 | + local service="$1" |
659 | + |
660 | + local services="$SERVICES" |
661 | + if [ "$service" ]; then |
662 | + name_in_list "$service" "$SERVICES" || error_exit invalid_command |
663 | + services="$service" |
664 | + fi |
665 | + |
666 | + for service in $services; do |
667 | service_print_status "$service" |
668 | done |
669 | } |
670 | @@ -54,20 +61,25 @@ Ubuntu Advantage offerings. |
671 | Currently available are: |
672 | - Ubuntu Extended Security Maintenance archive (https://ubuntu.com/esm) |
673 | - Canonical FIPS 140-2 Certified Modules |
674 | +- Canonical FIPS 140-2 Non-Certified Module Updates |
675 | - Canonical Livepatch Service (https://www.ubuntu.com/server/livepatch) |
676 | |
677 | Commands: |
678 | - version show the tool version |
679 | - status show current status of Ubuntu Advantage offerings |
680 | - enable-esm <token> enable the ESM repository |
681 | - disable-esm disable the ESM repository |
682 | - enable-fips <token> enable the FIPS PPA repository and install, |
683 | - configure and enable FIPS certified modules |
684 | - disabe-fips currently not supported |
685 | - enable-livepatch <token> enable the Livepatch service |
686 | - disable-livepatch [-r] disable the Livepatch service. With "-r", the |
687 | - canonical-livepatch snap will also be removed |
688 | - |
689 | + version show the tool version |
690 | + status [NAME] show current status of Ubuntu Advantage |
691 | + offerings (or of a specific one if provided) |
692 | + enable-esm <TOKEN> enable the ESM repository |
693 | + disable-esm disable the ESM repository |
694 | + enable-fips <TOKEN> enable the FIPS PPA repository and install, |
695 | + configure and enable FIPS certified modules |
696 | + disable-fips currently not supported |
697 | + enable-fips-updates <TOKEN> [-y] enable non-certified FIPS-UPDATES PPA |
698 | + repository and install updates. With an |
699 | + optional "-y" the user prompt will be |
700 | + bypassed. |
701 | + enable-livepatch <TOKEN> enable the Livepatch service |
702 | + disable-livepatch [-r] disable the Livepatch service. With "-r", the |
703 | + canonical-livepatch snap will also be removed |
704 | EOF |
705 | error_exit invalid_command |
706 | } |
707 | @@ -79,20 +91,40 @@ main() { |
708 | local service |
709 | service=$(service_from_command "$command") |
710 | # if the command contains a service name, check that it's valid |
711 | - if [ "$service" ] && ! name_in_list "$service" "$SERVICES"; then |
712 | + if [ "$service" ] && ! name_in_list "$service" "$SERVICES" \ |
713 | + && [ "$service" != "fips-updates" ]; then |
714 | error_msg "Invalid command: \"$command\"" |
715 | usage |
716 | fi |
717 | |
718 | case "$command" in |
719 | status) |
720 | - print_status |
721 | + print_status "$@" |
722 | ;; |
723 | |
724 | version) |
725 | package_version ubuntu-advantage-tools |
726 | ;; |
727 | |
728 | + # special case, adding it above enable-*. There is no separate |
729 | + # fips-update service. |
730 | + enable-fips-updates) |
731 | + local token="$1" |
732 | + local bypass_prompt=0 |
733 | + if [ -n "$2" ]; then |
734 | + if [ "$2" = "-y" ]; then |
735 | + bypass_prompt=1 |
736 | + else |
737 | + error_msg "Unknown option \"$2\"" |
738 | + usage |
739 | + fi |
740 | + fi |
741 | + service_check_user |
742 | + service_check_support "fips" |
743 | + fips_validate_token "$token" || error_exit invalid_token |
744 | + fips_updates_enable "$token" "$bypass_prompt" |
745 | + ;; |
746 | + |
747 | enable-*) |
748 | service_enable "$service" "$@" |
749 | ;; |
750 | diff --git a/ubuntu-advantage.1 b/ubuntu-advantage.1 |
751 | index 0fa3290..e86b85d 100644 |
752 | --- a/ubuntu-advantage.1 |
753 | +++ b/ubuntu-advantage.1 |
754 | @@ -55,6 +55,25 @@ cryptoapi. |
755 | disable-fips |
756 | It's currently not possible to disable FIPS after it has been enabled. |
757 | |
758 | +.TP |
759 | +.B |
760 | +enable-fips-updates \fItoken\fR [\fB\-y\fR] |
761 | +Updating the FIPS modules will take the system out of FIPS compliance as the |
762 | +updated modules are not FIPS certified. The option enables the FIPS-UPDATES |
763 | +PPA repository and installs the updated FIPS modules. If the system is |
764 | +installing FIPS modules for the first time, it configures FIPS on the |
765 | +system. After successfully executing the ubuntu-advantage script to |
766 | +update FIPS modules, the system MUST be rebooted if FIPS kernel was |
767 | +upgraded in the upgrade process. Failing to reboot will result |
768 | +in the system not running the updated FIPS kernel. |
769 | +The \fItoken\fR argument must be in the form "user:password". |
770 | +The \fB\-y\fR argument is optional to bypass the user prompt while |
771 | +installing updates. |
772 | + |
773 | +The following FIPS modules will be updated and put in FIPS mode - |
774 | +openssh-server, openssh-client, strongswan, openssl, and the kernel |
775 | +cryptoapi. |
776 | + |
777 | .SH Livepatch (Canonical Livepatch Service) |
778 | Managed live kernel patching. For more information, visit |
779 | https://www.ubuntu.com/server/livepatch |
I'll create matching commits for the entries in d/changelog, but there will be remaining commits that won't be mentioned there. d/changelog is not a git log after alll, and this LP branch is not a mirror of the upstream git repo.