Configuration

IBM® Application Gateway (IAG) uses YAML documents for all configuration data. When the container starts, it looks for a Kubernetes custom object (if specified), or in the /var/iag/config directory of the container for YAML documents.

Depending on your container environment, the files within the configuration directory can be bind mounted in, provided in a ConfigMap or any other mechanism which places the files in the configuration directory.

To get started with authoring IAG configuration YAML, refer to the OIDC with IBM Verify and YAML Reference.

Using multiple configuration YAML documents

If a Kubernetes custom object is not being used, then the IAG configuration that is contained within the configuration directory can span multiple YAML documents. Using multiple documents is useful for simplifying the management of configuration data.

IAG combines all YAML documents that are found in /var/iag/config according to the following rules:

  1. IAG configuration documents must have the file extension .yaml or .yml.

  2. Each file which contains IAG configuration must contain the version indicator. Documents which do not include the version indicator are not parsed as IAG configuration.

  3. All documents must have the same version. Mixing different configuration versions is not supported and IAG cannot start when it discovers more than one version. Refer to Versioning for further information.

  4. Each top-level key (secrets, server, identity, policies, authorization, services, logging, advanced) can be defined only one time across all configuration YAML documents, except for the resource_servers key.

  5. The top-level key resource_servers can be defined more than one time. IAG combines all resource_servers values.

Example of Multiple Configuration YAML Documents

This example illustrates how multiple configuration YAML documents can be provided to IAG. The following files are provided to the /var/iag/config path within the container.

  1. iag.yaml

  2. resource-servers-1.yaml

  3. resource-servers-2.yaml

  4. logging.yaml

iag.yaml - This file contains the top-level server and identity keys. Each document can provide more than one top-level key, provided they are only defined one time across the entire set of configuration documents.

version: "26.06.0"
server:
  ssl:
    front_end:
      certificate:
        - $CERT_PEM
        - $KEY_PEM
identity:
  oidc:
    client_id: $CLIENT_ID
    client_secret: $CLIENT_SECRET
    discovery_endpoint: "https://ibm-app-gw.verify.ibm.com/oidc/endpoint/default/.well-known/openid-configuration"

resource-servers-1.yaml - This file contains the resource_servers key and a single entry that defines one resource server. The resource_servers key is exceptional and can be defined more than once.

version: "26.06.0"
resource_servers:
  - virtual_host: iag-demo.ibm.com
    servers:
      - host: 10.10.10.200
        port: 80

resource-servers-2.yaml - This file contains a second resource_servers key and the definition for another resource server. Partitioning each resource server into its own YAML file makes it easy to add or remove resource servers by adding or removing the corresponding YAML file and re-creating the container.

version: "26.06.0"
resource_servers:
  - path: /
    servers:
      - host: 10.10.10.201
        port: 8080

logging.yaml - This file contains the logging key and sets a tracing entry useful for debugging. When debugging is completed, this file can be removed and the container be restarted to disable tracing.

version: "26.06.0"
logging:
  json_logging: false
  tracing:
    - file_name: /var/tmp/snoop.log
      component: pdweb.snoop
      level: 9

These separate documents are equivalent to providing the following as a single YAML document:

version: "26.06.0"
server:
  ssl:
    front_end:
      certificate:
        - $CERT_PEM
        - $KEY_PEM
identity:
  oidc:
    client_id: $CLIENT_ID
    client_secret: $CLIENT_SECRET
    redirect_uri_host: iag-demo.ibm.com
    discovery_endpoint: "https://ibm-app-gw.verify.ibm.com/oidc/endpoint/default/.well-known/openid-configuration"
resource_servers:
  - virtual_host: iag-demo.ibm.com
    servers:
      - host: 10.10.10.200
        port: 80
  - path: /
    servers:
      - host: 10.10.10.201
        port: 8080
logging:
  json_logging: false
  tracing:
    - file_name: /var/tmp/snoop.log
      component: pdweb.snoop
      level: 9

Setting configuration from environment variables

Each of the configuration entries can also be set by setting an environment variable, by using a normalized version of the configuration entry name. Separate each element within the configuration entry name by a period \(.\), and surround array subscripts by brackets \(\[\]\), or separate them from the name with two underscore characters \(__\). For example, the following YAML extract can be used to set the encryption key that is used by the container.

secrets:
  enc_key: "@private.pem"

This identifier might also be set by using the following environment variable name in the container context: secrets.enc_key.

As another example, the following YAML extract can be used to set the personal certificate files used in communication with the client:

server:
  ssl:
    front_end:
      certificate:
        - "@key.pem"

This identifier might also be set by using either the environment variable server.ssl.front_end.certificate[0] or server.ssl.front_end.certificate__0.

Attention: An environment variable that sets a configuration entry takes precedence over a configuration entry that is included in the YAML file.

Setting file reference values from environment variables

File reference contents can also be set by setting environment variables. To do so, set the environment variables file_override.name.<index> and file_override.value.<index>, where index is an integer that starts at 0 and increases for each file override. Use the file_override.name.<index> environment variable to specify the name of the file reference, and the file_override.value,<index> environment variable to specify the value.

For example, setting the following environment variables overrides the private.pem and key.pem file references.

file_override.name.0=private.pem
file_override.value.0=B64:LS0tLS1CRUdJT...
file_override.name.1=key.pem
file_override.value.1=secret:iag-secret/key

The value can be any type of allowed configuration value, but file reference overrides are only applied once. If a file override value is itself a file reference, no further overrides are applied to that value.

Special types

Three special types can be used in addition to plain text within the YAML file. These special types can be used to substitute values from alternative sources.

Type Syntax
Environment Variable $<environment variable>
External File "@<file name>"
Base64 Data B64:<base64 encoded string>
Obfuscated (Encrypted with Shared Secret) String OBF:<obfuscated string>
Encrypted (Encrypted with RSA) String ENC:<encrypted string>

Special types available in Kubernetes

In addition to the standard special types, two Kubernetes specific special types are available when IAG is running in a Kubernetes environment.

Type Syntax
Kubernetes ConfigMap configmap:<config map name>/<config map field>
Kubernetes Secret secret:<secret name>/<secret field>

Example environment variable

The following example shows how a value that is stored in an environment variable can be used in the YAML configuration document. Environment variables are useful when used along with Kubernetes secrets to hide sensitive data. In this example, the failover cookie key is loaded from an environment variable.

The environment variable MY_FAILOVER_SECRET is set in the container context:

MY_FAILOVER_SECRET=exampleOnlyDoNotUseThisValue

An IAG YAML configuration document can indicate that this value is loaded from the environment variable by specifying $MY_FAILOVER_SECRET as a value.

version: "26.06.0"
server:
...
  failover:
    key: $MY_FAILOVER_SECRET
    cookie_name: IAG-FAILOVER-COOKIE
...

The preceding example is equivalent to specifying the value as-is within the YAML configuration data.

version: "26.06.0"
server:
...
  failover:
    key: exampleOnlyDoNotUseThisValue
    cookie_name: IAG-FAILOVER-COOKIE
...

Example file reference

The following example shows a file reference that is used to source content from an external file. File references are not supported when a Kubernetes custom object is being used to store the configuration information. In this example, a rate limiting rule is loaded from an external file.

The following two files are present in the configuration directory /var/iag/config:

config.yaml
rate_limiting.yaml

In this example, rate_limiting.yaml is a simple YAML file with the content:

ip: true
capacity: 3
interval: 60
reaction: TEMPLATE

In the IAG configuration file config.yaml, the content of rate_limiting.yaml is included by specifying "@rate_limiting.yaml" as a value.

version: "26.06.0"
policies:
...
  rate_limiting:
    - name: "limited_by_ip"
      methods:
        - "*"
      paths:
        - "/my_app*"
      rule: "@rate_limiting.yaml"
...

The preceding example is equivalent to including the text content as-is within the YAML configuration data.

version: "26.06.0"
policies:
...
  rate_limiting:
    - name: "limited_by_ip"
      methods:
        - "*"
      paths:
        - "/my_app*"
      rule: |
        ip: true
        capacity: 3
        interval: 60
        reaction: TEMPLATE
...
 
Attention: Quotation marks must always surround a file reference as the @ character cannot appear at the beginning of an unquoted YAML value.

Example Base64 data

Some types of data cannot be stored as text within the configuration YAML. In some scenarios, it is useful to be able to embed all data within a single configuration YAML document. In these cases, the values can be Base64 encoded and embedded as values within the configuration YAML.

The following example shows a transformation rule that is embedded in the configuration YAML as Base64 encoded data.

First, generate the Base64 representation of the file. On macOS and other UNIX-like systems, you can use the base64 command.

$ base64 Req-AddStaticHeader.xsl
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHhzbDpzdHlsZXNoZWV0IHht
...

In the IAG configuration YAML, this value is placed on a single line and preceded by the B64: prefix.

version: "26.06.0"
policies:
  ...
    http_transformations:
      request:
        - name: req-static-headers
          method: GET
          url: "*"
          rule: B64:PD94bWwgdmVyc2lvbj0i...
...

The preceding example is equivalent to including the text content as-is within the YAML configuration data.

version: "26.06.0"
policies:
  ...
    http_transformations:
      request:
        - name: req-static-headers
          method: GET
          url: "*"
          rule: |
            <?xml version="1.0" encoding="UTF-8"?>
            <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
                <xsl:strip-space elements="*" />
                <xsl:template match="/">
            ...
...

Example obfuscated (encrypted with shared secret) string

Configuration data can also be provided as encrypted entries which are obfuscated by using a shared secret or password. The shared secret is provided in the secrets section of the YAML and is used to decrypt all OBF: prefixed entries found within the configuration YAML.

The following example shows the data wPP8rM8N0d being encrypted with the shared secret myIAGExampleSecret:

echo -n "wPP8rM8N0d" | openssl enc -aes256 \
  -pbkdf2 -md sha512 -pass pass:"myIAGExampleSecret" \
  -base64

OpenSSL 1.1.1 or newer is required for the preceding command.

This command produces a Base64 string similar to U2FsdGVkX1+UHIKgqQOgjyqY2ANixZs2sW+b1Nr7fcg=. Due to salting, this command produces a different encrypted representation of the input data each time it is run.

Entire files can also be obfuscated with a similar command:

openssl enc -aes256 -pbkdf2 -md sha512 -pass pass:"myIAGExampleSecret" \
  -base64 -in myLocalPages.zip

The resulting encrypted Base64 string can be provided to IAG by using the OBF: prefix:

version: "26.06.0"
secrets:
  obf_key: "myIAGExampleSecret"
...
identity:
  oidc:
    client_secret: "OBF:U2FsdGVkX1+UHIKgqQOgjyqY2ANixZs2sW+b1Nr7fcg="

Any number of values in the YAML configuration document can be obfuscated but they all must use the same shared secret. Only a single shared secret can be provided per IAG instance.

version: "26.06.0"
secrets:
  obf_key: "myIAGExampleSecret"
...
identity:
  oidc:
    client_secret: "OBF:U2FsdGVkX1+UHIKgqQOgjyqY2ANixZs2sW+b1Nr7fcg="
    client_id: "OBF:U2FsdGVkX1/OHj8jarx2+yzaFICy+z5ZDIDFXEMtVR/oLaafLtjVi9u+huCwZhnD5/aMWEm7h1G1cgtJE/yu3w=="
...
server:
  local_pages:
    content: "OBF:U2FsdGVkX19nCQVvJZtKatPZE/TEDEYlYMpak7hAZJoC..."
    type: zip

Reversing an obfuscated string

An obfuscated string can be reversed by using a technique similar to the one used to create it:

echo "U2FsdGVkX1+UHIKgqQOgjyqY2ANixZs2sW+b1Nr7fcg=" | openssl enc -d -aes256 \
  -pbkdf2 -md sha512 -pass pass:"myIAGExampleSecret" \
  -base64

Detailed description of the expected format for encrypted data

The requirements for an obfuscated entry are:

  • The data must be encrypted with the AES-256 cipher -aes256

  • The key used to encrypt the data must:

    • be derived from a passphrase which can be supplied in the YAML -pass pass:<passphrase>

    • be derived by using the PBKDF2 algorithm -pbkdf2

    • use SHA-512 message digest -md sha152

    • perform 10,000 iterations -iter 10000 (the current default for OpenSSL)

  • The data must be Base64 encoded -base64

  • When Base64 decoded, the data must be in OpenSSL format:

    • Bytes 0-7 is Salted__

    • Bytes 8-15 is the salt that is used while deriving the key

    • Byte 16 onwards is the encrypted data

Example encrypted (encrypted with RSA) string

Configuration data can also be provided as RSA encrypted entries. The private key used to decrypt the entry is provided in the secrets section of the YAML and is used to decrypt all ENC: prefixed entries found within the configuration YAML.

To use RSA encryption, generate a private certificate:

openssl genrsa -out private.pem 2048

This private certificate is used to decrypt the entries when provided in the configuration YAML. To create encrypted entries, generate a corresponding public key which is used for the encryption operations:

openssl rsa -pubout -in private.pem -out public.pem

The following example shows the data wPP8rM8N0d being encrypted with the public key public.pem and Base64 encoded:

echo -n "wPP8rM8N0d" | openssl rsautl -encrypt -inkey public.pem -pubin | base64

This command produces a Base64 encoded string. The encrypted Base64 encoded string can be provided to IAG by specifying the ENC: prefix:

version: "26.06.0"
secrets:
  enc_key: "@private.pem"
...
identity:
  oidc:
    client_secret: "ENC:gg05Dn9WnV13OPpkwxszzlxQQG3WM1N88BHggtb2JbNI..."

Any number of values in the configuration YAML can be encrypted but they all must require the same private key for decryption. Only a single RSA private key can be provided per IAG instance.

version: "26.06.0"
secrets:
  obf_key: "myIAGExampleSecret"
...
identity:
  oidc:
    client_secret: "ENC:gg05Dn9WnV13OPpkwxszzlxQQG3WM1N88BHggtb2JbNI..."
    client_id: "ENC:PS56fPQGSg/LPT2mgktLw1T2YMuBxaaQMM5AZMq06xEs..."

Reversing an obfuscated string

An obfuscated string can be reversed by using a technique similar to the one used to create it:

echo -n "PS56fPQGSg/LPT2mgktLw1T2YMuBxaaQMM5AZMq06xEs..." \
  | base64 -d | openssl rsautl -decrypt -inkey private.pem

Using the encrypted and obfuscated types together

The amount of data which can be encrypted by using this technique is limited by the size of the RSA private key. To protect entries which are too large for RSA encryption, the following approach is recommended:

  1. Entries are obfuscated by using the OBF:<value> technique

  2. The obfuscation key is encrypted by using the ENC:<value> technique

version: "26.06.0"
secrets:
  enc_key: "@private.pem"
  obf_key: "ENC:OsG1/Aw5iNpP/AutK9q0bVF5z1sO/psBvpY7zpRpd8V..."
identity:
  oidc:
    client_secret: "OBF:U2FsdGVkX1+UHIKgqQOgjyqY2ANixZs2sW+b1Nr7fcg="
    client_id:     "OBF:U2FsdGVkX1/OHj8jarx2+yzaFICy+z5ZDIDFXEMtVR/o..."
...
server:
  local_pages:
    content: "OBF:U2FsdGVkX19nCQVvJZtKatPZE/TEDEYlYMpak7hAZJoC..."
    type: zip

Example Kubernetes ConfigMap

The Kubernetes ConfigMap type can be used to directly reference a field from a particular ConfigMap within the IAG configuration YAML. During bootstrapping, the IAG container uses the Kubernetes REST API endpoints to retrieve the ConfigMap and substitute the value into the configuration YAML.

Consider the following secret that is named verify-endpoint containing the fields discovery_url and proxy_server:

apiVersion: v1
kind: ConfigMap
metadata:
  name: verify-endpoint
  ...
data:
  discovery_url: https://ibm-app-gw.verify.ibm.com/oidc/endpoint/default/.well-known/openid-configuration
  proxy_server: https://proxy.ibm.com:3128

To reference these values within the configuration YAML, use the syntax for the Kubernetes ConfigMap type:

version: "26.06.0"
identity:
  oidc:
    discovery_endpoint: "configmap:verify-endpoint/discovery_url"
    proxy: "configmap:verify-endpoint/proxy_server"
...

During bootstrapping, IAG retrieves the ConfigMap and substitutes it into the configuration YAML:

version: "26.06.0"
identity:
  oidc:
    discovery_endpoint: https://ibm-app-gw.verify.ibm.com/oidc/endpoint/default/.well-known/openid-configuration
    proxy: https://proxy.ibm.com:3128
...

Example Kubernetes secret

The Kubernetes Secret type can be used to directly reference a field from a particular secret within the IAG configuration YAML. During bootstrapping, the IAG container uses the Kubernetes REST API endpoints to retrieve the secret and substitute the secret value into the configuration YAML.

Consider the following secret that is named verify-oidc containing the fields client_id and client_secret:

apiVersion: v1
kind: Secret
type: Opaque
metadata:
  name: verify-oidc
  ...
data:
  client_id:     ZTdiMzA0ZWItYTU1NC00MzQ5LTlhODAtNTA1Y2IzZGRmMTBi
  client_secret: Z2VSVEY0RldSWA==

To reference these values within the configuration YAML, use the syntax for the Kubernetes Secret type:

version: "26.06.0"
identity:
  oidc:
    client_id: "secret:verify-oidc/client_id"
    client_secret: "secret:verify-oidc/client_secret"
...

During bootstrapping, IAG retrieves the secret, Base64 decodes the data and substitute it into the configuration YAML:

version: "26.06.0"
identity:
  oidc:
    client_id: e7b304eb-a554-4349-9a80-505cb3ddf10b
    client_secret: geRTF4FWRX
...

Kubernetes TLS secrets

This mechanism can also be used with the Kubernetes TLS Secret type kubernetes.io/tls. Consider the following TLS Secret named iag-tls-secret which contains the fields tls.crt and tls.key:

apiVersion: v1
kind: Secret
type: kubernetes.io/tls
metadata:
  name: iag-tls-secret
  ...
data:
  tls.crt: LS0t...Cg==
  tls.key: LS0t...LS0K

This TLS Secret can be specified by using the Kubernetes Secret syntax:

version: "26.06.0"
server:
  ssl:
    certificate:
      - "secret:iag-tls-secret/tls.key"
      - "secret:iag-tls-secret/tls.crt"
...