All Products
Search
Document Center

Container Service for Kubernetes:Use TEE SDK to develop and build Intel SGX 2.0 applications

Last Updated:Mar 27, 2026

This topic walks you through building an Intel Software Guard Extensions (SGX) 2.0 application using the trusted execution environment (TEE) SDK, then packaging and deploying it to an ACK confidential computing cluster. The example application, helloworld, runs inside an enclave, generates messages periodically, and prints them to the terminal.

Prerequisites

Before you begin, make sure you have:

How it works

image

An Intel SGX 2.0 application has two components:

  • Untrusted component: Unencrypted memory that contains the main() entry function and any OCALL (outside call) implementations. In the diagram, main() and bar() run in the untrusted component.

  • Trusted component (enclave): Encrypted memory created and protected by the CPU. Only the CPU can access the code and data inside. In the diagram, helloworld() and foo() run in the enclave.

To call enclave functions from untrusted code, the application uses ECALL (enclave call). To call untrusted functions from inside the enclave, it uses OCALL. Both are declared in Enclave Definition Language (EDL) files.

Sample code and directory structure

The helloworld source code is on GitHub. It includes the application source, Makefile, and Dockerfile.

Top-level structure:

sgx-device-plugin/samples/hello_world/
├── Dockerfile
├── Makefile
├── README.md
└── src
     ├── App
     │ ├── App.cpp
     │ └── App.h
     ├── Enclave
     │ ├── Enclave.config.xml
     │ ├── Enclave.cpp
     │ ├── Enclave.edl
     │ ├── Enclave.h
     │ ├── Enclave.lds
     │ └── Enclave_private.pem
     └── Makefile

The src directory has two subdirectories:

Directory

Description

Key files

App

Untrusted code: the main() entry function and OCALL implementations

App.cpp (untrusted code), App.h (header)

Enclave

Trusted code that runs inside the enclave

Enclave.edl (EDL file), Enclave.lds (linker script), Enclave_private.pem (signing key), Enclave.config.xml (enclave config), Enclave.h and Enclave.cpp (trusted implementation)

Key source files

`Enclave/Enclave.edl` — declares the ECALL and OCALL interface. Every SGX application must declare at least one trusted {} block (ECALLs) or one untrusted {} block (OCALLs) in the EDL file.

In this example, the application only needs one ECALL: ecall_hello_from_enclave. It creates a buffer inside the enclave, writes "Hello world" into it, then copies the buffer content to an untrusted buffer so the untrusted component can call printf.

enclave {
 trusted {
 public void ecall_hello_from_enclave([out, size=len] char* buf, size_t len);
 };
};

`Enclave/Enclave.config.xml` — controls the enclave's runtime resource limits. Three parameter groups determine memory and thread behavior:

  • TCS parameters (TCSNum, TCSPolicy): TCSNum sets the number of Thread Control Structures, which determines how many threads can run concurrently inside the enclave. TCSPolicy controls whether TCS slots are bound to OS threads or can be reused.

  • Stack parameters (StackMaxSize): the maximum stack size available to each enclave thread. If your enclave uses deep call stacks or large local variables, increase this value.

  • Heap parameters (HeapMaxSize): the maximum heap size available to the enclave. Set this based on how much dynamic memory your enclave code allocates.

For production builds, change DisableDebug from 0 to 1 to prevent debuggers from attaching to the enclave.

<EnclaveConfiguration>
    <ProdID>0</ProdID>
    <ISVSVN>0</ISVSVN>
    <StackMaxSize>0x40000</StackMaxSize>
    <HeapMaxSize>0x100000</HeapMaxSize>
    <TCSNum>10</TCSNum>
    <TCSPolicy>1</TCSPolicy>
    <!-- Change 'DisableDebug' to 1 before release to prevent debugger access -->
    <DisableDebug>0</DisableDebug>
    <MiscSelect>0</MiscSelect>
    <MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>

`Enclave/Enclave_private.pem` — the RSA private key used to sign enclave.so. Generated with:

openssl genrsa -out Enclave/Enclave_private.pem -3 3072

