Skip to content

Commit

Permalink
EDB Connect: Add db query tool
Browse files Browse the repository at this point in the history
  • Loading branch information
BedrockSquirrel committed Jun 18, 2024
1 parent 85e6cd0 commit 0ef7251
Show file tree
Hide file tree
Showing 10 changed files with 387 additions and 14 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/manual-deploy-testnet-l2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ jobs:
--command-id RunShellScript \
--scripts 'mkdir -p /home/obscuro \
&& git clone --depth 1 -b ${{ env.BRANCH_NAME }} https://github.com/ten-protocol/go-ten.git /home/obscuro/go-obscuro \
&& cp /home/obscuro/go-obscuro/tools/edbconnect/edb-connect.sh /home/obscurouser/edb-connect.sh \
&& chown obscurouser:obscurouser /home/obscurouser/edb-connect.sh \
&& chmod u+x /home/obscurouser/edb-connect.sh' \
&& docker network create --driver bridge node_network || true \
&& docker run -d --name datadog-agent \
--network node_network \
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/manual-publish-edb-connect.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Publishes the latest version of edb-connect to the Azure Container Registry
# Users will then have access to this latest version when they run the edb-connect.sh script on the node VMs.

name: "[M] Publish EDB Connect"
run-name: "[M] Publish EDB Connect"
on:
workflow_dispatch:

jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3

- name: "Set up Docker"
uses: docker/setup-buildx-action@v1

- name: "Login to Azure docker registry"
uses: azure/docker-login@v1
with:
login-server: testnetobscuronet.azurecr.io
username: testnetobscuronet
password: ${{ secrets.REGISTRY_PASSWORD }}

- name: "Login via Azure CLI"
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Build and Push Docker EDB Connect Image
run: |
DOCKER_BUILDKIT=1 docker build -t ${{ vars.DOCKER_BUILD_TAG_EDB_CONNECT }} -f ./tools/edbconnect/Dockerfile .
docker push ${{ vars.DOCKER_BUILD_TAG_EDB_CONNECT }}
27 changes: 14 additions & 13 deletions go/enclave/storage/init/edgelessdb/edgelessdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@ import (
)

