module

Pyrite

Pyrite provides hardware-bound and cloud-gated binary execution sealing and real-time anti-tamper verification for Crystal applications.

Core Architecture

Applications protected by Pyrite are incomplete at rest. Their production configuration and credentials are encrypted inside a sealed envelope (bootstrap.enc) bound to a physical TPM 2.0 chip or Cloud KMS workload identity.

At boot, Pyrite.bootstrap! unseals the envelope, streams the running /proc/self/exe binary in 16KB chunks to compute its live SHA-256 digest, compares it in constant-time against the authorized digest inside the envelope, and deserializes the configuration into a strongly typed JSON::Serializable struct.

Basic Usage

require "pyrite"

struct AppConfig
  include JSON::Serializable

  getter database_url : String
  getter session_secret : String
  getter api_token : String
end

# Single-call bootstrap with automatic trust anchor detection:
config = Pyrite.bootstrap!(AppConfig)

puts "Verified binary execution. DB: #{config.database_url}"

Constants

VERSION = "0.2.0"

Current library version

Class methods

auto_detect_provider

Automatically detects the ambient hardware or cloud trust anchor on the current machine.

Detection precedence:

  1. Explicit Environment Overrides:
    • $KMS_KEY_RESOURCE -> Google Cloud KMS
    • $AWS_KMS_KEY_ID or $AWS_CONTAINER_CREDENTIALS_RELATIVE_URI or $AWS_EXECUTION_ENV -> AWS KMS
    • $CREDENTIALS_DIRECTORY -> systemd credentials
  2. Local Hardware TPM 2.0:
    • /dev/tpmrm0 or /dev/tpm0 -> SystemdCreds if systemd-creds binary is available, else TPM2Direct
  3. DMI / Virtualization Identity:
    • Google Compute Engine / Cloud Run -> GCPKMS
    • Amazon EC2 -> AWSKMS
  4. Container & Metadata Server Discovery:
    • Container environments with active GCP metadata server -> GCPKMS

Raises Pyrite::HardwareAuthError if no supported trust anchor is detected.

Source
bootstrap!(schema : T.class, envelope_path : String = ENV.fetch("PYRITE_ENVELOPE", "bootstrap.enc"), provider : Provider | Nil = nil) : T forall T

Single-call bootstrap helper for consuming applications.

Unseals the target envelope using the resolved provider (or auto-detects the ambient hardware/cloud trust anchor), verifies the running binary's SHA-256 self-integrity against the authorized digest in constant-time, and returns strongly-typed application configuration deserialized into schema.

Parameters

  • schema (Class): A struct or class including JSON::Serializable representing the application configuration.
  • envelope_path (String): Path to the sealed envelope file. Defaults to $PYRITE_ENVELOPE or "bootstrap.enc".
  • provider (Provider?): Explicit provider instance to use. If nil, auto_detect_provider is invoked.

Errors

  • Pyrite::TamperError: Raised if the live binary SHA-256 does not match the authorized hash inside the envelope.
  • Pyrite::HardwareAuthError: Raised if hardware TPM or Cloud KMS rejects authorization/identity.
  • Pyrite::MissingEnvelopeError: Raised if envelope_path does not exist on disk.
  • Pyrite::ConfigError: Raised if decrypted JSON cannot be parsed into schema.

Example

struct ServerConfig
  include JSON::Serializable
  getter port : Int32
  getter secret_key : String
end

config = Pyrite.bootstrap!(ServerConfig, envelope_path: "config/prod.enc")
Source
gcp_metadata_available?

Validates connectivity and response headers from the Google Cloud Metadata Server (169.254.169.254).

Returns true if reachable and responding with header Metadata-Flavor: Google.

Source
unlock!(provider : Provider, envelope_path : String) : JSON::Any

Core execution gate and real-time self-integrity verification.

Unwraps the sealed envelope via provider, computes the live SHA-256 digest of /proc/self/exe, and performs constant-time comparison against the authorized_sha256 payload field.

Returns the raw JSON::Any payload if integrity is verified.

Errors

  • Pyrite::TamperError: Raised immediately if the running binary digest does not match the authorized hash.
  • Pyrite::HardwareAuthError: Raised if the provider unwrap fails.

Example

provider = Pyrite::Providers::SystemdCreds.new
payload = Pyrite.unlock!(provider, "bootstrap.enc")
puts "Authorized binary digest: #{payload["authorized_sha256"]}"
Source

Nested types