From bbef9fd363e023cc6f2fd3425c06e7c085634c12 Mon Sep 17 00:00:00 2001 From: Johannes Meyer Date: Thu, 15 Jul 2021 12:47:09 +0200 Subject: [PATCH] RedisConfigForm: Store pem files on disk, not in config --- application/forms/RedisConfigForm.php | 68 +++++++++++++++++++++++++ library/Icingadb/Common/IcingaRedis.php | 50 +++--------------- 2 files changed, 74 insertions(+), 44 deletions(-) diff --git a/application/forms/RedisConfigForm.php b/application/forms/RedisConfigForm.php index aab5a86e..fc60f7cf 100644 --- a/application/forms/RedisConfigForm.php +++ b/application/forms/RedisConfigForm.php @@ -6,6 +6,10 @@ namespace Icinga\Module\Icingadb\Forms; use Exception; use Icinga\Application\Config; +use Icinga\Application\Icinga; +use Icinga\Exception\NotWritableError; +use Icinga\File\Storage\LocalFileStorage; +use Icinga\File\Storage\TemporaryLocalFileStorage; use Icinga\Forms\ConfigForm; use Icinga\Module\Icingadb\Common\IcingaRedis; use Icinga\Web\Form; @@ -261,6 +265,64 @@ class RedisConfigForm extends ConfigForm return true; } + public function onRequest() + { + $errors = []; + + $redisConfig = $this->config->getSection('redis'); + if ($redisConfig->get('tls', false)) { + foreach (['ca', 'cert', 'key'] as $name) { + $path = $redisConfig->get($name); + if (file_exists($path)) { + try { + $redisConfig[$name] = file_get_contents($path); + } catch (Exception $e) { + unset($redisConfig[$name]); + $errors['redis_' . $name] = sprintf( + t('Failed to read file "%s": %s'), + $path, + $e->getMessage() + ); + } + } else { + unset($redisConfig[$name]); + } + } + } + + parent::onRequest(); + + foreach ($errors as $elementName => $message) { + $this->getElement($elementName)->addError($message); + } + } + + public function onSuccess() + { + if ($this->getElement('redis_tls')->isChecked()) { + $storage = new LocalFileStorage(Icinga::app()->getStorageDir( + join(DIRECTORY_SEPARATOR, ['modules', 'icingadb', 'redis']) + )); + + foreach (['redis_ca', 'redis_cert', 'redis_key'] as $name) { + $pem = $this->getValue($name); + $pemFile = md5($pem) . '-' . $name . '.pem'; + if (! $storage->has($pemFile)) { + try { + $storage->create($pemFile, $pem); + } catch (NotWritableError $e) { + $this->getElement($name)->addError($e->getMessage()); + return false; + } + } + + $this->getElement($name)->setValue($storage->resolvePath($pemFile)); + } + } + + return parent::onSuccess(); + } + public function addSubmitButton() { parent::addSubmitButton() @@ -296,9 +358,15 @@ class RedisConfigForm extends ConfigForm $sections = []; $config = new Config(); + $storage = new TemporaryLocalFileStorage(); foreach (ConfigForm::transformEmptyValuesToNull($form->getValues()) as $sectionAndPropertyName => $value) { if ($value !== null) { list($section, $property) = explode('_', $sectionAndPropertyName, 2); + if (in_array($property, ['ca', 'cert', 'key'])) { + $storage->create("$property.pem", $value); + $value = $storage->resolvePath("$property.pem"); + } + $sections[$section][$property] = $value; } } diff --git a/library/Icingadb/Common/IcingaRedis.php b/library/Icingadb/Common/IcingaRedis.php index f5545b9c..df700b7a 100644 --- a/library/Icingadb/Common/IcingaRedis.php +++ b/library/Icingadb/Common/IcingaRedis.php @@ -6,9 +6,6 @@ namespace Icinga\Module\Icingadb\Common; use Exception; use Icinga\Application\Config; -use Icinga\Exception\NotFoundError; -use Icinga\File\Storage\CommonFileStorage; -use Icinga\File\Storage\TemporaryLocalFileStorage; use Predis\Client as Redis; trait IcingaRedis @@ -95,11 +92,8 @@ trait IcingaRedis private function getPrimaryRedis(Config $config = null) { - $pkiIsTemporary = true; - if ($config === null) { $config = Config::module('icingadb'); - $pkiIsTemporary = false; } $section = $config->getSection('redis1'); @@ -108,7 +102,7 @@ trait IcingaRedis 'host' => $section->get('host', 'localhost'), 'port' => $section->get('port', 6380), 'timeout' => 0.5 - ] + $this->getTlsParams($config, $pkiIsTemporary)); + ] + $this->getTlsParams($config)); $redis->ping(); @@ -117,11 +111,8 @@ trait IcingaRedis private function getSecondaryRedis(Config $config = null) { - $pkiIsTemporary = true; - if ($config === null) { $config = Config::module('icingadb'); - $pkiIsTemporary = false; } $section = $config->getSection('redis2'); @@ -135,14 +126,14 @@ trait IcingaRedis 'host' => $host, 'port' => $section->get('port', 6380), 'timeout' => 0.5 - ] + $this->getTlsParams($config, $pkiIsTemporary)); + ] + $this->getTlsParams($config)); $redis->ping(); return $redis; } - private function getTlsParams(Config $config, $pkiIsTemporary) + private function getTlsParams(Config $config) { $config = $config->getSection('redis'); @@ -159,7 +150,7 @@ trait IcingaRedis $ca = $config->get('ca'); if ($ca !== null) { - $ssl['cafile'] = $this->ensurePemOnDisk($ca, 'ca', $pkiIsTemporary); + $ssl['cafile'] = $ca; } } @@ -167,39 +158,10 @@ trait IcingaRedis $key = $config->get('key'); if ($cert !== null && $key !== null) { - $ssl['local_cert'] = $this->ensurePemOnDisk($cert, 'cert', $pkiIsTemporary); - $ssl['local_pk'] = $this->ensurePemOnDisk($key, 'key', $pkiIsTemporary); + $ssl['local_cert'] = $cert; + $ssl['local_pk'] = $key; } return ['scheme' => 'tls', 'ssl' => $ssl]; } - - private function ensurePemOnDisk($pem, $subject, $temporary) - { - if ($temporary) { - $storage = new TemporaryLocalFileStorage(); - $keepAlive = (object) ['storage' => $storage]; - - $storage->create("$subject.pem", $pem); - - // Keep a reference to $storage until shutdown - register_shutdown_function(function () use ($keepAlive) { - $keepAlive->storage = null; - }); - } else { - $storage = CommonFileStorage::module('redis'); - - try { - $create = $storage->read("$subject.pem") !== $pem; - } catch (NotFoundError $_) { - $create = true; - } - - if ($create) { - $storage->create("$subject.pem", $pem); - } - } - - return $storage->resolvePath("$subject.pem"); - } }