Security Gateway#

With the Blitz Identity Provider, you can implement access control when secured services are invoked by applications.

Providing authorization when applications invoke services is based on OAuth 2.0 specifications. Before using services, an application must obtain an access token (access_token) from Blitz Identity Provider. Various interaction methods are available to the application to obtain an access token. The access token can be obtained:

  • in the context of a user login - the token will include information about the user and a set of scopes (permissions) granted by the user to the application;

  • to the application outside of the user login - the token will include a set of scopes (permissions) from the granted to the application.

Then using the access token obtained, the application can invoke services. In doing so, the following complications will occur:

  • within each service it will be necessary to implement its own authorization logic - check the provided access token, extract information about the user and provided consents (permissions) from it and analyze whether they are sufficient for service execution or not. Logging of the access decision.

  • the application will use a single access token to invoke different services. In this case, the access token may contain more information about the user and a larger set of consents (permissions) than is necessary for a particular invoked service. This will violate the principle of least privilege - the service will get more access rights than it needs to perform its task.

To solve the above described difficulties, Blitz Identity Provider provides a special application - the Security Gateway (blitz-keeper). This application is a specialized proxy server used when calling protected services - the application does not call the services directly, but through the Security Gateway. The Security Gateway takes care of the following tasks:

  • Checks the authorization header included in the invoke of service, extracts the access token and, in interaction with the authorization service (blitz-idp), checks whether the access token is valid, and whether the user and the application has sufficient access rights to invoke the secured service.

  • In interaction with the authorization service (blitz-idp) replaces the access token in such a way that the security token transmitted from the Security Gateway to the protected service contains only the set of user information and permissions required for the protected service operation. Redundant permission and user information can be either removed from the security token or additional permissions and information added to the access token, if this is configured in the security policy.

  • Logs successful and unsuccessful access control events in the Blitz Identity Provider security event log.

The interaction between the Security Gateway and the authorization service is based on the OAuth 2.0 Token Exchange <https://tools.ietf.org/html/rfc8693>`__ specification. Picture of the interaction is shown in the diagram.

:size=80%

Configuring the use of the Security Gateway for services protection involves the following steps and is described in the following subsections:

  • Configuring Blitz Keeper.

  • Creating service access rules.

  • Registering access token exchange rules in blitz.conf.

Configuring Blitz Keeper#

Blitz Keeper is configured by editing the configuration file blitz-keeper.conf located in the /etc/blitz-keeper directory. Example of the configuration file:

{
  "authenticators": {
    "prod-auth": {
      "type": "token-exchange",
      "te": "https://blitz-host/blitz/oauth/te",
    },
  },
  "services" : {
    "api-1":{
      "display-name" : "secured services",
      "host": "service-host.com",
      "locations": {
        "/api/service1/**": {
          "methods" : ["GET","POST"],
          "authenticator": "prod-auth",
          "required-scopes": ["scope1","scope2"]
        },
        "/path/api/user/*/getdata/**": {
          "methods" : ["GET","PUT"],
          "authenticator": "prod-auth",
          "required-scopes": ["scope3"]
        }
      }
    }
  }
}

In the authenticators block it is necessary to register all used blitz-idp authorization services. Usually it is sufficient to use one single authorization service to protect the services, and then only one block needs to be filled in as in the example (in the example one authorization service named prod-auth is registered). If several separate Blitz Identity Provider installations are used in the system (for example, PROD and TEST environment or internal loop for employees and external loop for clients), then you can use a common security gateway that will interact with several different authorization services - then you need to specify the settings of several authorization services in the authenticators block. For each authorization service a name is set (in the example prod-auth is used, but you can set any name). In the settings block of the authorization service the type of interaction (type) is set in the value token-exchange (so far it is the only supported type of interaction) and the address (te) of the call of the Token Endpoint handler of the authorization service. If blitz-keeper is deployed on separate servers, it is recommended to specify the address of the handler with https and domain name. If the blitz-keeper application is deployed on the same server as the blitz-idp authorization service, it is recommended to specify a local name in te, e.g. http://localhost:9000/blitz/oauth/te.

