BLOG | NGINX

Sampling-Anfragen mit bedingter NGINX-Protokollierung

NGINX-Teil-von-F5-horiz-schwarz-Typ-RGB
Owen Garrett Miniaturbild
Owen Garrett
Veröffentlicht am 24. April 2019

NGINX kann ein sehr detailliertes Protokoll jeder verarbeiteten Transaktion aufzeichnen. Solche Protokolle werden als Zugriffsprotokolle bezeichnet und Sie können die für verschiedene Dienste oder Standorte aufgezeichneten Details mit einem anpassbaren Protokolldateiformat feinabstimmen.

Standardmäßig protokolliert NGINX jede Transaktion, die es verarbeitet. Dies kann aus Compliance- oder Sicherheitsgründen erforderlich sein, bei einer stark frequentierten Website kann die Menge der generierten Daten jedoch überwältigend sein. In diesem Artikel zeigen wir, wie Sie Transaktionen anhand verschiedener Kriterien selektiv protokollieren und wie Sie dieses Wissen nutzen, um schnell und einfach Datenpunkte zu Anfragen zu erfassen.

Sofern nicht anders angegeben, gilt dieser Beitrag sowohl für NGINX Open Source als auch für NGINX Plus. Der Lesbarkeit halber beziehen wir uns durchgehend auf NGINX .

Hintergrund – Kurzübersicht über die Konfiguration des NGINX-Zugriffsprotokolls

NGINX-Zugriffsprotokolle werden mit der Direktive log_format definiert. Sie können mehrere verschiedene benannte Protokollformate definieren, beispielsweise ein vollständiges Protokollformat mit dem Namen main und ein verkürztes Protokollformat mit dem Namen notes, um drei Datenpunkte zu einer Anforderung aufzuzeichnen:

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';

log_format notes '$remote_addr "$request" $status';

Das Protokollformat kann auf NGINX-Variablen und andere zum Zeitpunkt der Protokollierung berechnete Werte verweisen.

Anschließend verwenden Sie die Direktive „access_log“, um NGINX anzuweisen, eine Transaktion nach Abschluss zu protokollieren. Diese Anweisung gibt den Speicherort der Protokolldatei und das zu verwendende Protokollformat an:

Zugriffsprotokoll /var/log/nginx/access.log Haupt;

Standardmäßig protokolliert NGINX alle Transaktionen mit der folgenden Konfiguration:

access_log Protokolle/access.log kombiniert;

Wenn Sie Ihr eigenes Zugriffsprotokoll definieren, überschreibt (ersetzt) es das Standardzugriffsprotokoll.

Bedingte Protokollierung

Manchmal möchten Sie möglicherweise nur bestimmte Anfragen protokollieren. Dies geschieht mithilfe der bedingten Protokollierung wie folgt:

server {
listen 80;

set $logme 0;
if ( $uri ~ ^/secure ) {
set $logme 1;
}

# Auditoren benötigen ein zusätzliches Protokoll für Anfragen an /secure
access_log /var/log/nginx/secure.log notes if=$logme;

# Wenn wir ein globales Zugriffsprotokoll haben, müssen wir es hier erneut deklarieren
access_log /var/log/nginx/access.log main;

location / {
# ...
}
}

Zugriffsprotokolle werden nicht übernommen

Zugriffsprotokolleinstellungen werden nicht gestapelt oder vererbt. Eine access_log- Direktive in einem Kontext überschreibt (ersetzt) die in übergeordneten Kontexten deklarierten Zugriffsprotokolle.

Wenn Sie beispielsweise zusätzliche Informationen zum Datenverkehr zur URI /secure protokollieren möchten, können Sie ein Zugriffsprotokoll in einem Location- /secure- Block {...} definieren. Dieses Zugriffsprotokoll ersetzt das allgemeine Zugriffsprotokoll, das an anderer Stelle in der Konfiguration definiert ist.

