diff options
-rw-r--r-- | buildstream/_artifactcache/casserver.py | 73 |
1 files changed, 57 insertions, 16 deletions
diff --git a/buildstream/_artifactcache/casserver.py b/buildstream/_artifactcache/casserver.py index 1456095be..bedbac66b 100644 --- a/buildstream/_artifactcache/casserver.py +++ b/buildstream/_artifactcache/casserver.py @@ -72,6 +72,56 @@ def create_server(repo, *, enable_push): return server +class _SSLServerCredentialsCallable: + + def __init__(self, server_key, server_cert, client_certs): + self.server_key = server_key + self.server_cert = server_cert + self.client_certs = client_certs + self.client_certs_stat = None + self.load_server_key() + self.load_server_cert() + self.load_client_certs() + + def load_server_key(self): + with open(self.server_key, 'rb') as f: + self.server_key_bytes = f.read() + + def load_server_cert(self): + with open(self.server_cert, 'rb') as f: + self.server_cert_bytes = f.read() + + def load_client_certs(self): + if self.client_certs: + with open(self.client_certs, 'rb') as f: + stat = os.fstat(f.fileno()) + if stat != self.client_certs_stat: + # The stat is different. We need to reload the client certs + self.client_certs_bytes = f.read() + self.client_certs_stat = stat + return True + return False + else: + self.client_certs_stat = None + self.client_certs_bytes = None + # Nothing has been loaded + return False + + def get_ssl_server_credentials(self): + return grpc.ssl_server_certificate_configuration( + private_key_certificate_chain_pairs=[(self.server_key_bytes, self.server_cert_bytes)], + root_certificates=self.client_certs_bytes, + ) + + def __call__(self): + if self.load_client_certs(): + # We performed a reload + return self.get_ssl_server_credentials() + else: + # Nothing changed + return None + + @click.command(short_help="CAS Artifact Server") @click.option('--port', '-p', type=click.INT, required=True, help="Port number") @click.option('--server-key', help="Private server key for TLS (PEM-encoded)") @@ -94,22 +144,13 @@ def server_main(repo, port, server_key, server_cert, client_certs, enable_push): sys.exit(-1) if use_tls: - # Read public/private key pair - with open(server_key, 'rb') as f: - server_key_bytes = f.read() - with open(server_cert, 'rb') as f: - server_cert_bytes = f.read() - - if client_certs: - with open(client_certs, 'rb') as f: - client_certs_bytes = f.read() - else: - client_certs_bytes = None - - credentials = grpc.ssl_server_credentials([(server_key_bytes, server_cert_bytes)], - root_certificates=client_certs_bytes, - require_client_auth=bool(client_certs)) - server.add_secure_port('[::]:{}'.format(port), credentials) + credentials_gen = _SSLServerCredentialsCallable(server_key, server_cert, client_certs) + initial_credentials = credentials_gen.get_ssl_server_credentials() + dynamic_credentials = grpc.dynamic_ssl_server_credentials( + initial_certificate_configuration=initial_credentials, + certificate_configuration_fetcher=credentials_gen, + require_client_authentication=bool(client_certs)) + server.add_secure_port('[::]:{}'.format(port), dynamic_credentials) else: server.add_insecure_port('[::]:{}'.format(port)) |