Project:Infrastructure/SSSS secret storage
This proposal addresses the problem of storing high-security secrets; that is, secrets that aren't necessary in daily Infra operations but need to be available for Infra members for special cases. Those secrets can include primary OpenPGP keys, admin account passwords etc. The proposal is based on the use of M-out-of-N secret sharing scheme to combine the two goals: reducing the exposure of secrets to individual Infra members while at the same time avoiding a low bus factor.
Goals
The goals of this proposal are:
- Infra member can only gain access to the secret if (M-1) other infra members agree with it.
- All secret accesses are logged in the audit log, by all infra members participating in the process. Each successive member taking part in secret decryption verifies the log entry of his predecessors, effectively requiring M compromised members to prevent the access from being logged.
Procedures
Encrypting and decrypting secrets
A new secret is being encrypted as follows:
- The secret S is encrypted using symmetric algorithm with randomly generated key K into ciphertext S'. The secret S is discarded.
- The key K is split into N shares Ki using a secret sharing scheme. The original key K is discarded.
- Each of the shares Ki is OpenPGP-encrypted to one of the Infra members Ki'. The original shares Ki are discarded.
- The encrypted secret S' is stored in the secret store. The encrypted shares Ki' are either stored in the secret store or sent to the appropriate Infra members.
A secret is being decrypted as follows:
- M infra members decrypt their shares Ki'.
- The decrypted shares Ki are used to reconstruct the original key K.
- The key K is used to decrypt the secret S'.
Audit log
Each secret is accompanied with an audit log whose main purpose is to clearly indicate which developers had access to the secret. The audit log is created when the secret is initially encrypted, and it lists all accesses to the point of the secret being either rotated or retired.
Each access to the secret starts with an audit log entry from the developer wishing to access it. Afterwards, the (M-1) other developers sharing their parts of the key verify the previous audit log entries and add their own note to the original request. This ensures that each access attempt is actually logged, and each entry is verified by at least one more Infra member. Upon finishing the use of the secret, the original developer verifies all previous signatures and closes the audit log entry.
Secret rotation
The stored secrets are classified into two groups:
- Secrets suitable for frequent rotation — e.g. website passwords;
- Secrets unsuitable for frequent rotation — e.g. OpenPGP keys.
If a secret is suitable for frequent rotation, it is recommended that it is rotated every time a different developer accesses it from the one previously having access. Furthermore, periodic rotation is suggested in case a single developer only is accessing it repeatedly.
The goal is to keep the exposure of each secret to the minimum, and to make it possible to clearly figure out the leak in case of compromise. If this practice is followed, each past key would be accessed by at most two distinct developers, and each current key by only one.
If a secret is unsuitable for frequent rotation, it is recommended that the same developer accesses it every time. Access to other Infra members should be given only if the original developer is unavailable and the matter is urgent.
Complete procedure
The procedure for storing a new secret is:
- Developer C creates the new secret and:
- encrypts the secret as outlined above
- starts a new audit log for the new secret
- stores the encrypted secret and encrypted shares
The procedure for obtaining a secret is:
- Developer A wishes to obtain a secret. He:
- adds his request to the audit log for the secret, with note on what he needs it for
- sends a request for shares to other infra members
- If developer B wishes to participate in the request:
- he reads the audit log and verifies the request from dev A, as well as other signatures made on it
- decrypts his own share of the key and reencrypts it to dev A
- adds an entry to the audit log stating that he participated in the request from dev A
- sends the encrypted share to dev A
- Once developer A obtains (M-1) shares, he:
- verifies the audit log entries made by developer sending him shares
- decrypts his own share and combines it with other shares to obtain the key
- decrypts the secret and uses it to perform necessary actions
- rotates the secret if appropriate
- discards the secret and shares
- closes his log entry indicating that the secret has been discarded (and possibly rotated)
Proposed implementation
Secret storage
app-admin/pass would be extended to support SSSS. The proposed directory structure would be:
dir/file.bin
dir/file.share.admin1.gpg
dir/file.share.admin2.gpg
dir/file.share.admin3.gpg
...
file.bin would be the symmetrically-encrypted secret. file.share.*.gpg would be the encryption key shares encrypted to individual Infra members.
Audit log
Audit log would be implemented as a dedicated git repository. The commit signatures would provide authenticity verification for log entries.
Each secret would be to put into a separate directory. Files in those directories would indicate successive rotated secrets. For example, admin passwords to service X would be stored as follows:
service-x/0001.log
service-x/0002.log
service-x/0003.log
Every log file would be started on encrypting the secret. The initial content would be:
Secret: admin password for service X
Created by: admin3
Created on: YYYY-MM-DD HH:MM:SS UTC
Notes:
You also need to take TOTP token using secret from service-x-otp.
Each decryption request would be appended to the log as follows:
Decryption request by: admin2
Requested on: YYYY-MM-DD HH:MM:SS UTC
Purpose:
Change our avatar to unicorns.
Shares provided by:
1. admin2
Developers sending their shares would append to the list on the bottom:
Shares provided by:
1. admin2
2. admin3; YYYY-MM-DD HH:MM:SS UTC
3. admin7: YYYY-MM-DD HH:MM:SS UTC
After finishing the work, admin2 would close the entry:
Secret discarded on: YYYY-MM-DD HH:MM:SS UTC
[Secret rotated]
[Secret retired]