Das Beispiel im vorherigen Abschnitt befasst sich mit diesem Problem. Es verwendet zwei Zugriffsprotokolle im selben Kontext mit bedingter Protokollierung, die Anforderungen für /secure in einer dedizierten Protokolldatei protokolliert.

Herausforderungen mit Zugriffsprotokollen

Angenommen, Sie möchten statistische Informationen zum Verkehr auf Ihrer Website ermitteln:

  • Wie ist die typische geografische Aufteilung der Benutzer?
  • Welche SSL/TLS-Chiffren und Protokolle verwenden meine Benutzer?
  • Wie ist die Aufteilung der Webbrowser?

Das allgemeine Zugriffsprotokoll ist oft nicht der geeignete Ort, um diese Informationen zu protokollieren. Möglicherweise möchten Sie das Zugriffsprotokoll nicht mit den für Ihre Studie erforderlichen zusätzlichen Feldern überladen, und auf einer stark ausgelasteten Site wäre der Aufwand für die Protokollierung aller Transaktionen zu hoch.

In diesem Fall können Sie eine begrenzte Anzahl von Feldern in einem speziellen Protokoll protokollieren. Um die Belastung des Systems zu verringern, möchten Sie möglicherweise auch eine Teilmenge der Anfragen abfragen.

Sampling-Techniken

Stichprobenentnahme aus 1 % der Anfragen

Die folgende Konfiguration verwendet die Variable $request_id als eindeutige Kennung für jede Anforderung. Es verwendet einen Split_Clients- Block zum Abtasten von Daten, indem nur 1 % der Anfragen protokolliert werden:

split_clients $request_id $logme {
1% 1;
* 0;
}

server {
listen 80;

access_log /var/log/nginx/secure.log Notizen if=$logme;

# ...
}

Stichprobenziehung von 1 % der Einzelnutzer

Angenommen, wir möchten von jedem Benutzer (oder von 1 % der Benutzer) einen Datenpunkt abtasten, beispielsweise den User-Agent -Header. Wir können nicht einfach eine Stichprobe aus allen Anfragen ziehen, da Benutzer, die viele Anfragen generieren, in unseren Daten dann überrepräsentiert sind.

Wir verwenden einen Kartenblock , um das Vorhandensein eines Sitzungscookies zu erkennen, das uns mitteilt, ob eine Anforderung von einem neuen Benutzer oder von einem Benutzer stammt, den wir bereits gesehen haben. Anschließend prüfen wir nur die Anfragen neuer Benutzer:

map $cookie_SESSION $logme {
"" $perhaps; # Wenn das Cookie fehlt, loggen wir uns ein, wenn $perhaps
Standard 0;
}

split_clients $request_id $perhaps {
1% 1; # $perhaps ist 1 % der Zeit wahr
* 0;
}

server {
listen 80;

access_log /var/log/nginx/secure.log Notizen, wenn=$logme;

# Optional: Wenn die Anwendung kein Session-Cookie generiert, 
# generieren wir unser eigenes
add_header Set-Cookie SESSION=1;

# ...
}

Einzigartige Dinge probieren

Allerdings akzeptieren nicht alle Clients Sitzungscookies. Beispielsweise könnte ein Web-Spider Cookies ignorieren, sodass jede von ihm gesendete Anfrage als von einem neuen Benutzer stammend identifiziert wird und dadurch unsere Ergebnisse verfälscht werden.

Wäre es nicht großartig, wenn wir Anfragen als Stichprobe nehmen könnten, wenn wir etwas Neues zum ersten Mal sehen? Dabei kann es sich um eine neue IP-Adresse, einen neuen Sitzungscookie-Wert, einen neuen User-Agent -Header, einen noch nie dagewesenen Host-Header oder sogar eine Kombination davon handeln. Auf diese Weise erfassen wir die Daten für jedes Objekt nur einmal.

