From 9d3bc471c73d540e046ce72da5fcd1bcc29f7d2e Mon Sep 17 00:00:00 2001 From: abin Date: Thu, 13 Apr 2023 12:14:53 +0530 Subject: [PATCH] Remove Gramine dependencies that are not needed at runtime To remove these Gramine dependencies, a new command-line argument `--remove-gramine-deps` (alias to `-Dremove-gramine-deps=true`) is introduced. By default it is not set, since removing Gramine dependencies could also remove packages required by original app. This option is useful to minimize the final Docker image, in terms of the amount of installed software. Signed-off-by: abin --- Documentation/index.rst | 10 +++++++ gsc.py | 35 ++++++++++++++++++++++- templates/Dockerfile.common.sign.template | 10 +++++++ templates/centos/Dockerfile.sign.template | 16 +++++++++++ templates/debian/Dockerfile.sign.template | 19 ++++++++++++ 5 files changed, 89 insertions(+), 1 deletion(-) diff --git a/Documentation/index.rst b/Documentation/index.rst index e5dfc053..2631e50b 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -169,6 +169,16 @@ of the signing key in them. Provide passphrase for the enclave signing key (if applicable) +.. option:: -D, --define + + Set image sign-time variables during :command:`gsc sign`. + +.. option:: --remove-gramine-deps + + Remove Gramine dependencies that are not needed at runtime. This may have + a negative side effect of removing even those dependencies that are actually + needed by the original application. Use with care! + .. option:: IMAGE-NAME Name of the application Docker image diff --git a/gsc.py b/gsc.py index e0b5ebda..a6daeff3 100755 --- a/gsc.py +++ b/gsc.py @@ -21,6 +21,18 @@ import tomli_w # pylint: disable=import-error import yaml # pylint: disable=import-error +def test_trueish(value): + if not value: + return False + value = value.casefold() + if value in ('false', 'off', 'no'): + return False + if value in ('true', 'on', 'yes'): + return True + if value.isdigit(): + return bool(int(value)) + raise ValueError(f'Invalid value for trueish: {value!r}') + def gsc_image_name(original_image_name): return f'gsc-{original_image_name}' @@ -131,6 +143,17 @@ def extract_build_args(args): sys.exit(1) return buildargs_dict +def extract_define_args(args): + defineargs_dict = {} + for item in args.define: + if '=' in item: + key, value = item.split('=', maxsplit=1) + defineargs_dict[key] = value + else: + print(f'Invalid value for argument `{item}`, expected `--define {item}=`') + sys.exit(1) + return defineargs_dict + def extract_user_from_image_config(config, env): user = config['User'] if not user: @@ -345,6 +368,9 @@ def gsc_sign_image(args): # using the user-provided config file with info on OS distro, Gramine version and SGX driver env = jinja2.Environment() env.globals.update(yaml.safe_load(args.config_file)) + extract_user_from_image_config(unsigned_image.attrs['Config'], env) + env.globals['args'] = extract_define_args(args) + env.tests['trueish'] = test_trueish distro = env.globals['Distro'] distro, _ = distro.split(':') @@ -510,7 +536,14 @@ def gsc_info_image(args): sub_sign.add_argument('image', help='Name of the application (base) Docker image.') sub_sign.add_argument('key', help='Key to sign the Intel SGX enclaves inside the Docker image.') sub_sign.add_argument('-p', '--passphrase', help='Passphrase for the signing key.') - +sub_sign.add_argument('-D','--define', action='append', default=[], + help='Set image sign-time variables.') +sub_sign.add_argument('--remove-gramine-deps', action='append_const', dest='define', + const='remove_gramine_deps=true', help='Remove Gramine dependencies that are not needed' + ' at runtime.') +sub_sign.add_argument('--no-remove-gramine-deps', action='append_const', dest='define', + const='remove_gramine_deps=false', help='Retain Gramine dependencies that are not needed' + ' at runtime.') sub_info = subcommands.add_parser('info-image', help='Retrieve information about a graminized ' 'Docker image') sub_info.set_defaults(command=gsc_info_image) diff --git a/templates/Dockerfile.common.sign.template b/templates/Dockerfile.common.sign.template index cee5993e..02942d5d 100644 --- a/templates/Dockerfile.common.sign.template +++ b/templates/Dockerfile.common.sign.template @@ -17,3 +17,13 @@ FROM {{image}} COPY --from=unsigned_image /gramine/app_files/*.sig /gramine/app_files/ COPY --from=unsigned_image /gramine/app_files/*.sgx /gramine/app_files/ + +{% if args.remove_gramine_deps is trueish %} +# Temporarily switch to the root user to uninstall packages +USER root + +{% block uninstall %}{% endblock %} + +# Switch back to original app_image user +USER {{app_user}} +{% endif %} diff --git a/templates/centos/Dockerfile.sign.template b/templates/centos/Dockerfile.sign.template index 6b38ad8f..5bd16e81 100644 --- a/templates/centos/Dockerfile.sign.template +++ b/templates/centos/Dockerfile.sign.template @@ -1,3 +1,19 @@ {% extends "Dockerfile.common.sign.template" %} +{% block uninstall %} +RUN \ + pip3 uninstall -y click jinja2 \ + tomli tomli-w \ + toml \ + && dnf remove -y binutils \ + epel-release \ + expect \ + openssl \ + python3-protobuf \ + python3-pyelftools \ + python3-cryptography \ + tcl \ + && dnf -y clean all; +{% endblock %} + {% block path %}export PYTHONPATH="${PYTHONPATH}:$(find /gramine/meson_build_output/lib64 -type d -path '*/site-packages')" &&{% endblock %} diff --git a/templates/debian/Dockerfile.sign.template b/templates/debian/Dockerfile.sign.template index 7ed0e2fa..e36af184 100644 --- a/templates/debian/Dockerfile.sign.template +++ b/templates/debian/Dockerfile.sign.template @@ -1,3 +1,22 @@ {% extends "Dockerfile.common.sign.template" %} +{% block uninstall %} +RUN \ + apt-get update -y \ + && apt-get install -y python3-pip \ + && pip3 uninstall -y click jinja2 \ + tomli tomli-w \ + toml \ + && apt-get remove -y binutils \ + expect \ + libcurl4-openssl-dev \ + openssl \ + python3-pip \ + python3-protobuf \ + python3-cryptography \ + python3-pyelftools \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/*; +{% endblock %} + {% block path %}export PYTHONPATH="${PYTHONPATH}:$(find /gramine/meson_build_output/lib -type d -path '*/site-packages')" &&{% endblock %}