Skip to content

Commit 3e07422

Browse files
committed
Secret-vm-scripts refactoring
1 parent df8fdf3 commit 3e07422

File tree

17 files changed

+299
-388
lines changed

17 files changed

+299
-388
lines changed

config/secret-vm.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
2-
"domain_name": "auto-scrt-agent.scrtlabs.com",
3-
"ip_addr": "72.10.166.70/29",
4-
"gateway": "72.10.166.65"
2+
"domain_name": "tee-dev.scrtlabs.com",
3+
"ip_addr": "67.215.13.124/27",
4+
"gateway": "67.215.13.97",
5+
"secret_fs_persistent": false
56
}

meta-secret-vm/recipes-core/secret-vm-attest-rest-server/secret-vm-attest-rest-server.bb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ LICENSE = "MIT"
44
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
55

66
SRC_URI = "git://github.com/scrtlabs/secret-vm-attest-rest-server.git;branch=master;protocol=https"
7-
SRCREV = "d0012733be47086f28b0dc8158ce299c40d49e96"
7+
SRCREV = "95b08ea413d53e99612d694ba249da1144a8c623"
88

99
GO_IMPORT = "github.com/scrtlabs/secret-vm-attest-rest-server"
1010
GO_INSTALL = "${GO_IMPORT}"

meta-secret-vm/recipes-core/secret-vm-scripts/files/rtmr-ext.sh

Lines changed: 0 additions & 40 deletions
This file was deleted.

meta-secret-vm/recipes-core/secret-vm-scripts/files/secret-vm-generate-cert.sh renamed to meta-secret-vm/recipes-core/secret-vm-scripts/files/scripts/secret-vm-generate-cert.sh

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,30 +15,6 @@
1515
# Note: For production use, ensure secure master secret generation
1616
#==============================================================================
1717

