Close paramiko connections explicitly

We have observed at least one case in the wild where an unreadable ssh
private key file results in thousands of connections being made to
Gerrit over a relatively short period of time. We expect this is due to
newer paramiko behavior that requires you explicitly close connections
(even when they fail).

Fix this by adding explicit client closes.

Change-Id: I713cb704ac24db5d38cd9c0c2d60962dca647f75
Story: 2000923
This commit is contained in:
Clark Boylan 2017-03-17 09:56:09 -07:00
parent 773651ad7b
commit 12d9aa67e6
1 changed files with 23 additions and 11 deletions

View File

@ -192,13 +192,16 @@ class GerritWatcher(threading.Thread):
stdout.channel.close()
ret = stdout.channel.recv_exit_status()
self.log.debug("SSH exit status: %s" % ret)
client.close()
if ret and ret not in [-1, 130]:
raise Exception("Gerrit error executing stream-events")
except:
self.log.exception("Exception on ssh event stream:")
time.sleep(5)
finally:
# If we don't close on exceptions to connect we can leak the
# connection and DoS Gerrit.
client.close()
def run(self):
while not self._stopped:
@ -353,16 +356,25 @@ class GerritConnection(BaseConnection):
return alldata
def _open(self):
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect(self.server,
username=self.user,
port=self.port,
key_filename=self.keyfile)
transport = client.get_transport()
transport.set_keepalive(self.keepalive)
self.client = client
if self.client:
# Paramiko needs explicit closes, its possible we will open even
# with an unclosed client so explicitly close here.
self.client.close()
try:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.WarningPolicy())
client.connect(self.server,
username=self.user,
port=self.port,
key_filename=self.keyfile)
transport = client.get_transport()
transport.set_keepalive(self.keepalive)
self.client = client
except Exception:
client.close()
self.client = None
raise
def _ssh(self, command, stdin_data=None):
if not self.client: