Skip to content

envcas

envcas provides a convenient way to launch a native subprocess with

  • environment variables und arguments populated from SCONE CAS,
  • configuration files automatically generated and populated from SCONE CAS.

The tool is inspired by envconsul, envdir and envchain. However, envcas runs as a confidential application and we perform an attestation of envcas first. Hence, one can even require an OTP (One Time Password) to be able to execution of envcas with the help of the policy of envcas.

Configuration

envcas takes its environment variables and its arguments and execute a given native program.

envcas is controlled by the following configuration file

  • /etc/envcas/config.yaml is the configuration file. It contains the following sections:
program:  path/to/native/binary
injected_file:
  - from: /etc/envcas/original_injected_file1
    to: /path/to/injected_file1
  - from: /etc/envcas/original_injected_file2
    to: /path/to/injected_file2

The program is the binary that should be executed and the injected files, the from is the file injected by CAS into envcas and that is copied to a certain location indicated by to. We assume that all directories on the to path exists, i.e., envcas will fail to write the files in case the path does not exists.

This configuration files is typically defined within the policy of envcas.

Python Example

In the envcas example repository there is a runnable example on how to use envcas for a native Python3.9 app. It includes an example of how to get normal environment variables in addition to those included in the security policy.

Bash Example

An example policy that creates two configuration files:

  • /work/out1 that contains ASCII secret example_secret
  • /work/out2 that contains binary secret example2_secret
  • sets one environment variable SECRET_ENV, and
  • executes bash with arguments -c 'cat /work/out1'

We show once how to configure a native application with and without an OTP (One Time Password:

  • see service envcas in the policy for how to configure without an OTP
  • see service with_otp to see how to configure with an OTP. The OTP secret can be defined as a secret. We explicitly define it in the session. Typically, we would import this secret from another session to limit who can see the secret in the clear.

Our policy (session.yaml) could look as follows:

name: $SESSION
version: "0.3.10"

security:
  attestation:
    tolerate: [debug-mode,hyperthreading, outdated-tcb]
    ignore_advisories: "*"

images:
  - name: envcas_image
    injection_files:
     - path: /etc/envcas/config.yaml
       content: |
          program:  /bin/bash
          injection_files:
            - from: /etc/envcas/injected_file1
              to: /work/out1
            - from: /etc/envcas/injected_file2
              to: /work/out2
     - path: /etc/envcas/injected_file1
       content: |
          Secret="$$SCONE::example_secret$$"
     - path: /etc/envcas/injected_file2
       content: |
          Secret=$$SCONE::example2_secret$$

services:
   - name: envcas
     image_name: envcas_image
     mrenclaves: [$MRENCLAVE]
     command: envcas -c 'cat /work/out1'
     environment:
        SCONE_MODE: hw
        SCONE_LOG: ERROR
     pwd: /
   - name: with_otp
     image_name: envcas_image
     attestation:
        mrenclave: "$MRENCLAVE"
     one_time_password_shared_secret: $$SCONE::otp_secret$$
     command: envcas -c 'cat /work/out1'
     environment:
        SCONE_MODE: hw
        SCONE_LOG: ERROR
     pwd: /

secrets:
  - name: example_secret
    kind: ascii
    size: 32
  - name: example2_secret
    kind: binary
    size: 64
  - name: otp_secret
    kind: ascii
    value: JJBFGV2ZGNCFARKIKBFTGUCYKBNFKVQK

One can instantiate the environment variables in session.yaml and then upload this policy as follows:

cd /work

export SCONE_CAS_ADDR=edge.scone-cas.cf
export SCONE_LAS_ADDR=172.17.0.1
export SESSION=envcas-example-$RANDOM-$RANDOM
export MRENCLAVE=$(docker run --rm -v $PWD:/work registry.scontain.com/edge/envcas sh -c "SCONE_HASH=1 /bin/envcas")

scone cas attest $SCONE_CAS_ADDR --only_for_testing-trust-any --only_for_testing-debug  --only_for_testing-ignore-signer -C -G -S
scone session create -e SESSION=$SESSION -e MRENCLAVE=$MRENCLAVE session.yaml

SCONE_CONFIG_ID=$SESSION/envcas /bin/envcas

The binary envcas is part of image registry.scontain.com/edge/envcas. You can run it as follows:

SCONE_CONFIG_ID=$SESSION/envcas /bin/envcas

In this example, we would output the generated secret, i.e., the output could look as follows:

Secret="`Y'/c'fV],=G9JJHdJz9(6HaZ>>t}x}Y"

A runnable example can be found in here.

Using OTPs

To require an OTP, you would define a service like with_otp. Note. In this case, you would not define service envcas to avoid that one can circumvent using an OTP.

The OTP is enabled by defining the key one_time_password_shared_secret in the service description:

     one_time_password_shared_secret: $$SCONE::otp_secret$$

The OTP secret is defined in the secret section. In this example, we define with an explicit value. As we mentioned above, our recommendation is to import this from another session to limit visibility of this secret.

To run binary envcas as service with_otp, we need to add an OTP to the `SCONE_CONFIG_ID':

export OTP=... # define OTP using an authenticator
SCONE_CONFIG_ID=$SESSION/with_otp@$OTP /bin/envcas

If the OTP is correct, the output might look as follows:

Secret="=0r|GdtX9lGS*HtR/U'^U'PPH)H^\T<{"

If the OTP would be incorrect or already used, the output might look as follows:

[SCONE|FATAL] src/process/init.c:302:__scone_prepare_secure_config(): Could not initialize enclave state: Attestation failed
  Caused by: CAS sent an attestation/configuration error: Failed to retrieve service attestation configuration
  Caused by: A One-time Password was already used within this time-step. Please try again in the next time-step
Note: Connecting to CAS at edge.scone-cas.cf (port 18765) using service ID envcas-example-31925-25152/with_otp@964428
[SCONE|ERROR] tools/starter/signal.c:70:die_by_signal(): Enclave terminated due to signal: Aborted
Aborted (core dumped)

The example for OTP usage is in the same policy as the Bash one, in here.