Skip to content

Commit

Permalink
g3tiles: allow to use remote tls ticketer
Browse files Browse the repository at this point in the history
  • Loading branch information
zh-jq-b committed Oct 16, 2024
1 parent f25d463 commit 6297881
Show file tree
Hide file tree
Showing 20 changed files with 399 additions and 45 deletions.
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions g3tiles/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ g3-openssl.workspace = true
g3-statsd-client.workspace = true
g3-histogram.workspace = true
g3-slog-types.workspace = true
g3-tls-ticket = { workspace = true, features = ["yaml"] }
g3tiles-proto = { path = "proto" }

[build-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion g3tiles/doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
project = 'g3tiles'
copyright = '2024, Zhang Jingqiang'
author = 'Zhang Jingqiang'
release = '0.3.5'
release = '0.3.6'

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
13 changes: 13 additions & 0 deletions g3tiles/doc/configuration/servers/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,19 @@ Set misc udp socket options on created udp sockets.

**default**: not set

.. _conf_server_common_tls_ticketer:

tls_ticketer
------------

**optional**, **type**: :ref:`tls ticketer <conf_value_tls_ticketer>`

Set a (remote) rolling TLS ticketer.

**default**: not set

.. versionadded:: 0.3.6

.. _conf_server_common_task_idle_check_duration:

task_idle_check_duration
Expand Down
1 change: 1 addition & 0 deletions g3tiles/doc/configuration/servers/openssl_proxy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The following common keys are supported:
* :ref:`tcp_copy_buffer_size <conf_server_common_tcp_copy_buffer_size>`
* :ref:`tcp_copy_yield_size <conf_server_common_tcp_copy_yield_size>`
* :ref:`tcp_misc_opts <conf_server_common_tcp_misc_opts>`
* :ref:`tls_ticketer <conf_server_common_tls_ticketer>`
* :ref:`task_idle_check_duration <conf_server_common_task_idle_check_duration>`
* :ref:`task_idle_max_count <conf_server_common_task_idle_max_count>`
* :ref:`extra_metrics_tags <conf_server_common_extra_metrics_tags>`
Expand Down
1 change: 1 addition & 0 deletions g3tiles/doc/configuration/servers/plain_quic_port.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ The following common keys are supported:

* :ref:`listen_in_worker <conf_server_common_listen_in_worker>`
* :ref:`ingress_network_filter <conf_server_common_ingress_network_filter>`
* :ref:`tls_ticketer <conf_server_common_tls_ticketer>`

listen
------
Expand Down
1 change: 1 addition & 0 deletions g3tiles/doc/configuration/servers/rustls_proxy.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ The following common keys are supported:
* :ref:`tcp_copy_buffer_size <conf_server_common_tcp_copy_buffer_size>`
* :ref:`tcp_copy_yield_size <conf_server_common_tcp_copy_yield_size>`
* :ref:`tcp_misc_opts <conf_server_common_tcp_misc_opts>`
* :ref:`tls_ticketer <conf_server_common_tls_ticketer>`
* :ref:`task_idle_check_duration <conf_server_common_task_idle_check_duration>`
* :ref:`task_idle_max_count <conf_server_common_task_idle_max_count>`
* :ref:`extra_metrics_tags <conf_server_common_extra_metrics_tags>`
Expand Down
150 changes: 150 additions & 0 deletions g3tiles/doc/configuration/values/tls.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,156 @@ Set TLS version to use.
The valid string values are: tls1.0, tls1.1, tls1.2, tls1.3.
The valid f64 values are: 1.0, 1.1, 1.2, 1.3.

.. _conf_value_tls_ticketer:

tls ticketer
============

**yaml type**: map

A rolling TLS ticketer which support:

- new encrypt key generation
- old decrypt key update / expire check
- sync keys from remote source

The supported fields are:

* check_interval

**optional**, **type**: :ref:`humanize duration <conf_value_humanize_duration>`

Set the check interval for key expiration. It will also try to fetch keys from remote source.

If the encryption key is expired with it's lifetime, and no new key is fetched from remote source,
a new random key will be generated locally.

**default**: 5min

* local_lifetime

**optional**, **type**: u32

Set the lifetime value (in seconds) for local generated key. The expire time will be half of this lifetime value.

**default**: 12 * 3600

* source

**optional**, **type**: :ref:`tls ticket remote source <conf_value_tls_ticket_remote_source>`

Set the remote source to use.

**default**: not set

.. _conf_value_tls_ticket_remote_source:

tls ticket remote source
========================

**yaml type**: map

Set the remote source to fetch TLS ticket keys.

There may be many types of sources available, the **type** config key should be used to set the remote source type.

Key Format
----------

.. _conf_value_tls_ticket_encrypt_key:

encrypt key
^^^^^^^^^^^

**json type**: map

The config keys are:

* name

**required**, **type**: hex str

Set the name, which should be of 16 bytes.

* aes

**required**, **type**: hex str

Set the AES KEY, which should be of 32 bytes.

* hmac

**required**, **type**: hex str

Set the HMAC KEY, which should be of 16 bytes.

* lifetime

**optional**, **type**: u32

Set the lifetime value.

**default**: 24 * 3600

.. _conf_value_tls_ticket_decrypt_key:

decrypt key
^^^^^^^^^^^

**json type**: map

The config keys are:

* name

**required**, **type**: hex str

Set the name, which should be of 16 bytes.

* aes

**required**, **type**: hex str

Set the AES KEY, which should be of 32 bytes.

* hmac

**required**, **type**: hex str

Set the HMAC KEY, which should be of 16 bytes.

* expire

**required**, **type**: :ref:`rfc3339 datetime str <conf_value_rfc3339_datetime_str>`

Set the expire datetime.

Source Types
------------

redis
^^^^^

**yaml type**: map

A redis TLS ticket key source.

The following keys are supported:

* enc_key

**required**, **type**: str

Set the redis key name that will contain the :ref:`encrypt key <conf_value_tls_ticket_encrypt_key>` json string.

* dec_set

**required**, **type**: str

Set the redis set name that will contain the :ref:`encrypt key <conf_value_tls_ticket_decrypt_key>` json strings.

* :ref:`nested redis config map <conf_value_db_redis>`

Check warning on line 178 in g3tiles/doc/configuration/values/tls.rst

View workflow job for this annotation

GitHub Actions / build (g3tiles)

undefined label: conf_value_db_redis (if the link has no caption the label must precede a section header)

.. _conf_value_tls_certificates:

tls certificates
Expand Down
4 changes: 2 additions & 2 deletions g3tiles/src/config/server/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ pub(crate) enum AnyServerConfig {
DummyClose(dummy_close::DummyCloseServerConfig),
PlainTcpPort(plain_tcp_port::PlainTcpPortConfig),
#[cfg(feature = "quic")]
PlainQuicPort(plain_quic_port::PlainQuicPortConfig),
PlainQuicPort(Box<plain_quic_port::PlainQuicPortConfig>),
OpensslProxy(openssl_proxy::OpensslProxyServerConfig),
RustlsProxy(rustls_proxy::RustlsProxyServerConfig),
KeylessProxy(keyless_proxy::KeylessProxyServerConfig),
Expand Down Expand Up @@ -172,7 +172,7 @@ fn load_server(
"plain_quic_port" | "plainquicport" | "plain_quic" | "plainquic" => {
let server = plain_quic_port::PlainQuicPortConfig::parse(map, position)
.context("failed to load this PlainQuicPort server")?;
Ok(AnyServerConfig::PlainQuicPort(server))
Ok(AnyServerConfig::PlainQuicPort(Box::new(server)))
}
"openssl_proxy" | "opensslproxy" => {
let server = openssl_proxy::OpensslProxyServerConfig::parse(map, position)
Expand Down
51 changes: 46 additions & 5 deletions g3tiles/src/config/server/openssl_proxy/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

use anyhow::{anyhow, Context};
use openssl::ex_data::Index;
use openssl::ssl::{
SslAcceptor, SslContext, SslContextBuilder, SslOptions, SslSessionCacheMode, SslVerifyMode,
SslAcceptor, SslAcceptorBuilder, SslContext, SslContextBuilder, SslOptions,
SslSessionCacheMode, SslVerifyMode, TicketKeyStatus,
};
use openssl::stack::Stack;
use openssl::x509::store::X509StoreBuilder;
use openssl::x509::X509;
use std::sync::Arc;
use yaml_rust::Yaml;

use g3_types::collection::NamedValue;
use g3_types::limit::RateLimitQuotaConfig;
use g3_types::metrics::MetricsName;
use g3_types::net::{OpensslCertificatePair, OpensslSessionIdContext, TcpSockSpeedLimitConfig};
use g3_types::net::{
OpensslCertificatePair, OpensslSessionIdContext, OpensslTicketKey, RollingTicketer,
TcpSockSpeedLimitConfig,
};
use g3_types::route::AlpnMatch;
use g3_yaml::{YamlDocPosition, YamlMapCallback};

Expand Down Expand Up @@ -124,7 +129,10 @@ impl OpensslHostConfig {
Ok(())
}

pub(crate) fn build_ssl_context(&self) -> anyhow::Result<Option<SslContext>> {
pub(crate) fn build_ssl_context(
&self,
ticketer: Option<Arc<RollingTicketer<OpensslTicketKey>>>,
) -> anyhow::Result<Option<SslContext>> {
if self.cert_pairs.is_empty() {
return Ok(None);
}
Expand Down Expand Up @@ -152,6 +160,11 @@ impl OpensslHostConfig {
}
if self.no_session_ticket {
ssl_builder.set_options(SslOptions::NO_TICKET);
} else if let Some(ticketer) = ticketer {
let ticket_key_index = SslContext::new_ex_index()
.map_err(|e| anyhow!("failed to create ex index: {e}"))?;
ssl_builder.set_ex_data(ticket_key_index, ticketer);
set_ticket_key_callback(&mut ssl_builder, ticket_key_index)?;
}

self.set_client_auth(&mut ssl_builder, &mut id_ctx)?;
Expand Down Expand Up @@ -189,7 +202,10 @@ impl OpensslHostConfig {
}

#[cfg(feature = "vendored-tongsuo")]
pub(crate) fn build_tlcp_context(&self) -> anyhow::Result<Option<SslContext>> {
pub(crate) fn build_tlcp_context(
&self,
ticketer: Option<Arc<RollingTicketer<OpensslTicketKey>>>,
) -> anyhow::Result<Option<SslContext>> {
if self.tlcp_cert_pairs.is_empty() {
return Ok(None);
}
Expand All @@ -212,6 +228,11 @@ impl OpensslHostConfig {
}
if self.no_session_ticket {
ssl_builder.set_options(SslOptions::NO_TICKET);
} else if let Some(ticketer) = ticketer {
let ticket_key_index = SslContext::new_ex_index()
.map_err(|e| anyhow!("failed to create ex index: {e}"))?;
ssl_builder.set_ex_data(ticket_key_index, ticketer);
set_ticket_key_callback(&mut ssl_builder, ticket_key_index)?;
}

self.set_client_auth(&mut ssl_builder, &mut id_ctx)?;
Expand Down Expand Up @@ -244,6 +265,26 @@ impl OpensslHostConfig {
}
}

fn set_ticket_key_callback(
builder: &mut SslAcceptorBuilder,
ticket_key_index: Index<SslContext, Arc<RollingTicketer<OpensslTicketKey>>>,
) -> anyhow::Result<()> {
builder
.set_ticket_key_callback(move |ssl, name, iv, cipher_ctx, hmac_ctx, is_enc| {
match ssl.ssl_context().ex_data(ticket_key_index) {
Some(ticketer) => {
if is_enc {
ticketer.encrypt_init(name, iv, cipher_ctx, hmac_ctx)
} else {
ticketer.decrypt_init(name, iv, cipher_ctx, hmac_ctx)
}
}
None => Ok(TicketKeyStatus::FAILED),
}
})
.map_err(|e| anyhow!("failed to set ticket key callback: {e}"))
}

impl YamlMapCallback for OpensslHostConfig {
fn type_name(&self) -> &'static str {
"OpensslHostConfig"
Expand Down
10 changes: 10 additions & 0 deletions g3tiles/src/config/server/openssl_proxy/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use ascii::AsciiString;
use yaml_rust::{yaml, Yaml};

use g3_io_ext::LimitedCopyConfig;
use g3_tls_ticket::TlsTicketConfig;
use g3_types::acl::AclNetworkRuleBuilder;
use g3_types::metrics::{MetricsName, StaticMetricsTags};
use g3_types::net::{TcpListenConfig, TcpMiscSockOpts, TcpSockSpeedLimitConfig};
Expand Down Expand Up @@ -53,6 +54,7 @@ pub(crate) struct OpensslProxyServerConfig {
pub(crate) task_idle_max_count: i32,
pub(crate) tcp_copy: LimitedCopyConfig,
pub(crate) tcp_misc_opts: TcpMiscSockOpts,
pub(crate) tls_ticketer: Option<TlsTicketConfig>,
pub(crate) spawn_task_unconstrained: bool,
pub(crate) alert_unrecognized_name: bool,
}
Expand All @@ -75,6 +77,7 @@ impl OpensslProxyServerConfig {
task_idle_max_count: 1,
tcp_copy: Default::default(),
tcp_misc_opts: Default::default(),
tls_ticketer: None,
spawn_task_unconstrained: false,
alert_unrecognized_name: false,
}
Expand Down Expand Up @@ -186,6 +189,13 @@ impl OpensslProxyServerConfig {
.context(format!("invalid tcp misc sock opts value for key {k}"))?;
Ok(())
}
"tls_ticketer" => {
let lookup_dir = g3_daemon::config::get_lookup_dir(self.position.as_ref())?;
let ticketer = TlsTicketConfig::parse_yaml(v, Some(lookup_dir))
.context(format!("invalid tls ticket config value for key {k}"))?;
self.tls_ticketer = Some(ticketer);
Ok(())
}
"spawn_task_unconstrained" | "task_unconstrained" => {
self.spawn_task_unconstrained = g3_yaml::value::as_bool(v)?;
Ok(())
Expand Down
Loading

0 comments on commit 6297881

Please sign in to comment.