App gateways (Legacy)

App gateways (Legacy)

ℹ️
This topic refers to legacy configuration syntax. App gateways are now defined as Proxy apps.

AppGateways control user access to apps by providing declarative tools for proxies and connectors. AppGateways proxy apps, and can determine which identity systems should be used to authenticate and authorize users. They may also be used to extend those identity systems by managing sessions or by mapping attributes or claims to specific headers which legacy apps need to allow access. AppGateways can also use attrProviders to obtain additional data which can be used to evaluate policy.

ℹ️
As a security measure, the orchestrator does not forward Maverics cookies to upstream apps.

Name

The name value is a unique identifier for each AppGateway.

Base Path

The basePath defines the path prefix that the AppGateway will listen for requests on. For example, a basePath of /foo means that the AppGateway will listen for all requests that are made with a prefix of /foo, such as /foo/index.html.

Host

host is an optional field used to route requests to the correct AppGateway when the basePaths of one or more AppGateways conflict. For instance, two applications may have a basePath of / and therefore need a host value specified to enable correct routing.

appgateways:
  - name: alpha
    basePath: /
    host: alpha.com

  - name: beta
    basePath: /
    host: beta.com

Upstream

upstream is the URL of app that is being protected and proxied to. This could be an IP address or hostname, and port that the application listens on.

Preserve Host

preserveHost is an optional boolean field used to determine if the Host header should be preserved on outbound requests. By default, the orchestrator will set the host header to match the upstream’s host. This field is often used when the orchestrator is forwarding traffic to another reverse proxy such as Apache.

TLS

The tls field is used to specify the TLS configuration for outbound requests to the upstream. The value must reference a TLS object defined in the top-level TLS configuration. This field is optional, and is typically used when the upstream target uses certificates signed by an unknown certificate authority.

Rewrites

rewrites are used to replace URLs on the request and on the response. This can be handy when proxying to an application that uses absolute URLs. This feature should be used with caution as it will impact the performance of an AppGateway.

appgateways:
  - name: rewritesExample
    basePath: /
    rewrites:
      # The URL on the left side of the colon is replaced with the URL on the right.
      https://app-internal.example.com: https://app.example.com

Attribute Providers

attrProviders represent the identity system or data store from which an AppGateway retrieves additional attributes required for evaluating policies and building headers.

appgateways:
  - name: exampleAttrProvider
    basePath: /
    attrProviders:
      - connector: ldap
        usernameMapping: azure.mail
      - connector: mysql
        usernameMapping: azure.mail

Connector

connector references the connector that will be used to load attributes.

Username Mapping

Specifies the attribute to use as a lookup key in order to load attributes from the attribute provider. The value usually comes from the IDP that was used for primary authentication, for example, azure.sub.

Headers

AppGateways often protect applications that require an external identity provider to authenticate the user and set values in HTTP headers before allowing access. Headers are configured as a mapping key value pairs where the key is header’s name and the value is the header’s value. The values are declared using a namespace such as azure.sub.

appgateways:
  - name: exampleHeaders
    basePath: /
    headers:
      SM_USER: azure.sub
      firstName: ldap.givenName
      lastName: ldap.sn

Create Header Service Extension

Custom headers can be created by using the createHeader Service Extension. For more info, please see the Create Header Service Extension docs.

Policies

policies determine whether a given request should be allowed, ultimately defining which users are allowed application access. If no policies are defined in the AppGateway config, it will deny all requests.

AppGateways use authentication and authorization to evaluate whether a user should be allowed to access an application location. These policies extend the native authentication and authorization policies of the connected identity system(s). The user is allowed to access if they meet configured conditions: such as having been authenticated by the idp, or carrying attributes that may indicate membership in a group or some other aspect of the user that is evaluated in policy.

Location

A policy location is used to map an application resource to a policy. The AppGateway will match a request to the most specific location. The ordering in config of policy locations does not matter.

appgateways:
  - name: examplePolicy
    basePath: /
    policies:
      - location: /index.html
        authentication:
          allowUnauthenticated: true
        authorization:
          allowAll: true

To apply Regular Expression matching to resource path, add ~ (note the space) at the front of the location. You can use tools such as regex101 (choose Golang) to test your regex against URL paths you would like to match. For example, to match any resource that starts with myresource:

appgateways:
  - name: examplePolicyWithRegex
    basePath: /
    policies:
      - location: ~ ^/myresource.*
        authentication:
          allowUnauthenticated: true
        authorization:
          allowAll: true

