Merge ~ahasenack/ubuntu/+source/ubuntu-advantage-tools:v17-fips-updates into ubuntu/+source/ubuntu-advantage-tools:ubuntu/devel

Proposed by Andreas Hasenack
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)
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

Description of the change

ubuntu-advantage-tools FIPS updates. These are not used in bionic, because fips is not supported in bionic yet, but are needed for an upcoming xenial SRU.

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://launchpad.net/~ahasenack/+archive/ubuntu/ua-tools-fips-updates-1759280

sudo add-apt-repository ppa:ahasenack/ua-tools-fips-updates-1759280

To post a comment you must log in.
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

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.

Revision history for this message
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://github.com/CanonicalLtd/ubuntu-advantage-script/commits/master and https://github.com/CanonicalLtd/ubuntu-advantage-script/pulls?q=is%3Apr+is%3Aclosed respectively. Please let me know if you need any other information or have other questions.

Revision history for this message
Steve Langasek (vorlon) wrote :

Reviewing with respect to archive and feature freeze only. Comments inline.

review: Approve
Revision history for this message
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.

review: Needs Information
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Replied to commends from Steve and Christian inline. Thanks guys!

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Upstream issues opened.

Revision history for this message
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

review: Approve
Revision history for this message
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://assets.ubuntu.com/v1/f35fe02e-Canonical+FIPS+Installation+Instructions.pdf?utm_source=ubunteu&utm_medium=url_shortner&utm_term=fips-install&utm_campaign=shortner

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.

Revision history for this message
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.

Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

