Skip to content
Snippets Groups Projects
Emanuele Aina's avatar
Emanuele Aina authored
The buildah/buildah image has seen its last update 4 years ago.

Switch to the official Skopeo image instead

Signed-off-by: Emanuele Aina's avatarEmanuele Aina <emanuele.aina@collabora.com>
98a46fcf
History

AuthZ mediator

This repository contains authorization mediator implementation for Apertis Platform infrastructure.

Prerequisites

Dependencies

  • OIDC Provider (e.g. Dex IdP)
  • Service that requires authorization (e.g. GitLab)

Configuration

Required

AuthZ mediator requires following parameters to run:

  1. OIDC Client secret declared in OIDC Provider
  2. Self listen address (to pass it to the service that requires authorization)
  3. OIDC Provider URL (used for token origin verification)
  4. Service authorization callback URL (to redirect tokens)
  5. Membership mapping backend

When using GitLab group membership mapping backend an API token is required as well.

Both OIDC Client secret and GitLab API token are expected to be set in AuthZ mediator environment (as AUTHZ_MEDIATOR_SECRET and GITLAB_SECRET, respectively).

Remaining required parameters can be set either in the configuration file or in the environment (environment takes precedence over configuration file):

Parameter Configuration Environment
Provider URL provider AUTHZ_MEDIATOR_PROVIDER
Self address mediator AUTHZ_MEDIATOR_SELF
Callback URL redirect AUTHZ_MEDIATOR_REDIRECT
Mapping backend backend AUTHZ_MEDIATOR_BACKEND

Configuration file path can be passed to the AuthZ mediator as an argument for -config flag. Configuration file example is available in authz-mediator.yaml.sample.

Optional

Additional parameters can be used to adjust AuthZ mediator to custom needs:

  • Mediator ID (to register OIDC Client on OIDC Provider)
  • Extend scope request with groups (YAML boolean: yes/true or no/false)
  • API calls retries number to verify user presence (integer)
  • API calls interval to verify user presence (integer; milliseconds)
  • Port for the mediator to listen on
  • Group mapping: if specified, groups listed here are renamed according to the mapping
  • Groups the logging in user must be a member of (glob-style patterns are accepted; processed after the mapping)
  • Groups to be synchronised ("included groups"): only the groups matching one or more of the patterns are be processed; if no pattern is specified, nothing will be processed at all.
  • Whether group membership should be enforced by periodically re-checking it against the source and blocking users when they’re no longer members of the required groups (available for MS Graph API only). The interval can be specified as an integer with a duration unit such as s, m, h: 10s, 15m, 3h. The shortest allowed interval is one minute.
  • When enforcing group membership, rules shouldn’t apply to the mediator’s own user, if one exists — this username defaults to mediator, but can be specified in the configuration file only. If the mediator doesn’t use a dedicated user, set the username to any invalid username, e.g. !.

These parameters can also be set either in the configuration file or in the environment (environment takes precedence over configuration file):

Parameter Configuration Environment
Mediator ID id AUTHZ_MEDIATOR_ID
Groups Scope groups AUTHZ_MEDIATOR_GROUPS
API retries retries AUTHZ_MEDIATOR_RETRIES
API backoff backoff AUTHZ_MEDIATOR_BACKOFF
Server port port AUTHZ_MEDIATOR_PORT
Group mapping group_map AUTHZ_MEDIATOR_GROUP_MAP
Included groups included_groups AUTHZ_MEDIATOR_INCLUDED_GROUPS
Required groups required_groups AUTHZ_MEDIATOR_REQUIRED_GROUPS
Enforce groups enforce_groups AUTHZ_MEDIATOR_ENFORCE_GROUPS
Enforcement interval enforce_groups_interval AUTHZ_MEDIATOR_ENFORCE_GROUPS_INTERVAL
Usernames to be skipped enforce_groups_ignore_users AUTHZ_MEDIATOR_ENFORCE_GROUPS_IGNORE_USERS
Don't actually lock users enforce_groups_audit_only AUTHZ_MEDIATOR_ENFORCE_GROUPS_AUDIT_ONLY
Mediator username mediator_username AUTHZ_MEDIATOR_USERNAME

When the group mapping is passed through the environment, use YAML/JSON mapping notation. Group lists are passed as space-separated lists.

Extending scope request can also be set by a command line flag -groups which takes precedence over environment variable and configuration file.

Standalone deployment example

Have a look at docker-compose.yaml file. It can be used an evaluation environment for AuthZ mediator.

Key parameters to adjust are described below.

OIDC Provider: Dex IdP

Mount dex.config.tmpl as /etc/dex/config.docker.yaml and use following environment:

