-
Notifications
You must be signed in to change notification settings - Fork 20
ENT-13005: Added integrity check to cf-remote remote installation #174
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -e | ||
|
|
||
| # Arg parsing | ||
|
|
||
| INSECURE=0 | ||
| HAS_WGET=0 | ||
| CHECKSUM="" | ||
|
|
||
| while getopts c:IW option; do | ||
| case "${option}" in | ||
| I) | ||
| INSECURE=1 | ||
| ;; | ||
| W) | ||
| HAS_WGET=1 | ||
| ;; | ||
| c) | ||
| CHECKSUM=$OPTARG | ||
| ;; | ||
| *) | ||
| echo "Usage: $0 [-I] [-c checksum] package_url" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| exit 1 | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| shift $((OPTIND - 1)) | ||
|
|
||
| PACKAGE=$1 | ||
| if [ -z "$PACKAGE" ]; then | ||
| echo "Usage: $0 [-I] [-c checksum] package_url" | ||
| exit 1; | ||
| fi | ||
|
|
||
| # temp file | ||
|
|
||
| tmpfile=$(mktemp) | ||
| cleanup() { | ||
| rm -f "$tmpfile" | ||
| } | ||
| trap cleanup EXIT QUIT TERM INT | ||
|
|
||
| # Download | ||
|
|
||
| if [ "$HAS_WGET" -eq 1 ]; then | ||
| wget -nv -O "$tmpfile" "$PACKAGE" | ||
| else | ||
| curl --fail -sS -o "$tmpfile" "$PACKAGE" | ||
| fi | ||
|
|
||
| # Checksum | ||
|
|
||
| filename="$(basename "$PACKAGE")" | ||
|
|
||
| if [ -n "$CHECKSUM" ]; then | ||
| hash="$(sha256sum "$tmpfile" | awk '{print $1}')" | ||
|
|
||
| if [[ "$CHECKSUM" != "$hash" ]]; then | ||
| if [ "$INSECURE" -eq 0 ]; then | ||
| echo "Package '$PACKAGE' doesn't match the expected checksum '$CHECKSUM'. Run with --insecure to skip" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit confusing. I'm guessing the If |
||
| exit 1 | ||
| fi | ||
| echo "Package '$PACKAGE' doesn't match the expected checksum '$CHECKSUM'. Continuing due to insecure flag" | ||
| fi | ||
| fi | ||
|
|
||
| mv "$tmpfile" "$filename" | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,6 +1,7 @@ | ||||||||||||||||||||||||||||||||||||||||
| #!/usr/bin/env python3 | ||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||
| import re | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| from os.path import basename, dirname, join, exists | ||||||||||||||||||||||||||||||||||||||||
| from collections import OrderedDict | ||||||||||||||||||||||||||||||||||||||||
| from typing import Union | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -276,7 +277,17 @@ def get_info(host, *, users=None, connection=None): | |||||||||||||||||||||||||||||||||||||||
| data["role"] = "hub" if discovery.get("NTD_CFHUB") else "client" | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| data["bin"] = {} | ||||||||||||||||||||||||||||||||||||||||
| for bin in ["dpkg", "rpm", "yum", "apt", "pkg", "zypper", "curl"]: | ||||||||||||||||||||||||||||||||||||||||
| for bin in [ | ||||||||||||||||||||||||||||||||||||||||
| "dpkg", | ||||||||||||||||||||||||||||||||||||||||
| "rpm", | ||||||||||||||||||||||||||||||||||||||||
| "yum", | ||||||||||||||||||||||||||||||||||||||||
| "apt", | ||||||||||||||||||||||||||||||||||||||||
| "pkg", | ||||||||||||||||||||||||||||||||||||||||
| "zypper", | ||||||||||||||||||||||||||||||||||||||||
| "curl", | ||||||||||||||||||||||||||||||||||||||||
| "wget", | ||||||||||||||||||||||||||||||||||||||||
| "sha256sum", | ||||||||||||||||||||||||||||||||||||||||
| ]: | ||||||||||||||||||||||||||||||||||||||||
| path = discovery.get("NTD_{}".format(bin.upper())) | ||||||||||||||||||||||||||||||||||||||||
victormlg marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||
| if path: | ||||||||||||||||||||||||||||||||||||||||
| data["bin"][bin] = path | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -432,7 +443,7 @@ def bootstrap_host(host_data, policy_server, *, connection=None, trust_server=Tr | |||||||||||||||||||||||||||||||||||||||
| def _package_from_list(tags, extension, packages): | ||||||||||||||||||||||||||||||||||||||||
| artifacts = [Artifact(None, p) for p in packages] | ||||||||||||||||||||||||||||||||||||||||
| artifact = filter_artifacts(artifacts, tags, extension)[-1] | ||||||||||||||||||||||||||||||||||||||||
| return artifact.url | ||||||||||||||||||||||||||||||||||||||||
| return artifact.url, artifact | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| def _package_from_releases( | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -445,7 +456,7 @@ def _package_from_releases( | |||||||||||||||||||||||||||||||||||||||
| release = releases.pick_version(version) | ||||||||||||||||||||||||||||||||||||||||
| if release is None: | ||||||||||||||||||||||||||||||||||||||||
| print("Could not find a release for version {}".format(version)) | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
| return None, None | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| release.init_download() | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
@@ -455,7 +466,7 @@ def _package_from_releases( | |||||||||||||||||||||||||||||||||||||||
| version, edition | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
| return None, None | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| artifacts = release.find(tags, extension) | ||||||||||||||||||||||||||||||||||||||||
| if not artifacts: | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -464,13 +475,16 @@ def _package_from_releases( | |||||||||||||||||||||||||||||||||||||||
| "hub" if "hub" in tags else "client" | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
| return None, None | ||||||||||||||||||||||||||||||||||||||||
| artifact = artifacts[-1] | ||||||||||||||||||||||||||||||||||||||||
| if remote_download: | ||||||||||||||||||||||||||||||||||||||||
| return artifact.url | ||||||||||||||||||||||||||||||||||||||||
| return artifact.url, artifact | ||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||
| return download_package( | ||||||||||||||||||||||||||||||||||||||||
| artifact.url, checksum=artifact.checksum, insecure=insecure | ||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||
| download_package( | ||||||||||||||||||||||||||||||||||||||||
| artifact.url, checksum=artifact.checksum, insecure=insecure | ||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||
| artifact, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
@@ -514,13 +528,103 @@ def get_package_from_host_info( | |||||||||||||||||||||||||||||||||||||||
| tags.extend(tag for tag in package_tags if tag != "msi") | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if packages is None: # No command line argument given | ||||||||||||||||||||||||||||||||||||||||
| package = _package_from_releases( | ||||||||||||||||||||||||||||||||||||||||
| package, artifact = _package_from_releases( | ||||||||||||||||||||||||||||||||||||||||
| tags, extension, version, edition, remote_download, insecure | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||
| package = _package_from_list(tags, extension, packages) | ||||||||||||||||||||||||||||||||||||||||
| package, artifact = _package_from_list(tags, extension, packages) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return package, artifact | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return package | ||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||
| Remotely download package on host. | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| This function checks for avalaible binaries, copies remote-download.sh to the host, then runs it to download the package. | ||||||||||||||||||||||||||||||||||||||||
| The script ensures package integrity by comparing checksums. | ||||||||||||||||||||||||||||||||||||||||
| """ | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+540
to
+545
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Docstrings go inside the function, as the first statement after the def line |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| def _remote_download( | ||||||||||||||||||||||||||||||||||||||||
| host, package, artifact, pkg_binary, insecure=False, connection=None | ||||||||||||||||||||||||||||||||||||||||
victormlg marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I'm missing something, but the |
||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if not pkg_binary: | ||||||||||||||||||||||||||||||||||||||||
| log.error("No binary could be found on host '{}'.format(host)") | ||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
victormlg marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if "sha256sum" not in pkg_binary: | ||||||||||||||||||||||||||||||||||||||||
| if not insecure: | ||||||||||||||||||||||||||||||||||||||||
| log.error( | ||||||||||||||||||||||||||||||||||||||||
| "Cannot check file integrity. sha256sum is not installed on host '{}'. Run with --insecure to skip".format( | ||||||||||||||||||||||||||||||||||||||||
| host | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
| log.warning( | ||||||||||||||||||||||||||||||||||||||||
| "Cannot check file integrity. sha256sum is not installed on host '{}'. Continuing due to insecure flag".format( | ||||||||||||||||||||||||||||||||||||||||
| host | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if "wget" in pkg_binary: | ||||||||||||||||||||||||||||||||||||||||
| has_wget = True | ||||||||||||||||||||||||||||||||||||||||
| elif "curl" in pkg_binary: | ||||||||||||||||||||||||||||||||||||||||
| has_wget = False | ||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||
| log.error( | ||||||||||||||||||||||||||||||||||||||||
| "Cannot download remotely. wget and/or curl are not installed on host '{}'".format( | ||||||||||||||||||||||||||||||||||||||||
| host | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+570
to
+580
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could consider:
Suggested change
Also the log message should say |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if not (artifact and artifact.checksum): | ||||||||||||||||||||||||||||||||||||||||
| if not insecure: | ||||||||||||||||||||||||||||||||||||||||
| log.error( | ||||||||||||||||||||||||||||||||||||||||
| "Cannot check file integrity on '{}'. No artifact associated with package '{}' found. Run with --insecure to skip".format( | ||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does the term artifact refer to? A docstring would be very helpful. |
||||||||||||||||||||||||||||||||||||||||
| host, package | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
| log.warning( | ||||||||||||||||||||||||||||||||||||||||
| "Cannot check file integrity on '{}'. No artifact associated with package '{}' found. Continuing due to insecure flag".format( | ||||||||||||||||||||||||||||||||||||||||
| host, package | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| cf_remote_dir = dirname(__file__) | ||||||||||||||||||||||||||||||||||||||||
| script_path = join(cf_remote_dir, "remote-download.sh") | ||||||||||||||||||||||||||||||||||||||||
| if not exists(script_path): | ||||||||||||||||||||||||||||||||||||||||
| sys.exit("%s does not exist" % script_path) | ||||||||||||||||||||||||||||||||||||||||
| scp( | ||||||||||||||||||||||||||||||||||||||||
| script_path, | ||||||||||||||||||||||||||||||||||||||||
| host, | ||||||||||||||||||||||||||||||||||||||||
| connection, | ||||||||||||||||||||||||||||||||||||||||
| hide=True, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| args = "" | ||||||||||||||||||||||||||||||||||||||||
| if insecure: | ||||||||||||||||||||||||||||||||||||||||
| args += "-I " | ||||||||||||||||||||||||||||||||||||||||
| if has_wget: | ||||||||||||||||||||||||||||||||||||||||
| args += "-W " | ||||||||||||||||||||||||||||||||||||||||
| if artifact: | ||||||||||||||||||||||||||||||||||||||||
| args += "-c {} ".format("hhh") | ||||||||||||||||||||||||||||||||||||||||
| args += package | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| ret = ssh_cmd(connection, "bash remote-download.sh {}".format(args), errors=True) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if ret is None: | ||||||||||||||||||||||||||||||||||||||||
| return None | ||||||||||||||||||||||||||||||||||||||||
| if insecure: | ||||||||||||||||||||||||||||||||||||||||
| warning = re.search(r"Package.*", ret) | ||||||||||||||||||||||||||||||||||||||||
| if warning: | ||||||||||||||||||||||||||||||||||||||||
| log.warning(warning.group(0)) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| log.debug("Successfully remotely downloaded package on host '{}'".format(host)) | ||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about something like |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return basename(package) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| @auto_connect | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -552,9 +656,10 @@ def install_host( | |||||||||||||||||||||||||||||||||||||||
| elif packages and len(packages) == 1: | ||||||||||||||||||||||||||||||||||||||||
| package = packages[0] | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| artifact = None | ||||||||||||||||||||||||||||||||||||||||
| if not package: | ||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||
| package = get_package_from_host_info( | ||||||||||||||||||||||||||||||||||||||||
| package, artifact = get_package_from_host_info( | ||||||||||||||||||||||||||||||||||||||||
| data.get("package_tags"), | ||||||||||||||||||||||||||||||||||||||||
| data.get("bin"), | ||||||||||||||||||||||||||||||||||||||||
| data.get("arch"), | ||||||||||||||||||||||||||||||||||||||||
|
|
@@ -574,19 +679,16 @@ def install_host( | |||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| if remote_download: | ||||||||||||||||||||||||||||||||||||||||
| if ("bin" not in data) or ("curl" not in data["bin"]): | ||||||||||||||||||||||||||||||||||||||||
| log.error( | ||||||||||||||||||||||||||||||||||||||||
| "Couldn't download remotely. Curl is not installed on host '%s'" % host | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| print("Downloading '%s' on '%s' using curl" % (package, host)) | ||||||||||||||||||||||||||||||||||||||||
| r = ssh_cmd( | ||||||||||||||||||||||||||||||||||||||||
| cmd="curl --fail -O {}".format(package), connection=connection, errors=True | ||||||||||||||||||||||||||||||||||||||||
victormlg marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||
| package = _remote_download( | ||||||||||||||||||||||||||||||||||||||||
| host, | ||||||||||||||||||||||||||||||||||||||||
| package, | ||||||||||||||||||||||||||||||||||||||||
| artifact, | ||||||||||||||||||||||||||||||||||||||||
| data.get("bin"), | ||||||||||||||||||||||||||||||||||||||||
| connection=connection, | ||||||||||||||||||||||||||||||||||||||||
| insecure=insecure, | ||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||
| if r is None: | ||||||||||||||||||||||||||||||||||||||||
| if package is None: | ||||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||||
| package = basename(package) | ||||||||||||||||||||||||||||||||||||||||
| elif not getattr(connection, "is_local", False): | ||||||||||||||||||||||||||||||||||||||||
| scp(package, host, connection=connection) | ||||||||||||||||||||||||||||||||||||||||
| package = basename(package) | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
Uh oh!
There was an error while loading. Please reload this page.