In the services block you must register the protected services. You can create a common settings block or several separate blocks for all protected services. Each block has a name (in the example, api-1). The settings are defined inside the block:

  • display-name - text description of the service (any comment or description);

  • host - server address of the secured service;

  • locations - allowed paths and operations of service invoke.

The locations block specifies the settings of all service paths and allowed methods. The service address is specified as the name of each nested block. It is acceptable to use an asterisk (*) in the address to indicate the omission of a separate component in the service path address and it is acceptable to use a double asterisk (**) to indicate that the rest of the service path can be any component. Within the service address nested block, you can optionally list the allowed methods of the service (methods setting), specify the name of the authorization service to be used (authenticator setting) and a list of permissions (required-scopes setting) for the target access token to be included in the access token passed to the protected service.

After changing the settings in blitz-keeper.conf, the security gateway must be restarted.

Creating service access rules#

Service access rules are created in the /usr/share/identityblitz/blitz-config/token_exchange/rules/ directory. Each rule is created as a separate text file without extension.

Example of a file with an access rule (the specialize type):

{
    "name": "rule-name",
    "type": "specialize",
    "desc": "",
    "subjectTokenCond": {
        "clientRights": [],
        "userRights": [],
        "scopes": ["openid"],
        "userClaims": {},
        "userGroups": []
    },
    "issue": {
        "ttlInSec": 3600,
        "allowedScopes": ["openid","profile"],
        "allowedClaims": ["sub","global_role","org_id","rights"],
        "addingScopes": [],
        "addingClaims": []
    }
}

Example of a file with an access rule (the impersonate type):