DEX_ISSUER=http://${oidc-provider}:${oidc-provider-port:-5556}/dex
DEX_STATIC_CLIENT_ID=authz-mediator
DEX_STATIC_CLIENT_REDIRECT_URI=http://${mediator}:${mediator-port:-5555}/callback
DEX_STATIC_CLIENT_NAME='Authorization mediator'
DEX_STATIC_CLIENT_SECRET=${MEDIATOR_SECRET}

Remember to open ${oidc-provider-port} declared in DEX_ISSUER.

Service requiring authorization: GitLab

Seed GitLab configuration using following example:

GITLAB_HTTPS: 'false'
GITLAB_ROOT_PASSWORD: ${GITLAB_PASSWD}
GITLAB_OMNIBUS_CONFIG: |
    external_url 'http://gitlab'
    gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']
    gitlab_rails['omniauth_block_auto_created_users'] = false
    gitlab_rails['omniauth_auto_link_user'] = ['openid_connect']
    gitlab_rails['omniauth_providers'] = [
        {
            'name' => 'openid_connect',
            'label' => 'Test OpenID-Connect',
            'args' => {
                'name' => 'openid_connect',
                'scope' => ['openid', 'profile', 'email'],
                'response_type' => 'code',
                'issuer' => 'http://${oidc-provider}:${oidc-provider-port:-5556}/dex',
                'discovery' => false, # GitLab discovery expects HTTPS
                'uid_field' => 'preferred_username',
                'client_options' => {
                    'identifier' => 'authz-mediator',
                    'secret' => '${MEDIATOR_SECRET}',
                    'redirect_uri' => 'http://${mediator}:${mediator-port:-5555}/callback',
                    'authorization_endpoint' => 'http://${mediator}:${mediator-port:-5555}/auth',
                    'token_endpoint' => 'http://${mediator}:${mediator-port:-5555}/token',
                    'userinfo_endpoint' => 'http://${mediator}:${mediator-port:-5555}/userinfo',
                    'jwks_uri' => 'http://${mediator}:${mediator-port:-5555}/keys'
                }
            }
        }
    ]

Note that for the OpenID-Connect spec basic is the default client auth method if no different mechanism is configured at the client registration time.

Quoting the GitLab documentation:

  • client_auth_method (optional) specifies the method used for authenticating the client with the OpenID Connect provider.
    • Supported values are:
      • basic - HTTP Basic Authentication.
      • jwt_bearer - JWT-based authentication (private key and client secret signing).
      • mtls - Mutual TLS or X.509 certificate validation.
      • Any other value posts the client ID and secret in the request body.
    • If not specified, this value defaults to basic.

Remember to open 80 port and create API token for later use by the AuthZ mediator.

AuthZ mediator

Use following environment (when working with Dex IdP and GitLab):

GITLAB_SECRET=${GITLAB_API_TOKEN}
AUTHZ_MEDIATOR_SECRET=${MEDIATOR_SECRET}
AUTHZ_MEDIATOR_SELF=http://${mediator}:${mediator-port:-5555}
AUTHZ_MEDIATOR_PROVIDER=http://${oidc-provider}:${oidc-provider-port:-5556}/dex
AUTHZ_MEDIATOR_REDIRECT=http://${service:-gitlab}/${authz-callback:-users/auth/openid_connect/callback}

Remember to open ${mediator-port} declared in AUTHZ_MEDIATOR_SELF.

High level design

AuthZ mediator consists of three base components:

  1. Main command which collects mediator configuration and reports fatal conditions if any
  2. Five handlers for relaying traffic between OIDC Provider and a service that requires authorization
  3. Membership mapping backend for supported service

Relayed traffic is snooped twice:

  1. To add request for groups scope (if required and explicitly set in mediator configuration) - modifies traffic
  2. To extract code required for token exchange - read-only, not affecting traffic

Membership mapping is run as a separate goroutine from request handling and does not affect user authorization. Please note that this requires additional checks for user availibility in membership mapping because it may start before user initialization is completed.

Implementation overview

Handlers

The main goal for handler functions was to be transparent for both OIDC Provider and the service. This is why there are as few interactions as possible with the relayed traffic. Handlers mostly ensure that no important information is missing from passed requests.

Currently only ID token is used for membership mapping. Additional information can be read from mediator.TokenResponse returned from mediator.(*Mediator).exchange().

Service API

Service support is provided by a pair of structures:

  • Low-level service API client
  • High-level service logic handler (implementing mediator.MediatorBackend interface)

This way handling service logic can be tested without actual service instance but with a mockup instead. Reducing pairs of structures to simpler architecture with single mapper and service clients with unified error handling could require too much resources when number of supported backends increases.

Configuration options

When introducing new configuration options it is worth to consider:

  • Can it be safely put in the configuration file?
  • Can it be assigned a sane default value?

Getting values from environmental variables is encouraged for easy cloud-native migration.