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 %}