Skip to content

Commit 0308d58

Browse files
author
epriestley
committed
Deactivate SSH keys instead of destroying them completely
Summary: Ref T10917. Currently, when you delete an SSH key, we really truly delete it forever. This isn't very consistent with other applications, but we built this stuff a long time ago before we were as rigorous about retaining data and making it auditable. In partiular, destroying data isn't good for auditing after security issues, since it means we can't show you logs of any changes an attacker might have made to your keys. To prepare to improve this, stop destoying data. This will allow later changes to become transaction-oriented and show normal transaction logs. The tricky part here is that we have a `UNIQUE KEY` on the public key part of the key. Instead, I changed this to `UNIQUE (key, isActive)`, where `isActive` is a nullable boolean column. This works because MySQL does not enforce "unique" if part of the key is `NULL`. So you can't have two rows with `("A", 1)`, but you can have as many rows as you want with `("A", null)`. This lets us keep the "each key may only be active for one user/object" rule without requiring us to delete any data. Test Plan: - Ran schema changes. - Viewed public keys. - Tried to add a duplicate key, got rejected (already associated with another object). - Deleted SSH key. - Verified that the key was no longer actually deleted from the database, just marked inactive (in future changes, I'll update the UI to be more clear about this). - Uploaded a new copy of the same public key, worked fine (no duplicate key rejection). - Tried to upload yet another copy, got rejected. - Generated a new keypair. - Tried to upload a duplicate to an Almanac device, got rejected. - Generated a new pair for a device. - Trusted a device key. - Untrusted a device key. - "Deleted" a device key. - Tried to trust a deleted device key, got "inactive" message. - Ran `bin/ssh-auth`, got good output with unique keys. - Ran `cat ~/.ssh/id_rsa.pub | ./bin/ssh-auth-key`, got good output with one key. - Used `auth.querypublickeys` Conduit method to query keys, got good active keys. Reviewers: chad Reviewed By: chad Maniphest Tasks: T10917 Differential Revision: https://secure.phabricator.com/D15943
1 parent 49eb640 commit 0308d58

18 files changed

+82
-12
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
2+
ADD isActive BOOL;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
UPDATE {$NAMESPACE}_auth.auth_sshkey
2+
SET isActive = 1;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
ALTER TABLE {$NAMESPACE}_auth.auth_sshkey
2+
ADD UNIQUE KEY `key_activeunique` (keyIndex, isActive);

scripts/ssh/ssh-auth-key.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
$key = id(new PhabricatorAuthSSHKeyQuery())
1515
->setViewer(PhabricatorUser::getOmnipotentUser())
1616
->withKeys(array($public_key))
17+
->withIsActive(true)
1718
->executeOne();
1819
if (!$key) {
1920
exit(1);

scripts/ssh/ssh-auth.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
$keys = id(new PhabricatorAuthSSHKeyQuery())
88
->setViewer(PhabricatorUser::getOmnipotentUser())
9+
->withIsActive(true)
910
->execute();
1011

1112
if (!$keys) {

src/applications/almanac/controller/AlmanacDeviceViewController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ private function buildSSHKeysTable(AlmanacDevice $device) {
146146
$keys = id(new PhabricatorAuthSSHKeyQuery())
147147
->setViewer($viewer)
148148
->withObjectPHIDs(array($device_phid))
149+
->withIsActive(true)
149150
->execute();
150151

151152
$table = id(new PhabricatorAuthSSHKeyTableView())

src/applications/almanac/management/AlmanacManagementRegisterWorkflow.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ public function execute(PhutilArgumentParser $args) {
141141
$public_key = id(new PhabricatorAuthSSHKeyQuery())
142142
->setViewer($this->getViewer())
143143
->withKeys(array($key_object))
144+
->withIsActive(true)
144145
->executeOne();
145146

146147
if (!$public_key) {

src/applications/almanac/management/AlmanacManagementTrustKeyWorkflow.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ public function execute(PhutilArgumentParser $args) {
3535
pht('No public key exists with ID "%s".', $id));
3636
}
3737

38+
if (!$key->getIsActive()) {
39+
throw new PhutilArgumentUsageException(
40+
pht('Public key "%s" is not an active key.', $id));
41+
}
42+
3843
if ($key->getIsTrusted()) {
3944
throw new PhutilArgumentUsageException(
4045
pht('Public key with ID %s is already trusted.', $id));

src/applications/auth/conduit/PhabricatorAuthQueryPublicKeysConduitAPIMethod.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ protected function execute(ConduitAPIRequest $request) {
2828
$viewer = $request->getUser();
2929

3030
$query = id(new PhabricatorAuthSSHKeyQuery())
31-
->setViewer($viewer);
31+
->setViewer($viewer)
32+
->withIsActive(true);
3233

3334
$ids = $request->getValue('ids');
3435
if ($ids !== null) {

src/applications/auth/controller/PhabricatorAuthSSHKeyController.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,7 @@ protected function newKeyForObjectPHID($object_phid) {
2525
return null;
2626
}
2727

28-
return id(new PhabricatorAuthSSHKey())
29-
->setObjectPHID($object_phid)
30-
->attachObject($object);
28+
return PhabricatorAuthSSHKey::initializeNewSSHKey($viewer, $object);
3129
}
3230

3331
}

0 commit comments

Comments
 (0)