Skip to content

Sconify Container Image (Standard Edition)

We show how to sconify an existing container image using a tool provided by the SCONE Standard Edition we

  • sconify the binary of the application running inside the container, i.e., converting it such that it runs inside of an SGX enclave
  • encrypt the files that the application accesses including libraries and code examples (like Python code)
  • creating a SCONE policy (a session) to ensure that the encryption key of the filesystem and the secrets that we generate can only be accessed by this application

Sconify Image Workflow

sconify_image supports only Alpine Linux-based images

This 1-step conversion supports native images based on Alpine Linux only. We plan to support Ubuntu-based images in the near future too.

CI/CD Workflow

In a typical workflow, one would perform the sconification of an image as part of the CI/CD pipeline: One would test the native image first, sconify the image and test the sconified image again. After a successful test, the binary would be pushed to a container image repository.

Namespace

To reduce the chances of a name conflict, we first generate a namespace. Let's create a random namespace for this example:

export NS="NS-$RANDOM"

Policy Extension

We sconify the same image as in the previous section, i.e., native_flask_restapi_image. This image requires the generation of a TLS certificate and a private key. To do so, we define a secret section for the generated policy that we store in a local file:

mkdir -p policy
cat > policy/secrets.yml <<EOF
secrets:
    - name: api_ca_key
      kind: private-key
    - name: api_ca_cert
      kind: x509-ca
      export_public: true
      private_key: api_ca_key
    - name: flask_key
      kind: private-key
    - name: flask
      kind: x509
      private_key: flask_key
      issuer: api_ca_cert
      dns:
        - api
EOF

We also define the location in which the sconified application can read the certificate and the private key:

cat > policy/injected_files.yml <<EOF
     injection_files:
        - path: "/tls/flask.crt"
          content: \$\$SCONE::flask.crt\$\$
        - path: "/tls/flask.key"
          content: "\$\$SCONE::flask.key\$\$"
EOF

Creating Sconified Image

To attest the CAS and uploaded a policy, we need access to the SGX device. Hence, we first determine the SGX device (see):

determine_sgx_device
mkdir -p cas

We use a public CAS service (--cas=4-2-1.scone-cas.cf) that is running in debug mode and hence, we set --cas_debug to ensure that attestation of CAS passes despite the CAS being in debug mode. The clients key used in the attestation are stored in the local directory cas.

SESSION=$(docker run -it --rm $MOUNT_SGXDEVICE -v "$(pwd)/policy:/policy" -v "$(pwd)/cas:/root/.cas"  -v /var/run/docker.sock:/var/run/docker.sock sconecuratedimages/sconecli:sconify_image --name=flask --from=native_flask_restapi_image --to=new_image --cas=4-2-1.scone-cas.cf  --cas_debug --binary=/usr/bin/python3 --dir=/home --dir=/usr/local/lib --dir=/app --dir=/usr/lib/python3.7 --dir=/lib  --plain=/usr/lib/libpython3.7m.so.1.0 --secrets=/policy/secrets.yml --injectedfiles=/policy/injected_files.yml --create_namespace --namespace=$NS)  

For production, you need to drop --cas_debug and to sign the binary

You can now execute the image in the context of session $SESSION: please read the previous section to learn how to do so.

Supported Options

sconify_image supports the following options:

  • --from=NATIVE_IMAGE: name of native image (mandatory)
  • --to=TO_IMAGE: name of encrypted image (mandatory)
  • --template=TEMPLATE_FILE: file containing policy template (default=session-template.yml)
  • --session=SESSION_FILE: file that will contain the session (default=session.yml)
  • --namespace=NAMESPACE: namespace of this session (default is a random namespace)
  • --create_namespace: create namespace NAMESPACE first
  • --dir=DIRECTORY: add directory to encrypt; add one option per directory
  • --plain=DIRECTORIES: copy directories that are not encrypted
  • --cas=CAS_ADDR: set the name of the CAS_ADDR
  • --cas_debug: permit CAS to be in debug mode
  • --base=BASE: set the base image used to generate the encrypted image
  • --cli=CLI: set the SCONE CLI image
  • --trace=TRACEFILE: use tracefile to create encrypted files
  • --name=SESSION: name of CAS policy session
  • --secrets=FILE: policy section that defines secrets
  • --injectedfiles=FILE: policy section that defines the injected files
  • --sign=KEYPATH: sign the binary (uses other arguments from environment)
  • --heap=INT: heap size in [K,M,G]
  • --stack=INT: stack size in [K,M,G]
  • --dlopen=[0|1|2]: dlopen: 0 - disable, 1 - enable and require authentication (default), 2 - debug only [SCONE_ALLOW_DLOPEN]

Next Step

Using this approach, we 1) attest CAS and 2) ensure that the policy is only pushed to a trusted CAS. For production, you need to sign the service: for this, you need to provide a signing key that you need to pass via option --sign=KEYPATH.