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:
parent
dd2d7fee4c
commit
3647139920
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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"]
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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):
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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!")
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue