Documentation

Guides, how-tos, and integration examples for the Asynk specification and CLI.

OK

Overview

What is Asynk

Asynk is an implementation of MLS RFC 9420 — the IETF Messaging Layer Security standard — that adds abstract interfaces for how the shared group state is kept and how the secret material is protected. The protocol itself is never modified: Asynk layers pluggable responsibilities on top of it, so the cryptographic guarantees come straight from MLS while the operational strategy can be tailored to the infrastructure.

At the base lies MLS RFC 9420, providing group end-to-end encryption, forward secrecy and post-compromise security. The streamMLS bulk extension (patent-pending) sits above the protocol, enabling bounded atomic encryption and decryption of massive files. The Runtime bundles a StateStore and a ProtectionProvider — pluggable implementations for where the group state lives (filesystem passphrase, relational databases such as Postgres or Oracle, HSM or HashiCorp Vault) and how secrets are guarded. On top of the stack sits the fundamental API surface and the CLI, used to create the group offline.

Once the group state is bootstrapped offline, it can be migrated for online use onto a database so that services can derive the symmetric keys they need and communicate online — inheriting MLS forward secrecy and post-compromise security without bespoke key-exchange logic. For the full protocol specification, see RFC 9420.

ASYNK · LAYERED ARCHITECTUREFundamental API & CLIasynk init · group · proposal · commit · welcome · bulkRUNTIME · PLUGGABLEStateStoreshared group statefilesystem · Postgres · Oraclemigrate offline → online DBProtectionProvidersecret materialpassphrase · HSM · Vaultenvelope encryptionstreamMLS · bulk extension (patent-pending)bounded atomic encrypt/decrypt · forward secrecy per chunkMLS · RFC 9420group E2E · forward secrecy · post-compromise securityPROTOCOL FOUNDATION
RT

Concept

Runtime

In one lineThe runtime is the implementation chosen for where to keep the group state and how to protect the secrets.

Asynk decouples the MLS protocol from its storage and protection strategy through two pluggable interfaces: a StateStore and a ProtectionProvider. The runtime bundles a concrete pair of implementations and is selected when a workspace is scaffolded with asynk init --runtime=…. The runtime’s fingerprint is pinned into every later request, so state transitions stay auditable and reproducible.

The StateStore owns the shared group state — the cryptographic history and topology committed by MLS — while the ProtectionProvider owns the secret material (private keys, epoch secrets) and decides how it is encrypted and unlocked. Swapping the runtime never changes the protocol; it only changes the backing surface for those two responsibilities.

APPLICATION RUNTIMEApplicationMLS encrypt / decryptcommit / rotate epochAsynkStateStoreatomic load / savegeneration + epoche.g. Postgres · KV · fileProtectionProviderwrap / unwrap statewrapping key stays in KMSstate unwrapped at loadload statesave new epochwrap(state)unwrap(blob)HashiCorp Vaulttransit/encrypttransit/decryptkey: asynk-groupAPIEXTERNAL KMS
Workshop defaultfilesystem-passphrase

State on the local filesystem, secrets guarded by a passphrase file. Simplest to run, fine for demos and single-host setups.

Enterprisevault-kms

State in a protected store, secrets held by a HashiCorp Vault-backed KMS. Suited to shared, audited infrastructure.

High assurancehsm

State in a tamper-resistant store, secrets inside an HSM. For regulated environments demanding hardware key custody.

Full reference for every runtime, the StateStore and ProtectionProvider interfaces, and migration between runtimes will be published as part of the complete documentation.

SC

Reference

Scenarios

In one lineThe same runtime and the same group semantics, deployed in three different topologies.

Every scenario below reuses the same two abstractions — a StateStore and a ProtectionProvider — and the same MLS group lifecycle. What changes is who the members are: applications, gateways, or workloads inside a cluster.

Scenario 01

App-to-app across organizations

The group is created offline. Each organization contributes a KeyPackage, the creator commits the membership change and hands out one Welcome per joining member. Welcomes and KeyPackages carry no private key material, so they can travel over any channel — including email or removable media.

From that point on each organization’s applications load the shared MLS state from their own runtime and communicate online, with key rotation guaranteed by MLS RFC 9420: forward secrecy, post-compromise security, and no static shared secret sitting at rest.

CONTROL PLANE · OFFLINE GROUP AGREEMENT (ASYNK)YOUR ORG · boundaryCommitterCreates MLS group stateCISO-approved cadenceasynk bootstrap createUNTRUSTED DELIVERY CHANNELemail · SFTP · any transportORG 3 · boundaryRecipientasynk state importORG 2 · boundaryRecipientasynk state importpublishwelcome_3welcome_2DATA PLANE · ONLINE APPLICATION MESSAGING (MLS RFC 9420)ORG 3 APPLoads shared MLS stateForward secrecyPost-compromise securityE2EE app messagesYOUR APPLoads shared MLS stateForward secrecyPost-compromise securityE2EE app messagesORG 2 APPLoads shared MLS stateForward secrecyPost-compromise securityE2EE app messagesload stateload state

Control plane (offline, Asynk): organizations agree on group state and exchange Welcome bundles across boundaries. Data plane (online, MLS RFC 9420): each org’s applications load the shared state and exchange end-to-end encrypted messages with continuous key rotation.

The CLI flow for this scenario — from workspace scaffolding to the first bulk exchange — is walked through step by step in the three-organization workshop.

terminal · initialize one workspace per organization
$ asynk init workspaces/payment-processor \  --member=payment-processor \  --certificate=workspaces/payment-processor/payment-processor.crt \  --private-key=workspaces/payment-processor/payment-processor.key \  --trust-anchor=workspaces/payment-processor/root-ca.crt \  --runtime=filesystem-passphrase \  --passphrase-file=workspaces/payment-processor/secrets/payment-processor.passphrase \  --cipher-suite="$SUITE" \  --no-initialize-group
terminal · create the group, commit members, process Welcomes
$ asynk group initialize --input=requests/groups/payment-channel/initialize.yaml$ asynk proposal create add --input=requests/groups/payment-channel/add-acquirer.yaml$ asynk commit create --input=requests/groups/payment-channel/commit.yaml$ asynk welcome process --input=requests/groups/payment-channel/welcome-acquirer.yaml

Scenario 02

Crypto gateways at the trusted boundary

Workloads that cannot embed MLS natively — trading platforms, settlement engines, custody systems — delegate to a local Asynk gateway deployed inside each organization. Replicas reach their own gateway over mTLS in-VPC; the gateways are the MLS members and carry end-to-end encrypted traffic across the public transport.

Adding a microservice becomes a local operation, not a new MLS onboarding: the group membership stays stable while the internal topology evolves.

BANK A · TRUSTEDApp replicatrading-svcno MLS stackmTLS (in-VPC)Asynk GatewayMLS RFC 9420StateStoreVault-backed keysas-a-serviceBANK B · TRUSTEDApp replicasettlement-svcno MLS stackmTLS (in-VPC)Asynk GatewayMLS RFC 9420StateStoreVault-backed keysas-a-serviceBANK C · TRUSTEDApp replicacustody-svcno MLS stackmTLS (in-VPC)Asynk GatewayMLS RFC 9420StateStoreVault-backed keysas-a-serviceMLS GROUP · END-TO-END BETWEEN GATEWAYSAny transport (public internet, message bus, broker) — treated as untrustedTrust boundary of the E2EE channel = the gateways, not the app replicas

Each organization runs one gateway holding the protected group state; internal replicas never see MLS material, only the mTLS channel to their gateway.

Scenario 03

Zero-trust internal mesh on Kubernetes

Dozens of microservices are treated as a single MLS group. Each pod is a leaf of the group: the pods of a given service share the same workload identity — the same X.509 credential issued to that service — but every pod joins with its own distinct KeyPackage, so it owns its private leaf material and never shares it with a sibling replica.

That distinction matters operationally. Scaling a deployment up means adding leaves under an identity the group already trusts; terminating a pod means removing exactly that leaf with a Commit, which starts a new epoch and rotates the key schedule. A compromised replica can therefore be evicted without re-onboarding the service and without touching the other pods.

Joining is an offline DevOps operation: the CI/CD pipeline issues the KeyPackage and receives a signed Welcome, and the next deployment rolls out the updated group state. At runtime each pod derives short-lived keys from the current epoch to wrap REST payloads as JWE (RFC 7516) — so the network, the service mesh and any intermediary only ever see ciphertext.

ORGANIZATION · KUBERNETES CLUSTERDevOps · offline group add (CI/CD)Shared Asynk group state · mesh-svcpodpayments-apiPCIleaf · own KeyPackage → JWEpodcards-vaultPCIleaf · own KeyPackage → JWEpodkyc-serviceGDPRleaf · own KeyPackage → JWEpodledgerPCIleaf · own KeyPackage → JWEpodrisk-engineinternalleaf · own KeyPackage → JWEpodreportingGDPRleaf · own KeyPackage → JWEMLS EPOCH · KEY SCHEDULE SHARED BY ALL PODSsame workload identity · one distinct leaf and KeyPackage per podPOST /charges · Content-Type: application/jose · JWE payloadZero-trust mesh: every service-to-service call is E2EE; PCI / GDPR data is never in cleartext on the network

All pods share one MLS epoch and key schedule. Pods of the same service present the same workload identity, yet each one is a separate leaf with its own KeyPackage — so replicas can be added or evicted individually with a single Commit.