Verify AMD SEV-SNP Attestation
This guide covers verifying the cryptographic attestation reports from your Teenode TEE VMs running AMD SEV-SNP. Attestation proves your VM is running in a genuine confidential environment with tamper-proof measurements.
What is Attestation?
Attestation provides cryptographic proof that:
- Your VM is running genuine AMD SEV-SNP hardware
- The hypervisor hasn’t tampered with the VM
- Your application code and configuration are intact
- The system hasn’t been modified since launch
It’s like a digital seal of authenticity for your confidential environment.
Prerequisites
- Running TEE VM on Teenode
- Teenode CLI installed and authenticated
- Basic familiarity with cryptographic concepts
- Optional: OpenSSL for advanced verification
Quick Attestation Check
Get Attestation Report
# Retrieve attestation from running VM
teenode vm attest my-vm-name
# Output shows basic attestation info
# Includes VM identity, measurements, and launch timeVerify Report Immediately
# Get and verify attestation in one command
teenode vm attest my-vm-name --verify
# Output indicates:
# ✓ VERIFIED - Attestation is valid
# ✗ FAILED - Attestation validation failedDetailed Attestation Report
Save Full Report
# Save attestation to file
teenode vm attest my-vm-name --output attestation.json
# View report
cat attestation.jsonAttestation report structure:
{
"report": {
"version": 2,
"guest_svn": 1,
"policy": {
"abi_major": 0,
"abi_minor": 0,
"smt_allowed": false,
"migrate_ma": false,
"debug_allowed": false,
"single_socket": false
},
"family_id": "abcd1234...",
"image_id": "efgh5678...",
"vmpl": 0,
"signature_algo": 1,
"current_tcb": {
"microcode": 1,
"snp": 3,
"sec_processor": 3,
"tee": 0
},
"platform_info": {
"smt_enabled": false,
"tsme_enabled": true,
"ecc_enabled": true
},
"author_key_en": true,
"report_data": "00000000...",
"measurement": "a1b2c3d4e5f6...",
"host_data": "",
"id_key_digest": "x1y2z3a4b5c6...",
"author_key_digest": "p1q2r3s4t5u6...",
"report_id": "vm-report-123...",
"report_id_ma": "ma-report-456...",
"reported_tcb": {
"microcode": 1,
"snp": 3,
"sec_processor": 3,
"tee": 0
},
"tee_type": 0,
"snp_fw_version": "0.40.01"
},
"certificates": {
"vcek": "-----BEGIN CERTIFICATE-----...",
"vlek": "-----BEGIN CERTIFICATE-----...",
"ask": "-----BEGIN CERTIFICATE-----..."
},
"verification": {
"attestation_valid": true,
"report_signature_valid": true,
"certificate_chain_valid": true,
"launch_measurement_valid": true
}
}Understanding Measurements
VM Measurement
The measurement field is a cryptographic hash representing:
- VM firmware (OVMF/UEFI)
- VM kernel
- Initial filesystem
- Boot configuration
Same VM configuration always produces the same measurement (deterministic).
# Extract measurement
cat attestation.json | jq '.report.measurement'
# Output:
# "a1b2c3d4e5f6789abcdef0123456789abcdef0123456789abcdef0123456789"
# Measurement changes if:
# - Kernel version changes
# - Boot parameters change
# - Firmware updated
# - Any system files modifiedReport Data
Report data can be used to verify application-specific information:
# Set report data when creating VM
teenode vm create my-vm \
--report-data "my-app-v1.2.3"
# Later, verify it matches
cat attestation.json | jq '.report.report_data'Policy Verification
Check security policy settings:
# View policy
cat attestation.json | jq '.report.policy'
# Key fields:
# - debug_allowed: Should be false for production
# - migrate_ma: Whether migration is allowed
# - smt_allowed: Simultaneous multi-threading
# - single_socket: Restrict to single socketVerify Attestation Programmatically
Using Teenode CLI
# Get and verify with details
teenode verify-attestation attestation.json --verbose
# Output shows each verification step:
# ✓ Attestation version valid (v2)
# ✓ Report signature verified with VCEK
# ✓ Certificate chain valid
# ✓ TCB version secure
# ✓ Debug mode disabled
# ✓ All checks passedCustom Verification Script
Build verification into your application:
// attestation-verifier.ts
import { exec } from 'child_process';
import { readFileSync } from 'fs';
interface AttestationReport {
report: {
measurement: string;
policy: { debug_allowed: boolean };
current_tcb: { snp: number; microcode: number };
verification: { attestation_valid: boolean };
};
}
async function verifyAttestation(vmName: string): Promise<boolean> {
// Get attestation report
const report = await getAttestationReport(vmName);
// Verify core properties
const checks = {
attestationValid: report.report.verification.attestation_valid,
debugDisabled: !report.report.policy.debug_allowed,
tcbSecure: report.report.current_tcb.snp >= 3,
measurementPresent: report.report.measurement.length > 0,
};
// Log results
console.log('Attestation Verification Results:');
Object.entries(checks).forEach(([check, passed]) => {
console.log(` ${passed ? '✓' : '✗'} ${check}`);
});
// Fail if any check failed
return Object.values(checks).every(v => v);
}
async function getAttestationReport(vmName: string): Promise<AttestationReport> {
return new Promise((resolve, reject) => {
exec(`teenode vm attest ${vmName} --output /dev/stdout`, (error, stdout) => {
if (error) reject(error);
resolve(JSON.parse(stdout));
});
});
}
// Usage
verifyAttestation('my-vm-name')
.then(valid => {
if (valid) {
console.log('✓ VM attestation verified - safe to proceed');
process.exit(0);
} else {
console.error('✗ VM attestation failed - do not trust VM');
process.exit(1);
}
})
.catch(error => {
console.error('Attestation verification error:', error);
process.exit(2);
});Verify Measurement
# Get VM measurement
teenode vm attest my-vm-name --output attestation.json | jq '.report.measurement' > measurement.txt
# Store expected measurement
EXPECTED_MEASUREMENT="a1b2c3d4e5f6789abcdef0123456789abcdef0123456789abcdef0123456789"
# Compare
ACTUAL=$(cat measurement.txt | tr -d '"')
if [ "$ACTUAL" = "$EXPECTED_MEASUREMENT" ]; then
echo "✓ Measurement verified"
else
echo "✗ Measurement mismatch!"
echo "Expected: $EXPECTED_MEASUREMENT"
echo "Actual: $ACTUAL"
exit 1
fiAttestation Certificates
Verify Certificate Chain
Attestation uses AMD’s certificate chain:
# Extract certificates from report
cat attestation.json | jq -r '.certificates.vcek' > vcek.pem
cat attestation.json | jq -r '.certificates.ask' > ask.pem
# View certificate details
openssl x509 -in vcek.pem -text -noout | head -20
# Check certificate validity
openssl x509 -in vcek.pem -noout -dates
# Verify certificate chain
openssl verify -CAfile ask.pem vcek.pemUnderstand Certificate Types
- VCEK - Versioned Chip Endorsement Key (specific to hardware)
- VLEK - Versioned Launch Endorsement Key
- ASK - AMD Signing Key (root authority)
Continuous Attestation Monitoring
Periodic Verification
#!/bin/bash
# verify-attestation-periodic.sh
VM_NAME="my-vm-name"
CHECK_INTERVAL=3600 # 1 hour
ALERT_EMAIL="[email protected]"
while true; do
echo "Verifying attestation for $VM_NAME at $(date)"
# Get attestation
teenode vm attest "$VM_NAME" --verify
RESULT=$?
if [ $RESULT -ne 0 ]; then
echo "ALERT: Attestation verification failed!"
echo "VM: $VM_NAME" | mail -s "Teenode Attestation Alert" "$ALERT_EMAIL"
else
echo "✓ Attestation verified successfully"
fi
# Wait before next check
sleep $CHECK_INTERVAL
done# Run as systemd service
# Save script as /opt/teenode/verify-attestation.sh
chmod +x /opt/teenode/verify-attestation.sh
# Create systemd service file
sudo cat > /etc/systemd/system/teenode-attestation-verify.service << 'EOF'
[Unit]
Description=Teenode Attestation Verification
After=network.target
[Service]
Type=simple
ExecStart=/opt/teenode/verify-attestation.sh
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
# Enable and start service
sudo systemctl daemon-reload
sudo systemctl enable teenode-attestation-verify
sudo systemctl start teenode-attestation-verify
# Check service status
sudo systemctl status teenode-attestation-verifyMeasurement Change Detection
#!/bin/bash
# detect-measurement-change.sh
VM_NAME="my-vm-name"
BASELINE_FILE="/opt/teenode/baseline-measurement.txt"
# Get current measurement
CURRENT=$(teenode vm attest "$VM_NAME" | jq -r '.report.measurement')
# Check baseline
if [ -f "$BASELINE_FILE" ]; then
BASELINE=$(cat "$BASELINE_FILE")
if [ "$CURRENT" != "$BASELINE" ]; then
echo "ALERT: VM measurement changed!"
echo "VM: $VM_NAME"
echo "Baseline: $BASELINE"
echo "Current: $CURRENT"
# Trigger alert - measurement change indicates modification
exit 1
fi
else
# Store baseline on first run
echo "$CURRENT" > "$BASELINE_FILE"
echo "Baseline measurement stored"
fi
echo "✓ Measurement unchanged"
exit 0Kubernetes Integration
Verify VMs during pod scheduling:
apiVersion: batch/v1
kind: Job
metadata:
name: attestation-verifier
spec:
template:
spec:
serviceAccountName: attestation-verifier
containers:
- name: verifier
image: teenode-cli:latest
command:
- /bin/sh
- -c
- |
VM_NAME=$(cat /etc/hostname)
teenode vm attest $VM_NAME --verify || exit 1
echo "Attestation verified"
env:
- name: TEENODE_API_TOKEN
valueFrom:
secretKeyRef:
name: teenode-creds
key: api-token
restartPolicy: Never
backoffLimit: 3Automated Verification on Deployment
CI/CD Pipeline Integration
# GitHub Actions workflow
name: Deploy with Attestation Verification
on: [workflow_dispatch]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Deploy to Teenode
run: |
npm install -g teenode-cli
teenode auth login --token ${{ secrets.TEENODE_TOKEN }}
# Deploy VM
teenode vm create my-vm \
--cpu 4 \
--memory 8192 \
--region us-east
- name: Verify Attestation
run: |
# Wait for VM to boot
sleep 30
# Verify attestation
teenode vm attest my-vm --verify
# If fails, roll back
if [ $? -ne 0 ]; then
echo "Attestation failed - rolling back"
teenode vm delete my-vm
exit 1
fi
echo "✓ Attestation verified - deployment successful"
- name: Verify Security Policy
run: |
# Check debug mode is disabled
ATTESTATION=$(teenode vm attest my-vm --output /dev/stdout)
DEBUG_ALLOWED=$(echo "$ATTESTATION" | jq '.report.policy.debug_allowed')
if [ "$DEBUG_ALLOWED" = "true" ]; then
echo "✗ Debug mode enabled - security violation"
teenode vm delete my-vm
exit 1
fi
echo "✓ Security policy verified"Terraform Verification
# main.tf
resource "teenode_vm" "app" {
name = "app-vm"
cpu = 4
memory = 8192
region = "us-east"
}
# Verify attestation after creation
resource "null_resource" "verify_attestation" {
depends_on = [teenode_vm.app]
provisioner "local-exec" {
command = "teenode vm attest \${teenode_vm.app.name} --verify"
}
}
# Store measurement for future verification
resource "local_file" "measurement" {
content = data.external.get_measurement.result.measurement
filename = "\${path.module}/.measurements/\${teenode_vm.app.name}.txt"
}
data "external" "get_measurement" {
program = ["teenode", "vm", "attest", \${teenode_vm.app.name}, "--output", "/dev/stdout"]
}Troubleshooting Attestation
Attestation Verification Fails
# Get detailed error
teenode vm attest my-vm-name --verify --verbose
# Common causes:
# - VM not fully booted yet (wait 1-2 minutes)
# - AMD SEV-SNP not enabled on host (contact support)
# - Certificate chain invalid (very rare)
# - Network connectivity to attestation service down
# Solutions:
# 1. Wait for VM to stabilize
sleep 60
teenode vm attest my-vm-name --verify
# 2. Check VM status
teenode vm describe my-vm-name
# 3. Check VM logs
teenode vm logs my-vm-name --followMeasurement Mismatch
# Measurement changed after deployment - investigate
CURRENT=$(teenode vm attest my-vm-name | jq -r '.report.measurement')
echo "Current measurement: $CURRENT"
# Check what changed
# Common reasons:
# - Kernel security update installed
# - BIOS/firmware patched
# - Boot configuration changed
# If unexpected, this could indicate an attack:
# 1. Don’t trust the VM
# 2. Save attestation as evidence
# 3. Contact Teenode support
# 4. Delete and recreate VMCertificate Chain Invalid
# Verify certificates manually
cat attestation.json | jq -r '.certificates.vcek' > vcek.pem
cat attestation.json | jq -r '.certificates.ask' > ask.pem
# Check certificate dates
openssl x509 -in vcek.pem -noout -dates
openssl x509 -in ask.pem -noout -dates
# Expired certificates could indicate:
# - System clock out of sync
# - AMD revoked certificate (very rare)
# - Attestation service issue
# Solutions:
# 1. Verify system time is correct
date
timedatectl
# 2. Update CA certificates
apt update && apt upgrade -y
# 3. Try again
teenode vm attest my-vm-name --verifySecurity Best Practices
Automate Verification
Don’t rely on manual verification. Automate it:
- Verify on every deployment
- Monitor continuously for measurement changes
- Alert on any verification failure
- Fail fast if attestation is invalid
Store Baseline Measurements
# Keep record of expected measurements
cat > /opt/teenode/baselines.json << 'EOF'
{
"app-v1.0": "a1b2c3d4e5f6...",
"app-v1.1": "b2c3d4e5f6g7...",
"cache-server": "c3d4e5f6g7h8..."
}
EOF
# Verify against baseline
MEASUREMENT=$(teenode vm attest my-vm | jq -r '.report.measurement')
BASELINE=$(jq -r '.["app-v1.0"]' /opt/teenode/baselines.json)
if [ "$MEASUREMENT" = "$BASELINE" ]; then
echo "✓ Measurement matches baseline"
else
echo "✗ Measurement mismatch - investigate"
fiIntegrate with Incident Response
# Create incident if attestation fails
if ! teenode vm attest my-vm --verify; then
# Create incident ticket
curl -X POST https://incident.example.com/api/incidents \
-H "Authorization: Bearer $INCIDENT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Attestation Verification Failed",
"severity": "critical",
"vm_name": "my-vm-name",
"timestamp": "'$(date -Iseconds)'"
}'
# Notify security team
# Quarantine VM if necessary
teenode vm stop my-vm-name
fiAdvanced Topics
Custom Report Data
Use report data to verify application state:
# During VM creation
teenode vm create my-vm \
--report-data "$(sha256sum /app/config.json | cut -d' ' -f1)"
# Later, verify configuration hash matches
REPORT_DATA=$(teenode vm attest my-vm | jq -r '.report.report_data')
CONFIG_HASH=$(sha256sum /app/config.json | cut -d' ' -f1)
if [ "$REPORT_DATA" = "$CONFIG_HASH" ]; then
echo "✓ Configuration verified"
else
echo "✗ Configuration mismatch"
fiAggregate Attestation
Verify multiple VMs at once:
#!/bin/bash
# verify-all-vms.sh
RESULTS=()
for vm in $(teenode vm list | jq -r '.[].name'); do
echo "Verifying $vm..."
if teenode vm attest "$vm" --verify; then
RESULTS+=("✓ $vm")
else
RESULTS+=("✗ $vm")
fi
done
echo "Attestation Report:"
for result in "${RESULTS[@]}"; do
echo " $result"
done
# Exit with error if any VM failed
[[ ! " ${RESULTS[@]} " =~ ✗ ]] && exit 0 || exit 1