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 time

Verify 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 failed
If verification passes, your VM is confirmed to be running in a genuine SEV-SNP environment.

Detailed Attestation Report

Save Full Report

# Save attestation to file
teenode vm attest my-vm-name --output attestation.json

# View report
cat attestation.json

Attestation 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 modified

Report 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 socket
Ensure debug_allowed is false for production VMs. Debug mode compromises security.

Verify 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 passed

Custom 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
fi

Attestation 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.pem

Understand 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-verify

Measurement 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 0

Kubernetes 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: 3

Automated 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 --follow

Measurement 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 VM

Certificate 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 --verify

Security 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"
fi

Integrate 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
fi

Advanced 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"
fi

Aggregate 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

Next Steps

You now have the knowledge to verify and automate attestation checks for your confidential workloads!
    Verify AMD SEV-SNP Attestation - Teenode Guides