Tag push and sponsoring done as requested

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.gitignore b/.gitignore
0new file mode 1006440new file mode 100644
index 0000000..34972a2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
1*.pyc
2*.pyo
3__pycache__
4.tox
diff --git a/debian/changelog b/debian/changelog
index bb95c3d..39ea084 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,15 @@
1ubuntu-advantage-tools (17) bionic; urgency=medium
2
3 * New upstream release (LP: #1759280):
4 - Added enable-fips-updates command. This command enables the fips-updates
5 repository to install updates to FIPS modules. The updated modules from
6 fips-updates repository are non-certified.
7 - Add repository pinning for FIPS packages
8 - Check that all prerequisite packages are installed when enabling FIPS
9 - Support returning the status for a single service
10
11 -- Andreas Hasenack <andreas@canonical.com> Wed, 21 Mar 2018 14:20:04 -0300
12
1ubuntu-advantage-tools (16) bionic; urgency=medium13ubuntu-advantage-tools (16) bionic; urgency=medium
214
3 * d/t/update-motd-run: fix path to the esm motd (LP: #1757490)15 * d/t/update-motd-run: fix path to the esm motd (LP: #1757490)
diff --git a/keyrings/ubuntu-fips-updates-keyring.gpg b/keyrings/ubuntu-fips-updates-keyring.gpg
4new file mode 10064416new file mode 100644
index 0000000..d00f63f
5Binary files /dev/null and b/keyrings/ubuntu-fips-updates-keyring.gpg differ17Binary files /dev/null and b/keyrings/ubuntu-fips-updates-keyring.gpg differ
diff --git a/modules/apt.sh b/modules/apt.sh
index 8a9a2ab..3d73d12 100644
--- a/modules/apt.sh
+++ b/modules/apt.sh
@@ -35,19 +35,31 @@ apt_remove_repo() {
35 _apt_remove_auth "$repo_url"35 _apt_remove_auth "$repo_url"
36}36}
3737
38apt_add_repo_pinning() {
39 local repo_file="$1"
40 local origin="$2"
41 local priority="$3"
42
43 cat <<EOF >"$repo_file"
44Package: *
45Pin: release o=${origin}, n=${SERIES}
46Pin-Priority: ${priority}
47EOF
48}
49
38apt_get() {50apt_get() {
39 DEBIAN_FRONTEND=noninteractive \51 DEBIAN_FRONTEND=noninteractive \
40 apt-get -y -o Dpkg::Options::='--force-confold' "$@"52 apt-get -y -o Dpkg::Options::='--force-confold' "$@"
41}53}
4254
43is_package_installed() {55apt_is_package_installed() {
44 local package="$1"56 local package="$1"
4557
46 dpkg-query -s "$package" >/dev/null 2>&158 dpkg-query -s "$package" >/dev/null 2>&1
47}59}
4860
49# Install a package if the specified file doesn't exist61# Install a package if the specified file doesn't exist
50install_package_if_missing_file() {62apt_install_package_if_missing_file() {
51 local file="$1"63 local file="$1"
52 local package="$2"64 local package="$2"
5365
diff --git a/modules/service-esm.sh b/modules/service-esm.sh
index 0bbfaa2..de281f8 100644
--- a/modules/service-esm.sh
+++ b/modules/service-esm.sh
@@ -14,8 +14,8 @@ esm_enable() {
14 check_token "$ESM_REPO_URL" "$token"14 check_token "$ESM_REPO_URL" "$token"
15 apt_add_repo "$ESM_REPO_LIST" "$ESM_REPO_URL" "$token" \15 apt_add_repo "$ESM_REPO_LIST" "$ESM_REPO_URL" "$token" \
16 "${KEYRINGS_DIR}/${ESM_REPO_KEY_FILE}"16 "${KEYRINGS_DIR}/${ESM_REPO_KEY_FILE}"
17 install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https17 apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https
18 install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates18 apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates
19 echo -n 'Running apt-get update... '19 echo -n 'Running apt-get update... '
20 check_result apt_get update20 check_result apt_get update
21 echo 'Ubuntu ESM repository enabled.'21 echo 'Ubuntu ESM repository enabled.'
diff --git a/modules/service-fips.sh b/modules/service-fips.sh
index 38c2c6d..4df3872 100644
--- a/modules/service-fips.sh
+++ b/modules/service-fips.sh
@@ -7,6 +7,11 @@ FIPS_SUPPORTED_ARCHS="x86_64 ppc64le s390x"
7FIPS_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/fips"7FIPS_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/fips"
8FIPS_REPO_KEY_FILE="ubuntu-fips-keyring.gpg"8FIPS_REPO_KEY_FILE="ubuntu-fips-keyring.gpg"
9FIPS_REPO_LIST=${FIPS_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-fips-${SERIES}.list"}9FIPS_REPO_LIST=${FIPS_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-fips-${SERIES}.list"}
10FIPS_REPO_PREFERENCES=${FIPS_REPO_PREFERENCES:-"/etc/apt/preferences.d/ubuntu-fips-${SERIES}"}
11FIPS_UPDATES_REPO_URL="https://private-ppa.launchpad.net/ubuntu-advantage/fips-updates"
12FIPS_UPDATES_REPO_KEY_FILE="ubuntu-fips-updates-keyring.gpg"
13FIPS_UPDATES_REPO_LIST=${FIPS_UPDATES_REPO_LIST:-"/etc/apt/sources.list.d/ubuntu-fips-updates-${SERIES}.list"}
14FIPS_UPDATES_REPO_PREFERENCES=${FIPS_UPDATES_REPO_PREFERENCES:-"/etc/apt/preferences.d/ubuntu-fips-updates-${SERIES}"}
10FIPS_ENABLED_FILE=${FIPS_ENABLED_FILE:-"/proc/sys/crypto/fips_enabled"}15FIPS_ENABLED_FILE=${FIPS_ENABLED_FILE:-"/proc/sys/crypto/fips_enabled"}
11if [ "$ARCH" = "s390x" ]; then16if [ "$ARCH" = "s390x" ]; then
12 FIPS_BOOT_CFG=${FIPS_BOOT_CFG:-"/etc/zipl.conf"}17 FIPS_BOOT_CFG=${FIPS_BOOT_CFG:-"/etc/zipl.conf"}
@@ -15,28 +20,30 @@ else
15 FIPS_BOOT_CFG=${FIPS_BOOT_CFG:-"${FIPS_BOOT_CFG_DIR}/99-fips.cfg"}20 FIPS_BOOT_CFG=${FIPS_BOOT_CFG:-"${FIPS_BOOT_CFG_DIR}/99-fips.cfg"}
16fi21fi
17FIPS_HMAC_PACKAGES="openssh-client-hmac openssh-server-hmac libssl1.0.0-hmac \22FIPS_HMAC_PACKAGES="openssh-client-hmac openssh-server-hmac libssl1.0.0-hmac \
18 linux-fips strongswan-hmac"23 linux-fips strongswan-hmac"
24FIPS_OTHER_PACKAGES="openssh-client openssh-server openssl libssl1.0.0 \
25 fips-initramfs strongswan"
1926
20fips_enable() {27fips_enable() {
21 local token="$1"28 local token="$1"
2229
23 _fips_check_packages_installed || error_exit service_already_enabled30 _fips_check_installed || error_exit service_already_enabled
2431
25 check_token "$FIPS_REPO_URL" "$token"32 check_token "$FIPS_REPO_URL" "$token"
26 apt_add_repo "$FIPS_REPO_LIST" "$FIPS_REPO_URL" "$token" \33 apt_add_repo "$FIPS_REPO_LIST" "$FIPS_REPO_URL" "$token" \
27 "${KEYRINGS_DIR}/${FIPS_REPO_KEY_FILE}"34 "${KEYRINGS_DIR}/${FIPS_REPO_KEY_FILE}"
28 install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https35 apt_add_repo_pinning "$FIPS_REPO_PREFERENCES" \
29 install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates36 LP-PPA-ubuntu-advantage-fips 1001
37 apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https
38 apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates
30 echo -n 'Running apt-get update... '39 echo -n 'Running apt-get update... '
31 check_result apt_get update40 check_result apt_get update
32 echo 'Ubuntu FIPS PPA repository enabled.'41 echo 'Ubuntu FIPS PPA repository enabled.'
3342
34 # install all the fips packages43 # install all the fips packages
35 echo -n 'Installing FIPS packages (this may take a while)... '44 echo -n 'Installing FIPS packages (this may take a while)... '
36 check_result apt_get install openssh-client openssh-client-hmac \45 # shellcheck disable=SC2086
37 openssh-server openssh-server-hmac openssl libssl1.0.0 \46 check_result apt_get install $FIPS_HMAC_PACKAGES $FIPS_OTHER_PACKAGES
38 libssl1.0.0-hmac fips-initramfs linux-fips \
39 strongswan strongswan-hmac
4047
41 echo "Configuring FIPS... "48 echo "Configuring FIPS... "
42 _fips_configure49 _fips_configure
@@ -47,8 +54,73 @@ fips_disable() {
47 not_supported 'Disabling FIPS'54 not_supported 'Disabling FIPS'
48}55}
4956
57fips_updates_enable() {
58 local token="$1"
59 local bypass_prompt="$2"
60
61 local fips_configured=0
62 local fips_kernel_version=0
63 local result=0
64
65 _fips_updates_is_enabled || result=$?
66 if [ $result -eq 0 ]; then
67 error_msg "FIPS-UPDATES repository is already enabled."
68 error_exit service_already_enabled
69 fi
70
71 check_token "$FIPS_UPDATES_REPO_URL" "$token"
72
73 echo "Installing updates from FIPS-UPDATES repository will take the system out of FIPS compliance."
74 if [ "$bypass_prompt" -ne 1 ]; then
75 if ! prompt_user 'Do you want to proceed?'; then
76 error_msg "Aborting updating FIPS packages..."
77 return
78 fi
79 fi
80
81 # add the fips-updates repo if the system is undergoing updates the first time
82 if [ ! -f "$FIPS_UPDATES_REPO_LIST" ]; then
83 apt_add_repo "$FIPS_UPDATES_REPO_LIST" "$FIPS_UPDATES_REPO_URL" "$token" \
84 "${KEYRINGS_DIR}/${FIPS_UPDATES_REPO_KEY_FILE}"
85 apt_add_repo_pinning "$FIPS_UPDATES_REPO_PREFERENCES" \
86 LP-PPA-ubuntu-advantage-fips-updates 1001
87 apt_install_package_if_missing_file "$APT_METHOD_HTTPS" apt-transport-https
88 apt_install_package_if_missing_file "$CA_CERTIFICATES" ca-certificates
89 echo -n 'Running apt-get update... '
90 check_result apt_get update
91 echo 'Ubuntu FIPS-UPDATES PPA repository enabled.'
92 fi
93
94 # if a fips package is found on the system, assume fips was configured before
95 # users could be running with fips=0 or fips=1, so just checking package here
96 if apt_is_package_installed fips-initramfs; then
97 fips_configured=1
98 # get the fips kernel version installed here
99 fips_kernel_version=$(package_version linux-fips)
100 fi
101
102 # update all the fips packages
103 echo -n 'Updating FIPS packages (this may take a while)... '
104 # shellcheck disable=SC2086
105 check_result apt_get install $FIPS_HMAC_PACKAGES $FIPS_OTHER_PACKAGES
106
107 # if fips was never configured before and is enabled for the
108 # first time, configure fips
109 if [ "$fips_configured" -eq 0 ]; then
110 echo "Configuring FIPS... "
111 _fips_configure
112 fi
113 echo "Successfully updated FIPS packages."
114
115 # show the message to reboot only if fips kernel has undergone an upgrade or fips is
116 # being configured the first time
117 if [ "$fips_kernel_version" != "$(package_version linux-fips)" ] || [ "$fips_configured" -eq 0 ]; then
118 echo "Please reboot into the new FIPS kernel."
119 fi
120}
121
50fips_is_enabled() {122fips_is_enabled() {
51 is_package_installed fips-initramfs && [ "$(_fips_enabled_check)" -eq 1 ]123 apt_is_package_installed fips-initramfs && [ "$(_fips_enabled_check)" -eq 1 ]
52}124}
53125
54fips_validate_token() {126fips_validate_token() {
@@ -80,6 +152,21 @@ fips_check_support() {
80 esac152 esac
81}153}
82154
155fips_print_status() {
156 local result=0
157
158 _fips_updates_is_enabled || result=$?
159 if [ $result -eq 0 ]; then
160 echo "fips-updates (uncertified): enabled"
161 else
162 echo "fips-updates (uncertified): disabled"
163 fi
164}
165
166_fips_updates_is_enabled() {
167 apt-cache policy | grep -Fq "$FIPS_UPDATES_REPO_URL"
168}
169
83_fips_configure() {170_fips_configure() {
84 local bootdev fips_params result171 local bootdev fips_params result
85172
@@ -118,16 +205,22 @@ _fips_enabled_check() {
118 echo 0205 echo 0
119}206}
120207
208_fips_check_installed() {
209 if ! _fips_check_packages_installed; then
210 return
211 fi
212
213 if fips_is_enabled; then
214 error_msg "FIPS is already enabled."
215 else
216 error_msg "FIPS is already installed. Please reboot into the FIPS kernel to enable it."
217 fi
218 return 1
219}
220
121_fips_check_packages_installed() {221_fips_check_packages_installed() {
122 local pkg222 local pkg
123 for pkg in $FIPS_HMAC_PACKAGES; do223 for pkg in $FIPS_HMAC_PACKAGES; do
124 if is_package_installed "$pkg"; then224 apt_is_package_installed "$pkg" || return 1
125 if fips_is_enabled; then
126 error_msg "FIPS is already enabled."
127 else
128 error_msg "FIPS is already installed. Please reboot into the FIPS kernel to enable it."
129 fi
130 return 1
131 fi
132 done225 done
133}226}
diff --git a/modules/service-livepatch.sh b/modules/service-livepatch.sh
index 7b3a5ad..0e35020 100644
--- a/modules/service-livepatch.sh
+++ b/modules/service-livepatch.sh
@@ -81,7 +81,7 @@ _livepatch_validate_token() {
81}81}
8282
83_livepatch_install_prereqs() {83_livepatch_install_prereqs() {
84 install_package_if_missing_file "$SNAPD" snapd84 apt_install_package_if_missing_file "$SNAPD" snapd
85 if ! snap list canonical-livepatch >/dev/null 2>&1; then85 if ! snap list canonical-livepatch >/dev/null 2>&1; then
86 echo 'Installing the canonical-livepatch snap.'86 echo 'Installing the canonical-livepatch snap.'
87 echo 'This may take a few minutes depending on your bandwidth.'87 echo 'This may take a few minutes depending on your bandwidth.'
diff --git a/modules/service.sh b/modules/service.sh
index 1ac3243..26dc63e 100644
--- a/modules/service.sh
+++ b/modules/service.sh
@@ -12,8 +12,8 @@ service_enable() {
12 local service="$1"12 local service="$1"
13 local token="$2"13 local token="$2"
1414
15 _service_check_user15 service_check_user
16 _service_check_support "$service"16 service_check_support "$service"
17 _service_check_enabled "$service" || error_exit service_already_enabled17 _service_check_enabled "$service" || error_exit service_already_enabled
18 "${service}_validate_token" "$token" || error_exit invalid_token18 "${service}_validate_token" "$token" || error_exit invalid_token
19 "${service}_enable" "$token"19 "${service}_enable" "$token"
@@ -22,8 +22,8 @@ service_enable() {
22service_disable() {22service_disable() {
23 local service="$1"23 local service="$1"
2424
25 _service_check_user25 service_check_user
26 _service_check_support "$service"26 service_check_support "$service"
27 _service_check_disabled "$service" || error_exit service_already_disabled27 _service_check_disabled "$service" || error_exit service_already_disabled
28 shift 128 shift 1
29 "${service}_disable" "$@"29 "${service}_disable" "$@"
@@ -58,14 +58,14 @@ service_print_status() {
58 fi58 fi
59}59}
6060
61_service_check_user() {61service_check_user() {
62 if [ "$(id -u)" -ne 0 ]; then62 if [ "$(id -u)" -ne 0 ]; then
63 error_msg "This command must be run as root (try using sudo)"63 error_msg "This command must be run as root (try using sudo)"
64 error_exit not_root64 error_exit not_root
65 fi65 fi
66}66}
6767
68_service_check_support() {68service_check_support() {
69 local service="$1"69 local service="$1"
7070
71 check_series_arch_supported "$service"71 check_series_arch_supported "$service"
diff --git a/modules/utils.sh b/modules/utils.sh
index 1862fb4..5d13057 100644
--- a/modules/utils.sh
+++ b/modules/utils.sh
@@ -20,6 +20,26 @@ error_exit() {
20 exit "${codes[$code]}"20 exit "${codes[$code]}"
21}21}
2222
23# prompt the user to confirm
24#
25prompt_user() {
26 local answer
27
28 while true; do
29 read -r -p "$* [N/y] " answer 2>&1
30 case "$answer" in
31 y|Y)
32 return 0
33 ;;
34 ''|n|N)
35 return 1
36 ;;
37 *) echo "Please answer y or n."
38 ;;
39 esac
40 done
41}
42
23check_result() {43check_result() {
24 local result output44 local result output
25 result=045 result=0
diff --git a/tests/test_esm.py b/tests/test_esm.py
index 04f73e9..acd0707 100644
--- a/tests/test_esm.py
+++ b/tests/test_esm.py
@@ -20,7 +20,7 @@ class ESMTest(UbuntuAdvantageTest):
20 expected = (20 expected = (
21 'deb https://esm.ubuntu.com/ubuntu precise main\n'21 'deb https://esm.ubuntu.com/ubuntu precise main\n'
22 '# deb-src https://esm.ubuntu.com/ubuntu precise main\n')22 '# deb-src https://esm.ubuntu.com/ubuntu precise main\n')
23 self.assertEqual(expected, self.repo_list.read_text())23 self.assertEqual(expected, self.esm_repo_list.read_text())
24 self.assertEqual(24 self.assertEqual(
25 self.apt_auth_file.read_text(),25 self.apt_auth_file.read_text(),
26 'machine esm.ubuntu.com/ubuntu/ login user password pass\n')26 'machine esm.ubuntu.com/ubuntu/ login user password pass\n')
@@ -198,7 +198,7 @@ class ESMTest(UbuntuAdvantageTest):
198 process = self.script('disable-esm')198 process = self.script('disable-esm')
199 self.assertEqual(0, process.returncode)199 self.assertEqual(0, process.returncode)
200 self.assertIn('Ubuntu ESM repository disabled', process.stdout)200 self.assertIn('Ubuntu ESM repository disabled', process.stdout)
201 self.assertFalse(self.repo_list.exists())201 self.assertFalse(self.esm_repo_list.exists())
202 # the keyring file is removed202 # the keyring file is removed
203 keyring_file = self.trusted_gpg_dir / 'ubuntu-esm-keyring.gpg'203 keyring_file = self.trusted_gpg_dir / 'ubuntu-esm-keyring.gpg'
204 self.assertFalse(keyring_file.exists())204 self.assertFalse(keyring_file.exists())
diff --git a/tests/test_fips.py b/tests/test_fips.py
index 5efe325..433c0bf 100644
--- a/tests/test_fips.py
+++ b/tests/test_fips.py
@@ -23,7 +23,12 @@ class FIPSTest(UbuntuAdvantageTest):
23 'fips/ubuntu xenial main\n'23 'fips/ubuntu xenial main\n'
24 '# deb-src https://private-ppa.launchpad.net/'24 '# deb-src https://private-ppa.launchpad.net/'
25 'ubuntu-advantage/fips/ubuntu xenial main\n')25 'ubuntu-advantage/fips/ubuntu xenial main\n')
26 self.assertEqual(expected, self.repo_list.read_text())26 self.assertEqual(expected, self.fips_repo_list.read_text())
27 expected = (
28 'Package: *\n'
29 'Pin: release o=LP-PPA-ubuntu-advantage-fips, n=xenial\n'
30 'Pin-Priority: 1001\n')
31 self.assertEqual(self.fips_repo_preferences.read_text(), expected)
27 self.assertEqual(32 self.assertEqual(
28 self.apt_auth_file.read_text(),33 self.apt_auth_file.read_text(),
29 'machine private-ppa.launchpad.net/ubuntu-advantage/fips/ubuntu/'34 'machine private-ppa.launchpad.net/ubuntu-advantage/fips/ubuntu/'
@@ -67,6 +72,15 @@ class FIPSTest(UbuntuAdvantageTest):
67 'Please reboot into the FIPS kernel to enable it.',72 'Please reboot into the FIPS kernel to enable it.',
68 process.stderr.strip())73 process.stderr.strip())
6974
75 def test_enable_fips_not_all_packages_installed(self):
76 # one of the packages is not installed
77 self.make_fake_binary(
78 'dpkg-query', command='[ $2 != openssh-client-hmac ]')
79 process = self.script('enable-fips', 'user:pass')
80 self.assertEqual(process.returncode, 0)
81 self.assertIn('Installing FIPS packages', process.stdout)
82 self.assertIn('Successfully configured FIPS', process.stdout)
83
70 def test_enable_fips_writes_config(self):84 def test_enable_fips_writes_config(self):
71 """The enable-fips option writes fips configuration."""85 """The enable-fips option writes fips configuration."""
72 self.script('enable-fips', 'user:pass')86 self.script('enable-fips', 'user:pass')
@@ -249,3 +263,160 @@ class FIPSTest(UbuntuAdvantageTest):
249 self.assertIn(263 self.assertIn(
250 'Canonical FIPS 140-2 Modules is not enabled',264 'Canonical FIPS 140-2 Modules is not enabled',
251 process.stderr)265 process.stderr)
266
267 def test_update_fips(self):
268 """The enable-fips-updates option enables FIPS-UPDATES repository."""
269 process = self.script('enable-fips-updates', 'user:pass', '-y')
270 self.assertEqual(0, process.returncode)
271 self.assertIn('Ubuntu FIPS-UPDATES PPA repository enabled.',
272 process.stdout)
273 expected = (
274 'deb https://private-ppa.launchpad.net/ubuntu-advantage/'
275 'fips-updates/ubuntu xenial main\n'
276 '# deb-src https://private-ppa.launchpad.net/'
277 'ubuntu-advantage/fips-updates/ubuntu xenial main\n')
278 self.assertEqual(expected, self.fips_updates_repo_list.read_text())
279 expected = (
280 'Package: *\n'
281 'Pin: release o=LP-PPA-ubuntu-advantage-fips-updates, n=xenial\n'
282 'Pin-Priority: 1001\n')
283 self.assertEqual(self.fips_updates_repo_preferences.read_text(),
284 expected)
285 self.assertEqual(
286 self.apt_auth_file.read_text(),
287 'machine private-ppa.launchpad.net/ubuntu-advantage/'
288 'fips-updates/ubuntu/'
289 ' login user password pass\n')
290 self.assertEqual(self.apt_auth_file.stat().st_mode, 0o100600)
291 keyring_file = self.trusted_gpg_dir / 'ubuntu-fips-updates-keyring.gpg'
292 self.assertEqual('GPG key', keyring_file.read_text())
293 self.assertIn(
294 'Configuring FIPS...',
295 process.stdout)
296 self.assertIn(
297 'Successfully updated FIPS packages.\n'
298 'Please reboot into the new FIPS kernel',
299 process.stdout)
300
301 def test_update_fips_auth_if_other_entries(self):
302 """Existing auth.conf entries are preserved."""
303 auth = 'machine example.com login user password pass\n'
304 self.apt_auth_file.write_text(auth)
305 process = self.script('enable-fips-updates', 'user:pass', '-y')
306 self.assertEqual(0, process.returncode)
307 self.assertIn(auth, self.apt_auth_file.read_text())
308
309 def test_update_fips_writes_config(self):
310 """The enable-fips-updates option writes fips configuration."""
311 self.script('enable-fips-updates', 'user:pass', '-y')
312 self.assertEqual(
313 'GRUB_CMDLINE_LINUX_DEFAULT="$GRUB_CMDLINE_LINUX_DEFAULT fips=1"',
314 self.boot_cfg.read_text().strip())
315
316 def test_update_fips_writes_config_with_boot_partition(self):
317 """The fips configuration includes the /boot partition."""
318 self.fstab.write_text('/dev/sda1 /boot ext2 defaults 0 1\n')
319 self.script('enable-fips-updates', 'user:pass', '-y')
320 self.assertIn('bootdev=/dev/sda1', self.boot_cfg.read_text())
321
322 def test_update_fips_writes_config_s390x_parameters(self):
323 """On S390x, FIPS parameters are appended to the config file."""
324 self.ARCH = 's390x'
325 self.boot_cfg.write_text('parameters=foo\n')
326 self.script('enable-fips-updates', 'user:pass', '-y')
327 self.assertEqual('parameters=foo fips=1\n', self.boot_cfg.read_text())
328
329 def test_update_unsupported_on_i686(self):
330 """FIPS is unsupported on i686 arch."""
331 self.ARCH = 'i686'
332 process = self.script('enable-fips-updates', 'user:pass', '-y')
333 self.assertEqual(7, process.returncode)
334 self.assertIn(
335 'Sorry, but Canonical FIPS 140-2 Modules is not supported on i686',
336 process.stderr)
337
338 def test_update_fips_missing_token(self):
339 """The token must be specified when using enable-fips-updates."""
340 process = self.script('enable-fips-updates')
341 self.assertEqual(3, process.returncode)
342 self.assertIn(
343 'Invalid token, it must be in the form "user:password"',
344 process.stderr)
345
346 def test_update_fips_invalid_token_format(self):
347 """The FIPS token must be specified as "user:password"."""
348 process = self.script('enable-fips-updates', 'foo-bar', '-y')
349 self.assertEqual(3, process.returncode)
350 self.assertIn(
351 'Invalid token, it must be in the form "user:password"',
352 process.stderr)
353
354 def test_update_fips_invalid_token(self):
355 """If token is invalid, an error is returned."""
356 message = (
357 'E: Failed to fetch https://esm.ubuntu.com/'
358 ' 401 Unauthorized [IP: 1.2.3.4]')
359 self.make_fake_binary(
360 'apt-helper', command='echo "{}"; exit 1'.format(message))
361 process = self.script('enable-fips-updates', 'user:pass', '-y')
362 self.assertEqual(3, process.returncode)
363 self.assertIn('Checking token... ERROR', process.stdout)
364 self.assertIn('Invalid token', process.stderr)
365
366 def test_update_fips_invalid_token_trusty(self):
367 """Invalid token error is caught with apt-helper in trusty."""
368 message = 'E: Failed to fetch https://esm.ubuntu.com/ HttpError401'
369 self.make_fake_binary(
370 'apt-helper', command='echo "{}"; exit 1'.format(message))
371 process = self.script('enable-fips-updates', 'user:pass', '-y')
372 self.assertEqual(3, process.returncode)
373 self.assertIn('Checking token... ERROR', process.stdout)
374 self.assertIn('Invalid token', process.stderr)
375
376 def test_update_fips_error_checking_token(self):
377 """If token check fails, an error is returned."""
378 message = (
379 'E: Failed to fetch https://esm.ubuntu.com/'
380 ' 404 Not Found [IP: 1.2.3.4]')
381 self.make_fake_binary(
382 'apt-helper', command='echo "{}"; exit 1'.format(message))
383 process = self.script('enable-fips-updates', 'user:pass', '-y')
384 self.assertEqual(3, process.returncode)
385 self.assertIn('Checking token... ERROR', process.stdout)
386 self.assertIn(
387 'Failed checking token (404 Not Found [IP: 1.2.3.4])',
388 process.stderr)
389
390 def test_update_fips_only_supported_on_xenial(self):
391 """The enable-fips-updates option fails if not on Xenial."""
392 self.SERIES = 'zesty'
393 process = self.script('enable-fips-updates', 'user:pass', '-y')
394 self.assertEqual(4, process.returncode)
395 self.assertIn(
396 'Canonical FIPS 140-2 Modules is not supported on zesty',
397 process.stderr)
398
399 def test_update_fips_x86_64_aes_not_available(self):
400 """The enable-fips-updates command fails if AESNI is not available."""
401 self.cpuinfo.write_text('flags\t\t: fpu tsc')
402 process = self.script('enable-fips-updates', 'user:pass', '-y')
403 self.assertEqual(7, process.returncode)
404 self.assertEqual(
405 'FIPS requires AES CPU extensions', process.stderr.strip())
406
407 def test_update_fips_ppc64le_power8(self):
408 """POWER8 processors are supported by FIPS."""
409 self.ARCH = 'ppc64le'
410 self.cpuinfo.write_text('cpu\t\t: POWER8 (raw), altivec supported')
411 process = self.script('enable-fips-updates', 'user:pass', '-y')
412 self.assertEqual(0, process.returncode)
413 self.assertIn('Successfully updated FIPS packages', process.stdout)
414
415 def test_update_fips_ppc64le_older_power(self):
416 """processors older than POWER8 are not supported by FIPS."""
417 self.ARCH = 'ppc64le'
418 self.cpuinfo.write_text('cpu\t\t: POWER7')
419 process = self.script('enable-fips-updates', 'user:pass', '-y')
420 self.assertEqual(7, process.returncode)
421 self.assertEqual(
422 'FIPS requires POWER8 or later', process.stderr.strip())
diff --git a/tests/test_script.py b/tests/test_script.py
index 1feb400..4e7da93 100644
--- a/tests/test_script.py
+++ b/tests/test_script.py
@@ -79,6 +79,18 @@ class UbuntuAdvantageScriptTest(UbuntuAdvantageTest):
79 process = self.script('status')79 process = self.script('status')
80 self.assertIn("livepatch: disabled (not available)", process.stdout)80 self.assertIn("livepatch: disabled (not available)", process.stdout)
8181
82 def test_status_with_one_service(self):
83 """The status for a single service can be returned."""
84 self.SERIES = 'precise'
85 process = self.script('status', 'fips')
86 self.assertEqual(process.returncode, 0)
87 self.assertEqual(process.stdout, 'fips: disabled (not available)\n')
88
89 def test_status_with_one_service_unknown(self):
90 """The script exits with error on unknown service status name."""
91 process = self.script('status', 'unknown')
92 self.assertEqual(process.returncode, 1)
93
82 def test_version(self):94 def test_version(self):
83 """The version command shows the package version."""95 """The version command shows the package version."""
84 self.make_fake_binary('dpkg-query', command='echo 123')96 self.make_fake_binary('dpkg-query', command='echo 123')
diff --git a/tests/testing.py b/tests/testing.py
index a26eb6c..c684f48 100644
--- a/tests/testing.py
+++ b/tests/testing.py
@@ -50,10 +50,17 @@ class UbuntuAdvantageTest(TestWithFixtures):
50 def setUp(self):50 def setUp(self):
51 super(UbuntuAdvantageTest, self).setUp()51 super(UbuntuAdvantageTest, self).setUp()
52 self.tempdir = self.useFixture(TempDir())52 self.tempdir = self.useFixture(TempDir())
53 self.repo_list = Path(self.tempdir.join('repo.list'))
54 self.boot_cfg = Path(self.tempdir.join('boot.cfg'))53 self.boot_cfg = Path(self.tempdir.join('boot.cfg'))
55 self.fstab = Path(self.tempdir.join('fstab'))54 self.fstab = Path(self.tempdir.join('fstab'))
56 self.cpuinfo = Path(self.tempdir.join('cpuinfo'))55 self.cpuinfo = Path(self.tempdir.join('cpuinfo'))
56 self.esm_repo_list = Path(self.tempdir.join('esm-repo.list'))
57 self.fips_repo_list = Path(self.tempdir.join('fips-repo.list'))
58 self.fips_updates_repo_list = Path(
59 self.tempdir.join('fips-updates-repo.list'))
60 self.fips_repo_preferences = Path(
61 self.tempdir.join('preferences-fips'))
62 self.fips_updates_repo_preferences = Path(
63 self.tempdir.join('preferences-fips-updates'))
57 self.fips_enabled_file = Path(self.tempdir.join('fips_enabled_file'))64 self.fips_enabled_file = Path(self.tempdir.join('fips_enabled_file'))
58 self.bin_dir = Path(self.tempdir.join('bin'))65 self.bin_dir = Path(self.tempdir.join('bin'))
59 self.etc_dir = Path(self.tempdir.join('etc'))66 self.etc_dir = Path(self.tempdir.join('etc'))
@@ -73,6 +80,8 @@ class UbuntuAdvantageTest(TestWithFixtures):
73 self.trusted_gpg_dir.mkdir()80 self.trusted_gpg_dir.mkdir()
74 (self.keyrings_dir / 'ubuntu-esm-keyring.gpg').write_text('GPG key')81 (self.keyrings_dir / 'ubuntu-esm-keyring.gpg').write_text('GPG key')
75 (self.keyrings_dir / 'ubuntu-fips-keyring.gpg').write_text('GPG key')82 (self.keyrings_dir / 'ubuntu-fips-keyring.gpg').write_text('GPG key')
83 (self.keyrings_dir / 'ubuntu-fips-updates-keyring.gpg').write_text(
84 'GPG key')
76 self.cpuinfo.write_text('flags\t\t: fpu apic')85 self.cpuinfo.write_text('flags\t\t: fpu apic')
77 self.make_fake_binary('apt-get')86 self.make_fake_binary('apt-get')
78 self.make_fake_binary('apt-helper')87 self.make_fake_binary('apt-helper')
@@ -105,11 +114,15 @@ class UbuntuAdvantageTest(TestWithFixtures):
105 'PATH': path,114 'PATH': path,
106 'FSTAB': str(self.fstab),115 'FSTAB': str(self.fstab),
107 'CPUINFO': str(self.cpuinfo),116 'CPUINFO': str(self.cpuinfo),
108 'ESM_REPO_LIST': str(self.repo_list),117 'ESM_REPO_LIST': str(self.esm_repo_list),
109 'FIPS_REPO_LIST': str(self.repo_list),118 'FIPS_REPO_LIST': str(self.fips_repo_list),
119 'FIPS_UPDATES_REPO_LIST': str(self.fips_updates_repo_list),
110 'FIPS_BOOT_CFG': str(self.boot_cfg),120 'FIPS_BOOT_CFG': str(self.boot_cfg),
111 'FIPS_BOOT_CFG_DIR': str(self.etc_dir),121 'FIPS_BOOT_CFG_DIR': str(self.etc_dir),
112 'FIPS_ENABLED_FILE': str(self.fips_enabled_file),122 'FIPS_ENABLED_FILE': str(self.fips_enabled_file),
123 'FIPS_REPO_PREFERENCES': str(self.fips_repo_preferences),
124 'FIPS_UPDATES_REPO_PREFERENCES': str(
125 self.fips_updates_repo_preferences),
113 'KEYRINGS_DIR': str(self.keyrings_dir),126 'KEYRINGS_DIR': str(self.keyrings_dir),
114 'APT_HELPER': str(self.apt_helper),127 'APT_HELPER': str(self.apt_helper),
115 'APT_AUTH_FILE': str(self.apt_auth_file),128 'APT_AUTH_FILE': str(self.apt_auth_file),
diff --git a/ubuntu-advantage b/ubuntu-advantage
index 451e060..1ad03a5 100755
--- a/ubuntu-advantage
+++ b/ubuntu-advantage
@@ -38,8 +38,15 @@ load_modules() {
38}38}
3939
40print_status() {40print_status() {
41 local service41 local service="$1"
42 for service in $SERVICES; do42
43 local services="$SERVICES"
44 if [ "$service" ]; then
45 name_in_list "$service" "$SERVICES" || error_exit invalid_command
46 services="$service"
47 fi
48
49 for service in $services; do
43 service_print_status "$service"50 service_print_status "$service"
44 done51 done
45}52}
@@ -54,20 +61,25 @@ Ubuntu Advantage offerings.
54Currently available are:61Currently available are:
55- Ubuntu Extended Security Maintenance archive (https://ubuntu.com/esm)62- Ubuntu Extended Security Maintenance archive (https://ubuntu.com/esm)
56- Canonical FIPS 140-2 Certified Modules63- Canonical FIPS 140-2 Certified Modules
64- Canonical FIPS 140-2 Non-Certified Module Updates
57- Canonical Livepatch Service (https://www.ubuntu.com/server/livepatch)65- Canonical Livepatch Service (https://www.ubuntu.com/server/livepatch)
5866
59Commands:67Commands:
60 version show the tool version68 version show the tool version
61 status show current status of Ubuntu Advantage offerings69 status [NAME] show current status of Ubuntu Advantage
62 enable-esm <token> enable the ESM repository70 offerings (or of a specific one if provided)
63 disable-esm disable the ESM repository71 enable-esm <TOKEN> enable the ESM repository
64 enable-fips <token> enable the FIPS PPA repository and install,72 disable-esm disable the ESM repository
65 configure and enable FIPS certified modules73 enable-fips <TOKEN> enable the FIPS PPA repository and install,
66 disabe-fips currently not supported74 configure and enable FIPS certified modules
67 enable-livepatch <token> enable the Livepatch service75 disable-fips currently not supported
68 disable-livepatch [-r] disable the Livepatch service. With "-r", the76 enable-fips-updates <TOKEN> [-y] enable non-certified FIPS-UPDATES PPA
69 canonical-livepatch snap will also be removed77 repository and install updates. With an
7078 optional "-y" the user prompt will be
79 bypassed.
80 enable-livepatch <TOKEN> enable the Livepatch service
81 disable-livepatch [-r] disable the Livepatch service. With "-r", the
82 canonical-livepatch snap will also be removed
71EOF83EOF
72 error_exit invalid_command84 error_exit invalid_command
73}85}
@@ -79,20 +91,40 @@ main() {
79 local service91 local service
80 service=$(service_from_command "$command")92 service=$(service_from_command "$command")
81 # if the command contains a service name, check that it's valid93 # if the command contains a service name, check that it's valid
82 if [ "$service" ] && ! name_in_list "$service" "$SERVICES"; then94 if [ "$service" ] && ! name_in_list "$service" "$SERVICES" \
95 && [ "$service" != "fips-updates" ]; then
83 error_msg "Invalid command: \"$command\""96 error_msg "Invalid command: \"$command\""
84 usage97 usage
85 fi98 fi
8699
87 case "$command" in100 case "$command" in
88 status)101 status)
89 print_status102 print_status "$@"
90 ;;103 ;;
91104
92 version)105 version)
93 package_version ubuntu-advantage-tools106 package_version ubuntu-advantage-tools
94 ;;107 ;;
95108
109 # special case, adding it above enable-*. There is no separate
110 # fips-update service.
111 enable-fips-updates)
112 local token="$1"
113 local bypass_prompt=0
114 if [ -n "$2" ]; then
115 if [ "$2" = "-y" ]; then
116 bypass_prompt=1
117 else
118 error_msg "Unknown option \"$2\""
119 usage
120 fi
121 fi
122 service_check_user
123 service_check_support "fips"
124 fips_validate_token "$token" || error_exit invalid_token
125 fips_updates_enable "$token" "$bypass_prompt"
126 ;;
127
96 enable-*)128 enable-*)
97 service_enable "$service" "$@"129 service_enable "$service" "$@"
98 ;;130 ;;
diff --git a/ubuntu-advantage.1 b/ubuntu-advantage.1
index 0fa3290..e86b85d 100644
--- a/ubuntu-advantage.1
+++ b/ubuntu-advantage.1
@@ -55,6 +55,25 @@ cryptoapi.
55disable-fips55disable-fips
56It's currently not possible to disable FIPS after it has been enabled.56It's currently not possible to disable FIPS after it has been enabled.
5757
58.TP
59.B
60enable-fips-updates \fItoken\fR [\fB\-y\fR]
61Updating the FIPS modules will take the system out of FIPS compliance as the
62updated modules are not FIPS certified. The option enables the FIPS-UPDATES
63PPA repository and installs the updated FIPS modules. If the system is
64installing FIPS modules for the first time, it configures FIPS on the
65system. After successfully executing the ubuntu-advantage script to
66update FIPS modules, the system MUST be rebooted if FIPS kernel was
67upgraded in the upgrade process. Failing to reboot will result
68in the system not running the updated FIPS kernel.
69The \fItoken\fR argument must be in the form "user:password".
70The \fB\-y\fR argument is optional to bypass the user prompt while
71installing updates.
72
73The following FIPS modules will be updated and put in FIPS mode -
74openssh-server, openssh-client, strongswan, openssl, and the kernel
75cryptoapi.
76
58.SH Livepatch (Canonical Livepatch Service)77.SH Livepatch (Canonical Livepatch Service)
59Managed live kernel patching. For more information, visit78Managed live kernel patching. For more information, visit
60https://www.ubuntu.com/server/livepatch79https://www.ubuntu.com/server/livepatch

Subscribers

People subscribed via source and target branches

to status/vote changes: