@pipeline

Reusable named pipelines

The @pipeline block allows defining reusable named pipelines that can be invoked from multiple places in the configuration. This is useful for defining common processing logic that can be shared across different policies or handlers.

Note: The @pipeline prefix is the recommended syntax. The bare pipeline and template keywords are deprecated and emit warnings. Use @pipeline for new configurations.

Pipelines are defined inside an aaa block but can be placed in a different configuration file from the handlers that invoke them. Radiator loads all .radconf files from the configuration directory in alphabetical order and merges their aaa blocks, so a pipeline defined in one file is available to any handler in another file. A common pattern is to keep pipeline definitions in an early-loading file (for example 15_logging-pipelines.radconf) and invoke them from policy files that load later (for example 50_policies.radconf).

Examples

Logging

A common use case is to define a reusable logging pipeline:

aaa {
    @pipeline "LOG_AUTHENTICATION" {
        log "AUTHENTICATION" {
            json {
                "Timestamp" datetime.timestamp;
                "AAA-Identity" aaa.identity;
                "AAA-Method" aaa.method;
                "Reason" aaa.reason;
                "Result" "%{aaa.result}";
                "Errors" "%{aaa.errors}";
            }
        }
    }
}

The pipeline is invoked using the invoke action:

@final-execute {
    invoke "LOG_AUTHENTICATION";
}

LDAP bind authentication

Pipelines can contain any actions, including backend calls. For example, define a reusable LDAP bind authentication pipeline that first searches for the user's DN and then binds with the user's password:

aaa {
    @pipeline "LDAP_BIND_AUTH" {
        backend { name "LDAP"; query "FIND_USER"; }
        backend { name "LDAP"; query "BIND_USER"; }
    }
}
@execute {
    invoke "LDAP_BIND_AUTH";
}

Shared configuration variables

Pipelines can also be used to set shared configuration variables that multiple handlers need. For example, define a pipeline that sets common credential variables:

aaa {
    @pipeline "SET_CREDENTIALS" {
        modify {
            vars.aaa.oauth2.token-url = "https://example.com/oauth2/v2.0/token";
            vars.aaa.oauth2.client = "APPLICATION_ID";
            vars.aaa.oauth2.secret = "APPLICATION_SECRET";
        }
    }
}

Then invoke it at the beginning of a handler's execute block:

@execute {
    invoke "SET_CREDENTIALS";

    backend {
        name "MY_OAUTH2_BACKEND";
        query "AUTH_USERS";
    }
}

Passing variables to pipelines

Named pipelines do not support arguments, but you can simulate them by setting vars.* values before invoking the pipeline. The pipeline then reads those variables to customize its behavior.

For example, define a reusable VLAN assignment pipeline that reads the VLAN ID from a variable:

aaa {
    @pipeline "ASSIGN_VLAN" {
        modify {
            radius.reply.attr.Tunnel-Type:1 = "VLAN";
            radius.reply.attr.Tunnel-Medium-Type:1 = "Ether_802";
            radius.reply.attr.Tunnel-Private-Group-Id:1 = vars.vlan_id;
        }
    }
}

Each handler sets the desired VLAN ID before invoking the pipeline:

@execute {
    modify vars.vlan_id = "100";
    invoke "ASSIGN_VLAN";
}
@execute {
    modify vars.vlan_id = "200";
    invoke "ASSIGN_VLAN";
}