Logchains
Every member on a Krypton Team stores logs of their ssh
accesses, git
commits, and git
tags. As an admin, being able to monitor your team members’
host accesses and git
actions by viewing these audit logs can be very useful
for understanding the security of your infrastructure.
Logs are timestamped and encrypted before being sent to a logging endpoint, such as krypt.co’s team server, for storage. Just as with the team sigchain, the logging infrastructure is end-to-end-verified: every logchain block is verified by each admin on the team.
In other words, teams and their members only trust krypt.co for liveness. krypt.co cannot read the contents of the logs or change the order of individual member logs.
Why should I care about this? If nothing else, this should give you and your team comfort that even if krypt.co is compromised one day, the privacy and integrity of your team data will be safe.
What’s in a Logchain
Each Krypton team member’s logs are stored as an independent signed hash chain, which we refer to as their logchain
.
Logchains have the same structure as team sigchains with two main differences:
- Only a member can append to their own logchain
- A logchain may only be read by its corresponding member or the team admins
Whenever a new admin is promoted on the team, they are bootstrapped to be able to read any new logs each member encrypts. When an admin is demoted or removed, they lose the ability to decrypt new logs. This is critical as it prevents former admins from being able to read future log blocks.
The mechanism for log encryption and key rotation that enforces these rules is described in Wrapped Keys.
Contents
Protocol Extension
Below are the types used by logchains (note this is an extension to the main sigchain protocol types.
enum Body {
//...extended
Log(LogChain),
// a Message can encode other Body types for non-sigchain and non-logchain purposes
}
enum LogChain {
Create(GenesisLogBlock),
Append(LogBlock),
}
// the first log block in a chain
struct GenesisLogBlock {
team_pointer: TeamPointer,
wrapped_keys: Vec<BoxedMessage>,
}
// subsequent log blocks in a chain
struct LogBlock {
last_block_hash: Vec<u8>,
operation: LogOperation,
}
// reference to a team
enum TeamPointer {
PublicKey(Vec<u8>),
LastBlockHash(Vec<u8>),
}
// wraps a symmetric key for an admin
struct BoxedMessage {
recipient_public_key: Vec<u8>,
sender_public_key: Vec<u8>,
ciphertext: Vec<u8>, // box(..., JSON(PlaintextBody::LogEncryptionKey(symmetric_key)))
}
Log Chain
A LogChain
block has two variants:
-
Create. A
GenesisLogBlock
starts every logchain and stores bootstrapping information. Namely, it contains aTeamPointer
that identifies the member’s team by either team public key or main chain last block hash, and wrapped keys for all of the current admins. A logchain can be considered a side chain that is tied to the main chain by theGenesisLogBlock
. -
Append. Every
LogBlock
that follows theGenesisLogBlock
encodes operations on the logchain. These operations are either encrypted logs ofssh
accesses,git
commits, andgit
tags, or key management operations that deal with adding a wrapped key for a new admin and rotating the symmetric key when admins are demoted/removed.
Wrapped Keys
In order to enforce admin-only read access to log blocks in a way that adapts to the promotion and demotion/removal of admins, we utilize both symmetric and public key encryption.
For every member, the creation of a log chain or demotion/removal of an admin causes the member to:
- Create a new symmetric key to encrypt and decrypt their logs.
- Encrypt this key under each current admin’s public key, forming what we refer to as wrapped keys
Each wrapped key can only be unwrapped by the admin it was wrapped for, meaning that only admins will be able to know the symmetric key and decrypt logs.
When a new admin is promoted on the team, each member’s current symmetric key is wrapped and made available on their logchain for the new admin. This grants the new admin read access to future log blocks and some older blocks going back to the last admin demotion/removal.
Log Operations
This section provides an overview of the different types of log operations and how they work.
enum LogOperation {
EncryptLog(EncryptedLog),
AddWrappedKeys(Vec<BoxedMessage>),
RotateKey(Vec<BoxedMessage>),
}
Encrypting Logs
Whenever a member of a team ssh
’s into a host or signs a git
commit or tag, a Log
is created.
A Log
contains a timestamp, the device information from the member’s Session
, and the contents of the action being logged.
The Session
information gives admins insight into how many paired devices their members are using.
A Log
includes the following type definitions:
struct EncryptedLog {
ciphertext: [u8], // symmetrically encrypted `Log`
}
struct Log {
session: Session,
unix_seconds: u64,
body: LogBody,
}
struct Session {
device_name: String,
workstation_public_key_double_hash: Vec<u8>,
}
enum LogBody {
Ssh(SSHSignature),
GitTag(GitTagSignature),
GitCommit(GitCommitSignature),
}
struct SSHSignature {
user: String,
host_authorization: Option<HostAuthorization>,
session_data: Vec<u8>,
result: SSHSignatureResult,
}
struct GitCommitSignature {
tree: String,
parents: Vec<String>,
author: String,
committer: String,
message: Vec<u8>,
message_string: Option<String>,
result: GitSignatureResult,
}
struct GitTagSignature {
object: String,
type_: String,
tag: String,
tagger: String,
message: Vec<u8>,
message_string: Option<String>,
result: GitSignatureResult,
}
Each Log
is encrypted with the current symmetric key and added to the logchain.
Adding Wrapped Keys
Whenever a new admin is promoted on the team, they need to be able to able to read logs from their team’s members. To do so, each member:
- Creates
BoxedMessage
s containing the current symmetric key encrypted under each new admin’s public key - Adds an
AddWrappedKey
log block to their logchain containing the newly wrapped keys
This allows only the new admins access to the symmetric key, which will let them decrypt the member’s logs.
Rotating Keys
In the case that an admin loses admin status, we need to prevent them from
reading any new logs. When a team member learns that an admin has been demoted
or removed from the MainChain
, they will:
- Generate a new symmetric key
- Create
BoxedMessage
s that wrap the new key for each remaining admin - Post a
RotateKey
log block containing the newly wrapped keys - Encrypt future audit logs using the new symmetric key
When a remaining admin wants to read a new log, they first decrypt the log block that has the new symmetric key and continue as before.
The RotateKey
operation changes the symmetric key, which means that new logs
won’t be readable by former admins. Since logs are never re-encrypted, the
former admin will in theory always be able to decrypt logs that were encrypted
to them. However, krypt.co only serves logchain blocks to current team admins.