{
    "name": "rule-name",
    "type": "impersonate",
    "desc": "",
    "subjectTokenCond": {
        "clientRights": [],
        "userRights": [],
        "scopes": ["openid"],
        "userClaims": {},
        "userGroups": []
    },
    "authClientCond": {
        "requiredRights":[
            {
                "rights": ["right1"],
                "target": {
                    "type": "its",
                    "name": "app1"
                }
            }
    },
    "issue": {
        "ttlInSec": 3600,
        "allowedScopes": ["openid","profile"],
        "allowedClaims": ["sub","global_role","org_id","rights"],
        "addingScopes": [],
        "addingClaims": []
    }
}

Following attributes of the access rule must be set:

  • name - name of the rule, which must match the name of the file with the access rule;

  • type – type of the rule. The following rule types are supported:

    • specialize – according to this rule, an application requests the exchange of an access token issued to the same application. The exchange is performed for the purpose of specializing the access token: replacing permissions (scope), attributes (claims), the list of recipients (audience, aud), or the token format (jwt or opaque);

    • impersonate – according to this rule, an application requests the exchange of an access token issued to another application. The exchange is carried out provided that in the access token being exchanged, the requesting application is in the list of recipients (audience, aud). Such an exchange is used when application A initially received an access token, prepared it for transmission to application B (via an exchange using the specialize rule type), passed it on to application B, so that application B issued its own token based on the received one ( through an exchange using the impersonate rule type).

  • desc - description of the rule. You can enter any text information;

  • subjectTokenCond - conditions of rule fulfillment. If all the conditions specified in the rule are met, the rule is considered to be executed. If at least one of the conditions in the rule is not fulfilled, the whole rule is considered unfulfilled. The conditions of rule fulfillment can be as follows:

    • clientRights - check if the application has the specified access rights;

      Example of the rule:

      "clientRights": [
      {
          "rights": ["right1"],
          "target": {
          "type": "its",
          "name": "app1"
          }
      }
      ]
      

      In this example, the calling application checks whether the calling application has the right1 access right with respect to another application (app1). The its parameter in the target setting specifies the type of object against which the access right is checked. Possible values: its - right to an application; grps - right to an access group; no type - right to a user account.

    • userRights - check if the user has the specified access rights.

      Example 1 of a rule:

      "userRights": [
      {
          "rights": ["right2"],
          "target": {
          "type": "grps",
          "name": "org1",
          "ext": "orgs"
          }
      }
      ]
      

      In the example, it checks whether the user has the right2 access right with respect to the user group (org1). In case of the access group object type, an additional parameter ext is specified to define the access group profile (see Enabling the display of groups in blitz.conf).

      Example 2 of a rule:

      "userRights": [
      {
          "rights": ["security_administrator"],
          "target": {
          "type": "grps",
          "name": "${org_id}",
          "ext": "orgs"
          }
      }
      ]
      

      This rule checks whether the user has the security_administrator access right with respect to the user group from the orgs profile, which has an identifier that matches the value of the org_id attribute from the original access token. In contrast to Example 1, this example illustrates the possibility to specify not a specific object value as the name of the access right object, but to refer to the object based on the values from the submitted access token ($org_id).

      Example 3 of a rule:

      "userRights": [
      {
          "rights": ["right3"],
          "target": {
          "type": "its",
          "name": "app1"
          }
      }
      ]
      

      The above example checks if the user has the right3 access rights with respect to application app1.

    • scopes - checks the presence of the required permissions in the access token (see General OAuth 2.0 settings);

      Example of the rule:

      "scopes": ["scope1"]
      

      This example checks if the original access token scopes with the name scope1.

    • userClaims - checks that the attributes of the user account have specified values.

      Example of the rule:

      "userClaims": {"role":"FIN"}
      

      This example checks if a user has the role attribute in the account with the FIN value filled in. Only attributes with String type can be used.

    • userGroups - checks if the user account is part of the specified access groups.

      Example of the rule:

      "userGroups": [
      {
          "name": "admin",
          "profile": "roles"
      }
      ]
      

      This example checks that the user is in the admin access group with roles profile.

  • authClientCond – conditions for replacing client_id. These conditions are only checked for the impersonate rules. The rule verifies that the new application has the permissions to exchange the access token. The requiredRights condition is supported.

    Example of the rule:

    "requiredRights":[
      {
        "rights": ["right1"],
        "target": {
          "type": "its",
          "name": "app1"
        }
      }
    ]
    

    In this example, the calling application checks whether the calling application has the right1 access right with respect to another application (app1). The its parameter in the target setting specifies the type of object against which the access right is checked. Possible values: its - right to an application; grps - right to an access group; no type - right to a user account.

  • issue - rules for issuing a new access token, applied in case the rule was successfully executed. The rules for issuing a new access token consist of:

    • ttlInSec - the lifetime (in seconds) of the issued access token;

    • allowedScopes - the scopes that allowed in the issued access token;

    • allowedClaims - user attributes that allowed in the issued access token;

    • addingScopes - the scopes added to the access token;

    • addingClaims - user attributes added to the access token.

Configuring access token exchange rules#

To define for which protected services which access rules should be applied, you need to add a blitz.prod.local.idp.token-exchange configuration block of the following form in the blitz.prod.local.idp.token-exchange configuration file:

"token-exchange" : {
  "resources" : [
    {
      "uri" : http://secured_service_host/api/service1,
      "methods" : ["GET","POST"],
      "rules" : [
        "rule1",
        "rule2"
      ]
    },
    {
      "audience" : "secured-api",
      "rules" : [
        "rule3"
      ]
    },
    …
  ]
}

In the resources block you need to fill in the settings for each service:

  • rules - list the names of service access rules. Each rule corresponds to its own файл настроек. Access to the service is allowed if at least one of the rules in this list is met. If all the listed rules are not fulfilled, then access to the service will be denied;

  • uri – optional parameter, can specify the address of the protected service. In specifying the service address it is allowed to use an asterisk (*) to skip one component of the address path and a double asterisk (**) to skip the rest of the service address path;

  • methods - optional parameter, specifies the list of HTTP methods of the invoked service;

  • audience – optional parameter, can specify the application name. This value will be included in the issued new access token in the aud attribute. It is mandatory to specify one of the parameters uri or audience.