kind: ConfigMap
apiVersion: v1
metadata:
  name: deployment-configmap
  namespace: default
data:
  # Please add values for labels that are in format "{...}" in this file. Other values should not be changed.

  # Web UI Config
  webui-config.js: "var DeploymentConfig = {
      authEnabled: true,
      authType: 'aad',
      aad : {
          tenant: '{TenantId}',
          appId: '{ApplicationId}',
          instance: '{AADLoginInstance}'
      }
  }"

  # The connection string will be of format
  # "HostName={hubname}.azure-devices.net;SharedAccessKeyName={policy type};SharedAccessKey={Access Key};"
  # Policy Type can have following values: iothubowner, service, device, registryRead, registryReadWrite
  # The key will be shown in CLI window as output when remote-cli command has finished running.
  # Alternatively it can be accessed from http://portal.azure.com under {myResourceGroupName}
  # and resource type "Iot Hub" then "Shared access policies" menu.
  iothub.connstring: "{IoT Hub connection string}"


  # The connection string Document DB will be of format "AccountEndpoint={URI};AccountKey={Key};"
  # The key will be shown in CLI window as output when remote-cli command has finished running.
  # Alternatively it can be accessed from http://portal.azure.com under {myResourceGroupName}
  # and resource type "Azure Cosmos DB account" then "Keys" menu.
  docdb.connstring: "{DocumentDB connection string}"

  azureblob.account: "{Azure Blob account name}"
  azureblob.key: "{Azure Blob account key}"
  azureblob.endpointsuffix: "{Azure Blob account endpoint suffix}"
  azureblob.connstring: "{Azure Blob connection string}"

  azure.resourcemanager.endpoint.url: "{Azure Resource Manager endpoint url}"

  # Authentication
  auth.webservice.url: "http://auth-svc:9001/v1"

  # Storage Adapter
  storageadapter.webservice.url: "http://storage-adapter-svc:9022/v1"

  # IoT Hub Manager
  iothubmanager.webservice.url: "http://iothub-manager-svc:9002/v1"

  # Device Simulation
  devicesimulation.webservice.url: "http://device-simulation-svc:9003/v1"
  devicesimulation.template: "remote-monitoring-simulations-template"

  # Telemetry
  telemetry.webservice.url: "http://telemetry-svc:9004/v1"
  telemetry.storage.type: "tsi"
  telemetry.tsi.fqdn: "{TSI Data Access FQDN}"
  action.eventhub.connstring: "{Action Event hub connection string}"
  action.eventhub.name: "{Action Event hub name}"
  logicapp.endpoint.url: "{LogicApp endpoint url}"
  solution.website.url: "{Solution website url}"

  # PCS Config
  config.webservice.url: "http://config-svc:9005/v1"
  config.seedtemplate: "default"
  config.office365.connection.url: "{Office365 Connection Url}"

  # Auth
  security.auth.aad.endpoint.url: "{AAD endpoint url}"
  security.auth.tenant: "{AAD tenant Id}"
  security.auth.issuer: "{OAuth2 Issuer, e.g. STS URL with Tenant ID}"
  security.auth.audience: "{OAuth2 Audience, e.g. Application ID}"
  security.auth.serviceprincipal.secret: "{AAD application service principal secret}"
  security.auth.required: "true"
  security.cors.whitelist: ""
  security.application.secret: "{Application secret}"

  # Azure maps key
  azure.maps.key: "{AzureMapsKey}"

  # ASA Manager
  asa.eventhub.connstring: "{Event hub connection string}"
  asa.eventhub.name: "{Event hub name}"

  # Diagnostics
  diagnostics.webservice.url: "http://diagnostics-svc:9006/v1"
  diagnostics.cloud.type: "{Cloud environment name}"
  diagnostics.subscription.id: "{Subscription id}"
  diagnostics.iothub.name: "{Iot Hub name}"
  diagnostics.deployment.id: "{Deployment Id of the solution}"
  diagnostics.endpoint.url: "{Diagnostics endpoint URL}"
  diagnostics.solution.type: "{Solution type}"
  diagnostics.solution.name: "{Solution name}"

  # Nginx Template
  nginx.tmpl: |
              {{ $cfg := .cfg }}
              daemon off;

              worker_processes {{ $cfg.workerProcesses }};

              pid /run/nginx.pid;

              worker_rlimit_nofile 131072;

              pcre_jit on;

              events {
                  multi_accept        on;
                  worker_connections  {{ $cfg.maxWorkerConnections }};
                  use                 epoll;
              }

              http {
                  {{/* we use the value of the header X-Forwarded-For to be able to use the geo_ip module */}}
                  {{ if $cfg.useProxyProtocol -}}
                  set_real_ip_from    {{ $cfg.proxyRealIpCidr }};
                  real_ip_header      proxy_protocol;
                  {{ else }}
                  real_ip_header      X-Forwarded-For;
                  set_real_ip_from    0.0.0.0/0;
                  {{ end -}}

                  real_ip_recursive   on;

                  {{/* databases used to determine the country depending on the client IP address */}}
                  {{/* http://nginx.org/en/docs/http/ngx_http_geoip_module.html */}}
                  {{/* this is required to calculate traffic for individual country using GeoIP in the status page */}}
                  geoip_country       /etc/nginx/GeoIP.dat;
                  geoip_city          /etc/nginx/GeoLiteCity.dat;
                  geoip_proxy_recursive on;

                  {{- if $cfg.enableVtsStatus }}
                  vhost_traffic_status_zone shared:vhost_traffic_status:{{ $cfg.vtsStatusZoneSize }};
                  vhost_traffic_status_filter_by_set_key $geoip_country_code country::*;
                  {{ end -}}

                  # lua section to return proper error codes when custom pages are used
                  lua_package_path '.?.lua;./etc/nginx/lua/?.lua;/etc/nginx/lua/vendor/lua-resty-http/lib/?.lua;';
                  init_by_lua_block {
                      require("error_page")
                  }

                  sendfile            on;
                  aio                 threads;
                  tcp_nopush          on;
                  tcp_nodelay         on;

                  log_subrequest      on;

                  reset_timedout_connection on;

                  keepalive_timeout {{ $cfg.keepAlive }}s;

                  types_hash_max_size 2048;
                  server_names_hash_max_size {{ $cfg.serverNameHashMaxSize }};
                  server_names_hash_bucket_size 128;

                  include /etc/nginx/mime.types;
                  default_type text/html;
                  {{ if $cfg.useGzip -}}
                  gzip on;
                  gzip_comp_level 5;
                  gzip_http_version 1.1;
                  gzip_min_length 256;
                  gzip_types {{ $cfg.gzipTypes }};
                  gzip_proxied any;
                  {{- end }}

                  client_max_body_size "{{ $cfg.bodySize }}";

                  log_format upstreaminfo '{{ if $cfg.useProxyProtocol }}$proxy_protocol_addr{{ else }}$remote_addr{{ end }} - '
                      '[$proxy_add_x_forwarded_for] - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" '
                      '$request_length $request_time $upstream_addr $upstream_response_length $upstream_response_time $upstream_status';

                  {{/* map urls that should not appear in access.log */}}
                  {{/* http://nginx.org/en/docs/http/ngx_http_log_module.html#access_log */}}
                  map $request $loggable {
                      {{- range $reqUri := $cfg.skipAccessLogUrls }}
                      {{ $reqUri }} 0;{{ end }}
                      default 1;
                  }

                  access_log /var/log/nginx/access.log upstreaminfo if=$loggable;
                  error_log  /var/log/nginx/error.log {{ $cfg.errorLogLevel }};

                  {{ if not (empty .defResolver) }}# Custom dns resolver.
                  resolver {{ .defResolver }} valid=30s;
                  {{ end }}

                  map $http_upgrade $connection_upgrade {
                      default upgrade;
                      ''      close;
                  }

                  # trust http_x_forwarded_proto headers correctly indicate ssl offloading
                  map $http_x_forwarded_proto $pass_access_scheme {
                    default $http_x_forwarded_proto;
                    ''      $scheme;
                  }

                  # Map a response error watching the header Content-Type
                  map $http_accept $httpAccept {
                      default          html;
                      application/json json;
                      application/xml  xml;
                      text/plain       text;
                  }

                  map $httpAccept $httpReturnType {
                      default          text/html;
                      json             application/json;
                      xml              application/xml;
                      text             text/plain;
                  }

                  server_name_in_redirect off;
                  port_in_redirect off;

                  ssl_protocols {{ $cfg.sslProtocols }};

                  # turn on session caching to drastically improve performance
                  {{ if $cfg.sslSessionCache }}
                  ssl_session_cache builtin:1000 shared:SSL:{{ $cfg.sslSessionCacheSize }};
                  ssl_session_timeout {{ $cfg.sslSessionTimeout }};
                  {{ end }}

                  # allow configuring ssl session tickets
                  ssl_session_tickets {{ if $cfg.sslSessionTickets }}on{{ else }}off{{ end }};

                  # slightly reduce the time-to-first-byte
                  ssl_buffer_size {{ $cfg.sslBufferSize }};

                  {{ if not (empty $cfg.sslCiphers) }}
                  # allow configuring custom ssl ciphers
                  ssl_ciphers '{{ $cfg.sslCiphers }}';
                  ssl_prefer_server_ciphers on;
                  {{ end }}

                  {{ if not (empty .sslDHParam) }}
                  # allow custom DH file http://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_dhparam
                  ssl_dhparam {{ .sslDHParam }};
                  {{ end }}

                  {{- if not $cfg.enableDynamicTlsRecords }}
                  ssl_dyn_rec_size_lo 0;
                  {{ end }}

                  {{- if .customErrors }}
                  # Custom error pages
                  proxy_intercept_errors on;
                  {{ end }}

                  {{- range $errCode := $cfg.customHttpErrors }}
                  error_page {{ $errCode }} = @custom_{{ $errCode }};{{ end }}

                  # In case of errors try the next upstream server before returning an error
                  proxy_next_upstream                     error timeout invalid_header http_502 http_503 http_504{{ if $cfg.retryNonIdempotent }} non_idempotent{{ end }};

                  {{range $name, $upstream := .upstreams}}
                  upstream {{$upstream.Name}} {
                      {{ if $cfg.enableStickySessions -}}
                      sticky hash=sha1 httponly;
                      {{ else -}}
                      least_conn;
                      {{- end }}
                      {{ range $server := $upstream.Backends }}server {{ $server.Address }}:{{ $server.Port }} max_fails={{ $server.MaxFails }} fail_timeout={{ $server.FailTimeout }};
                      {{ end }}
                  }
                  {{ end }}

                  {{/* build all the required rate limit zones. Each annotation requires a dedicated zone */}}
                  {{/* 1MB -> 16 thousand 64-byte states or about 8 thousand 128-byte states */}}
                  {{- range $zone := (buildRateLimitZones .servers) }}
                  {{ $zone }}
                  {{ end }}

                  {{ range $server := .servers }}
                  server {
                      server_name {{ $server.Name }};
                      listen 80{{ if $cfg.useProxyProtocol }} proxy_protocol{{ end }};
                      listen 443  ssl spdy http2;
                      # PEM sha: {{ $server.SSLPemChecksum }}
                      ssl_certificate /etc/nginx-ssl/default-tls-certificate.pem;
                      ssl_certificate_key /etc/nginx-ssl/default-tls-certificate.pem;
                      ssl_protocols TLSv1.2;

                      more_set_headers                            "Strict-Transport-Security: max-age=15724800; includeSubDomains; preload";

                      {{ if $cfg.enableVtsStatus }}vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name;{{ end }}

                      # Disable caching behavior for now
                      # TODO: enable cache for static content later
                      add_header Cache-Control "no-cache";
                      expires 0;

                      # when serving any content, include a X-Content-Type-Options: nosniff
                      # header along with the Content-Type: header, to disable content-type
                      # sniffing on some browsers.
                      add_header X-Content-Type-Options "nosniff" always;

                      # Don't allow the browser to render the page inside a frame/iframe
                      # and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
                      # If you need [i]frames, use SAMEORIGIN or set an uri with ALLOW-FROM uri
                      # See https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
                      add_header X-Frame-Options SAMEORIGIN always;

                      {{- range $location := $server.Locations }}
                      {{ $path := buildLocation $location }}
                      location {{ $path }} {
                          {{ if gt (len $location.Whitelist.CIDR) 0 }}
                          {{- range $ip := $location.Whitelist.CIDR }}
                          allow {{ $ip }};{{ end }}
                          deny all;
                          {{ end -}}

                          {{ if (and $server.SSL $location.Redirect.SSLRedirect) -}}
                          # enforce ssl on server side
                          if ($scheme = http) {
                              return 301 https://$host$request_uri;
                          }
                          {{- end }}
                          {{/* if the location contains a rate limit annotation, create one */}}
                          {{ $limits := buildRateLimit $location }}
                          {{- range $limit := $limits }}
                          {{ $limit }}{{ end }}

                          {{ if $location.Auth.Secured }}
                          {{ if eq $location.Auth.Type "basic" }}
                          auth_basic "{{ $location.Auth.Realm }}";
                          auth_basic_user_file {{ $location.Auth.File }};
                          {{ else }}
                          #TODO: add nginx-http-auth-digest module
                          auth_digest "{{ $location.Auth.Realm }}";
                          auth_digest_user_file {{ $location.Auth.File }};
                          {{ end }}
                          proxy_set_header Authorization "";
                          {{- end }}

                          proxy_set_header Host                   $host;

                          # Pass Real IP
                          proxy_set_header X-Real-IP              $remote_addr;

                          # Allow websocket connections
                          proxy_set_header                        Upgrade           $http_upgrade;
                          proxy_set_header                        Connection        $connection_upgrade;

                          proxy_set_header X-Forwarded-For        $proxy_add_x_forwarded_for;
                          proxy_set_header X-Forwarded-Host       $host;
                          proxy_set_header X-Forwarded-Port       $server_port;
                          proxy_set_header X-Forwarded-Proto      $pass_access_scheme;

                          # mitigate HTTPoxy Vulnerability
                          # https://www.nginx.com/blog/mitigating-the-httpoxy-vulnerability-with-nginx/
                          proxy_set_header Proxy                  "";

                          # TODO ~devis: remove - https://github.com/Azure/azure-iot-pcs-remote-monitoring-dotnet/issues/11
                          # Public preview only: used to distinguish internal/external traffic
                          proxy_set_header     X-Source external;

                          proxy_connect_timeout                   {{ $cfg.proxyConnectTimeout }}s;
                          proxy_send_timeout                      {{ $cfg.proxySendTimeout }}s;
                          proxy_read_timeout                      {{ $cfg.proxyReadTimeout }}s;

                          proxy_redirect                          off;
                          proxy_buffering                         off;

                          proxy_http_version                      1.1;

                          {{/* rewrite only works if the content is not compressed */}}
                          {{ if $location.Redirect.AddBaseURL -}}
                          proxy_set_header                        Accept-Encoding     "";
                          {{- end }}

                          {{- buildProxyPass $location }}
                      }
                      {{ end }}

                      {{ if eq $server.Name "_" }}
                      # this is required to avoid error if nginx is being monitored
                      # with an external software (like sysdig)
                      location /nginx_status {
                          allow 127.0.0.1;
                          deny all;

                          access_log off;
                          stub_status on;
                      }
                      {{ end }}
                      {{ template "CUSTOM_ERRORS" $cfg }}
                  }
                  {{ end }}

                  # default server, used for NGINX healthcheck and access to nginx stats
                  server {
                      # Use the port 18080 (random value just to avoid known ports) as default port for nginx.
                      # Changing this value requires a change in:
                      # https://github.com/kubernetes/contrib/blob/master/ingress/controllers/nginx/nginx/command.go#L104
                      listen 18080 default_server reuseport backlog={{ .backlogSize }};

                      location /healthz {
                          access_log off;
                          return 200;
                      }

                      location /nginx_status {
                          {{ if $cfg.enableVtsStatus -}}
                          vhost_traffic_status_display;
                          vhost_traffic_status_display_format html;
                          {{ else }}
                          access_log off;
                          stub_status on;
                          {{- end }}
                      }

                      location / {
                          proxy_pass             http://upstream-default-backend;
                      }
                      {{- template "CUSTOM_ERRORS" $cfg }}
                  }

                  # default server for services without endpoints
                  server {
                      listen 8181;

                      location / {
                          {{ if .customErrors }}
                          content_by_lua_block {
                              openURL(503)
                          }
                          {{ else }}
                          return 503;
                          {{ end }}
                      }
                  }
              }

              stream {
              # TCP services
              {{ range $i, $tcpServer := .tcpUpstreams }}
                  upstream tcp-{{ $tcpServer.Upstream.Name }} {
                      {{ range $server := $tcpServer.Upstream.Backends }}server {{ $server.Address }}:{{ $server.Port }};
                      {{ end }}
                  }

                  server {
                      listen {{ $tcpServer.Path }};
                      proxy_connect_timeout  {{ $cfg.proxyConnectTimeout }};
                      proxy_timeout          {{ $cfg.proxyReadTimeout }};
                      proxy_pass             tcp-{{ $tcpServer.Upstream.Name }};
                  }
              {{ end }}

              # UDP services
              {{ range $i, $udpServer := .udpUpstreams }}
                  upstream udp-{{ $udpServer.Upstream.Name }} {
                      {{ range $server := $udpServer.Upstream.Backends }}server {{ $server.Address }}:{{ $server.Port }};
                      {{ end }}
                  }

                  server {
                      listen {{ $udpServer.Path }} udp;
                      proxy_timeout          10s;
                      proxy_responses        1;
                      proxy_pass             udp-{{ $udpServer.Upstream.Name }};
                  }
              {{ end }}
              }

              {{/* definition of templates to avoid repetitions */}}
              {{ define "CUSTOM_ERRORS" }}
                      {{ range $errCode := .customHttpErrors }}
                      location @custom_{{ $errCode }} {
                          internal;
                          content_by_lua_block {
                              openURL({{ $errCode }})
                          }
                      }
                      {{ end }}
              {{ end }}
