Security

The charm makes deliberate security decisions across three areas: client to charm, charm to backend, and internal process security.

Client to charm

Transport security

The charm terminates TLS for incoming client requests when the certificates relation (interface: tls-certificates) is established with a TLS certificate provider such as lego (referred to as cache-lego).

When a certificate is available, nginx listens on the allocated port with SSL enabled (listen <port> ssl) using the PEM stored at /etc/nginx/certs/<unit-ip>.pem that contains the certificate and key. The cache-backend relation data returns https:// URLs so that HAProxy can connect over HTTPS. HAProxy integrates with cache-lego via certificate_transfer to obtain the CA certificate needed to trust the content-cache certificate.

If the certificates relation is present but the certificate has not yet been issued, the charm enters WaitingStatus. When the relation is removed, the charm deletes the cert file and nginx reverts to HTTP.

Without the certificates relation, nginx listens on HTTP only. Client-facing TLS termination must then be handled by an upstream ingress component such as haproxy configured with the ingress-configurator charm.

Client authentication

The charm provides no client authentication mechanism. Any client that can reach the charm’s HTTP listener can request cached content. This is an intentional design constraint: the charm is built for publicly accessible static content. There are no plans to add a native authentication feature.

Rate limiting

The charm does not configure nginx rate limiting (limit_req or limit_conn). Operators who need protection against abuse or denial-of-service attacks must add rate limiting at a component placed in front of the charm, such as a load balancer, reverse proxy, or Web Application Firewall (WAF).

Charm to backend

Backend protocol

Backends are specified as full URLs in the form <http|https>://<ip>:<port> via the backends configuration option on content-cache-backends-config. The URL scheme controls whether nginx contacts backends over HTTP or HTTPS. Operators should use HTTPS backend URLs unless backends do not support TLS.

Backend SSL certificate verification

The charm contacts backends over two separate code paths: the Lua healthcheck module (periodic health pings) and the nginx proxy_pass directive (actual proxied requests). These have different SSL verification behavior.

Healthchecks — the healthcheck-ssl-verify configuration option on content-cache-backends-config controls whether the Lua healthcheck module verifies the backend SSL certificate during health pings. The configuration defaults to true. Setting the configuration to false disables certificate verification for healthchecks and should only be used in controlled environments, for example, when backends use self-signed certificates on a trusted private network.

Proxied requests — when the receive-ca-cert relation provides a CA certificate, the charm configures nginx with proxy_ssl_verify enabled and proxy_ssl_trusted_certificate pointing to the received CA bundle. nginx will then verify the backend TLS certificate against that CA. If HTTPS backends are configured but no receive-ca-cert relation is present, the charm enters WaitingStatus and nginx is not reconfigured. Traffic is paused until a CA certificate is supplied.

Internal

Process user

On Ubuntu, the nginx package is configured to run worker processes as www-data via the user directive in the system nginx.conf. www-data is a low-privilege system account with no login shell and no sudo rights. If nginx were compromised, the attacker would have only the limited access of www-data — they cannot read arbitrary files owned by other users or escalate privileges without a separate exploit.

The charm creates and owns all cache files as www-data. The cache directory at /data/nginx/cache/ is owned by www-data (set via os.chown in the charm code). CA certificate files received via receive-ca-cert are stored at /etc/nginx/certs/ and are readable by nginx at runtime.

Status page access

The nginx status page at /nginx_status and the backend health status page at /nginx_backends_status are restricted to 127.0.0.1 using the nginx allow/deny directives. External clients cannot access these endpoints. This behavior is hard-coded in the generated nginx configuration and cannot be changed via charm configuration.

Subprocess security

The charm uses shell=False for all subprocess calls, preventing shell injection attacks from malformed configuration values.

Cached data risks

Public-only content

The charm’s cache key is based on the nginx default $scheme$proxy_host$request_uri. It does not include request headers such as Cookie or Authorization. Two requests for the same URL with different session cookies share a single cache entry: the first response is cached and served to every subsequent requester of that URL, regardless of their identity.

Operators must ensure that only public, non-personalized content is routed through the charm. Routing personalized or session-dependent content through the charm means users will receive each other’s responses.

No cache purge

The charm provides no mechanism to purge a cached response on demand. Cache entries are only removed when their proxy-cache-valid TTL expires or when nginx’s inactive eviction removes them (default: 10 minutes of no access). If sensitive content is accidentally cached, operators must wait for natural expiry.

Best practices

Practice

Recommendation

Incoming TLS

Handle at the ingress layer (e.g. haproxy with ingress-configurator)

Backend protocol

Use HTTPS backend URLs with the receive-ca-cert relation for verified connections

Backend SSL verification

Integrate receive-ca-cert to enable proxy_ssl_verify on with the provided CA bundle

Access control

Place an authenticating reverse proxy or WAF in front if the content is not fully public

Rate limiting

Add rate limiting at a component placed in front of the charm (load balancer, reverse proxy, or WAF) if abuse protection is needed

Cached content

Only route public, non-personalized content through the charm

Machine access

Restrict local user access to the Juju machine