mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
mod_proxy_beacon: accept a random hex: key for ProxyBeaconSecret
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939364 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -107,7 +107,7 @@ to the reverse proxy over unicast UDP datagrams</description>
|
||||
<highlight language="config">
|
||||
# Receive backend announcements on the cluster network interface (UDP).
|
||||
ProxyBeaconListen 0.0.0.0:5555
|
||||
ProxyBeaconSecret "a-long-random-shared-cluster-secret"
|
||||
ProxyBeaconSecret "hex:00112233445566778899aabbccddeeff"
|
||||
ProxyBeaconBalancer cluster
|
||||
|
||||
# A backend is dropped from rotation if it does not announce for 30 seconds.
|
||||
@@ -126,7 +126,7 @@ ProxyPassReverse "/" "balancer://cluster/"
|
||||
# Announce this backend's routable origin to the proxy every 10 seconds (UDP).
|
||||
ProxyBeaconAddress proxy.example.com:5555
|
||||
ProxyBeaconAdvertise http://10.0.0.5:8080
|
||||
ProxyBeaconSecret "a-long-random-shared-cluster-secret"
|
||||
ProxyBeaconSecret "hex:00112233445566778899aabbccddeeff"
|
||||
ProxyBeaconInterval 10
|
||||
</highlight>
|
||||
|
||||
@@ -446,7 +446,7 @@ is taken out of rotation</description>
|
||||
<directivesynopsis>
|
||||
<name>ProxyBeaconSecret</name>
|
||||
<description>Pre-shared secret used to authenticate announcements</description>
|
||||
<syntax>ProxyBeaconSecret <em>secret</em></syntax>
|
||||
<syntax>ProxyBeaconSecret <em>secret</em>|hex:<em>key</em></syntax>
|
||||
<contextlist><context>server config</context><context>virtual host</context>
|
||||
</contextlist>
|
||||
|
||||
@@ -474,11 +474,16 @@ is taken out of rotation</description>
|
||||
silently rejected (and logged), which appears as the backend never joining
|
||||
the balancer.</p>
|
||||
|
||||
<p>The secret must be at least 16 characters; shorter values are rejected
|
||||
when the configuration is read. The MAC key is derived from it with a fast
|
||||
hash and the authentication tag is 64 bits, so anyone who captures a single
|
||||
announcement can test passphrase guesses offline at full speed: use a long
|
||||
random value, not a memorable password.</p>
|
||||
<p>Use a random key. Generate one with <code>openssl rand -hex 16</code>
|
||||
and configure it as <code>hex:</code> followed by the 32 hex digits; that
|
||||
value is used directly as the 128-bit MAC key, so there is nothing to guess.
|
||||
Any other value is treated as a passphrase: it must be at least 16
|
||||
characters, and the MAC key is derived from it with a fast hash. Because the
|
||||
authentication tag is 64 bits, anyone who captures a single announcement can
|
||||
test passphrase guesses offline at full speed, so a passphrase protects only
|
||||
as well as it is random and long. A value that begins with <code>hex:</code>
|
||||
is always read as a key and is rejected if it is not exactly 32 hex
|
||||
digits.</p>
|
||||
|
||||
<note type="warning"><title>The secret is a membership credential</title>
|
||||
<p>A valid MAC proves only that the sender holds the secret. It does not
|
||||
|
||||
@@ -208,9 +208,10 @@ Authentication (ProxyBeaconSecret, REQUIRED):
|
||||
genuine sub-second announcements always advance. seq= is NOT used for replay
|
||||
(it resets when a backend restarts); the wall-clock ts= does not.
|
||||
|
||||
The secret must be at least 16 characters. The key is MD5(passphrase) and the
|
||||
tag is 64 bits: a captured announcement permits offline guessing at full speed,
|
||||
so the secret should be long and random. A valid MAC shows possession of the
|
||||
"hex:<32 hex digits>" is the 128-bit SipHash key itself (openssl rand -hex 16):
|
||||
no passphrase, nothing to guess. Any other value is a passphrase of at least 16
|
||||
characters; the key is then MD5(passphrase) and the tag is 64 bits, so a
|
||||
captured announcement permits offline guessing at full speed. A valid MAC shows possession of the
|
||||
secret, nothing more: every holder can register any reachable origin, speak for
|
||||
other members and consume slots/records. The secret is a membership-
|
||||
administrator credential, not a boundary between partially trusted workloads.
|
||||
|
||||
@@ -80,7 +80,7 @@ httpd -l | grep mod_proxy_beacon # static build
|
||||
```apache
|
||||
# Receive backend announcements on the cluster-facing interface (UDP/5555).
|
||||
ProxyBeaconListen 0.0.0.0:5555
|
||||
ProxyBeaconSecret "a-long-random-shared-cluster-secret"
|
||||
ProxyBeaconSecret "hex:00112233445566778899aabbccddeeff"
|
||||
ProxyBeaconBalancer cluster
|
||||
|
||||
# Drop a backend from rotation if it goes silent for 30s; re-add on next beacon.
|
||||
@@ -101,7 +101,7 @@ ProxyPassReverse "/" "balancer://cluster/"
|
||||
# Announce this backend's routable origin to the proxy every 10s (UDP).
|
||||
ProxyBeaconAddress proxy.example.com:5555
|
||||
ProxyBeaconAdvertise http://10.0.0.5:8080
|
||||
ProxyBeaconSecret "a-long-random-shared-cluster-secret"
|
||||
ProxyBeaconSecret "hex:00112233445566778899aabbccddeeff"
|
||||
ProxyBeaconInterval 10
|
||||
```
|
||||
|
||||
@@ -125,7 +125,7 @@ as an enabled member of `balancer://cluster` on the proxy. Stop one, and after
|
||||
| `ProxyBeaconListen [addr][:port]` | — | **Marks this server as the receiver.** Binds a UDP socket. `addr`/`port` are optional and inherited from the server's own `Listen`/`ServerName` when omitted (see note below). |
|
||||
| `ProxyBeaconBalancer name` | — | Balancer that announced backends are added to. Bare name (`cluster`); a leading `balancer://` is stripped. Must already exist with spare `growth`. |
|
||||
| `ProxyBeaconTimeout interval` | `0` (no eviction) | Seconds of silence before a member is disabled. `0` = add-only, never auto-remove. Set to a small multiple of the backends' interval to get self-healing. |
|
||||
| `ProxyBeaconSecret secret` | — (**required**) | Shared cluster secret; **same value on proxy and all backends**, at least 16 characters (long and random). The server fails to start if a participating server omits it or it is too short. |
|
||||
| `ProxyBeaconSecret secret` | — (**required**) | Shared cluster secret; **same value on proxy and all backends**, either `hex:` + 32 hex digits (a random key: `openssl rand -hex 16`) or a passphrase of at least 16 characters (weaker: guessable offline from one captured packet). The server fails to start if a participating server omits it or it is invalid. |
|
||||
| `ProxyBeaconMaxSkew interval` | `30` | Anti-replay freshness window: reject announcements whose signed timestamp is more than this far from now (either direction). Sub-second values (`500ms`) are honoured. |
|
||||
|
||||
**Inheriting the listen address:** because UDP and TCP are separate port spaces,
|
||||
|
||||
@@ -168,6 +168,8 @@ typedef struct {
|
||||
#define BEACON_MAC_HEXLEN (APR_SIPHASH_DSIZE * 2)
|
||||
/* Shortest ProxyBeaconSecret accepted. */
|
||||
#define BEACON_MIN_SECRET_LEN 16
|
||||
/* A secret of this form is used directly as the MAC key (no passphrase). */
|
||||
#define BEACON_HEXKEY_PREFIX "hex:"
|
||||
#define BEACON_MAXSKEW_DEFAULT apr_time_from_sec(30)
|
||||
|
||||
/* Max announcement datagram we accept. Our messages are a few hundred bytes;
|
||||
@@ -409,6 +411,11 @@ static const char *beacon_set_timeout(cmd_parms *cmd, void *dummy,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int beacon_hexval(char c)
|
||||
{
|
||||
return apr_isdigit(c) ? c - '0' : apr_tolower(c) - 'a' + 10;
|
||||
}
|
||||
|
||||
static const char *beacon_set_secret(cmd_parms *cmd, void *dummy, const char *arg)
|
||||
{
|
||||
beacon_ctx_t *ctx = ap_get_module_config(cmd->server->module_config,
|
||||
@@ -420,6 +427,29 @@ static const char *beacon_set_secret(cmd_parms *cmd, void *dummy, const char *ar
|
||||
if (!*arg) {
|
||||
return "ProxyBeaconSecret: empty secret";
|
||||
}
|
||||
/* hex:<32 hex digits> is the key itself: a random 128-bit key has no
|
||||
* passphrase to guess, so it needs no key derivation. */
|
||||
if (!strncmp(arg, BEACON_HEXKEY_PREFIX, sizeof(BEACON_HEXKEY_PREFIX) - 1)) {
|
||||
const char *h = arg + sizeof(BEACON_HEXKEY_PREFIX) - 1;
|
||||
int i;
|
||||
|
||||
if (strlen(h) != 2 * sizeof(ctx->mac_key)) {
|
||||
return apr_psprintf(cmd->pool,
|
||||
"ProxyBeaconSecret: hex: needs exactly %d hex "
|
||||
"digits (e.g. from 'openssl rand -hex %d')",
|
||||
(int)(2 * sizeof(ctx->mac_key)),
|
||||
(int)sizeof(ctx->mac_key));
|
||||
}
|
||||
for (i = 0; i < (int)sizeof(ctx->mac_key); i++) {
|
||||
if (!apr_isxdigit(h[2 * i]) || !apr_isxdigit(h[2 * i + 1])) {
|
||||
return "ProxyBeaconSecret: hex: value has a non-hex digit";
|
||||
}
|
||||
ctx->mac_key[i] = (unsigned char)
|
||||
((beacon_hexval(h[2 * i]) << 4) | beacon_hexval(h[2 * i + 1]));
|
||||
}
|
||||
ctx->has_secret = 1;
|
||||
return NULL;
|
||||
}
|
||||
/* The MAC key is derived from the passphrase with a fast hash, so anyone who
|
||||
* captures one announcement can test guesses offline at full speed; only a
|
||||
* long random secret resists that. */
|
||||
|
||||
Reference in New Issue
Block a user