@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Cache generation of the SSH authentication keyfile for sshd

Summary:
Ref T11469. This isn't directly related, but has been on my radar for a while: building SSH keyfiles (particular for installs with a lot of keys, like ours) can be fairly slow.

At least one cluster instance is making multiple clone requests per second. While that should probably be rate limited separately, caching this should mitigate the impact of these requests.

This is pretty straightforward to cache since it's exactly the same every time, and only changes when users modify SSH keys (which is rare).

Test Plan:
- Ran `bin/auth-ssh`, saw authfile generate.
- Ran it again, saw it read from cache.
- Changed an SSH key.
- Ran it again, saw it regenerate.

Reviewers: chad

Reviewed By: chad

Maniphest Tasks: T11469

Differential Revision: https://secure.phabricator.com/D16744

+99 -56
+65 -55
scripts/ssh/ssh-auth.php
··· 4 4 $root = dirname(dirname(dirname(__FILE__))); 5 5 require_once $root.'/scripts/__init_script__.php'; 6 6 7 - $keys = id(new PhabricatorAuthSSHKeyQuery()) 8 - ->setViewer(PhabricatorUser::getOmnipotentUser()) 9 - ->withIsActive(true) 10 - ->execute(); 7 + $cache = PhabricatorCaches::getMutableCache(); 8 + $authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY; 9 + $authfile = $cache->getKey($authfile_key); 11 10 12 - if (!$keys) { 13 - echo pht('No keys found.')."\n"; 14 - exit(1); 15 - } 11 + if ($authfile === null) { 12 + $keys = id(new PhabricatorAuthSSHKeyQuery()) 13 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 14 + ->withIsActive(true) 15 + ->execute(); 16 16 17 - $bin = $root.'/bin/ssh-exec'; 18 - foreach ($keys as $ssh_key) { 19 - $key_argv = array(); 20 - $object = $ssh_key->getObject(); 21 - if ($object instanceof PhabricatorUser) { 22 - $key_argv[] = '--phabricator-ssh-user'; 23 - $key_argv[] = $object->getUsername(); 24 - } else if ($object instanceof AlmanacDevice) { 25 - if (!$ssh_key->getIsTrusted()) { 26 - // If this key is not a trusted device key, don't allow SSH 27 - // authentication. 17 + if (!$keys) { 18 + echo pht('No keys found.')."\n"; 19 + exit(1); 20 + } 21 + 22 + $bin = $root.'/bin/ssh-exec'; 23 + foreach ($keys as $ssh_key) { 24 + $key_argv = array(); 25 + $object = $ssh_key->getObject(); 26 + if ($object instanceof PhabricatorUser) { 27 + $key_argv[] = '--phabricator-ssh-user'; 28 + $key_argv[] = $object->getUsername(); 29 + } else if ($object instanceof AlmanacDevice) { 30 + if (!$ssh_key->getIsTrusted()) { 31 + // If this key is not a trusted device key, don't allow SSH 32 + // authentication. 33 + continue; 34 + } 35 + $key_argv[] = '--phabricator-ssh-device'; 36 + $key_argv[] = $object->getName(); 37 + } else { 38 + // We don't know what sort of key this is; don't permit SSH auth. 28 39 continue; 29 40 } 30 - $key_argv[] = '--phabricator-ssh-device'; 31 - $key_argv[] = $object->getName(); 32 - } else { 33 - // We don't know what sort of key this is; don't permit SSH auth. 34 - continue; 35 - } 36 41 37 - $key_argv[] = '--phabricator-ssh-key'; 38 - $key_argv[] = $ssh_key->getID(); 42 + $key_argv[] = '--phabricator-ssh-key'; 43 + $key_argv[] = $ssh_key->getID(); 39 44 40 - $cmd = csprintf('%s %Ls', $bin, $key_argv); 45 + $cmd = csprintf('%s %Ls', $bin, $key_argv); 41 46 42 - $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); 43 - if (strlen($instance)) { 44 - $cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd); 45 - } 47 + $instance = PhabricatorEnv::getEnvConfig('cluster.instance'); 48 + if (strlen($instance)) { 49 + $cmd = csprintf('PHABRICATOR_INSTANCE=%s %C', $instance, $cmd); 50 + } 46 51 47 - // This is additional escaping for the SSH 'command="..."' string. 48 - $cmd = addcslashes($cmd, '"\\'); 52 + // This is additional escaping for the SSH 'command="..."' string. 53 + $cmd = addcslashes($cmd, '"\\'); 49 54 50 - // Strip out newlines and other nonsense from the key type and key body. 55 + // Strip out newlines and other nonsense from the key type and key body. 51 56 52 - $type = $ssh_key->getKeyType(); 53 - $type = preg_replace('@[\x00-\x20]+@', '', $type); 54 - if (!strlen($type)) { 55 - continue; 56 - } 57 + $type = $ssh_key->getKeyType(); 58 + $type = preg_replace('@[\x00-\x20]+@', '', $type); 59 + if (!strlen($type)) { 60 + continue; 61 + } 57 62 58 - $key = $ssh_key->getKeyBody(); 59 - $key = preg_replace('@[\x00-\x20]+@', '', $key); 60 - if (!strlen($key)) { 61 - continue; 62 - } 63 + $key = $ssh_key->getKeyBody(); 64 + $key = preg_replace('@[\x00-\x20]+@', '', $key); 65 + if (!strlen($key)) { 66 + continue; 67 + } 63 68 64 - $options = array( 65 - 'command="'.$cmd.'"', 66 - 'no-port-forwarding', 67 - 'no-X11-forwarding', 68 - 'no-agent-forwarding', 69 - 'no-pty', 70 - ); 71 - $options = implode(',', $options); 69 + $options = array( 70 + 'command="'.$cmd.'"', 71 + 'no-port-forwarding', 72 + 'no-X11-forwarding', 73 + 'no-agent-forwarding', 74 + 'no-pty', 75 + ); 76 + $options = implode(',', $options); 72 77 73 - $lines[] = $options.' '.$type.' '.$key."\n"; 78 + $lines[] = $options.' '.$type.' '.$key."\n"; 79 + } 80 + 81 + $authfile = implode('', $lines); 82 + $ttl = phutil_units('24 hours in seconds'); 83 + $cache->setKey($authfile_key, $authfile, $ttl); 74 84 } 75 85 76 - echo implode('', $lines); 86 + echo $authfile; 77 87 exit(0);
+14
src/applications/auth/editor/PhabricatorAuthSSHKeyEditor.php
··· 191 191 return 'ssh-key-'.$object->getPHID(); 192 192 } 193 193 194 + protected function applyFinalEffects( 195 + PhabricatorLiskDAO $object, 196 + array $xactions) { 197 + 198 + // After making any change to an SSH key, drop the authfile cache so it 199 + // is regenerated the next time anyone authenticates. 200 + $cache = PhabricatorCaches::getMutableCache(); 201 + $authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY; 202 + $cache->deleteKey($authfile_key); 203 + 204 + return $xactions; 205 + } 206 + 207 + 194 208 protected function getMailTo(PhabricatorLiskDAO $object) { 195 209 return $object->getObject()->getSSHKeyNotifyPHIDs(); 196 210 }
+2
src/applications/auth/query/PhabricatorAuthSSHKeyQuery.php
··· 3 3 final class PhabricatorAuthSSHKeyQuery 4 4 extends PhabricatorCursorPagedPolicyAwareQuery { 5 5 6 + const AUTHFILE_CACHEKEY = 'ssh.authfile'; 7 + 6 8 private $ids; 7 9 private $phids; 8 10 private $objectPHIDs;
+17
src/applications/cache/PhabricatorCaches.php
··· 99 99 return $caches; 100 100 } 101 101 102 + public static function getMutableCache() { 103 + static $cache; 104 + if (!$cache) { 105 + $caches = self::buildMutableCaches(); 106 + $cache = self::newStackFromCaches($caches); 107 + } 108 + return $cache; 109 + } 110 + 111 + private static function buildMutableCaches() { 112 + $caches = array(); 113 + 114 + $caches[] = new PhabricatorKeyValueDatabaseCache(); 115 + 116 + return $caches; 117 + } 118 + 102 119 103 120 /* -( Repository Graph Cache )--------------------------------------------- */ 104 121
+1 -1
src/applications/cache/PhabricatorKeyValueDatabaseCache.php
··· 98 98 $this->establishConnection('w'), 99 99 'DELETE FROM %T WHERE cacheKeyHash IN (%Ls)', 100 100 $this->getTableName(), 101 - $keys); 101 + $map); 102 102 } 103 103 104 104 return $this;