RedisConfigForm: Store pem files on disk, not in config

This commit is contained in:
Johannes Meyer 2021-07-15 12:47:09 +02:00
parent 0e1771a3c2
commit bbef9fd363
2 changed files with 74 additions and 44 deletions

View file

@ -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;
}
}

View file

@ -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");
}
}