Move key_store_password to keystore section in zuul.conf

This is likely to be needed by executors as well since passing
decrypted secrets to the executors via zookeeper has the same
encrypted-at-rest concerns as they keystore itself.  To avoid
confusion around executors needing a zuul.conf with a scheduler
section, start a new keystore section which we can later indicate
is used by schedulers and executors.  It also makes it convenient
to add new options (like those dealing with rotation, or even
using an external keystore).

Also change some log levels from debug to info where it's useful
for the operator to know that the backup keystore was used (or
a key was generated).

Change-Id: If2491bbe4eb80b76435a274cf5354a4918315e65
This commit is contained in:
James E. Blair 2021-04-12 13:53:51 -07:00
parent dd2d7fee4c
commit 3647139920
9 changed files with 34 additions and 20 deletions

View File

@ -111,11 +111,13 @@ An example ``zuul.conf``:
[zookeeper] [zookeeper]
hosts=zk1.example.com,zk2.example.com,zk3.example.com hosts=zk1.example.com,zk2.example.com,zk3.example.com
[keystore]
password=MY_SECRET_PASSWORD
[web] [web]
status_url=https://zuul.example.com/status status_url=https://zuul.example.com/status
[scheduler] [scheduler]
key_store_password=MY_SECRET_PASSWORD
log_config=/etc/zuul/scheduler-logging.yaml log_config=/etc/zuul/scheduler-logging.yaml
A minimal Zuul system may consist of a :ref:`scheduler` and A minimal Zuul system may consist of a :ref:`scheduler` and
@ -303,13 +305,16 @@ The following sections of ``zuul.conf`` are used by the scheduler:
.. TODO: is this effectively required? .. TODO: is this effectively required?
.. attr:: scheduler .. attr:: keystore
.. attr:: key_store_password .. attr:: password
:required: :required:
Encryption password for private data stored in Zookeeper. Encryption password for private data stored in Zookeeper.
.. attr:: scheduler
.. attr:: command_socket .. attr:: command_socket
:default: /var/lib/zuul/scheduler.socket :default: /var/lib/zuul/scheduler.socket

View File

@ -10,8 +10,10 @@ tls_cert=/var/certs/certs/client.pem
tls_key=/var/certs/keys/clientkey.pem tls_key=/var/certs/keys/clientkey.pem
tls_ca=/var/certs/certs/cacert.pem tls_ca=/var/certs/certs/cacert.pem
[keystore]
password=secret
[scheduler] [scheduler]
key_store_password=secret
tenant_config=/etc/zuul/main.yaml tenant_config=/etc/zuul/main.yaml
[connection "gerrit"] [connection "gerrit"]

View File

@ -131,8 +131,10 @@ service in Zuul, and a connection to Gerrit.
**zuul.conf**:: **zuul.conf**::
[keystore]
password=secret
[scheduler] [scheduler]
key_store_password=secret
tenant_config=/etc/zuul/main.yaml tenant_config=/etc/zuul/main.yaml
[gearman_server] [gearman_server]

View File

@ -72,8 +72,10 @@ to appropriate values for your setup.
[web] [web]
listen_address=0.0.0.0 listen_address=0.0.0.0
[keystore]
password=secret
[scheduler] [scheduler]
key_store_password=secret
tenant_config=/etc/zuul/main.yaml tenant_config=/etc/zuul/main.yaml
EOF" EOF"

View File

@ -18,8 +18,10 @@ start=true
;ssl_key=/path/to/server.key ;ssl_key=/path/to/server.key
;port=4730 ;port=4730
[keystore]
password=secret
[scheduler] [scheduler]
key_store_password=secret
tenant_config=/etc/zuul/main.yaml tenant_config=/etc/zuul/main.yaml
log_config=/etc/zuul/logging.conf log_config=/etc/zuul/logging.conf
pidfile=/var/run/zuul/zuul.pid pidfile=/var/run/zuul/zuul.pid

View File

@ -3,12 +3,12 @@ features:
- | - |
Project secrets keys and SSH keys are now stored in Zookeeper. All private Project secrets keys and SSH keys are now stored in Zookeeper. All private
data will be encrypted at rest, which requires a new mandatory setting data will be encrypted at rest, which requires a new mandatory setting
:attr:`scheduler.key_store_password` in ``zuul.conf``. :attr:`keystore.password` in ``zuul.conf``.
For backup purposes the secrets keys and SSH keys will still exist on the For backup purposes the secrets keys and SSH keys will still exist on the
local filesystem of the scheduler as before. local filesystem of the scheduler as before.
upgrade: upgrade:
- | - |
As project secrets keys and SSH keys are stored encrypted in Zookeeper the As project secrets keys and SSH keys are stored encrypted in Zookeeper the
new :attr:`scheduler.key_store_password` option in ``zuul.conf`` is new :attr:`keystore.password` option in ``zuul.conf`` is
required. Please add it to your configuration. required. Please add it to your configuration.