Step 1: Compile the hello_world application

  1. Install Git:

    sudo yum install git
  2. Clone the repository and compile:

    git clone https://github.com/AliyunContainerService/sgx-device-plugin
    cd sgx-device-plugin/samples/hello_world
    SGX_SDK=/opt/alibaba/teesdk/intel/sgxsdk make build

    The build runs six steps:

    1. sgx_edger8r and the sgx_ecall ECALL function generate untrusted stub code (Enclave_u.c, Enclave_u.h) in the App directory.

    2. The untrusted binary files in App are compiled.

    3. sgx_edger8r generates trusted code (Enclave_t.c, Enclave_t.h) in the Enclave directory.

    4. enclave.so is compiled as a trusted dynamic-link library.

    5. sgx_sign signs enclave.so, producing enclave.signed.so.

    6. The final hello_world binary is linked.

    A successful build ends with output similar to:

    GEN  =>  App/Enclave_u.h
    CC   <=  App/Enclave_u.c
    CXX  <=  App/App.cpp
    LINK =>  app
    GEN  =>  Enclave/Enclave_t.h
    CC   <=  Enclave/Enclave_t.c
    CXX  <=  Enclave/Enclave.cpp
    LINK =>  enclave.so
    ...
    tcs_num 10, tcs_max_num 10, tcs_min_pool 1
    The required memory is 3960832B.
    The required memory is 0x3c7000, 3868 KB.
    Succeed.
    SIGN =>  enclave.signed.so
    The project has been built in debug hardware mode

    Verify that the last line reads The project has been built in debug hardware mode. This confirms the build used real SGX hardware (not simulation mode) and that signing completed successfully. The compiled output tree:

    sgx-device-plugin/samples/hello_world/src/
    ├── hello_world          #[generated]
    ├── App
    │ ├── App.cpp
    │ ├── App.h
    │ ├── App.o              #[generated]
    │ ├── Enclave_u.c        #[generated]
    │ ├── Enclave_u.h        #[generated]
    │ └── Enclave_u.o        #[generated]
    ├── Enclave
    │ ├── Enclave.config.xml
    │ ├── Enclave.cpp
    │ ├── Enclave.edl
    │ ├── Enclave.h
    │ ├── Enclave.lds
    │ ├── Enclave.o          #[generated]
    │ ├── Enclave_private.pem
    │ ├── Enclave_t.c        #[generated]
    │ ├── Enclave_t.h        #[generated]
    │ └── Enclave_t.o        #[generated]
    ├── enclave.signed.so    #[generated]
    ├── enclave.so           #[generated]
    └── Makefile
  3. Run the application on an SGX-capable instance to verify it works:

    cd src/
    ./hello_world

    Expected output:

    Wed May  6 06:53:33 2020
    Hello world From SGX Enclave!
    Wed May  6 06:53:34 2020
    Hello world From SGX Enclave!
    ...

Step 2: Build and deploy the helloworld application

Use an Alibaba Cloud Linux base image and install the latest SGX SDK. Update the SDK periodically to get security patches.

Sample Dockerfile

FROM registry.cn-hangzhou.aliyuncs.com/alinux/alinux3

ARG REGION_ID=cn-hangzhou

RUN yum install -y curl && \
repo_url=https://enclave-${REGION_ID}.oss-${REGION_ID}.aliyuncs.com/repo/alinux/enclave-expr.repo && \
yum install -y yum-utils && \
yum-config-manager --add-repo ${repo_url} && \
yum install -y libsgx-urts libsgx-uae-service # Add more SGX runtime dependencies on demand.

WORKDIR /src
COPY src/hello_world src/enclave.signed.so /src
ENTRYPOINT ["/src/hello_world"]

The Dockerfile installs two required SGX runtime packages:

  • libsgx-urts: the SGX untrusted runtime system, required to load and run enclaves.

  • libsgx-uae-service: the platform services library for remote attestation and related operations.

Build and push the container image

  1. Build and push the container image. Replace ${IMAGE_URL} with your image registry address:

    cd sgx-device-plugin/samples/hello_world
    TARGET_IMAGE=${IMAGE_URL} SGX_SDK=/opt/alibaba/teesdk/intel/sgxsdk make image
    docker push ${IMAGE_URL}
  2. Deploy the helloworld application to your ACK cluster. Replace ${IMAGE_URL} with the image address from the previous step:

    cat <<EOF | kubectl create -f -
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: helloworld
      namespace: default
    spec:
      replicas: 2
      selector:
        matchLabels:
          app: helloworld
      template:
        metadata:
          labels:
            app: helloworld
        spec:
          containers:
          - image: ${IMAGE_URL}
            imagePullPolicy: Always
            name: helloworld
            resources:
              limits:
                cpu: 250m
                memory: 512Mi
                alibabacloud.com/sgx_epc_MiB: 2
    EOF

What's next