fix(shared): F-S-009 require PICLOUD_DEV_INSECURE_KEY acknowledgement for dev master key
PICLOUD_DEV_MODE=true alone fell through to a fully public deterministic
master key — SHA-256("picloud-dev-master-key-v1.1.7"). The warning was
correct but the gate was a single env var. An operator copying a dev
docker-compose file into prod silently encrypted everything with a
world-known key.
Require both:
- PICLOUD_DEV_MODE=true
- PICLOUD_DEV_INSECURE_KEY=i-understand-this-is-insecure
Without the literal-string acknowledgement, MasterKey::from_env returns
the new DevModeUnacknowledged error and the process refuses to start.
Production deployments aren't affected (they set PICLOUD_SECRET_KEY).
AUDIT.md anchor: F-S-009.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -144,6 +144,15 @@ pub enum MasterKeyError {
|
||||
/// Decoded to the wrong number of bytes.
|
||||
#[error("PICLOUD_SECRET_KEY must decode to exactly {KEY_LEN} bytes, got {0}")]
|
||||
WrongLength(usize),
|
||||
|
||||
/// F-S-009: PICLOUD_DEV_MODE=true was set without PICLOUD_SECRET_KEY,
|
||||
/// AND without the explicit PICLOUD_DEV_INSECURE_KEY acknowledgement.
|
||||
#[error(
|
||||
"PICLOUD_DEV_MODE=true without PICLOUD_SECRET_KEY requires an explicit acknowledgement. \
|
||||
Set PICLOUD_DEV_INSECURE_KEY=i-understand-this-is-insecure to confirm — but never in \
|
||||
production: the dev master key is a fully public deterministic value."
|
||||
)]
|
||||
DevModeUnacknowledged,
|
||||
}
|
||||
|
||||
impl MasterKey {
|
||||
@@ -189,6 +198,18 @@ impl MasterKey {
|
||||
let dev_mode = std::env::var("PICLOUD_DEV_MODE")
|
||||
.map(|v| is_truthy(&v))
|
||||
.unwrap_or(false);
|
||||
// F-S-009: PICLOUD_DEV_MODE alone falls through to a fully
|
||||
// public deterministic key (the warning is correct but the gate
|
||||
// is a single env var — copying a dev docker-compose file into
|
||||
// prod silently encrypts everything with a world-known key).
|
||||
// Require an explicit second knob acknowledging the risk before
|
||||
// we accept dev mode without a real secret.
|
||||
let dev_ack = std::env::var("PICLOUD_DEV_INSECURE_KEY")
|
||||
.map(|v| v == "i-understand-this-is-insecure")
|
||||
.unwrap_or(false);
|
||||
if dev_mode && secret.as_deref().map(str::trim).unwrap_or("").is_empty() && !dev_ack {
|
||||
return Err(MasterKeyError::DevModeUnacknowledged);
|
||||
}
|
||||
Self::resolve(secret.as_deref(), dev_mode)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user