diff --git a/Documentation/index.rst b/Documentation/index.rst index 3c740bf1..f91a27e5 100644 --- a/Documentation/index.rst +++ b/Documentation/index.rst @@ -139,23 +139,27 @@ Docker image called ``gsc-``. :command:`gsc sign-image` always removes intermediate Docker images, if successful or not, to ensure the removal of the signing key in them. -:command:`gsc sign-image` [*OPTIONS*] <*IMAGE-NAME*> <*KEY-FILE*> +:command:`gsc sign-image` [*OPTIONS*] <*IMAGE-NAME*> .. option:: -c Specify configuration file. Default: :file:`config.yaml` +.. option:: -k KEY-FILE + + Provide key to sign the Intel SGX enclave. + .. option:: -p Provide passphrase for the enclave signing key (if applicable) -.. option:: IMAGE-NAME +.. option:: -t - Name of the application Docker image + Provide Dockerfile to use for signing the enclave (e.g., with an HSM) -.. option:: KEY-FILE +.. option:: IMAGE-NAME - Used to sign the Intel SGX enclave + Name of the application Docker image .. program:: gsc-build-gramine @@ -275,9 +279,10 @@ follows three main stages and produces an image named ``gsc-``. tool to generate SIGSTRUCT files for SGX enclave initialization. This tool also generates an SGX-specific manifest file. The required signing key is provided by the user via the :command:`gsc sign-image` command and copied - into this Docker build stage. The generated image is called - ``gsc-`` and includes all necessary files to start an Intel SGX - enclave. + into this Docker build stage. The users can also supply their own Dockerfile + templates using `--template` option of this command to sign (e.g. with HSM). + The generated image is called ``gsc-`` and includes all necessary + files to start an Intel SGX enclave. In the future we plan to provide prebuilt Gramine images for popular cloud-provider offerings. diff --git a/gsc.py b/gsc.py index cfcefc93..e8abd917 100755 --- a/gsc.py +++ b/gsc.py @@ -349,27 +349,38 @@ def gsc_sign_image(args): distro = env.globals['Distro'] distro, _ = distro.split(':') - env.loader = jinja2.FileSystemLoader('templates/') - sign_template = env.get_template(f'{distro}/Dockerfile.sign.template') + sign_template = None + build_args = {} os.makedirs(tmp_build_path, exist_ok=True) + + # Use default steps if user has not provided a Dockerfile/template for signing + if args.template is None: + # copy user-provided signing key and signing Bash script to our tmp build dir (to copy them + # later inside Docker image) + tmp_build_key_path = tmp_build_path / 'gsc-signer-key.pem' + tmp_build_sign_path = tmp_build_path / 'sign.sh' + shutil.copyfile(os.path.abspath(args.key), tmp_build_key_path) + shutil.copy(os.path.abspath('sign.sh'), tmp_build_sign_path) + env.loader = jinja2.FileSystemLoader('templates/') + sign_template = env.get_template(f'{distro}/Dockerfile.sign.template') + build_args = {"passphrase": args.passphrase} + else: + extract_user_from_image_config(unsigned_image.attrs['Config'], env) + env.loader = jinja2.FileSystemLoader(os.path.dirname(args.template)) + sign_template = env.get_template(os.path.basename(args.template)) + with open(tmp_build_path / 'Dockerfile.sign', 'w') as dockerfile: dockerfile.write(sign_template.render(image=unsigned_image_name)) - # copy user-provided signing key and signing Bash script to our tmp build dir (to copy them - # later inside Docker image) - tmp_build_key_path = tmp_build_path / 'gsc-signer-key.pem' - tmp_build_sign_path = tmp_build_path / 'sign.sh' - shutil.copyfile(os.path.abspath(args.key), tmp_build_key_path) - shutil.copy(os.path.abspath('sign.sh'), tmp_build_sign_path) - try: # `forcerm` parameter forces removal of intermediate Docker images even after unsuccessful # builds, to not leave the signing key lingering in any Docker containers build_docker_image(docker_socket.api, tmp_build_path, signed_image_name, 'Dockerfile.sign', - forcerm=True, buildargs={"passphrase": args.passphrase}) + forcerm=True, buildargs=build_args) finally: - os.remove(tmp_build_key_path) + if args.template is None: + os.remove(tmp_build_key_path) if get_docker_image(docker_socket, signed_image_name) is None: print(f'Failed to build a signed graminized Docker image `{signed_image_name}`.') @@ -501,7 +512,10 @@ def gsc_info_image(args): sub_sign.add_argument('-c', '--config_file', type=argparse.FileType('r', encoding='UTF-8'), default='config.yaml', help='Specify configuration file.') 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('-k', '--key', + help='Key to sign the Intel SGX enclaves inside the Docker image.') +sub_sign.add_argument('-t', '--template', + help='Custom Dockerfile/template to use for signing, say, with an HSM.') sub_sign.add_argument('-p', '--passphrase', help='Passphrase for the signing key.') sub_info = subcommands.add_parser('info-image', help='Retrieve information about a graminized '