Notice the ^ to ensure the regex matches only at the beginning of the resource path. The orchestrator automatically escapes / characters in the URL path, so do not escape these manually (e.g. ^\/).

Poorly constructed regexes can impact orchestrator performance. Use anchors (^ or $) where possible, and counters or ranges (.{0,15}) instead of “greedy” wildcards (.*).

Query Param Matching

useQueryParamsForMatchingPolicy is used to match requests with query parameters to the correct policy. Query parameter matching only works with locations that use regex matching (i.e. preceded with a ~).

In order to match URLs which include query parameters such as the URL https://mydomain.com/myresource/?param=abcd, you would define a policy similar to:

appgateways:
  - name: examplePolicyWithQueryParams
    basePath: /
    policies:
      - location: ~ ^/myresource/\?param=abcd
        useQueryParamsForMatchingPolicy: true
        authentication:
          allowUnauthenticated: true
        authorization:
          allowAll: true

For multiple query parameters with consistent ordering:

appgateways:
  - name: examplePolicyWithQueryParams
    basePath: /
    policies:
      - location: ~ ^/myresource/\?param=abc&code=def
        useQueryParamsForMatchingPolicy: true
        authentication:
          allowUnauthenticated: true
        authorization:
          allowAll: true

If the query parameters could appear in either order, with other params between them:

appgateways:
  - name: examplePolicyWithQueryParams
    basePath: /
    policies:
      - location: ~ ^/myresource/\?.{0,15}(param=abc|code=def){1}.{0,15}\&(param=abc|code=def){1}
        useQueryParamsForMatchingPolicy: true
        authentication:
          allowUnauthenticated: true
        authorization:
          allowAll: true

Authentication

authentication declares a location’s authentication policy. When an unauthenticated request for a resource is received, a default authentication policy will handle the unauthenticated request and redirect a user to an IDP or MFA provider for login as needed.

Example using Azure for authentication:

appgateways:
  - name: exampleAuthnPolicy
    basePath: /
    policies:
      - location: /sonar
        authentication:
          idps:
            - azure
        authorization:
          allowAll: true

Example using Azure for primary authentication and PingOne for MFA:

include:
  - "/etc/maverics/configs/connectors/azure.yaml"
  - "/etc/maverics/configs/connectors/pingone.yaml"

appgateways:
  - name: exampleAuthnMFAPolicy
    basePath: /
    policies:
      - location: /sonar
        authentication:
          idps:
              - azure
          mfa:
            - pingone:
                mapping:
                  - email: azure.email

IDPs

idps take a list of one or more IDP connector names to use for authentication.

MFA

mfa takes a list of one or more MFA (multi-factor authentication) connector names. Under each connector, a mapping section is required to define how an MFA identity is mapped to the corresponding IDP identity.

The mapping field supports the keywords and, or and not to express complex evaluations. If the names are a YAML list with no keywords they will be evaluated with an implicit and.

Allow Unauthenticated Access

The allowUnauthenticated operator can be used to allow open access to a resource. If set to true, the resource for this policy does not require any authentication. This operator is typically, used is for resources like error or login pages.

Authorization

The authorization operator declares a location’s authorization policy and enables the formation of arbitrarily complex policies. The authorization operator can be used in conjunction with the all, any, equal, and contains operators. If unspecified, access to the location is denied. The authorization section can use the evaluators detailed below
to construct authorization policy.

Example with simple authorization policy:

appgateways:
  - name: exampleAuthzPolicy
    basePath: /

    policies:
      - location: /
        authentication:
          idps:
            - azure
        authorization:
          - or:
            - contains: ["{{azure.groups}}", "admins"]
            - contains: ["{{azure.groups}}", "executives"]

Allow All

The allowAll operator (allowAll: true) authorizes all users for a location. This must be set explicitly for each location to be accessible to all users and should not be used in combination with any other policy rules for a location.

And

All conditions/operators defined in an and block need to evaluate to true for the policy to evaluate to true.

Or

Any of the conditions/operators defined in an or block need to evaluate to true for the policy to evaluate to true.

Not

Any condition or operator defined in a not block evaluates to the inverse. If the condition in the not policy is true, the policy will be evaluated to false and vice-versa. To evaluate a list of conditions with not, you must nest the conditions in an or or and block.

Contains

