diff --git a/modules/akvorado.py b/modules/akvorado.py new file mode 100644 index 00000000..c0b89096 --- /dev/null +++ b/modules/akvorado.py @@ -0,0 +1,138 @@ +# vim: ts=4: sts=4: sw=4: expandtab +# Copyright 2024 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +import lib +import os +import sqlite3 +import yaml + +DB_FILE = '/etc/ipplan.db' + +def get_sflow_clients(): + if os.path.isfile(DB_FILE): + try: + conn = sqlite3.connect(DB_FILE) + db = conn.cursor() + except sqlite3.Error as e: + print("An error occurred: {}".format(e.args[0])) + exit(2) + else: + print("No database file found: {}".format(DB_FILE)) + exit(3) + db.execute( + "SELECT h.name AS hostname, h.ipv4_addr_txt AS ipv4_addr ,h.ipv6_addr_txt AS ipv6_addr, o2.value AS layer " + "FROM host h " + "INNER JOIN option o1 ON h.node_id = o1.node_id " + "INNER JOIN option o2 ON h.node_id = o2.node_id " + "WHERE o1.name='pkg' AND o1.value='sflowclient' " + "AND o2.name='layer';" + ) + res = db.fetchall() + if not res: + return None + + column_names = [description[0] for description in db.description] + conn.close() + rows_dict = [dict(zip(column_names, row)) for row in res] + + return rows_dict + +def get_snmpv2_providers(): + providers = [] + clients = get_sflow_clients() + if not clients: + return providers + current_event = lib.get_current_event() + for client in clients: + key = current_event+'-mgmt/snmpv2:'+client['layer'] + secrets = lib.read_secret(key) + if not secrets: + return providers + if "community" in secrets: + provider = { + "ipv4": client["ipv4_addr"], + "community": secrets["community"], + } + providers.append(provider) + return providers + +def get_snmpv3_providers(): + providers = [] + clients = get_sflow_clients() + if not clients: + return providers + current_event = lib.get_current_event() + for client in clients: + key = current_event+'-mgmt/snmpv3:'+client['layer'] + secrets = lib.read_secret(key) + if not secrets: + return providers + if "user" in secrets: + provider = { + "ipv4": client["ipv4_addr"], + "authentication-passphrase": secrets["auth"], + "authentication-protocol": secrets["authtype"].replace(" ","").upper(), + "privacy-passphrase": secrets["priv"], + "privacy-protocol": secrets["privtype"].replace(" ","").replace("128","").upper(), + "user": secrets["user"], + } + providers.append(provider) + return providers + +def get_prefixes(ipversion): + if os.path.isfile(DB_FILE): + try: + conn = sqlite3.connect(DB_FILE) + db = conn.cursor() + except sqlite3.Error as e: + print("An error occurred: {}".format(e.args[0])) + exit(2) + else: + print("No database file found: {}".format(DB_FILE)) + exit(3) + + if ipversion == "4": + db.execute( + 'SELECT SUBSTR(name,1, INSTR(name, "@")-1) AS location, name, short_name, ipv4_txt' + ' FROM network' + ' WHERE node_id NOT IN (SELECT option.node_id FROM option WHERE name = "no-akv")' + ' AND name LIKE "%@%" AND ipv4_txt IS NOT NULL' + ) + + elif ipversion == "6": + db.execute( + 'SELECT SUBSTR(name,1, INSTR(name, "@")-1) AS location, name, short_name, ipv6_txt' + ' FROM network' + ' WHERE node_id NOT IN (SELECT option.node_id FROM option WHERE name = "no-akv")' + ' AND name LIKE "%@%" AND ipv6_txt IS NOT NULL' + ' AND NOT (name = "BOGAL@DREAMHACK" AND ipv6_txt = "2a05:2240:5000::/48")' + ) + else: + raise NetworkTypeNotFoundError('network type must be 4 or 6') + + res = db.fetchall() + if not res: + raise NetworkNotFoundError('network not found') + + column_names = [description[0] for description in db.description] + conn.close() + rows_dict = [dict(zip(column_names, row)) for row in res] + + return rows_dict + + +def requires(host, *args): + return ['apache(ldap)'] + + +def generate(host, *args): + + info = {} + info['snmpv3_providers'] = get_snmpv3_providers() + info['snmpv2_providers'] = get_snmpv2_providers() + info['current_event'] = lib.get_current_event() + info['ipv6_prefixes'] = get_prefixes('6') + info['ipv4_prefixes'] = get_prefixes('4') + return {'akvorado': info} diff --git a/modules/akvorado/files/akvorado-console.service b/modules/akvorado/files/akvorado-console.service new file mode 100644 index 00000000..23e2f587 --- /dev/null +++ b/modules/akvorado/files/akvorado-console.service @@ -0,0 +1,15 @@ +[Unit] +Description=Akvorado Console +After=akvorado-orch.service +Requires=akvorado-orch.service + +[Service] +Type=simple +Restart=on-failure +RestartSec=15 +User=akvorado +ExecStart=/usr/local/bin/akvorado console http://127.0.0.1:8080 + +[Install] +WantedBy=multi-user.target + diff --git a/modules/akvorado/files/akvorado-inlet.service b/modules/akvorado/files/akvorado-inlet.service new file mode 100644 index 00000000..1930cb0c --- /dev/null +++ b/modules/akvorado/files/akvorado-inlet.service @@ -0,0 +1,15 @@ +[Unit] +Description=Akvorado Inlet +After=akvorado-orch.service +Requires=akvorado-orch.service + +[Service] +Type=simple +Restart=on-failure +RestartSec=15 +User=akvorado +ExecStart=/usr/local/bin/akvorado inlet http://127.0.0.1:8080 + +[Install] +WantedBy=multi-user.target + diff --git a/modules/akvorado/files/akvorado-orch.service b/modules/akvorado/files/akvorado-orch.service new file mode 100644 index 00000000..23e0f153 --- /dev/null +++ b/modules/akvorado/files/akvorado-orch.service @@ -0,0 +1,13 @@ +[Unit] +Description=Akvorado Orchestrator +After=network.target +[Service] +Type=simple +Restart=on-failure +RestartSec=15 +User=akvorado +ExecStart=/usr/local/bin/akvorado orchestrator /etc/akvorado/akvorado.yaml + +[Install] +WantedBy=multi-user.target + diff --git a/modules/akvorado/files/akvorado-outlet.service b/modules/akvorado/files/akvorado-outlet.service new file mode 100644 index 00000000..639674c4 --- /dev/null +++ b/modules/akvorado/files/akvorado-outlet.service @@ -0,0 +1,15 @@ +[Unit] +Description=Akvorado Outlet +After=akvorado-orch.service +Requires=akvorado-orch.service + +[Service] +Type=simple +Restart=on-failure +RestartSec=15 +User=akvorado +ExecStart=/usr/local/bin/akvorado outlet http://127.0.0.1:8080 + +[Install] +WantedBy=multi-user.target + diff --git a/modules/akvorado/files/kafka.service b/modules/akvorado/files/kafka.service new file mode 100644 index 00000000..feea2bfe --- /dev/null +++ b/modules/akvorado/files/kafka.service @@ -0,0 +1,13 @@ +[Unit] +Description=Apache Kafka Service +After=network.target + +[Service] +Type=simple +User=kafka +ExecStart=/bin/sh -c ' /var/lib/kafka/bin/kafka-server-start.sh /var/lib/kafka/config/server.properties > /var/log/kafka/kafka.log 2>&1' +ExecStop=/var/lib/kafka/bin/kafka-server-stop.sh +Restart=on-abnormal + +[Install] +WantedBy=multi-user.target diff --git a/modules/akvorado/manifests/init.pp b/modules/akvorado/manifests/init.pp new file mode 100644 index 00000000..eab29bee --- /dev/null +++ b/modules/akvorado/manifests/init.pp @@ -0,0 +1,267 @@ +# Copyright 2018 dhtech +# +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file +# +# == Class: akvorado +# +# Alert manager for prometheus to handle sending alerts +# +# === Parameters +# + +class akvorado ($current_event, $ipv4_prefixes, $ipv6_prefixes, $snmpv3_providers, $snmpv2_providers) { + + + ##Kafka installation + ensure_packages([ + 'openjdk-17-jre', + ]) + group { 'kafka': + ensure => 'present', + } + -> user { 'kafka': + ensure => 'present', + system => true, + home => '/var/lib/kafka', + managehome => true, + } + -> file { '/var/lib/kafka/kafka.tgz': + ensure => file, + links => follow, + source => 'puppet:///data/kafka-latest.tgz', + notify => Exec['untar-kafka'] + } + -> file { '/var/log/kafka': + ensure => 'directory', + owner => 'kafka', + group => 'kafka', + mode => '0700', + } + exec { 'untar-kafka': + command => '/bin/tar -xvf /var/lib/kafka/kafka.tgz -C /var/lib/kafka --strip 1', + refreshonly => true, + user => 'kafka', + } + file { '/etc/systemd/system/kafka.service': + ensure => present, + source => 'puppet:///modules/akvorado/kafka.service', + mode => '0644', + owner => 'root', + group => 'root', + notify => [ Exec['systemctl-daemon-reload'], Service['kafka'] ], + } + -> file_line { 'kafka-enabledeletetopics': + ensure => 'present', + path => '/var/lib/kafka/config/server.properties', + line => 'delete.topic.enable = true', + notify => Service['kafka'], + } + -> file_line { 'kafka-quorumvoters': + ensure => 'present', + path => '/var/lib/kafka/config/server.properties', + line => 'controller.quorum.voters=1@localhost:9093', + notify => Service['kafka'], + } + -> file_line { 'kafka-listenlocalhost': + ensure => 'present', + path => '/var/lib/kafka/config/server.properties', + line => 'listeners=PLAINTEXT://localhost:9092,CONTROLLER://localhost:9093', + match => 'listeners=PLAINTEXT://:9092,CONTROLLER://:9093', + notify => Service['kafka'], + } + -> file_line { 'kafka-logdir': + ensure => 'present', + path => '/var/lib/kafka/config/server.properties', + line => 'log.dirs=/var/log/kafka', + match => 'log.dirs=/tmp/kafka-logs', + notify => Service['kafka'], + } + -> exec { 'format-kafka-storage': + # lint:ignore:140chars + command => '/var/lib/kafka/bin/kafka-storage.sh format -t $(/var/lib/kafka/bin/kafka-storage.sh random-uuid) -c /var/lib/kafka/config/server.properties --standalone', + # lint:endignore + refreshonly => true, + user => 'kafka', + } + service { 'kafka': + ensure => running, + enable => true, + } + + ##Clickhouse installation + ensure_packages([ + 'apt-transport-https', + 'ca-certificates', + 'curl', + 'gnupg', + ]) + file { 'clickhouse-source-add': + ensure => file, + path => '/etc/apt/sources.list.d/clickhouse.list', + content => 'deb [signed-by=/usr/share/keyrings/clickhouse-keyring.gpg] https://packages.clickhouse.com/deb stable main', + notify => Exec['clickhouse-source-key'], + } + exec { 'clickhouse-source-key': + command => '/usr/bin/curl -fsSL https://packages.clickhouse.com/rpm/lts/repodata/repomd.xml.key | gpg --dearmor > /usr/share/keyrings/clickhouse-keyring.gpg', + logoutput => 'on_failure', + try_sleep => 1, + refreshonly => true, + notify => Exec['apt-update'], + } + exec { 'apt-update': + command => '/usr/bin/apt-get update', + logoutput => 'on_failure', + try_sleep => 1, + refreshonly => true, + require => Package['apt-transport-https'], + } + + package { 'clickhouse-server': + ensure => installed, + require => [File['clickhouse-source-add'], Exec['clickhouse-source-key'], Exec['apt-update']], + } + -> package { 'clickhouse-client': + ensure => installed, + } + -> service { 'clickhouse-server': + ensure => running, + enable => true, + } + + #Create user/group for Akvorodo + ensure_packages([ + 'redis', + ],{ + ensure => 'present', + notify => Service['redis'], + }) + group { 'akvorado': + ensure => 'present', + } + -> user { 'akvorado': + ensure => 'present', + system => true, + home => '/var/lib/akvorado', + managehome => true, + } + #Create directories for akvorado + -> file { '/etc/akvorado': + ensure => 'directory', + owner => 'root', + group => 'akvorado', + mode => '0750', + } + #Copy akvorado to the server + -> file { '/usr/local/bin/akvorado': + ensure => file, + owner => 'root', + group => 'akvorado', + mode => '0550', + links => follow, + source => 'puppet:///data/akvorado-latest', + notify => [Service['akvorado-orch']] + } + file { '/etc/akvorado/akvorado.yaml': + ensure => file, + content => template('akvorado/akvorado.yaml.erb'), + notify => Service['akvorado-orch'], + } + #Systemctl config + file { '/etc/systemd/system/akvorado-orch.service': + ensure => present, + source => 'puppet:///modules/akvorado/akvorado-orch.service', + mode => '0644', + owner => 'root', + group => 'root', + notify => [Exec['systemctl-daemon-reload'],Service['akvorado-orch']], + } + file { '/etc/systemd/system/akvorado-inlet.service': + ensure => present, + source => 'puppet:///modules/akvorado/akvorado-inlet.service', + mode => '0644', + owner => 'root', + group => 'root', + notify => [Exec['systemctl-daemon-reload'],Service['akvorado-inlet']], + } + file { '/etc/systemd/system/akvorado-outlet.service': + ensure => present, + source => 'puppet:///modules/akvorado/akvorado-outlet.service', + mode => '0644', + owner => 'root', + group => 'root', + notify => [Exec['systemctl-daemon-reload'],Service['akvorado-outlet']], + } + file { '/etc/systemd/system/akvorado-console.service': + ensure => present, + source => 'puppet:///modules/akvorado/akvorado-console.service', + mode => '0644', + owner => 'root', + group => 'root', + notify => [Exec['systemctl-daemon-reload'],Service['akvorado-console']], + } + file { '/usr/share/GeoIP': + ensure => 'directory', + owner => 'root', + group => 'root', + mode => '0755', + } + file { '/usr/share/GeoIP/asn.mmdb': + ensure => present, + source => 'puppet:///data/GeoLite2-ASN.mmdb', + mode => '0644', + owner => 'root', + group => 'root', + } + file { '/usr/share/GeoIP/country.mmdb': + ensure => present, + source => 'puppet:///data/GeoLite2-Country.mmdb', + mode => '0644', + owner => 'root', + group => 'root', + } + file { '/usr/share/GeoIP/city.mmdb': + ensure => present, + source => 'puppet:///data/GeoLite2-City.mmdb', + mode => '0644', + owner => 'root', + group => 'root', + } + apache::proxy { '1_akvorado-orch-api': + url => '/api/v0/orchestrator/', + backend => 'http://localhost:8080/api/v0/orchestrator/', + } + apache::proxy { '2_akvorado-inlet-api': + url => '/api/v0/inlet/', + backend => 'http://localhost:8081/api/v0/inlet/', + } + apache::proxy { '3_akvorado-console': + url => '/', + backend => 'http://localhost:8082/', + allow_encoded_slashes => true, + } + service { 'akvorado-orch': + ensure => running, + enable => true, + } + service { 'akvorado-inlet': + ensure => running, + enable => true, + } + service { 'akvorado-outlet': + ensure => running, + enable => true, + } + service { 'akvorado-console': + ensure => running, + enable => true, + } + service { 'redis': + ensure => running, + enable => true, + } + exec { 'systemctl-daemon-reload': + command => '/bin/systemctl daemon-reload', + refreshonly => true, + } +} diff --git a/modules/akvorado/templates/akvorado.yaml.erb b/modules/akvorado/templates/akvorado.yaml.erb new file mode 100644 index 00000000..06f91994 --- /dev/null +++ b/modules/akvorado/templates/akvorado.yaml.erb @@ -0,0 +1,338 @@ +--- +# AUTOGENERATED BY PUPPET +# All manual changes will be overwritten +reporting: + logging: {} + metrics: {} +http: + listen: :8080 + profiler: true + cache: + type: memory +clickhouse: + servers: + - 127.0.0.1:9000 + cluster: "" + database: default + username: default + password: "" + maxopenconns: 10 + dialtimeout: 5s + tls: + enable: false + verify: true + cafile: "" + certfile: "" + keyfile: "" + skipmigrations: false + kafka: + topic: flows + brokers: + - 127.0.0.1:9092 + tls: + enable: false + verify: true + cafile: "" + certfile: "" + keyfile: "" + saslusername: "" + saslpassword: "" + saslmechanism: none + consumers: 1 + groupname: clickhouse + enginesettings: [] + resolutions: + - interval: 0s + ttl: 360h0m0s + - interval: 1m0s + ttl: 168h0m0s + - interval: 5m0s + ttl: 2160h0m0s + - interval: 1h0m0s + ttl: 8640h0m0s + maxpartitions: 50 + systemlogttl: 720h0m0s + prometheusendpoint: "/metrics" + asns: + 25037: Dreamhack Events + networks: + # 2a01:db8:cafe:1::/64: + # name: ipv6-customers + # role: customers + # site: "" + # region: "" + # city: "" + # state: "" + # country: "" + # tenant: "" + # asn: 0 +<% @ipv4_prefixes.each do |ipv4| -%> + <%=ipv4['ipv4_txt']%>: + name: "<%= ipv4['short_name'] %>" + role: "<%= ipv4['location'] %>" +<% end -%> +<% @ipv6_prefixes.each do |ipv6| -%> + <%=ipv6['ipv6_txt']%>: + name: "<%= ipv6['short_name'] %>" + role: "<%= ipv6['location'] %>" +<% end -%> + networksources: {} + networksourcestimeout: 10s + orchestratorurl: "http://localhost:8080" +kafka: + topic: flows + brokers: + - 127.0.0.1:9092 + tls: + enable: false + verify: true + cafile: "" + certfile: "" + keyfile: "" + saslusername: "" + saslpassword: "" + saslmechanism: none + topicconfiguration: + numpartitions: 8 + replicationfactor: 1 + configentries: + cleanup.policy: delete + compression.type: producer + retention.ms: "86400000" + segment.bytes: "1073741824" + configentriesstrictsync: true +geoip: + asn-database: + - /usr/share/GeoIP/asn.mmdb + geo-database: + - /usr/share/GeoIP/city.mmdb + optional: false +outlet: + - metadata: + cacheduration: 30m0s + cacherefresh: 1h0m0s + cachecheckinterval: 2m0s + cachepersistfile: "" + providers: +<% unless @snmpv2_providers.empty? -%> + - agents: {} + communities: +<% @snmpv2_providers.each do |provider| -%> + <%=provider['ipv4']%>: <%=provider['community']%> +<% end -%> + ports: + ::/0: 161 + securityparameters: {} + type: snmp +<% end -%> +<% unless @snmpv3_providers.empty? -%> + - agents: {} + ports: + ::/0: 161 + securityparameters: +<% @snmpv3_providers.each do |provider| -%> + <%=provider['ipv4']%>: + user-name: <%=provider['user']%> + authentication-protocol: <%=provider['authentication-protocol']%> + authentication-passphrase: <%=provider['authentication-passphrase']%> + privacy-protocol: <%=provider['privacy-protocol']%> + privacy-passphrase: <%=provider['privacy-passphrase']%> +<% end -%> + type: snmp +<% end -%> + - agents: {} + communities: + ::/0: + - public + pollerretries: 1 + pollertimeout: 1s + ports: + ::/0: 161 + securityparameters: {} + type: snmp + workers: 1 + maxbatchrequests: 10 + http: + listen: :8083 + profiler: true + cache: + type: memory + routing: + provider: + collectasns: true + collectaspaths: true + collectcommunities: true + keep: 5m0s + listen: :10179 + rds: [] + ribpeerremovalbatchroutes: 5000 + ribpeerremovalmaxqueue: 10000 + ribpeerremovalmaxtime: 100ms + ribpeerremovalsleepinterval: 500ms + type: bmp + core: + workers: 6 + exporterclassifiers: + - ClassifySiteRegex(Exporter.Name, "^([^-]+)-", "$1") + - ClassifyRegion("europe") + - ClassifyRole("edge") + interfaceclassifiers: + - | + ClassifyConnectivityRegex(Interface.Description, "^(?i)(transit|pni|ppni|ix):? ", "$1") && + ClassifyProviderRegex(Interface.Description, "^\\S+?\\s(\\S+)", "$1") && + ClassifyExternal() + - ClassifyInternal() + classifiercacheduration: 5m0s + defaultsamplingrate: 1 + overridesamplingrate: {} + asnproviders: + - flow + - routing + netproviders: + - flow + - routing +inlet: + - reporting: + logging: {} + metrics: {} + http: + listen: :8081 + profiler: true + cache: + type: memory + flow: + inputs: + - decoder: netflow + listen: :2055 + queuesize: 100000 + receivebuffer: 10485760 + timestampsource: udp + type: udp + usesrcaddrforexporteraddr: false + workers: 6 + - decoder: sflow + listen: :6343 + queuesize: 100000 + receivebuffer: 10485760 + timestampsource: udp + type: udp + usesrcaddrforexporteraddr: false + workers: 6 + kafka: + topic: flows + brokers: + - 127.0.0.1:9092 + tls: + enable: false + verify: true + cafile: "" + certfile: "" + keyfile: "" + saslusername: "" + saslpassword: "" + saslmechanism: none + flushinterval: 10s + flushbytes: 104857599 + maxmessagebytes: 1000000 + compressioncodec: zstd + queuesize: 32 +console: + - reporting: + logging: {} + metrics: {} + http: + listen: :8082 + profiler: true + cache: + db: 0 + password: "" + protocol: tcp + server: localhost:6379 + type: redis + username: "" + defaultvisualizeoptions: + graphtype: stacked + start: 6 hours ago + end: now + filter: "" + dimensions: + - SrcAS + limit: 10 + homepagetopwidgets: + - src-as + - src-port + - protocol + - src-country + - etype + homepagegraphfilter: "" + dimensionslimit: 50 + cachettl: 0h10m0s + clickhouse: + servers: + - 127.0.0.1:9000 + cluster: "" + database: default + username: default + password: "" + maxopenconns: 10 + dialtimeout: 5s + tls: + enable: false + verify: true + cafile: "" + certfile: "" + keyfile: "" + auth: + headers: + login: X-Proxy-REMOTE-USER + name: "" + email: "" + logouturl: "" + defaultuser: + login: "" + name: "" + email: "" + logouturl: "" + database: + driver: sqlite + dsn: /var/lib/akvorado/console.sqlite + savedfilters: + - description: From Netflix + content: InIfBoundary = external AND SrcAS = AS2906 + - description: From GAFAM + content: InIfBoundary = external AND SrcAS IN (AS15169, AS16509, AS32934, AS6185, AS8075) + - description: From Swedish Armed Forces + content: InIfBoundary = external AND SrcAS = AS9201 + - description: Valve Corporation + content: InIfBoundary = external AND SrcAS = AS32590 + - description: Axians + content: InIfBoundary = external AND SrcAS = AS20514 + - description: Edgevana + content: InIfBoundary = external AND SrcAS = AS215724 + - description: Elisa Oyj + content: InIfBoundary = external AND SrcAS = AS6667 + - description: NORDUnet + content: InIfBoundary = external AND SrcAS = AS2603 + - description: 31173 Services + content: InIfBoundary = external AND SrcAS = AS39351 + - description: Riot Games, Inc + content: InIfBoundary = external AND SrcAS = AS6507 + - description: Hi3G Access AB + content: InIfBoundary = external AND SrcAS = AS44034 + - description: Telia + content: InIfBoundary = external AND SrcAS = AS3301 + - description: Arelion + content: InIfBoundary = external AND SrcAS = AS1299 + - description: CDN77 + content: InIfBoundary = external AND SrcAS = AS60068 + - description: Epic games + content: InIfBoundary = external AND SrcAS = AS4356 + + schema: + disabled: [] + enabled: [] + maintableonly: [] + notmaintableonly: [] + materialize: [] + customdictionaries: {} +demoexporter: [] diff --git a/modules/apache/manifests/init.pp b/modules/apache/manifests/init.pp index 97c90a8b..f9058da5 100644 --- a/modules/apache/manifests/init.pp +++ b/modules/apache/manifests/init.pp @@ -47,7 +47,7 @@ notify => Service['apache2'], } - if $::fqdn == 'status.event.dreamhack.se' or $::fqdn == 'grafana.event.dreamhack.se' { + if $::fqdn == 'status.event.dreamhack.se' or $::fqdn == 'grafana.event.dreamhack.se' or $::fqdn == 'sflow1.event.dreamhack.se' { file { 'apache-security.conf': ensure => present, path => '/etc/apache2/conf-available/security.conf', diff --git a/modules/apache/manifests/proxy.pp b/modules/apache/manifests/proxy.pp index bf5fa09f..16f832dc 100644 --- a/modules/apache/manifests/proxy.pp +++ b/modules/apache/manifests/proxy.pp @@ -3,7 +3,7 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file # -define apache::proxy($url, $backend) { +define apache::proxy($url, $backend, $allow_encoded_slashes = false) { exec { "apache_proxy_reload_${name}": command => '/usr/sbin/apachectl graceful', refreshonly => true, diff --git a/modules/apache/templates/proxy.conf.erb b/modules/apache/templates/proxy.conf.erb index c1b9f6de..763f23e7 100644 --- a/modules/apache/templates/proxy.conf.erb +++ b/modules/apache/templates/proxy.conf.erb @@ -4,3 +4,8 @@ ProxyPass <%= @url %> <%= @backend %> RequestHeader set X-Proxy-REMOTE-USER %{REMOTE_USER}s ProxyPreserveHost on + +<% if @allow_encoded_slashes == true -%> +AllowEncodedSlashes On +<% end -%> +