18-
# Generates a deterministic master secret based on system UUID
19-
#
20-
# This function creates a deterministic secret by hashing the system's UUID
21-
# obtained via dmidecode. If dmidecode fails, it uses a fallback UUID value.
22-
# The resulting hash serves as a seed for key generation.
23-
#
24-
# Returns:
25-
# SHA-256 hash of the system UUID as a hex string
26-
#
27-
set -ex
28-
29-
get_master_secret() {
30-
local secret_file="/mnt/secure/master_secret.txt"
31-
32-
# Check if the file exists
33-
if [ -f "$secret_file" ]; then
34-
# Read the content of the file (trimming any whitespace)
35-
cat "$secret_file" | tr -d '[:space:]'
36-
else
37-
echo "Error: Master secret file not found at $secret_file" >&2
38-
return 1
39-
fi
40-
}
41-
4218
# Generates a Let's Encrypt signed certificate with private and public keys
4319
#
4420
# This function obtains a properly signed certificate from Let's Encrypt
@@ -64,7 +40,7 @@ generate_cert() {
6440
local domain="${3:-secretvm.scrtlabs.com}" # Domain name, with default
6541
local email="${4:-secretvm@scrtlabs.com}" # Email for Let's Encrypt notifications
6642

67-
local CERTBOT='docker run --rm
43+
local certbot='docker run --rm
6844
-v /etc/letsencrypt:/etc/letsencrypt
6945
-v /var/lib/letsencrypt:/var/lib/letsencrypt
7046
-p 80:80
@@ -102,7 +78,7 @@ generate_cert() {
10278
echo "Requesting Let's Encrypt certificate for domain: ${domain}"
10379

10480
# Request certificate using certbot in standalone mode
105-
if ! $CERTBOT certonly --standalone \
81+
if ! $certbot certonly --standalone \
10682
--staging \
10783
--non-interactive \
10884
--agree-tos \
@@ -194,4 +170,3 @@ generate_cert() {
194170
echo "openssl x509 -in ${prefix}_cert.pem -pubkey -noout -outform PEM | sha256sum"
195171
echo "The above commands should produce the same hash if the keys match."
196172
}
197-
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
#!/bin/bash
2+
3+
set -x
4+
5+
# ================================
6+
# GLOBAL VARIABLES
7+
# ================================
8+
9+
if command -v nvidia-smi; then
10+
GPU_MODE=1
11+
fi
12+
13+
CONFIG_DIR=/mnt/config
14+
CONFIG_FILE=$CONFIG_DIR/secret-vm.json
15+
16+
SECRET_FS_PERSISTENT=$(jq -r '.secret_fs_persistent' $CONFIG_FILE)
17+
SECRET_FS_MOUNT_POINT=/mnt/secure
18+
SECRET_FS_DEVICE=/dev/vda
19+
20+
CERT_DIR=$SECRET_FS_MOUNT_POINT/cert
21+
CERT_NAME=secret_vm
22+
CERT_PATH=$CERT_DIR/"$CERT_NAME"_cert.pem
23+
DOMAIN_NAME=$(jq -r '.domain_name' $CONFIG_FILE)
24+
25+
26+
PATH_ATTESTATION_TDX=$SECRET_FS_MOUNT_POINT/tdx_attestation.txt
27+
PATH_ATTESTATION_GPU_1=$SECRET_FS_MOUNT_POINT/gpu_attestation.txt
28+
PATH_ATTESTATION_GPU_2=$SECRET_FS_MOUNT_POINT/gpu_attestation_token.txt
29+
30+
KMS_SERVICE_ID=0
31+
32+
# the following variables will be set up during setup_env function call
33+
G_ERROR=""
34+
SEED=""
35+
QUOTE=""
36+
COLLATERAL=""
37+
38+
# ================================
39+
# INCLUDES
40+
# ================================
41+
42+
source secret-vm-generate-cert.sh
43+
source utils.sh
44+
45+
# ================================
46+
# FUNCTIONS
47+
# ================================
48+
49+
setup_env() {
50+
# get random 32 bytes
51+
SEED=$(crypt-tool rand)
52+
if ! test_valid_hex_data "SEED"; then
53+
return 1
54+
fi
55+
56+
# use it to derive initial pubkey
57+
local pubkey=$(crypt-tool generate-key -s $SEED)
58+
if ! test_valid_hex_data "pubkey"; then
59+
return 1
60+
fi
61+
62+
# get attestation with this pubkey as report data
63+
echo "Getting initial attestation..."
64+
65+
QUOTE=$(attest-tool attest $pubkey)
66+
if ! test_valid_hex_data "QUOTE"; then
67+
return 1
68+
fi
69+
70+
COLLATERAL=$(curl -s -X POST https://pccs.scrtlabs.com/dcap-tools/quote-parse -H "Content-Type: application/json" -d "{\"quote\": \"$QUOTE\"}" |jq '.collateral')
71+
COLLATERAL=$(echo $COLLATERAL | sed 's/"//g') # remove quotes
72+
if ! test_valid_hex_data "COLLATERAL"; then
73+
return 1
74+
fi
75+
}
76+
77+
setup_gpu() {
78+
nvidia-smi conf-compute -srs 1
79+
nvidia-ctk config --set nvidia-container-cli.no-cgroups --in-place
80+
}
81+
82+
setup_docker() {
83+
systemctl stop docker
84+
85+
# setup docker config
86+
mkdir -p /etc/docker
87+
echo '{}' > /etc/docker/daemon.json
88+
test -n "$GPU_MODE" && nvidia-ctk runtime configure --runtime=docker
89+
jq ". + {data-root: \"$SECRET_FS_MOUNT_POINT\"}" /etc/docker/daemon.json > tmp.json
90+
mv tmp.json /etc/docker/daemon.json
91+
92+
# create docker working directory
93+
mkdir -p $SECRET_FS_MOUNT_POINT/docker_wd
94+
cp $CONFIG_DIR/docker-compose.yaml $SECRET_FS_MOUNT_POINT/docker_wd
95+
96+
pushd .
97+
cd $SECRET_FS_MOUNT_POINT/docker_wd
98+
# these files are optional
99+
#local kms_res=$(kms-query get_env_by_image $QUOTE $COLLATERAL)
100+
cp $CONFIG_DIR/docker-files.tar . && tar xvf ./docker-files.tar || true
101+
popd
102+
103+
systemctl start docker
104+
}
105+
106+
setup_network() {
107+
systemctl stop systemd-networkd
108+
local ip_addr=$(jq -r '.ip_addr' $CONFIG_FILE)
109+
local gateway=$(jq -r '.gateway' $CONFIG_FILE)
110+
sed -i "s%IP_ADDR_PLACEHOLDER%$ip_addr%" /usr/lib/systemd/network/10-enp.network
111+
sed -i "s%GATEWAY_PLACEHOLDER%$gateway%" /usr/lib/systemd/network/10-enp.network
112+
systemctl start systemd-networkd
113+
}
114+
115+
setup_secret_fs() {
116+
if [ "$SECRET_FS_PERSISTENT" == false ]; then
117+
local password=$(crypt-tool rand)
118+
if ! test_valid_hex_data "password"; then
119+
return 1
120+
fi
121+
else
122+
if get_master_secret; then
123+
local password=$MASTER_SECRET
124+
echo "$MASTER_SECRET" > $SECRET_FS_MOUNT_POINT/master_secret.txt
125+
else
126+
echo "Couldn't get master secret: $G_ERROR"
127+
exit 1
128+
fi
129+
fi
130+
131+
mount_secret_fs $password $SECRET_FS_DEVICE
132+
safe_remove_outdated
133+
attest-tool report > $SECRET_FS_MOUNT_POINT/self_report.txt
134+
}
135+
136+
safe_remove_outdated() {
137+
rm -f $PATH_ATTESTATION_GPU_1
138+
rm -f $PATH_ATTESTATION_GPU_2
139+
rm -f $PATH_ATTESTATION_TDX
140+
}
141+
142+
# Get the master secret from kms contract, based on our attestation
143+
get_master_secret() {
144+
# Query kms contract
145+
echo "Querying KMS..."
146+
147+
local kms_res=$(kms-query get_secret_key $KMS_SERVICE_ID $QUOTE $COLLATERAL)
148+
149+
# the result must consist of 2 lines, which are encrypted master secret and the export pubkey respectively. Parse it.
150+
kms_res=$(echo "$kms_res" | xargs) # strip possible leading and trailing spaces
151+
152+
read encrypted_secret export_pubkey <<< "$kms_res"
153+
if ! test_valid_hex_data "encrypted_secret"; then
154+
return 1
155+
fi
156+
157+
if ! test_valid_hex_data "export_pubkey"; then
158+
return 1
159+
fi
160+
161+
# finally decrypt the result
162+
MASTER_SECRET=$(crypt-tool decrypt -s $SEED -d $encrypted_secret -p $export_pubkey)
163+
if ! test_valid_hex_data "master_secret"; then
164+
return 1
165+
fi
166+
167+
return 0
168+
}
169+
170+
mount_secret_fs() {
171+
local fs_passwd="$1"
172+
local fs_container_path="$2"
173+
174+
echo "Opening existing encrypted file system..."
175+
if ! (echo -n $fs_passwd | cryptsetup luksOpen $fs_container_path encrypted_volume); then
176+
echo "Creating encrypted file system..."
177+
echo -n $fs_passwd | cryptsetup luksFormat --pbkdf pbkdf2 $fs_container_path
178+
echo -n $fs_passwd | cryptsetup luksOpen $fs_container_path encrypted_volume
179+
mkfs.ext4 /dev/mapper/encrypted_volume
180+
fi
181+
182+
echo "Mounting encrypted file system..."
183+
mkdir -p $SECRET_FS_MOUNT_POINT
184+
mount /dev/mapper/encrypted_volume $SECRET_FS_MOUNT_POINT
185+
}
186+
187+
finalize() {
188+
local ssl_cert_path="$1"
189+
190+
echo "Fetching fingerptint from SSL certificate..."
191+
local ssl_fingerprint=$(openssl x509 -in $ssl_cert_path -noout -fingerprint -sha256 | awk -F= '{gsub(":", "", $2); print $2}')
192+
193+
if ! test_valid_hex_data "ssl_fingerprint"; then
194+
return 1
195+
fi
196+
197+
safe_remove_outdated
198+
199+
echo "SSL certificate fingerprint: $ssl_fingerprint"
200+
local report_data="${ssl_fingerprint}"
201+
202+
if [ -n "$GPU_MODE" ]; then
203+
# get random 32 bytes
204+
local gpu_nonce=$(crypt-tool rand)
205+
if ! test_valid_hex_data "gpu_nonce"; then
206+
return 1
207+
fi
208+
209+
gpu-attest secret-vm $gpu_nonce $PATH_ATTESTATION_GPU_1 $PATH_ATTESTATION_GPU_2
210+
211+
if [ ! -e $PATH_ATTESTATION_GPU_1 ] || [ ! -e $PATH_ATTESTATION_GPU_2 ]; then
212+
echo "GPU attestation not created"
213+
return 1
214+
fi
215+
echo "GPU attestation nonce: $gpu_nonce"
216+
report_data="${report_data}${gpu_nonce}"
217+
fi
218+
219+
if [ ${#report_data} -gt 128 ]; then
220+
G_ERROR=$(echo "reportdata length: ${#report_data}")
221+
return 1
222+
fi
223+
224+
local quote=$(attest-tool attest $report_data)
225+
if ! test_valid_hex_data "quote"; then
226+
return 1
227+
fi
228+
229+
echo $quote > $PATH_ATTESTATION_TDX
230+
echo "TDX attestation done"
231+
232+
return 0
233+
}
234+
235+
# ================================
236+
# MAIN
237+
# ================================
238+
239+
# the order is crucial
240+
setup_network
241+
test -n "$GPU_MODE" && setup_gpu
242+
setup_env
243+
setup_secret_fs
244+
setup_docker
245+
246+
if [ ! -e $CERT_PATH ]; then
247+
echo "SSL certificate not ready yet. Attempting to generate..."
248+
generate_cert $CERT_NAME $CERT_DIR $DOMAIN_NAME $DOMAIN_EMAIL
249+
fi
250+
251+
finalize $CERT_PATH
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
set -ex
4+
5+
# helper function, tests if a variable is a valid hex-encoded data
6+
test_valid_hex_data()
7+
{
8+
local var_name="$1"
9+
local var_value="${!var_name}"
10+
11+
if [[ -n "$var_value" && "$var_value" =~ ^[[:xdigit:]]+$ ]]; then
12+
return 0
13+
# Valid hex
14+
else
15+
# echo "invalid value for " $var_name ": " $var_value
16+
g_Error=$(echo "invalid value for " $var_name ": " $var_value)
17+
return 1
18+
fi
19+
}

0 commit comments

Comments
 (0)