aboutsummaryrefslogtreecommitdiffstats
path: root/vespalib/src/vespa/vespalib/net/tls/auto_reloading_tls_crypto_engine.cpp
blob: a082ff9599e242b02b65bf8ee1c228b8bd409d82 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "auto_reloading_tls_crypto_engine.h"
#include "statistics.h"
#include "tls_context.h"
#include "tls_crypto_engine.h"
#include "transport_security_options.h"
#include "transport_security_options_reading.h"
#include "crypto_codec.h"

#include <functional>
#include <stdexcept>

#include <vespa/log/log.h>
LOG_SETUP(".vespalib.net.tls.auto_reloading_tls_crypto_engine");

namespace vespalib::net::tls {

namespace {

std::shared_ptr<TlsCryptoEngine> tls_engine_from_config_file(const vespalib::string& config_file_path,
                                                             AuthorizationMode authz_mode) {
    auto tls_opts = net::tls::read_options_from_json_file(config_file_path);
    return std::make_shared<TlsCryptoEngine>(*tls_opts, authz_mode);
}

std::shared_ptr<TlsCryptoEngine> try_create_engine_from_tls_config(const vespalib::string& config_file_path,
                                                                   AuthorizationMode authz_mode) {
    try {
        return tls_engine_from_config_file(config_file_path, authz_mode);
    } catch (std::exception& e) {
        LOG(warning, "Failed to reload TLS config file (%s): '%s'. Old config remains in effect.",
            config_file_path.c_str(), e.what());
        ConfigStatistics::get().inc_failed_config_reloads();
        return {};
    }
}

} // anonymous namespace

AutoReloadingTlsCryptoEngine::AutoReloadingTlsCryptoEngine(vespalib::string config_file_path,
                                                           AuthorizationMode mode,
                                                           TimeInterval reload_interval)
    : _authorization_mode(mode),
      _thread_mutex(),
      _thread_cond(),
      _engine_mutex(),
      _shutdown(false),
      _config_file_path(std::move(config_file_path)),
      _current_engine(tls_engine_from_config_file(_config_file_path, _authorization_mode)),
      _reload_interval(reload_interval),
      _reload_thread([this](){ run_reload_loop(); })
{
}

AutoReloadingTlsCryptoEngine::~AutoReloadingTlsCryptoEngine() {
    {
        std::lock_guard lock(_thread_mutex);
        _shutdown = true;
        _thread_cond.notify_all();
    }
    _reload_thread.join();
}

std::chrono::steady_clock::time_point AutoReloadingTlsCryptoEngine::make_future_reload_time_point() const noexcept {
    return std::chrono::steady_clock::now() + _reload_interval;
}

void AutoReloadingTlsCryptoEngine::run_reload_loop() {
    std::unique_lock lock(_thread_mutex);
    auto reload_at_time = make_future_reload_time_point();
    while (!_shutdown) {
        if (_thread_cond.wait_until(lock, reload_at_time) == std::cv_status::timeout) {
            LOG(debug, "TLS config reload time reached, reloading file '%s'", _config_file_path.c_str());
            try_replace_current_engine();
            reload_at_time = make_future_reload_time_point();
        } // else: spurious wakeup or shutdown
    }
}

void AutoReloadingTlsCryptoEngine::try_replace_current_engine() {
    auto new_engine = try_create_engine_from_tls_config(_config_file_path, _authorization_mode);
    if (new_engine) {
        ConfigStatistics::get().inc_successful_config_reloads();
        std::lock_guard guard(_engine_mutex);
        _current_engine = std::move(new_engine);
    }
}

AutoReloadingTlsCryptoEngine::EngineSP AutoReloadingTlsCryptoEngine::acquire_current_engine() const {
    std::lock_guard guard(_engine_mutex);
    return _current_engine;
}

CryptoSocket::UP AutoReloadingTlsCryptoEngine::create_client_crypto_socket(SocketHandle socket, const SocketSpec &spec) {
    return acquire_current_engine()->create_client_crypto_socket(std::move(socket), spec);
}

CryptoSocket::UP AutoReloadingTlsCryptoEngine::create_server_crypto_socket(SocketHandle socket) {
    return acquire_current_engine()->create_server_crypto_socket(std::move(socket));
}

bool
AutoReloadingTlsCryptoEngine::use_tls_when_client() const
{
    return acquire_current_engine()->use_tls_when_client();
}

bool
AutoReloadingTlsCryptoEngine::always_use_tls_when_server() const
{
    return acquire_current_engine()->always_use_tls_when_server();
}

std::unique_ptr<CryptoCodec>
AutoReloadingTlsCryptoEngine::create_tls_client_crypto_codec(const SocketHandle &socket, const SocketSpec &spec) {
    return acquire_current_engine()->create_tls_client_crypto_codec(socket, spec);
}

std::unique_ptr<CryptoCodec>
AutoReloadingTlsCryptoEngine::create_tls_server_crypto_codec(const SocketHandle &socket) {
    return acquire_current_engine()->create_tls_server_crypto_codec(socket);
}

}