SLURM

Introduction

There are reasons why you might legitimately want to modify the RPKI assertions validated and published by an RTR server:

  • To assert the validity of private IP addresses and/or AS numbers for local use. (Since they are outside of the scope of the global RPKI.)
  • To override temporarily incorrect or outdated global RPKI data.

The “Simplified Local Internet Number Resource Management with the RPKI” (SLURM) is a standard means to accomplish this. In a nutshell, it’s just a bunch of JSON files with which you can filter out or append arbitrary ROAs to FORT validator’s RTR payload.

Note that, with the exception of the following section, most of this document is just a summary of RFC 8416. You can find more details there.

Handling of SLURM Files

The SLURM files are defined by the --slurm flag. If the flag points to a file, the configuration is extracted from that single file. If it points to a directory, the configuration is the aggregation of the contents of its contained .slurm files.

None of the entries of the SLURM configuration are allowed to collide with each other. If there is a collision, the overall SLURM configuration is invalidated.

FORT validator reloads the SLURM files during every validation cycle. If the new configuration is invalid (due to either a syntax or content error) the validator will fall back to the previous valid SLURM configuration, and will log a message to indicate this action.

File Definition

Root

Each SLURM file is a JSON-formatted collection of filters and/or additions. Each of the members shown is mandatory:

{
	"slurmVersion": 1,

	"validationOutputFilters": {
		"prefixFilters": [ <Removed ROAs> ],
		"bgpsecFilters": [ <Removed Router Keys> ]
	},

	"locallyAddedAssertions": {
		"prefixAssertions": [ <Added ROAs> ],
		"bgpsecAssertions": [ <Added Router Keys> ]
	}
}

The root object contains a slurmVersion field (which, for now, must be set to 1), a listing of filters called validationOutputFilters, and a listing of additions called locallyAddedAssertions.

prefixFilters

<Removed ROAs> expands to a sequence of (zero or more) JSON objects, each of which follows this pattern:

{
	"prefix": <IP prefix>,
	"asn": <AS number>,
	"comment": <Explanatory comment>
}

Any ROAs that match prefix and asn will be invalidated. A ROA matches prefix by having an equal or more specific IP prefix, and asn by having the same AS number.

One of prefix and asn can be absent. On absence, any prefix matches prefix, and any AS number matches asn.

comment is always optional.

bgpsecFilters

<Removed Router Keys> expands to a sequence of (zero or more) JSON objects, each of which follows this pattern:

{
	"asn": <AS number>,
	"SKI": <Base64 of some SKI>,
	"comment": <Explanatory comment>
}

Any Router Keys that match asn and SKI will be invalidated. A Router Key matches asn by having the same AS number and SKI by having the same decoded Subject Key Identifier.

One of asn and SKI can be absent. On absence, any AS number matches asn, and any Subject Key Identifier matches SKI.

comment is always optional.

prefixAssertions

<Added ROAs> expands to a sequence of (zero or more) JSON objects, each of which follows this pattern:

{
	"prefix": <IP prefix>,
	"asn": <AS number>,
	"maxPrefixLength": <Prefix length>
	"comment": <Explanatory comment>
}

Will force the validator into believing that the [prefix, asn, maxPrefixLength] ROA validated successfully.

prefix and asn are mandatory, maxPrefixLength and comment are not. maxPrefixLength defaults to prefix’s length.

bgpsecAssertions

<Added Router Keys> expands to a sequence of (zero or more) JSON objects, each of which follows this pattern:

{
	"asn": <AS number>,
	"SKI": <Base64 of some SKI>,
	"routerPublicKey": <Base64 of some public key>,
	"comment": <Explanatory comment>
}

Will force the validator into believing that the [asn, SKI, routerPublicKey] Router Key validated successfully.

Only comment isn’t mandatory, the rest [asn, SKI, routerPublicKey] are mandatory.

File Example

{
	"slurmVersion": 1,

	"validationOutputFilters": {
		"prefixFilters": [
			{
				"prefix": "192.0.2.0/24",
				"comment": "All VRPs encompassed by prefix"
			}, {
				"asn": 64496,
				"comment": "All VRPs matching ASN"
			}, {
				"prefix": "198.51.100.0/24",
				"asn": 64497,
				"comment": "All VRPs encompassed by prefix, matching ASN"
			}
		],
		"bgpsecFilters": [
			{
				"asn": 64496,
				"comment": "All keys for ASN"
			}, {
				"SKI": "Q8KMeBsCto1PJ6EuhowleIGNL7A",
				"comment": "Key matching Router SKI"
			}, {
				"asn": 64497,
				"SKI": "g5RQYCnkMpDqEbt9WazTeB19nZs",
				"comment": "Key for ASN 64497 matching Router SKI"
			}
		]
	},

	"locallyAddedAssertions": {
		"prefixAssertions": [
			{
				"asn": 64496,
				"prefix": "198.51.100.0/24",
				"comment": "My important route"
			}, {
				"asn": 64496,
				"prefix": "2001:DB8::/32",
				"maxPrefixLength": 48,
				"comment": "My important de-aggregated routes"
			}
		],
		"bgpsecAssertions": [
			{
				"asn": 64496,
				"SKI", "Dulqji-sUM5sX5M-3mqngKaFDjE",
				"routerPublicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE-rkSLXlPpL_m-L7CfCfKrv1FHrM55FsIc8fMlnjHE6Y5nTuCn3UgWfCV6sYuGUZzPZ0Ey6AvezmfcELUB87eBA",
				"comment": "My known key for my important ASN"
			}
		]
	}
}