SCONE Online Boutique example
This demo showcases how the sconify-image tool can be used to turn existing microservices into confidential containers, with encrypted filesystems and remote attestation. For that purpose, we convert the Google Online Boutique demo, a well-known microservices application composed by 10 services in different languages, to run on SCONE.
This demo is executed in two stages:
Stage 1: One-step image transformation (sconify)
On a trusted machine,
sconify-image will transform all standard images into confidential images that run on top of SCONE, create security policies for remote attestation and generate Kubernetes manifests or Helm charts. Check the sconify documentation to learn more about this process.
Stage 2: Deployment
Using the generated deployment resources from the previous step, deploy the confidential services to a Kubernetes cluster with Intel SGX support. You don't need to trust or control the cluster nodes or the deployment process.
- Kubernetes cluster with Intel SGX support.
- SCONE LAS running on the cluster. Learn more.
git clone https://github.com/scontain/microservices-demo -b sconify cd microservices-demo # Specify the registry to which the confidential images will be pushed. # You must be logged in and have push permission. export IMAGE_REPOSITORY="docker.io/myrepo/online-boutique" # Configure Kubernetes namespace (required here so that the in-cluster # DNS names of the microservices are part of the security policies). export K8S_NAMESPACE="default" ./sconify-all.sh # Configure an imagePullSecret for Kubernetes, if necessary. export K8S_IMAGE_PULL_SECRET="sconeapps" # Configure which SGX device plugin you want to use ("scone", "azure" or "disabled") export K8S_DEVICE_PLUGIN="azure" ./deploy-all.sh
One-step image transformation
SCONE is a lift-and-shift framework for confidential containers. With that in mind, we support a one-step transformation process for standard containers (i.e., not confidential) into confidential containers. We call the process
sconify (learn more). This means that existing code and workflows (e.g., CI/CD pipelines) can benefit from SCONE guarantees with little-to-no effort.
Go services support
SCONE requires Go services to be built with
gccgo (learn more). For this reason, we use alternative Dockerfiles to build the standard services (
gcc.Dockerfile). Note that the original source code is untouched.
C# services support
SCONE support for C# is stil experimental. For this reason,
sconify-image does not support C# yet, and we provide a pre-built image for the C# service of the demo,
cartservice, with SCONE. Check
policies/cartservice.yaml for more information.
Compared to the original repository, the following directories are modified. Note that no source code changes are performed.
policies/ # Code to create a CAS namespace and creating policies for services that are not sconified (redis, cartservice) release/charts/ # Helm charts for services that not sconified (redis, cartservice). Generated Helm charts are saved here too src/ # Original source code, sconify.sh scripts and alternative Dockerfiles (if necessary)
In this example, we have an online boutique composed of the following services (the description was taken from the original repository):
|frontend||Go||Exposes an HTTP server to serve the website. Does not require signup/login and generates session IDs for all users automatically.|
|cartservice||C#||Stores the items in the user's shopping cart in Redis and retrieves it.|
|productcatalogservice||Go||Provides the list of products from a JSON file and ability to search products and get individual products.|
|currencyservice||Node.js||Converts one money amount to another currency. Uses real values fetched from European Central Bank. It's the highest QPS service.|
|paymentservice||Node.js||Charges the given credit card info (mock) with the given amount and returns a transaction ID.|
|shippingservice||Go||Gives shipping cost estimates based on the shopping cart. Ships items to the given address (mock)|
|emailservice||Python||Sends users an order confirmation email (mock).|
|checkoutservice||Go||Retrieves user cart, prepares order and orchestrates the payment, shipping and the email notification.|
|recommendationservice||Python||Recommends other products based on what's given in the cart.|
|adservice||Java||Provides text ads based on given context words.|
We perform the one-step transformation of all the services above. Each service has its own
sconify.sh script with the transformation parameters (e.g.,
sconify-image ships with sensible defaults so it's easy to get started, but it also supports a fair amount of configuration parameters, should you require more customization or additional integrations (e.g., integration to Azure services).
The flow is as follows:
- Build standard image (using the original source code).
- Transform it into a confidential image. Push the generated image to a container registry.
- Generate a security policy. Push it to a SCONE CAS.
- Generate Helm charts (or Kubernetes manifests).
You can trigger the sconification of a single service by running their own
sconify.sh. To transform all services at once, run
sconify-all.sh, which simply loops through all services and calls their
# Specify the registry to which the confidential images will be pushed. # You must be logged in and have push permission. export IMAGE_REPOSITORY="docker.io/myrepo/online-boutique" # Configure Kubernetes namespace (required here so that the in-cluster # DNS names of the microservices are part of the security policies). export K8S_NAMESPACE="default" ./sconify-all.sh
This will transform all images, and now the generated Helm charts will be in
sconify-all.sh supports the following environment variables:
|Environment variable||Description||Default value|
|IMAGE_REPOSITORY||Container image repository for the generated confidential images|
|SCONE_CAS_ADDR||Address of SCONE CAS that will receive the generated security policies||
|CAS_MRENCLAVE||The MrEnclave of the chosen SCONE CAS (for attestation and trust establishment)||
|K8S_NAMESPACE||The Kubernetes namespace for deploying the services, since the microservices talk to each other using their in-cluster DNS names||
This example also uses
redis as the storage backend for
cartservice. There is no need to sconify
redis, as we already provide it as one of our curated images.
The following service is part of the demo but does not run on SCONE (as it is just a benchmark):
|loadgenerator||Python/Locust||Continuously sends requests imitating realistic user shopping flows to the frontend.|
After the Helm charts are generated, one can deploy them to a Kubernetes cluster. Similar to
sconify-all.sh, we provide a
deploy-all.sh script, which loops through all Helm charts in
release/charts and install them. The following environment variables are accepted by
|Environment variable||Description||Default value|
|K8S_IMAGE_PULL_SECRET||You need a Secret to access private container registries. Learn more||
|K8S_DEVICE_PLUGIN||Configure which device plugin to use: "scone" for SCONE SGX device plugin, "azure" for the Azure SGX device plugin or "disabled" to access the SGX devices via hostPath volumes||
|K8S_FRONTEND_SERVICE_TYPE||Configure Service type of "frontend", i.e., how to expose it (LoadBalancer or NodePort)||
To deploy the services to an AKS cluster, for example, run:
# Configure an imagePullSecret for Kubernetes, if necessary. export K8S_IMAGE_PULL_SECRET="sconeapps" # Configure which SGX device plugin you want to use ("scone", "azure" or "disabled") export K8S_DEVICE_PLUGIN="azure" # Configure Service type of "frontend", i.e., how to expose it (LoadBalancer or NodePort) export K8S_FRONTEND_SERVICE_TYPE="LoadBalancer" ./deploy-all.sh
After all charts are deployed, you can see their pods running:
$ kubectl get pods NAME READY STATUS RESTARTS AGE adservice-sconify-adservice-5c5d79cd5-hmpmv 1/1 Running 0 7m44s cartservice-sconify-cartservice-557767665f-79ltl 1/1 Running 0 7m39s checkoutservice-sconify-checkoutservice-69cbcc9cf6-rsbpv 1/1 Running 0 7m33s currencyservice-sconify-currencyservice-d7cb458db-vtwqq 1/1 Running 0 7m28s emailservice-sconify-emailservice-84fb77d787-6gbhh 1/1 Running 0 7m22s frontend-sconify-frontend-77fdf9d665-mb2wh 1/1 Running 0 6m54s las-49fzx 1/1 Running 0 8h las-gjgr8 1/1 Running 0 8h paymentservice-sconify-paymentservice-79cd585dc9-nzqk5 1/1 Running 0 7m17s productcatalogservice-sconify-productcatalogservice-75bfc9pxbtg 1/1 Running 0 7m11s recommendationservice-sconify-recommendationservice-5c9bcbpghkm 1/1 Running 0 7m5s redis-cart-69b6f44897-nn45s 1/1 Running 0 7m50s shippingservice-sconify-shippingservice-68d544fcdc-v4h5g 1/1 Running 0 7m
You can now access the online boutique by fetching the
frontend service address. If you set
LoadBalancer, you should see the
EXTERNAL-IP field populated for the