/*
The Obscuro Enclave (OE) needs a way to persist data into a trusted database. Trusted not to reveal that data to anyone but that particular enclave.
The Ten Enclave (TE) needs a way to persist data into a trusted database. Trusted not to reveal that data to anyone but that particular enclave.
To achieve this, the OE must first perform Remote Attestation (RA), which gives it confidence that it is connected to
To achieve this, the TE must first perform Remote Attestation (RA), which gives it confidence that it is connected to
a trusted version of software running on trusted hardware. The result of this process is a Certificate which can be
used to set up a trusted TLS connection into the database.
The next step is to configure the database schema and users in such a way that the OE knows that the db engine will
The next step is to configure the database schema and users in such a way that the TE knows that the db engine will
only allow itself access to it. This is achieved by creating a "Manifest" file that contains the SQL init code and a
DBClient Certificate that is known only to the OE.
DBClient Certificate that is known only to the TE.
This "DBClient" Cert is used by the database to authenticate that it is communicating to the entity that has initialised that schema.
Expand Down Expand Up @@ -130,6 +130,7 @@ type Credentials struct {
UserKeyPEM string // db user private key, generated in our enclave
}

// Connector (re-)establishes a connection to the Edgeless DB for the Ten enclave
func Connector(edbCfg *Config, config config.EnclaveConfig, logger gethlog.Logger) (enclavedb.EnclaveDB, error) {
// rather than fail immediately if EdgelessDB is not available yet we wait up for `edgelessDBStartTimeout` for it to be available
err := waitForEdgelessDBToStart(edbCfg.Host, logger)
Expand All @@ -143,12 +144,12 @@ func Connector(edbCfg *Config, config config.EnclaveConfig, logger gethlog.Logge
return nil, err
}

tlsCfg, err := createTLSCfg(edbCredentials)
tlsCfg, err := CreateTLSCfg(edbCredentials)
if err != nil {
return nil, err
}

sqlDB, err := connectToEdgelessDB(edbCfg.Host, tlsCfg, logger)
sqlDB, err := ConnectToEdgelessDB(edbCfg.Host, tlsCfg, logger)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -183,7 +184,7 @@ func waitForEdgelessDBToStart(edbHost string, logger gethlog.Logger) error {

func getHandshakeCredentials(enclaveConfig config.EnclaveConfig, edbCfg *Config, logger gethlog.Logger) (*Credentials, error) {
// if we have previously performed the handshake we can retrieve the creds from disk and proceed
edbCreds, found, err := loadCredentialsFromFile()
edbCreds, found, err := LoadCredentialsFromFile()
if err != nil {
return nil, err
}
Expand All @@ -198,8 +199,8 @@ func getHandshakeCredentials(enclaveConfig config.EnclaveConfig, edbCfg *Config,
return edbCreds, nil
}

// loadCredentialsFromFile returns (credentials object, found flag, error), if file not found it will return nil error but found=false
func loadCredentialsFromFile() (*Credentials, bool, error) {
// LoadCredentialsFromFile returns (credentials object, found flag, error), if file not found it will return nil error but found=false
func LoadCredentialsFromFile() (*Credentials, bool, error) {
b, err := egoutils.ReadAndUnseal(edbCredentialsFilepath)
if err != nil {
if os.IsNotExist(err) {
Expand Down Expand Up @@ -227,8 +228,8 @@ func performHandshake(enclaveConfig config.EnclaveConfig, edbCfg *Config, logger
// the RA will ensure that we are connecting to a database that will not leak any data.
// The RA will return a Certificate which we'll use for the TLS mutual authentication when we connect to the database.
// The trust path is as follows:
// 1. The Obscuro Enclave performs RA on the database enclave, and the RA object contains a certificate which only the database enclave controls.
// 2. Connecting to the database via mutually authenticated TLS using the above certificate, will give the Obscuro enclave confidence that it is only giving data away to some code and hardware it trusts.
// 1. The Ten Enclave performs RA on the database enclave, and the RA object contains a certificate which only the database enclave controls.
// 2. Connecting to the database via mutually authenticated TLS using the above certificate, will give the Ten enclave confidence that it is only giving data away to some code and hardware it trusts.
edbPEM, err := performEDBRemoteAttestation(enclaveConfig, edbCfg.Host, defaultEDBConstraints, logger)
if err != nil {
return nil, err
Expand Down Expand Up @@ -304,7 +305,7 @@ func createManifestFormat(content string) (result []string) {
return
}

func createTLSCfg(creds *Credentials) (*tls.Config, error) {
func CreateTLSCfg(creds *Credentials) (*tls.Config, error) {
caCertPool := x509.NewCertPool()

if ok := caCertPool.AppendCertsFromPEM([]byte(creds.EDBCACertPEM)); !ok {
Expand Down Expand Up @@ -458,7 +459,7 @@ func verifyEdgelessDB(edbHost string, m *manifest, httpClient *http.Client, logg
return nil
}

func connectToEdgelessDB(edbHost string, tlsCfg *tls.Config, logger gethlog.Logger) (*sql.DB, error) {
func ConnectToEdgelessDB(edbHost string, tlsCfg *tls.Config, logger gethlog.Logger) (*sql.DB, error) {
err := mysql.RegisterTLSConfig("custom", tlsCfg)
if err != nil {
return nil, fmt.Errorf("failed to register tls config for mysql connection - %w", err)
Expand Down
9 changes: 9 additions & 0 deletions integration/common/testlog/testlog.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,12 @@ func Setup(cfg *Cfg) *os.File {
testlog = gethlog.New(log.CmpKey, log.TestLogCmp)
return f
}

// SetupSysOut will direct logs to stdout
func SetupSysOut() {
err := debug.Setup("terminal", "", false, 10000000, 0, 0, false, false, slog.LevelDebug, "")
if err != nil {
panic(err)
}
testlog = gethlog.New(log.CmpKey, log.TestLogCmp)
}
2 changes: 1 addition & 1 deletion integration/networktest/tests/helpful/smoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func TestExecuteNativeFundsTransfer(t *testing.T) {
networktest.Run(
"native-funds-smoketest",
t,
env.LocalDevNetwork(),
env.SepoliaTestnet(),
actions.Series(
&actions.CreateTestUser{UserID: 0},
&actions.CreateTestUser{UserID: 1},
Expand Down
41 changes: 41 additions & 0 deletions tools/edbconnect/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Build Stages:
# build-base = downloads modules and prepares the directory for compilation. Based on the ego-dev image
# build-enclave = copies over the actual source code of the project and builds it using a compiler cache
# deploy = copies over only the enclave executable without the source
# in a lightweight base image specialized for deployment and prepares the /data/ folder.

FROM ghcr.io/edgelesssys/ego-dev:v1.5.0 AS build-base

# setup container data structure
RUN mkdir -p /home/ten/go-ten

# Ensures container layer caching when dependencies are not changed
WORKDIR /home/ten/go-ten
COPY go.mod .
COPY go.sum .
RUN ego-go mod download

# Trigger new build stage for compiling the enclave
FROM build-base as build-enclave
COPY . .

WORKDIR /home/ten/go-ten/tools/edbconnect/main

# Build the enclave using the cross image build cache.
RUN --mount=type=cache,target=/root/.cache/go-build \
ego-go build

# New build stage for compiling the enclave with restricted flags mode
FROM build-enclave as sign-built-enclave
# Sign the enclave executable
RUN ego sign edb-enclave.json


# Trigger a new build stage and use the smaller ego version:
FROM ghcr.io/edgelesssys/ego-deploy:v1.5.0

# Copy the binary and the entrypoint script
COPY --from=sign-built-enclave \
/home/ten/go-ten/tools/edbconnect/main /home/ten/go-ten/tools/edbconnect/main

WORKDIR /home/ten/go-ten/tools/edbconnect/main
43 changes: 43 additions & 0 deletions tools/edbconnect/edb-connect.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/bash

# Variables
IMAGE_NAME="testnetobscuronet.azurecr.io/obscuronet/edbconnect:latest"
CONTAINER_BASE_NAME="edb-connect"
UNIQUE_ID=$(date +%s%3N) # Using milliseconds for uniqueness
CONTAINER_NAME="${CONTAINER_BASE_NAME}-${UNIQUE_ID}"
VOLUME_NAME="obscuronode-enclave-volume"
NETWORK_NAME="node_network"
SGX_ENCLAVE_DEVICE="/dev/sgx_enclave"
SGX_PROVISION_DEVICE="/dev/sgx_provision"
COMMAND="ego run /home/ten/go-ten/tools/edbconnect/main/main"

# Function to destroy exited containers matching the base name
destroy_exited_containers() {
exited_containers=$(docker ps -a -q -f name=${CONTAINER_BASE_NAME} -f status=exited)
if [ "$exited_containers" ];then
echo "Removing exited containers matching ${CONTAINER_BASE_NAME}..."
docker rm $exited_containers || true
else
echo "No exited containers to remove."
fi
}

# Destroy exited containers that match the base name
destroy_exited_containers

# Pull the latest image from Azure Docker repository
echo "Pulling the latest Docker image..."
docker pull $IMAGE_NAME

# Run the container with the specified command
echo "Running the new container with name ${CONTAINER_NAME}..."
docker run --name $CONTAINER_NAME \
--network $NETWORK_NAME \
-v $VOLUME_NAME:/enclavedata \
--device $SGX_ENCLAVE_DEVICE:$SGX_ENCLAVE_DEVICE:rwm \
--device $SGX_PROVISION_DEVICE:$SGX_PROVISION_DEVICE:rwm \
$IMAGE_NAME $COMMAND

# After the REPL exits, destroy the container
echo "Destroying the container ${CONTAINER_NAME} after command exits..."
docker rm $CONTAINER_NAME || true
19 changes: 19 additions & 0 deletions tools/edbconnect/main/edb-enclave.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"exe": "main",
"key": "testnet.pem",
"debug": true,
"heapSize": 4096,
"executableHeap": true,
"productID": 1,
"securityVersion": 1,
"mounts": [
{
"source": "/enclavedata",
"target": "/data",
"type": "hostfs",
"readOnly": false
}
],
"env": [
]
}
Loading

0 comments on commit 0ef7251

Please sign in to comment.