contains requires two strings, normally an attribute from the session and a value to compare it to, and returns true if the second string matches any part of the first (i.e. a substring match). Values from the user’s session can be included in the policy evaluation by enclosing them in double curly braces. For example, contains: ["{{azure.name}}", "@example.com"].

Equals

Evaluates to true if the two values are equal when the policy is run.

Headers

headers define the set of headers for a specific location. These headers will override headers of the same name that are defined at the AppGateway level. The createHeader Service Extension may be used at this level as well.

This sample configuration defines headers at the policy level to include headers for a specific location. It also overrides the headers at the AppGateway level.

appgateways:
  - name: Sonar
    basePath: /

    headers:
      SM_USER: azure.username
      firstname: azure.givenName
      lastname: azure.surname

    policies:
      - location: /
        authentication:
          idps:
            - azure
        headers:
          # Override 'firstname' header defined in 'headers'.
          firstname: azure.preferred_username

      - location: /admin
        authentication:
          idps:
            - azure
        headers:
          # Add new header for /admin location.
          IS_ADMIN: azure.isAdmin

Error Page

The errorPage is the URL a user is redirected when an error occurs.

Unauthorized Page

The unauthorizedPage is the URL a user is redirected when a policy evaluation denies access to the app.

Service Extensions

AppGateways use Service Extensions to enable custom logic that is not natively supported. Service Extensions can be used to load attributes, extend authentication and authorization policy evaluations, and create headers.

Authentication

Although Maverics supplies an abundance of connectors to use for user authentication, some organizations want to customize the authentication experience or may have needs not expressed in existing connectors. The Authentication Service Extensions allow administrators to define the authentication process in exactly the manner they need.

