feat(gateway): add security headers to all vhosts
X-Frame-Options, X-Content-Type-Options, Referrer-Policy at server scope on _, forge, and matrix vhosts. HSTS added when TLS is active. nginx inheritance rule: locations with their own add_header (CORS API endpoints like /.well-known/matrix/client, /_matrix/) are unaffected — they already carry the headers they need. HTML-serving and proxy locations pick the security headers up automatically.
This commit is contained in:
parent
5fdc3ffdbf
commit
18941848dc
1 changed files with 22 additions and 13 deletions
|
|
@ -444,15 +444,9 @@ in
|
|||
# - selfSignedTls=true: generated cert stored in persistent state dir.
|
||||
# - tls.certDir set: operator-provided cert bind-mounted at /run/hive-tls.
|
||||
tlsCert =
|
||||
if cfg.tls.certDir != null then
|
||||
"/run/hive-tls/${cfg.tls.certName}"
|
||||
else
|
||||
"${tlsDir}/cert.pem";
|
||||
if cfg.tls.certDir != null then "/run/hive-tls/${cfg.tls.certName}" else "${tlsDir}/cert.pem";
|
||||
tlsKey =
|
||||
if cfg.tls.certDir != null then
|
||||
"/run/hive-tls/${cfg.tls.keyName}"
|
||||
else
|
||||
"${tlsDir}/key.pem";
|
||||
if cfg.tls.certDir != null then "/run/hive-tls/${cfg.tls.keyName}" else "${tlsDir}/key.pem";
|
||||
# True when nginx should listen with TLS (any mode).
|
||||
hasTls = cfg.selfSignedTls || cfg.tls.certDir != null || cfg.tls.acme.enable;
|
||||
# Listen addresses every vhost shares. Plain http on `cfg.port`
|
||||
|
|
@ -498,6 +492,19 @@ in
|
|||
publicPort = if hasTls then cfg.httpsPort else cfg.port;
|
||||
publicPortDefault = if hasTls then 443 else 80;
|
||||
publicPortSuffix = if publicPort == publicPortDefault then "" else ":${toString publicPort}";
|
||||
|
||||
# Security headers added at the server scope on every vhost.
|
||||
# nginx's add_header inheritance rule: a location that defines its
|
||||
# own add_header does NOT inherit the server-level ones, so API
|
||||
# locations with CORS headers (e.g. /.well-known/matrix/client,
|
||||
# /_matrix/) are unaffected. HTML-serving and proxy locations that
|
||||
# carry no add_header of their own pick these up automatically.
|
||||
securityHeaders = ''
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
${lib.optionalString hasTls ''add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;''}
|
||||
'';
|
||||
in
|
||||
{
|
||||
system.stateVersion = "26.05";
|
||||
|
|
@ -794,7 +801,7 @@ in
|
|||
# agents without a nixos-rebuild. nginx's longest-prefix-
|
||||
# match rule ensures `/agent/<name>/` from this file beats
|
||||
# the `/agent/` catch-all above.
|
||||
extraConfig = ''
|
||||
extraConfig = securityHeaders + ''
|
||||
include /run/hive-state/agents.conf;
|
||||
'';
|
||||
};
|
||||
|
|
@ -808,6 +815,7 @@ in
|
|||
lib.optionalAttrs (forgeCfg.enable or false && forgeCfg.behindGateway or false) {
|
||||
"${forgeCfg.domain}" = vhostTls // {
|
||||
listen = vhostListen;
|
||||
extraConfig = securityHeaders;
|
||||
locations."/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString forgeCfg.httpPort}/";
|
||||
proxyWebsockets = true;
|
||||
|
|
@ -830,6 +838,7 @@ in
|
|||
lib.optionalAttrs (matrixCfg.enable && matrixCfg.gatewayHost != null) {
|
||||
"${matrixCfg.gatewayHost}" = vhostTls // {
|
||||
listen = vhostListen;
|
||||
extraConfig = securityHeaders;
|
||||
locations = {
|
||||
"/_matrix/" = {
|
||||
proxyPass = "http://127.0.0.1:${toString matrixCfg.httpPort}";
|
||||
|
|
@ -935,10 +944,10 @@ in
|
|||
};
|
||||
|
||||
networking.firewall = lib.mkIf cfg.openFirewall {
|
||||
allowedTCPPorts =
|
||||
[ cfg.port ]
|
||||
++ lib.optional (cfg.selfSignedTls || cfg.tls.certDir != null || cfg.tls.acme.enable)
|
||||
cfg.httpsPort;
|
||||
allowedTCPPorts = [
|
||||
cfg.port
|
||||
]
|
||||
++ lib.optional (cfg.selfSignedTls || cfg.tls.certDir != null || cfg.tls.acme.enable) cfg.httpsPort;
|
||||
};
|
||||
|
||||
# `/etc/hosts` entries for local dev — bare hive domain + any
|
||||
|
|
|
|||
Loading…
Reference in a new issue