全部產品
Search
文件中心

Container Service for Kubernetes:通過SDK開發和構建SGX2.0應用

更新時間:Jun 19, 2024

本文介紹如何基於TEE-SDK開發、構建並部署一個名為helloworld的SGX2.0應用,使其在可信區周期性地生產訊息並傳遞給不可信代碼(緩衝區),最終輸出到終端。

前提條件

基本原理

SGX2.0應用由untrusted不可信區和trusted可信區兩部分組成:

  • untrusted:如果代碼和資料運行在普通非加密記憶體地區,程式main入口必須在非可信區。SGX程式原理圖中的main()bar()函數均在非可信區。

  • trusted:如果代碼和資料運行在硬體加密記憶體地區,此地區由CPU建立且只有CPU有許可權訪問。SGX程式原理圖中的helloworld()foo()函數運行在可信區。

非可信區只能通過ECALL函數調用可信區內的函數;可信區只能通過OCALL函數調用非可信區的函數。ECALL函數和OCALL函數通過EDL檔案聲明。

範例程式碼及目錄結構

本樣本中SGX2.0應用helloworld所涉及的應用編譯、鏡像構建以及部署等樣本源碼位於github。範例程式碼的目錄結構如下。

App.hsgx-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

src代碼目錄和檔案說明如下。

目錄

說明

檔案

說明

App

存放不可信地區代碼,包括main入口、OCALL函數內具體邏輯代碼等。

App.cpp

不可信地區代碼。

App.h

標頭檔。

Enclave

存放可信地區代碼,包括ECALL函數內具體邏輯代碼。

Enclave.edl

EDL(Enclave Description Language)檔案。

Enclave.lds

Enclave linker script。

Enclave_private.pem

enclave.so的簽名密鑰。

Enclave.config.xml

Enclave設定檔,如堆棧大小、是否開啟Debug等。

Enclave.h和Enclave.cpp

應用安全區代碼實現。

步驟一:編譯hello_world

  1. 執行以下命令,安裝Git開發工具。

    sudo yum install git
  2. 執行以下命令,編譯hello_world應用。

    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

    專案根目錄下會產生一個名為hello_world的Binary檔案。

    展開查看完整的Binary檔案

    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
    <EnclaveConfiguration>
        <ProdID>0</ProdID>
        <ISVSVN>0</ISVSVN>
        <StackMaxSize>0x40000</StackMaxSize>
        <HeapMaxSize>0x100000</HeapMaxSize>
        <TCSNum>10</TCSNum>
        <TCSPolicy>1</TCSPolicy>
        <!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release -->
        <DisableDebug>0</DisableDebug>
        <MiscSelect>0</MiscSelect>
        <MiscMask>0xFFFFFFFF</MiscMask>
    </EnclaveConfiguration>
    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

  3. 在支援SGX的執行個體上執行命令./hello_world運行hello_world應用。

    cd src/
    ./hello_world

    預期輸出:

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

編譯流程和編譯後的代碼目錄結構說明如下。

展開查看編譯流程

  1. 通過sgx_edger8r工具在App/目錄下產生不可信代碼(Enclave_u.cEnclave_u.h),這部分產生的程式碼主要會調用ECALL(sgx_ecall)

  2. 編譯不可信部分Binary:app

  3. 通過sgx_edger8r工具在Enclave/目錄下產生可信代碼(Enclave_t.cEnclave_t.h)。

  4. 編譯可信動態連結程式庫(enclave.so)。

  5. 通過sgx_sign工具簽名可信動態連結程式庫(enclave.signed.so)。

  6. 結束。

展開查看編譯後代碼目錄結構

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

檔案路徑

說明

範例程式碼

Encalve/Enclave.edl

EDL中聲明了一個公用ECALL函數,每個SGX應用的EDL必須至少聲明一個:

  • public類型的ECALL函數。

  • trusted {...}內聲明ECALL函數。

  • untrusted {...}內聲明OCALL函數。

由於本例中安全區不需要向非安全區調用(OCALL),所以只聲明了一個ECALL函數ecall_hello_from_enclave,這個ECALL函數目的是在安全區建立一個Buffer並填充helloworld,然後將這個Buffer的內容拷貝到非安全的Buffer中,非安全區調用printf列印這個非安全Buffer內容。

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

Enclave/Enclave.lds

無。

enclave.so
{
    global:
        g_global_data_sim;
        g_global_data;
        enclave_entry;
        g_peak_heap_used;
    local:
        *;
};

Enclave/Enclave.config.xml

無。