Natürlich müssen wir den Status speichern (eine Liste der Dinge , die wir gesehen haben), und dafür greifen wir auf den Schlüssel-Wert- Speicher von NGINX Plus zurück. Der Schlüssel-Wert-Speicher verwaltet eine Schlüssel-Wert-Datenbank im Arbeitsspeicher, auf die über Variablen von der NGINX Plus-Konfiguration aus zugegriffen werden kann. Die Datenbank unterstützt optional das automatische Ablaufen von Einträgen (den Timeout- Parameter), die dauerhafte Speicherung ( Status ) und die Clustersynchronisierung ( Synchronisierung ). Für jedes Objekt , das sich noch nicht im Store befindet, protokollieren wir die Anforderung und fügen das Objekt dem Store hinzu, damit es nicht erneut protokolliert wird.

In NGINX Plus R18 und höher ist es sehr einfach , Schlüssel-Wert-Paare während der Verarbeitung einer Transaktion festzulegen :

# Definieren Sie eine Keyval-Zone mit den entsprechenden Parameternkeyval_zone zone=clients:80m timeout=3600s;

# Erstellen Sie eine Variable $seen für jede eindeutige $remote_addr
keyval $remote_addr $seen zone=clients;

log_format notes '$remote_addr "$request" $status';

server {
listen 80;

# wenn $seen leer ist, aktualisieren Sie den Keyval (set $seen 1;) und protokollieren Sie diese 
# Anfrage (set $logme 1;)
# Andernfalls wird $logme nicht gesetzt und wir protokollieren die Anfrage nicht
# Beachten Sie, dass $seen nach dem konfigurierten Timeout auf "" zurückgesetzt wird
if ($seen = "") {
set $seen 1;
set $logme 1;
}
access_log /var/log/nginx/secure.log notes if=$logme;

Standort / {
return 200 "Alles OK: -$seen-$logme-\n";
}

Standort /api {
api;
}
}

Ein Beispiel aus der Praxis – Sampling von TLS-Parametern

Dieser Artikel wurde von einem realen Problem inspiriert: Wie kann ich TLS gemäß bewährter Methoden konfigurieren, ohne Benutzer mit Legacy-Geräten auszuschließen?

Die bewährte TLS-Methode ist ein bewegliches Ziel. TLS 1.3 wurde vor einem Jahr ratifiziert, aber viele Clients verwenden nur vorherige TLS-Versionen. Chiffren gelten als „unsicher“ und werden nicht mehr verwendet, obwohl ältere Implementierungen auf sie angewiesen sind. ECC-Zertifikate bieten eine höhere Leistung als RSA, aber nicht alle Clients können ECC akzeptieren. Viele TLS-Angriffe basieren auf einem „Man-in-the-Middle“, der den Cipher-Negotiation-Handshake abfängt und Client und Server zwingt, eine weniger sichere Chiffre auszuwählen. Daher ist es wichtig, NGINX Plus so zu konfigurieren, dass schwache oder veraltete Chiffren nicht unterstützt werden. Dadurch werden jedoch möglicherweise veraltete Clients ausgeschlossen.

Im folgenden Konfigurationsbeispiel testen wir jeden TLS-Client und protokollieren das SSL-Protokoll, die Verschlüsselung und den User-Agent -Header. Unter der Annahme, dass jeder Client die aktuellsten Protokolle und sichersten Chiffren auswählt, die er unterstützt, können wir die abgetasteten Daten auswerten und bestimmen, welcher Anteil der Clients ausgeschlossen wird, wenn wir die Unterstützung für ältere Protokolle und Chiffren entfernen.

Wir identifizieren jeden Client durch seine einzigartige Kombination aus IP-Adresse und User-Agent . Die Identifizierung von Clients über Sitzungscookies oder eine andere Methode funktioniert jedoch genauso gut.

log_format sslparams '$ssl_protocol $ssl_cipher '
'$remote_addr "$http_user_agent"';

# Definieren Sie eine Keyval-Zone mit den entsprechenden Parametern
keyval_zone zone=clients:80m timeout=3600s;

# Erstellen Sie eine Variable $seen für jede eindeutige Kombination aus $remote_addr und 
# 'User-Agent'-Header
keyval $remote_addr:$http_user_agent $seen zone=clients;

