Skip to main content

Licensing

Surface Security requires a valid license signed by Surface Security to start in production mode. Licenses use Ed25519 public key cryptography and are verified entirely offline -- no network call is needed for license validation.

How Licensing Works

  1. Surface Security generates a license containing your tenant ID, tier, limits, and expiration
  2. The license payload is signed with Surface Security's Ed25519 private key
  3. Your deployment verifies the signature using the public key embedded in the binary at build time
  4. If the signature is valid and the license is not expired, the server starts normally

Security note: The Ed25519 public key is embedded into the binary at build time, not provided at runtime. This prevents substitution of the verification key.

First-Run Setup (Onboarding)

When the server starts with an empty database (zero admin users), it enters setup mode. A guided wizard walks the administrator through:

  1. Admin Registration -- create the first super_admin account (email, name, password)
  2. License Activation -- paste the license key into the dashboard
  3. Validation -- the backend verifies the license signature, creates the tenant and admin user atomically
  4. Dashboard Access -- JWT tokens are issued immediately so the admin can start using the platform

After setup completes:

  • All /api/v1/setup/* endpoints return 403 Forbidden
  • The login page no longer redirects to /setup
  • Existing deployments with admin users are completely unaffected

License Contents

FieldDescription
idUnique license identifier
tenant_idYour organization's tenant UUID
tierLicense tier (free, starter, team, business, enterprise)
issued_atWhen the license was issued
expires_atWhen the license expires
max_usersMaximum number of employees allowed
max_devicesMaximum number of browser extensions allowed
entitlementsFeature flags (e.g., siem_integration, advanced_analytics)

License Expiration and Grace Period

  • If the license has not yet expired, the server starts normally
  • If the license expired within the last 7 days, the server starts with a warning (grace period)
  • If the license expired more than 7 days ago, the server refuses to start
  • Licenses expiring within 30 days produce a warning log at startup

Obtaining a License

Contact Surface Security to obtain your license:

  1. Provide your organization name and desired tier
  2. Surface Security generates a signed license and provides:
    • License key -- the signed JSON payload (one long base64 string)
    • Public key -- the Ed25519 public key for verification (PEM format)
    • API token (optional) -- if you want portal connectivity for heartbeats and remote signature updates

Setting Up Licensing

Kubernetes

Step 1: Store the License Key as a Secret

# Online deployment (with portal connectivity)
kubectl create secret generic surfacesec-surface-license \
--namespace=surfacesec \
--from-literal=license-key="YOUR_SIGNED_LICENSE_KEY" \
--from-literal=api-token="YOUR_PORTAL_API_TOKEN"

# Offline / air-gapped deployment (no portal)
kubectl create secret generic surfacesec-surface-license \
--namespace=surfacesec \
--from-literal=license-key="YOUR_SIGNED_LICENSE_KEY"

Step 2: (Optional) Configure Portal Connectivity

By default, Surface Security connects to the central management portal for heartbeats, signature sync, and update notifications. The portal URL is configurable at runtime.

Using Helm:

# values.yaml
config:
surfacePortalUrl: "https://portal.surface-security.com" # default
# surfacePortalUrl: "" # offline mode

Using Kubernetes ConfigMap:

data:
surface-portal-url: "https://portal.surface-security.com"

For offline or air-gapped deployments, set the portal URL to an empty string. The license is verified entirely offline -- the portal is only needed for optional features like:

  • Heartbeat health reporting
  • Automatic signature updates
  • Extension config sync
  • Update availability notifications

Step 3: Apply and Verify

# Restart the API pods to pick up the new config
kubectl rollout restart deployment/surfacesec-api -n surfacesec

# Check logs for license verification
kubectl logs -n surfacesec -l component=api --tail=20 | grep -i license

Successful output:

{"level":"info","msg":"license verified successfully","license_id":"abc-123","tenant_id":"...","tier":"enterprise","expires_at":"2027-01-15T00:00:00Z","max_users":1000,"max_devices":5000}

If offline mode (no portal URL):

{"level":"info","msg":"portal URL not configured - running in offline mode (license verified locally)"}

Docker Compose

Set license environment variables in your .env file:

SURFACE_LICENSE_KEY=eyJsaWNlbnNlIjp7...
SURFACE_PORTAL_URL=https://portal.surface-security.com # or empty for offline
SURFACE_PORTAL_API_TOKEN=your-token-here

Renewing a License

  1. Contact Surface Security for a renewed license key
  2. Update the Kubernetes secret:
kubectl create secret generic surfacesec-surface-license \
--namespace=surfacesec \
--from-literal=license-key="NEW_LICENSE_KEY_HERE" \
--from-literal=api-token="your-api-token" \
--dry-run=client -o yaml | kubectl apply -f -
  1. Restart the API deployment:
kubectl rollout restart deployment/surfacesec-api -n surfacesec

Troubleshooting

SymptomCauseFix
license verification failedInvalid or missing licenseVerify the license key is set correctly
license signature verification FAILEDWrong public key or tampered licenseConfirm the public key matches the key Surface Security provided
license expired (grace period ended)License expired more than 7 days agoRenew the license with Surface Security
LICENSE EXPIRED - running in grace periodLicense expired less than 7 days agoRenew soon; server is running but will stop after the grace period