<EnclaveConfiguration>
  <ProdID>0</ProdID>
  <ISVSVN>0</ISVSVN>
  <StackMaxSize>0x40000</StackMaxSize>
  <HeapMaxSize>0x100000</HeapMaxSize>
  <TCSNum>10</TCSNum>
  <TCSPolicy>1</TCSPolicy>
  <!-- Recommend changing 'DisableDebug' to 1 to make the enclave undebuggable for enclave release -->
  <DisableDebug>0</DisableDebug>
  <MiscSelect>0</MiscSelect>
  <MiscMask>0xFFFFFFFF</MiscMask>
</EnclaveConfiguration>

Enclave/Enclave.h

這個標頭檔內容基本為空白。

#ifndef _ENCLAVE_H_
#define _ENCLAVE_H_
#endif

Enclave/Enclave.cpp

無。

#include "Enclave.h"
#include "Enclave_t.h" /* print_string */
#include <string.h>

void ecall_hello_from_enclave(char *buf, size_t len)
{
    const char *hello = "Hello world";

    size_t size = len;
    if(strlen(hello) < len)
    {
        size = strlen(hello) + 1;
    }

    memcpy(buf, hello, size - 1);
    buf[size-1] = '\0';
}

Enclave/Enclave_private.pem

產生簽名密鑰。

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

App/App.h

無。

#ifndef _APP_H_
#define _APP_H_

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

#include "sgx_error.h"       /* sgx_status_t */
#include "sgx_eid.h"     /* sgx_enclave_id_t */

#ifndef TRUE
# define TRUE 1
#endif

#ifndef FALSE
# define FALSE 0
#endif

# define TOKEN_FILENAME   "enclave.token"
# define ENCLAVE_FILENAME "enclave.signed.so"

extern sgx_enclave_id_t global_eid;    /* global enclave id */

#if defined(__cplusplus)
extern "C" {
#endif


#if defined(__cplusplus)
}
#endif

#endif /* !_APP_H_ */

App/App.cpp

無。

#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <time.h>
#include <ctime>

# include <unistd.h>
# include <pwd.h>
# define MAX_PATH FILENAME_MAX

#include "sgx_urts.h"
#include "App.h"
#include "Enclave_u.h"

/* Global EID shared by multiple threads */
sgx_enclave_id_t global_eid = 0;

int initialize_enclave(void)
{
    sgx_status_t ret = SGX_ERROR_UNEXPECTED;

    char enclavefile[256];
    getcwd(enclavefile, sizeof(enclavefile));
    strcat(enclavefile, "/enclave.signed.so");

    /* Call sgx_create_enclave to initialize an enclave instance */
    /* Debug Support: set 2nd parameter to 1 */
    ret = sgx_create_enclave(enclavefile, SGX_DEBUG_FLAG, NULL, NULL, &global_eid, NULL);
    if (ret != SGX_SUCCESS) {
        printf("Failed to create enclave, ret code: %d, enclave file: %s\n", ret, enclavefile);
        return -1;
    }

    return 0;
}

tm* get_time() {
    time_t rawtime;
    struct tm * timeinfo;
    time ( &rawtime );
    timeinfo = localtime ( &rawtime );
    return timeinfo;
}

/* Application entry */
int SGX_CDECL main(int argc, char *argv[])
{
    (void)(argc);
    (void)(argv);

    const size_t max_buf_len = 100;
    char buffer[max_buf_len] = {0};


    /* Initialize the enclave */
    if(initialize_enclave() < 0){
        printf("Enter a character before exit ...\n");
        getchar();
        return -1;
    }

    /* Enclave calls */
    while(1) {
        ecall_hello_from_enclave(global_eid, buffer, max_buf_len);

        printf("%s%s\n", asctime(get_time()), buffer);
        fflush(stdout);

        sleep(1);
    }

    /* Destroy the enclave */
    sgx_destroy_enclave(global_eid);

    printf("Info: SampleEnclave successfully returned.\n");

    printf("Enter a character before exit ...\n");
    getchar();
    return 0;
}

步驟二:構建並部署helloworld應用

建議您使用Alibaba Cloud Linux構建鏡像,安裝最新的SGX SDK並定期更新以避免潛在的安全問題。

Dockerfile樣本

以Alibaba Cloud Linux 3為例,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 # 按需添加更多SGX運行時依賴

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

操作步驟

  1. 安裝Docker。

    具體操作,請參見部署並使用Docker

  2. 執行以下命令編譯並構建測試鏡像。

    請將${IMAGE_URL}替換為您的測試鏡像地址。

    cd sgx-device-plugin/samples/hello_world
    TARGET_IMAGE=${IMAGE_URL} SGX_SDK=/opt/alibaba/teesdk/intel/sgxsdk make image
    docker push ${IMAGE_URL}
  3. 執行以下命令部署helloworld應用。

    請將${IMAGE_URL}替換為您在上一步操作中構建的測試鏡像地址。

    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

參考連結