{"id":302,"date":"2019-10-19T11:01:45","date_gmt":"2019-10-19T11:01:45","guid":{"rendered":"https:\/\/www.unsafehex.com\/?p=302"},"modified":"2024-09-27T17:29:17","modified_gmt":"2024-09-27T17:29:17","slug":"collecting-netscaler-web-logs","status":"publish","type":"post","link":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/","title":{"rendered":"Collecting Netscaler web logs"},"content":{"rendered":"\n<p>A little while ago I wrote about collecting AppFlow output from a Citrix Netscaler and turning it into Apache-style access logs. Whilst that might technically work, there are a few drawbacks &#8211; first and foremost that Logstash gobbles CPU cycles like nobody&#8217;s business.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><a href=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/top.png\"><img loading=\"lazy\" decoding=\"async\" width=\"657\" height=\"277\" src=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/top.png\" alt=\"\" class=\"wp-image-303\" srcset=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/top.png 657w, https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/top-300x126.png 300w, https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/top-624x263.png 624w\" sizes=\"(max-width: 657px) 100vw, 657px\" \/><\/a><\/figure>\n\n\n\n<p>Furthermore, since the Netscaler outputs separate AppFlow records for request  and response, if you want a normal reverse proxy log, you need to  put them back together yourself. Although I have already <a href=\"https:\/\/www.unsafehex.com\/index.php\/2017\/11\/22\/collecting-netscaler-appflow\/\">described how to achieve that<\/a>, as you can see above it is also not terribly efficient. So, is there a better way? There certainly is!<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">NetScaler Web Log Client<\/h5>\n\n\n\n<p>In order to deliver responses to requests correctly, the Netscaler must track the state of connections internally. Instead of creating our own Frankenstein&#8217;s Monster of a state machine to reassemble request and response from AppFlow, it would be much simpler if we could get everything from a place that already has the combined state. The good news is that Citrix have <a href=\"https:\/\/docs.citrix.com\/en-us\/netscaler\/12\/system\/web-server-logging\/installing-netscaler-web-logging-client.html\">provided a client application <\/a>to do just that. The bad news is that their documentation is a little on the shonky side, and it isn&#8217;t always clear what they mean. To fill in some of the gaps, I have written a brief guide to getting it running on CentOS 7. I will assume for this that you have installed CentOS 7 Minimal and updated it through yum.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Obtain the client<\/h5>\n\n\n\n<p>Citrix&#8217;s description of where to find the client on their site isn&#8217;t terribly helpful. Here&#8217;s how to get there at the time of writing:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<em>Citrix Portal &gt; Downloads &gt; Citrix Netscaler ADC &gt; Firmware &gt; [your version] &gt; Weblog Clients<\/em><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Prep the Netscaler<\/h5>\n\n\n\n<p>Ensure Web logging is turned on<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<em>System &gt; Settings &gt; Configure Advanced Features &gt; Web Logging<\/em><br><br>Ensure remote authentication is OFF for the <em>nsroot <\/em>user (not expecting many people to encounter this problem but it&#8217;s not easy to troubleshoot &#8211; the client just shows an authentication failure even if you entered the password correctly)<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<em>System &gt; User Administration &gt; Users &gt; nsroot &gt; Enable External Authentication<\/em><br><\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Install and configure the NSWL client<\/h5>\n\n\n\n<p>Extract the .rpm from the zip downloaded from the Citrix portal and transfer it to your CentOS system. Run the following commands as root:<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<em>$&gt; yum install glibc.i686<\/em><br><em>&nbsp;&nbsp;&nbsp;&nbsp;$&gt; rpm -i nswl_linux-[citrix_version].rpm<\/em><br><br>You need to be able to connect from the system you are running the client on to your Netscaler reverse proxy on port 3011.<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<em>$&gt; nc -v [netscaler_ip] 3011<\/em><br><br>Add the target IP and <em>nsroot <\/em>account credentials to the config file <a href=\"https:\/\/docs.citrix.com\/en-us\/netscaler\/12\/system\/web-server-logging\/configuring-nswl-client.html\">as described in the Citrix docs<\/a> (yes, some of their instructions are accurate &#8211; just not everything):<br><br>&nbsp;&nbsp;&nbsp;&nbsp;<em>$&gt; \/usr\/local\/netscaler\/bin\/nswl -addns -f \/usr\/local\/netscaler\/etc\/log.conf<\/em><br><br>Edit the config file to set the format, log output directory, rotation settings etc.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>----extract from \/usr\/local\/netscaler\/etc\/log.conf----\nlogFormat    NCSA %h %v %l %u %p &#91;%t] \"%r\" %s %j %J %{ms}T \"%{referer}i\" \"%{user-agent}i\"\nlogInterval\t\t\tDaily\nlogFileSizeLimit\t\t1024\nlogFilenameFormat\t\t\/var\/log\/netscaler\/nswl-%{%y%m%d}t.log\n------------------------------------------------------<\/code><\/pre>\n\n\n\n<p>Note: Citrix do not appear to provide a complete breakdown of what format strings are accepted, so I used the <a href=\"http:\/\/httpd.apache.org\/docs\/current\/mod\/mod_log_config.html\">Apache documentation<\/a> as a reference. However, not all of the variables are supported by the NSWL client, and some work in a different manner than expected. For example, <em>%D<\/em> does not output microseconds, but the <em>%{UNIT}T<\/em> style does work.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Configure a service to run the NSWL client<\/h5>\n\n\n\n<p>&nbsp;&nbsp;&nbsp;&nbsp;<em>$&gt; vim \/etc\/systemd\/system\/nswl.service<\/em><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>&#91;Unit]\nDescription=nswl\n\n&#91;Service]\nType=simple\nUser=nswl\nGroup=nswl\nExecStart=\/usr\/local\/netscaler\/bin\/nswl -start -f \/usr\/local\/netscaler\/etc\/log.conf\t\n\n&#91;Install]\nWantedBy=multi-user.target<\/code><\/pre>\n\n\n\n<p><em>&nbsp;&nbsp;&nbsp;&nbsp;$&gt; useradd -d &lt;log directory&gt; -s \/sbin\/nologin nswl <br>&nbsp;&nbsp;&nbsp;&nbsp;$&gt; chown -R nswl:nswl &lt;log directory&gt; <br>&nbsp;&nbsp;&nbsp;&nbsp;$&gt; systemctl daemon-reload <br>&nbsp;&nbsp;&nbsp;&nbsp;$&gt; service nswl start<\/em><\/p>\n\n\n\n<h5 class=\"wp-block-heading\"><strong>SIEM configuration and log rotation<\/strong><\/h5>\n\n\n\n<p>The <em>logFormat<\/em> directive shown above is similar to the standard Apache Combined format, but not identical. To parse the output, a slightly tweaked version of the regex is necessary:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>^(?&lt;src_ip>\\S+) (?&lt;site>\\S+) (?:-|(?&lt;ident>\\S+)) (?:-|(?&lt;user>\\S+)) (?&lt;dest_port>\\d+) \\&#91;&#91;^\\]]*] \"(?&lt;request>&#91;^\"]+)\" (?&lt;status>\\d+) (?&lt;request_bytes>\\d+) (?&lt;response_bytes>\\d+) (?&lt;response_time>\\d+) \"(?:-|(?&lt;http_referer>&#91;^\"]*))\" \"(?:-|(?&lt;http_user_agent>.*))\"<\/code><\/pre>\n\n\n\n<p>You should use a prefix pattern to match files to collect &#8211; do NOT use a suffix pattern like &#8216;<em>*.&lt;extension&gt;<\/em>&#8216; to track files. The NSWL client creates a new file with &#8216;<em>.&lt;number&gt;<\/em>&#8216; appended under many circumstances, including when the service is restarted, when the <em>logFileSizeLimit<\/em> is reached, and others. For example, if the service was restarted while writing to &#8216;<em>nswl-20191001.log<\/em>&#8216;, it would begin writing &#8216;<em>nswl-20191001.log.0<\/em>&#8216;.<\/p>\n\n\n\n<p>Make sure to take this into account when configuring log rotation &#8211; e.g. move the files before compressing: &#8216;<em>$&gt;<\/em> <em>gzip nswl-20191001.log<\/em>&#8216; results in &#8216;<em>nswl-20191001.log.gz<\/em>&#8216;, which matches the pattern &#8216;<em>nswl-*<\/em>&#8216;; SIEM agents <a href=\"https:\/\/docs.splunk.com\/Documentation\/Splunk\/latest\/Data\/Monitorfilesanddirectories\">may consider the latter file to be new and index it again<\/a>, resulting in duplicate data.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">Results<\/h5>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2020\/01\/top2.png\"><img loading=\"lazy\" decoding=\"async\" width=\"705\" height=\"306\" src=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2020\/01\/top2.png\" alt=\"\" class=\"wp-image-313\" srcset=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2020\/01\/top2.png 705w, https:\/\/www.unsafehex.com\/wp-content\/uploads\/2020\/01\/top2-300x130.png 300w, https:\/\/www.unsafehex.com\/wp-content\/uploads\/2020\/01\/top2-624x271.png 624w\" sizes=\"(max-width: 705px) 100vw, 705px\" \/><\/a><\/figure>\n\n\n\n<p>Using 1% CPU and a single process as opposed to the previous method of attempting to melt a CPU into the motherboard substrate is a definite improvement. Another plus is that it&#8217;s an officially supported tool, so in theory if something&#8217;s not working you can actually get some help with it. <\/p>\n\n\n\n<p>I&#8217;m pretty proud of my eldritch horror of a python script, it ran for nearly two years in production with no significant problems (unlike Logstash which needed CPR every 6 weeks or so), but it&#8217;s high time my code was retired.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A little while ago I wrote about collecting AppFlow output from a Citrix Netscaler and turning it into Apache-style access logs. Whilst that might technically work, there are a few drawbacks &#8211; first and foremost that Logstash gobbles CPU cycles like nobody&#8217;s business. Furthermore, since the Netscaler outputs separate AppFlow records for request and response, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":310,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[36,12],"tags":[93,54,92,94],"class_list":["post-302","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-logging","category-tutorials-and-guides","tag-citrix","tag-logging","tag-netscaler","tag-nswl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.3 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Collecting Netscaler web logs &#8211; unsafehex<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/\" \/>\n<meta property=\"og:locale\" content=\"en_GB\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Collecting Netscaler web logs &#8211; unsafehex\" \/>\n<meta property=\"og:description\" content=\"A little while ago I wrote about collecting AppFlow output from a Citrix Netscaler and turning it into Apache-style access logs. Whilst that might technically work, there are a few drawbacks &#8211; first and foremost that Logstash gobbles CPU cycles like nobody&#8217;s business. Furthermore, since the Netscaler outputs separate AppFlow records for request and response, [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/\" \/>\n<meta property=\"og:site_name\" content=\"unsafehex\" \/>\n<meta property=\"article:published_time\" content=\"2019-10-19T11:01:45+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-09-27T17:29:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/appflow.png\" \/>\n\t<meta property=\"og:image:width\" content=\"592\" \/>\n\t<meta property=\"og:image:height\" content=\"343\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"http_error_418\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@http_error_418\" \/>\n<meta name=\"twitter:site\" content=\"@http_error_418\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"http_error_418\" \/>\n\t<meta name=\"twitter:label2\" content=\"Estimated reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/\",\"url\":\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/\",\"name\":\"Collecting Netscaler web logs &#8211; unsafehex\",\"isPartOf\":{\"@id\":\"https:\/\/www.unsafehex.com\/#website\"},\"datePublished\":\"2019-10-19T11:01:45+00:00\",\"dateModified\":\"2024-09-27T17:29:17+00:00\",\"author\":{\"@id\":\"https:\/\/www.unsafehex.com\/#\/schema\/person\/69a7fc817171b5a3c4770875a1918652\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/#breadcrumb\"},\"inLanguage\":\"en-GB\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.unsafehex.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Collecting Netscaler web logs\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.unsafehex.com\/#website\",\"url\":\"https:\/\/www.unsafehex.com\/\",\"name\":\"unsafehex\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.unsafehex.com\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-GB\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.unsafehex.com\/#\/schema\/person\/69a7fc817171b5a3c4770875a1918652\",\"name\":\"http_error_418\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-GB\",\"@id\":\"https:\/\/www.unsafehex.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/fe9a4cdd9d9f058529884ce588767baf?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/fe9a4cdd9d9f058529884ce588767baf?s=96&d=mm&r=g\",\"caption\":\"http_error_418\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Collecting Netscaler web logs &#8211; unsafehex","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/","og_locale":"en_GB","og_type":"article","og_title":"Collecting Netscaler web logs &#8211; unsafehex","og_description":"A little while ago I wrote about collecting AppFlow output from a Citrix Netscaler and turning it into Apache-style access logs. Whilst that might technically work, there are a few drawbacks &#8211; first and foremost that Logstash gobbles CPU cycles like nobody&#8217;s business. Furthermore, since the Netscaler outputs separate AppFlow records for request and response, [&hellip;]","og_url":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/","og_site_name":"unsafehex","article_published_time":"2019-10-19T11:01:45+00:00","article_modified_time":"2024-09-27T17:29:17+00:00","og_image":[{"width":592,"height":343,"url":"https:\/\/www.unsafehex.com\/wp-content\/uploads\/2019\/10\/appflow.png","type":"image\/png"}],"author":"http_error_418","twitter_card":"summary_large_image","twitter_creator":"@http_error_418","twitter_site":"@http_error_418","twitter_misc":{"Written by":"http_error_418","Estimated reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/","url":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/","name":"Collecting Netscaler web logs &#8211; unsafehex","isPartOf":{"@id":"https:\/\/www.unsafehex.com\/#website"},"datePublished":"2019-10-19T11:01:45+00:00","dateModified":"2024-09-27T17:29:17+00:00","author":{"@id":"https:\/\/www.unsafehex.com\/#\/schema\/person\/69a7fc817171b5a3c4770875a1918652"},"breadcrumb":{"@id":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/#breadcrumb"},"inLanguage":"en-GB","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.unsafehex.com\/index.php\/2019\/10\/19\/collecting-netscaler-web-logs\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.unsafehex.com\/"},{"@type":"ListItem","position":2,"name":"Collecting Netscaler web logs"}]},{"@type":"WebSite","@id":"https:\/\/www.unsafehex.com\/#website","url":"https:\/\/www.unsafehex.com\/","name":"unsafehex","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.unsafehex.com\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-GB"},{"@type":"Person","@id":"https:\/\/www.unsafehex.com\/#\/schema\/person\/69a7fc817171b5a3c4770875a1918652","name":"http_error_418","image":{"@type":"ImageObject","inLanguage":"en-GB","@id":"https:\/\/www.unsafehex.com\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/fe9a4cdd9d9f058529884ce588767baf?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/fe9a4cdd9d9f058529884ce588767baf?s=96&d=mm&r=g","caption":"http_error_418"}}]}},"_links":{"self":[{"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/posts\/302"}],"collection":[{"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/comments?post=302"}],"version-history":[{"count":6,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/posts\/302\/revisions"}],"predecessor-version":[{"id":343,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/posts\/302\/revisions\/343"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/media\/310"}],"wp:attachment":[{"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/media?parent=302"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/categories?post=302"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.unsafehex.com\/index.php\/wp-json\/wp\/v2\/tags?post=302"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}