Example: Reading and Updating a SCONE Policy
A SCONE policy defines
- criteria to attest a service: e.g., the hash value of the service, the file system state, and the hosts that are permitted to execute the service.
- secrets: types of secrets and how the values of the secrets are generated / retrieved.
- secret release: the way how a secret is released to a service.
Deploy the CLI
We show how to create, read, and update a policy using the SCONE CLI. The SCONE CLI is deployed as part of a docker image:
export SCONE_CLI_IMAGE="registry.scontain.com/sconecuratedimages/sconecli:alpine3.10" docker pull $SCONE_CLI_IMAGE docker run -it $SCONE_CLI_IMAGE
Attesting SCONE CAS
SCONE CAS attests services on startup and also provisions secrets to attested services. Before uploading a policy to a CAS instance, we need to attest this CAS instance runs inside of an enclave, runs the expected code, and the server running the CAS has an up-to-date firmware and microcode.
This attestation can be performed via the SCONE CLI. In this example, we use one of our public CAS instances. This public CAS instance runs in debug mode. Hence, attestation will fail - unless we set a few options to indicate that we are ok that we communicate with a CAS that executes in debug mode.
scone cas attest performs the attestation of the CAS:
export SCONE_CAS_ADDR=scone-cas.cf scone cas attest "$SCONE_CAS_ADDR" --only_for_testing-debug --only_for_testing-ignore-signer --only_for_testing-trust-any
Creating a SCONE policy
We create a policy, read the policy back, and then update the policy.
sconify_image would create the namespace as well as the initial policy of a service.
In some cases, we might need to change the namespace and/or the policy at some later point.
Let's first create a unique namespace for our example. We ensure that only we have access to this namespace and that only we
can create policies in this namespace. Authorization is enforced with the help of a (random) public/private key pair.
This key pair is referred to as
CREATOR. This keypair is stored
$HOME/.cas/config.json. If the public/private key pair does not exist, it is automatically generated by the SCONE CLI.
Let us create a policy for creating a new namespace. We use a random file namespace name by append a random number:
export SESSION_LANG_VERSION="0.3" export NAMESPACE="MyNameSpace-$RANDOM" cat > my_namespace.yml <<EOF name: $NAMESPACE version: "$SESSION_LANG_VERSION" access_policy: read: - CREATOR update: - CREATOR create_sessions: - CREATOR EOF
We can now create this namespace with command scone session create:
scone session create --cas "$SCONE_CAS_ADDR" --only_for_testing-disable-attestation-verification --use-env my_namespace.yml
Determining the ID of an existing policy
This policy is associated with a unique ID. The ID could be viewed similar to a
git commit time stamp. This ID is needed when we want to update a session. The ID is printed when the policy / namespace is created. When this namespace/policy was created by
sconify_image, we might not remember this ID.
To recover the ID of a policy, we can perform the following steps. First, we read and store the current policy that describes this namespace as follows (see scone session read):
scone session read --cas "$SCONE_CAS_ADDR" $NAMESPACE --only_for_testing-disable-attestation-verification > my_namespace_from_cas.yml
The session that we read, might be slightly different from the policy that we created. For example, it contains the public key of the creator. Given the current policy, we can determine the ID as follows (see scone session verify):
scone session verify --cas "$SCONE_CAS_ADDR" -n $NAMESPACE --only_for_testing-disable-attestation-verification my_namespace_from_cas.yml > namespace_id export ID=$(cat namespace_id)
Updating the policy
When updating a policy, we need to set the
predecessor field, i.e., we need to say which policy version to update (to ensure a linear history of policy updates). The policy that we read from CAS contains a field
creator, this is the public key of the creator. We cannot change the creator's public key and hence, we replace that field. Technically, we can update the namespace / policy as follows:
sed "s/predecessor:.*/predecessor: $ID /; s/creator: .*/ /" my_namespace_from_cas.yml > new_namespace_policy.yml cat >> new_namespace_policy.yml <<EOF secrets: - name: my_generated_ascii_secret kind: ascii size: 12 EOF
The new namespace policy might look as follows:
--- version: "0.3" name: MyNameSpace-26322 predecessor: 33f0d91c71e7dd582042565b7d1f2e71bf7c13a7ef08866e3e71274ab16cecfe access_policy: read: - CREATOR update: - CREATOR create_sessions: - CREATOR secrets: - name: my_generated_ascii_secret kind: ascii size: 12
Note that the field
predecessor ensures that we do not overwrite any concurrent updates. In case of an concurrent update, the predecessor ID would be wrong and the update would fail. In this case, we would need to read the newest policy, determine the ID, and then update the policy.
Uploading the new policy
We can now upload the modified as follows (see scone session verify):
scone session update --cas "$SCONE_CAS_ADDR" --only_for_testing-disable-attestation-verification new_namespace_policy.yml
On success, the session update command will print the new ID of the updated policy.