server {
listen 443 ssl;

# Standard-NGINX-SSL-Konfiguration
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

if ($seen = "") {
set $seen 1;
set $logme 1;
}
access_log /tmp/sslparams.log sslparams if=$logme;

# ...
}

Dadurch wird eine Protokolldatei mit Einträgen wie den folgenden generiert:

TLSv1.2 AES128-SHA 1.1.1.1 „Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Firefox/45.0“ TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 2.2.2.2 „Mozilla/5.0 ( iPhone; CPU iPhone OS 9_1 wie Mac OS 5.0 (Windows NT 6.1; WOW64; rv:58.0) Gecko/20100101 Firefox/58.0"
TLSv1.2 ECDHE-RSA-AES128-GCM-SHA256 4.4.4.4 "Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0"
TLSv1 AES128-SHA 5.5 .5.5 „Mozilla/5.0 (Android 4.4.2; Tablet; rv:65.0) Gecko/65.0 Firefox/65.0“
TLSv1.2 ECDHE-RSA-CHACHA20-POLY1305 6.6.6.6 „Mozilla/5.0 (Linux; U; Android 5.0. 2; en-US; XT1068 Build/LXB22.46-28) AppleWebKit/537.36 (KHTML, wie Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.10.2.1164 Mobile Safari/537.36"

Wir können die Datei dann mit verschiedenen Methoden verarbeiten, um die Verbreitung der Daten zu bestimmen:

$ cat /tmp/sslparams.log | cut -d ' ' -f 2,2 | sort | uniq -c | sort -rn | perl -ane 'printf "%30s %s\n", $F[1], "="x$F[0];' ECDHE-RSA-AES128-GCM-SHA256 =========================== ECDHE-RSA-AES256-GCM-SHA384 ========= AES128-SHA ==== ECDHE-RSA-CHACHA20-POLY1305 == ECDHE-RSA-AES256-SHA384 ==

Wir ermitteln die weniger sicheren Chiffren mit geringem Volumen, überprüfen die Protokolle, um festzustellen, welche Clients sie verwenden, und treffen dann eine fundierte Entscheidung über das Entfernen der Chiffren aus der NGINX Plus-Konfiguration.

Abschluss

Mit der bedingten Protokollierung von NGINX können Sie eine Teilmenge der von NGINX verwalteten Anforderungen abtasten und ein Standard- oder Spezialprotokoll schreiben. Diese Technik ist nützlich, wenn Sie jemals schnell eine Stichprobe des Datenverkehrs für eine statistische Analyse entnehmen müssen, beispielsweise um die Streuung von SSL-Parametern zu bestimmen.

Sie müssen sich gut überlegen, wie Sie die Daten abtasten, damit vielbeschäftigte Benutzer oder Spider nicht überrepräsentiert sind. Sie können Variablen in der NGINX-Konfiguration zusammen mit den Anweisungen „map“ und „split_clients“ verwenden, um Anfragen auszuwählen und zu filtern.

Für Situationen, in denen die Entscheidung komplexer ist oder ein hohes Maß an Genauigkeit erforderlich ist, können Sie in der NGINX-Konfiguration ausgefeilte Selektoren erstellen. Mit dem Schlüssel-Wert-Speicher von NGINX Plus können Sie Status sammeln und diese bei Bedarf für mehrere NGINX Plus-Instanzen in einem Cluster freigeben.

Probieren Sie Request Sampling mit NGINX Plus selbst aus – starten Sie noch heute Ihre kostenlose 30-Tage-Testversion oder kontaktieren Sie uns , um Ihre Anwendungsfälle zu besprechen.


„Dieser Blogbeitrag kann auf Produkte verweisen, die nicht mehr verfügbar und/oder nicht mehr unterstützt werden. Die aktuellsten Informationen zu verfügbaren F5 NGINX-Produkten und -Lösungen finden Sie in unserer NGINX-Produktfamilie . NGINX ist jetzt Teil von F5. Alle vorherigen NGINX.com-Links werden auf ähnliche NGINX-Inhalte auf F5.com umgeleitet."