Details at [Authentication Service Extensions](service-extension-authentication.

Loading Attributes

Loading attributes about a user’s session is also customizable via Service Extensions.

Details at Loading Attributes via Service Extension.

Authorization

Service Extensions also give complete control over access to protected resources via authorization.

Details at Authorization via Service Extension.

Upstream Login

It can be useful to determine if a request to an upstream application is authenticated and to be able to login to an upstream app.

Details at Upstream Application Login.

Request and Response Modification

Certain situations require the ability to modify every request and response that flows through the AppGateway’s proxy.

Details at Request & Response Modification Service Extension

Overriding Default AppGateway Request Flow

Gain finer control over how a request is handled in an AppGateway.

Details at Serve Service Extension

Examples

Base

This sample base YAML config declares:

  • An app called “Sonar”
  • A location on the app that is protected
  • That a session must be present and validated in order for the user to access the app
  • A connected Azure AD tenant as the identity provider for the user
  • The attribute mappings from the Azure AD claims to HTTP headers
  • A policy that allows access to the app when the user is authenticated to Azure
  • A policy that allows access to a specific location only when the user’s data meets specific criteria
version: 0.1

tls:
  maverics:
    certFile: certs/example-strata.crt
    keyFile: certs/example-strata.key

http:
  address: :443
  tls: maverics

include:
  - "/etc/maverics/configs/connectors/azure.yaml"

appgateways:
  - name: Sonar
    basePath: /
    host: app.sonarsystems.com
    upstream: https://example.com:8443
    errorPage: https://app.sonarsystems.com/sonar/error
    unauthorizedPage: https://app.sonarsystems.com/sonar/accessdenied

    headers:
      SM_USER: azure.username
      firstname: azure.givenName
      lastname: azure.surname

    policies:
      - location: /
        authentication:
          idps:
            - azure
      - location: /sonar/accessdenied
        authentication:
          allowUnauthenticated: true
        authorization:
          allowAll: true
      - location: /sonar/execs
        authentication:
          idps:
            - azure
        authorization:
          - or:
              - contains: ["{{azure.email}}", "@sonarsystems.com"]
              - contains: ["{{azure.email}}", "@example.com"]

Authentication Policy

Authentication flow with MFA mapping using logical operators

In the authentication section, you will find one IDP and one MFA defined. The default authentication flow will have user authenticate with azure connector followed with the specified MFA (Multi-Factor Authentication) provider under the mfa section. In this example, the config is shown using pingone as the connector for the MFA provider. The mapping here is expressed as two different conditions in a scenario where some users are mapped to the email attribute and other users are mapped to the userid attribute for the same pingone connector. If the user doesn’t have the email attribute on their session, then the default authentication flow will try to authenticate the user to the pingone connector using the userid attribute.

...
include:
  - "/etc/maverics/configs/connectors/azure.yaml"
  - "/etc/maverics/configs/connectors/pingone.yaml"

appgateways:
  - name: Sonar
    # ...
    policies:
      - location: /sonar
        authentication:
          idps:
            - azure
          mfa:
            - pingone:
                mapping:
                  - or:
                      - email: azure.email
                      - userid: azure.userid

In the config below, the and operator is used to indicate a mapping of two fields are desired.

...
include:
  - "/etc/maverics/configs/connectors/azure.yaml"
  - "/etc/maverics/configs/connectors/pingone.yaml"

appgateways:
  - name: Sonar
    # ...
    policies:
      - location: /sonar
        authentication:
          idps:
            - azure
          mfa:
            - pingone:
                mapping:
                  - and:
                      - email: azure.email
                      - tenantID: azure.group

This config demonstrates a more advanced and complex scenario where it can be expressed with multiple operators.

...
include:
  - "/etc/maverics/configs/connectors/azure.yaml"
  - "/etc/maverics/configs/connectors/pingone.yaml"

appgateways:
  - name: Sonar
    # ...
    policies:
      - location: /sonar
        authentication:
          idps:
            - azure
          mfa:
            - pingone:
                mapping:
                  - or:
                      - and:
                          - email: azure.email
                          - tenantID: azure.group
                      - email: azure.email

This config demonstrates a mapping expressed with the not operator where if the attribute azure.custom exists on the session, then map user to pingone using the secondary email.

...
include:
  - "/etc/maverics/configs/connectors/azure.yaml"
  - "/etc/maverics/configs/connectors/pingone.yaml"

appgateways:
  - name: Sonar
    # ...
    policies:
      - location: /sonar
        authentication:
          idps:
            - azure
          mfa:
            - pingone:
                mapping:
                  - or:
                      - and:
                          - email: azure.verified_primary_email
                          - not:
                              custom: azure.custom
                      - email: azure.verified_secondary_email

Authorization Policy

The AppGateway uses authorization to protect resources, returning 403 Forbidden when trying to access the resource if the policy does not evaluate to true.

Policy using authorization with nested conditions

In this sample configuration, the AppGateway uses authorization to enable access to /sonar/reports for certain users. If user’s email contains the strata.io domain, access is enabled for users with the names Marie, Ivan, and Ludwig. If user email contains the sonarsystems.com domain, access is enabled for users with the names Donna, Jacob, and Rufus.

...
include:
  - "/etc/maverics/configs/connectors/azure.yaml"

appgateways:
  - name: Sonar
    # ...

    policies:
      - location: /sonar
        authentication:
          idps:
            - azure
        authorization:
          allowAll: true
      - location: /sonar/reports
        authentication:
          idps:
            - azure
        authorization:
          - and:
              - equal: [ "{{azure.custom}}", "expected" ]
              - or:
                  - and:
                      - contains: [ "{{azure.name}}", "@strata.io" ]
                      - or:
                          - equal: [ "{{azure.givenname}}", "Marie" ]
                          - equal: [ "{{azure.givenname}}", "Ivan" ]
                          - equal: [ "{{azure.givenname}}", "Ludwig" ]
                  - and:
                      - contains: [ "{{azure.name}}", "@sonarsystems.com" ]
                      - or:
                          - equal: [ "{{azure.givenname}}", "Donna" ]
                          - equal: [ "{{azure.givenname}}", "Jacob" ]
                          - equal: [ "{{azure.givenname}}", "Rufus" ]

Policy using Attributes from LDAP

This sample configuration uses an LDAP Connector instance to fetch additional information about users. When the additional attributes are loaded, Maverics will perform an authorization check against the loaded attributes before granting access to the user.

include:
  - "/etc/maverics/configs/connectors/azure.yaml"

connectors:
  - name: ldap
    type: ldap
    url: "ldap://ldap.example.com:389"
    serviceAccountPassword: <PASSWORD>
    serviceAccountUsername: cn=admin,dc=example,dc=com
    baseDN: ou=People,dc=example,dc=com
    usernameSearchKey: mail

appgateways:
  - name: Sonar
    # ...
    attrProviders:
      - connector: ldap
        usernameMapping: azure.emailaddress

    policies:
      - location: /sonar
        loadAttrsSE:
          funcName: LoadAttrs
          file: /etc/maverics/extensions/loadAttrs.go

        authentication:
          idps:
            - azure
        authorization:
          - equal: [ "{{ldap.department}}", "Accounting" ]