View File

@ -4254,8 +4254,8 @@ class ZuulTestCase(BaseTestCase):
self.config.set( self.config.set(
'scheduler', 'command_socket', 'scheduler', 'command_socket',
os.path.join(self.test_root, 'scheduler.socket')) os.path.join(self.test_root, 'scheduler.socket'))
if not self.config.has_option("scheduler", "key_store_password"): if not self.config.has_option("keystore", "password"):
self.config.set("scheduler", "key_store_password", self.config.set("keystore", "password",
uuid.uuid4().hex) uuid.uuid4().hex)
self.config.set('merger', 'git_dir', self.merger_src_root) self.config.set('merger', 'git_dir', self.merger_src_root)
self.config.set('executor', 'git_dir', self.executor_src_root) self.config.set('executor', 'git_dir', self.executor_src_root)
@ -4417,7 +4417,8 @@ class ZuulTestCase(BaseTestCase):
config.read(os.path.join(FIXTURE_DIR, config_file)) config.read(os.path.join(FIXTURE_DIR, config_file))
sections = [ sections = [
'zuul', 'scheduler', 'executor', 'merger', 'web', 'zookeeper' 'zuul', 'scheduler', 'executor', 'merger', 'web', 'zookeeper',
'keystore'
] ]
for section in sections: for section in sections:
if not config.has_section(section): if not config.has_section(section):

View File

@ -278,15 +278,15 @@ class ZooKeeperKeyStorage(ZooKeeperBase, KeyStorage):
if self.backup and self.backup.hasProjectSSHKeys( if self.backup and self.backup.hasProjectSSHKeys(
connection_name, project_name connection_name, project_name
): ):
self.log.debug("Using SSH key for %s/%s from backup key store", self.log.info("Using SSH key for %s/%s from backup key store",
connection_name, project_name) connection_name, project_name)
pk, _ = self.backup.getProjectSSHKeys(connection_name, pk, _ = self.backup.getProjectSSHKeys(connection_name,
project_name) project_name)
with io.StringIO(pk) as o: with io.StringIO(pk) as o:
key = paramiko.RSAKey.from_private_key(o) key = paramiko.RSAKey.from_private_key(o)
else: else:
self.log.debug("Generating a new SSH key for %s/%s", self.log.info("Generating a new SSH key for %s/%s",
connection_name, project_name) connection_name, project_name)
key = paramiko.RSAKey.generate(bits=RSA_KEY_SIZE) key = paramiko.RSAKey.generate(bits=RSA_KEY_SIZE)
try: try:
@ -330,14 +330,14 @@ class ZooKeeperKeyStorage(ZooKeeperBase, KeyStorage):
connection_name, project_name) connection_name, project_name)
if self.backup and self.backup.hasProjectSecretsKeys( if self.backup and self.backup.hasProjectSecretsKeys(
connection_name, project_name): connection_name, project_name):
self.log.debug( self.log.info(
"Using secrets key for %s/%s from backup key store", "Using secrets key for %s/%s from backup key store",
connection_name, project_name) connection_name, project_name)
private_key, public_key = self.backup.getProjectSecretsKeys( private_key, public_key = self.backup.getProjectSecretsKeys(
connection_name, project_name) connection_name, project_name)
else: else:
self.log.debug("Generating a new secrets key for %s/%s", self.log.info("Generating a new secrets key for %s/%s",
connection_name, project_name) connection_name, project_name)
private_key, public_key = encryption.generate_rsa_keypair() private_key, public_key = encryption.generate_rsa_keypair()
pem_private_key = encryption.serialize_rsa_private_key( pem_private_key = encryption.serialize_rsa_private_key(

View File

@ -595,7 +595,7 @@ class Scheduler(threading.Thread):
def _get_key_store_password(self): def _get_key_store_password(self):
try: try:
return self.config["scheduler"]["key_store_password"] return self.config["keystore"]["password"]
except KeyError: except KeyError:
raise RuntimeError("No key store password configured!") raise RuntimeError("No key store password configured!")