Spacenet/FreeRADIUS configuration

From RevSpace
Revision as of 20:53, 10 April 2024 by Shiz (talk | contribs) (Fix IPv6 listening (and thus remote SpaceFed logins))
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

The below configuration is used for SpaceNet at RevSpace, written for and tested with FreeRADIUS 3.2.1. The paths are relative to the base configuration directory, e.g. /etc/freeradius/3.0.

README

FreeRADIUS config - RevSpace edition

Operating principle:
  We are federated with SpaceFED (https://spacefed.net/) to provide the 'spacenet' network.
  Our participants can authenticate at any spacenet-compatible access point with their RevSpace LDAP credentials,
  and participants from other hackerspaces can authenticate through their own hackerspace via our access points.
  Usernames are formatted like <username>@<hackerspace.nl>, and the domain part is used to proxy the authentication
  to the correct remote RADIUS server through SpaceFED.

  In order to prevent credential sniffing by the local RADIUS server,
  a tunnel from the client to the remote RADIUS server is setup by means of EAP-TTLS or PEAP,
  and an anonymous outer identity (usually anonymous@<domain>) is used instead to route the request.

  We have three scenarios:
  - RevSpace participant authenticates at RevSpace spacenet:
    User -(802.1X)----------------> Local client (access point)
         -(RADIUS: lan.conf)------> Local server (outer.conf)
         -(EAP-TTLS or PEAP)------> Local server (inner.revspace.conf)
         -(PAP or EAP-GTC)--------> LDAP
  - RevSpace participant authenticates at other location:
    User -(802.1X)----------------> External client (access point)
         -(RADIUS)----------------> External server
         -(RADIUS: spacefed.conf)-> Local server (outer.conf)
         -(EAP-TTLS or PEAP)------> Local server (inner.revspace.conf)
         -(PAP or EAP-GTC)--------> LDAP
  - Spacenet participant authenticates at RevSpace spacenet:
    User -(802.1X)----------------> Local client (access point)
         -(RADIUS: lan.conf)------> Local server (outer.conf)
         -(RADIUS: spacefed.conf)-> External server
         -(EAP-TTLS or PEAP)------> External server

Authentication:
  While we could skip EAP-TTLS or PEAP for local-local authentication, this would make user configuration
  inconsistent between being at RevSpace and at other hackerspaces, defeating the point.
  Thus, we *always* use EAP-TTLS or PEAP as the outer authentication layer.
  Since we do not store LDAP passwords in plain text or a weak hash,
  we need to receive the plaintext password inside the encrypted TLS tunnel to compare it.
  This limits us to one of the following plaintext password mechanisms as the inner layer:
  - PAP
  - EAP-GTC

Configuration structure:
  - radiusd.conf            # main configuration file, generic settings and includes everything
  - modules.d/              # configuration for FreeRADIUS modules
    - realms.conf           #   ! realm /format/ configuration (user@realm)
    - eap.revspace.conf     #   ! EAP configuration (TLS certificates, mechanisms, ...)
    - ldap.revspace.conf    #   ! LDAP configuration (server, RADIUS server DN and password, filters, ...)
  - clients.d/              # configuration for RADIUS clients (entities like access points that talk to us to authenticate a user)
  - realms.d/               # configuration for RADIUS realms (the domain part, to figure out where to route authentication request)
    - default.conf          #   'must-define' realms LOCAL and NULL
    - revspace.conf         #   realms we handle, mostly empty configuration blocks to imply local processing
    - spacefed.conf         #   fallback realm, with instructions to proxy to SpaceFED
  - servers.d/              # configuration for RADIUS servers (that listen on ports and process authentication requests)
    - outer.conf            #   outer unencrypted tunnel, to determine where the request should be proxied towards
    - inner.revspace.conf   #   inner encrypted tunnel, for authenticating RevSpace participants

Debugging:
  As we use TLS, the usual recommended way to run FreeRADIUS in debug mode (`freeradius -X`) will not work.
  TLS on FreeRADIUS requires threads, and `-X` is a shorthand for `-sfxx -l stdout`; `-s` disables threading.
  Instead, use `-fxx -l stdout` when debugging.

radiusd.conf

# Paths

prefix = /usr
exec_prefix = /usr
sysconfdir = /etc
localstatedir = /var
runstatedir = /run
sbindir = ${exec_prefix}/sbin
logdir = ${localstatedir}/log/freeradius
libdir = ${exec_prefix}/lib/freeradius

raddbdir = ${sysconfdir}/freeradius/3.0
radacctdir = ${logdir}/radacct

name = freeradius
confdir = ${raddbdir}
modconfdir = ${confdir}/modules.d
certdir = ${confdir}/pki
cadir   = ${confdir}/pki
run_dir = ${runstatedir}/${name}
db_dir = ${raddbdir}
checkrad = ${sbindir}/checkrad

# Server

pidfile = ${run_dir}/${name}.pid

security {
	user = freerad
	group = freerad
	allow_core_dumps = no
	max_attributes = 200
	# reject immediately (no security delay)
	reject_delay = 0
	# respond to server status requests
	status_server = yes
}

thread pool {
	start_servers = 5
	max_servers = 32
	min_spare_servers = 3
	max_spare_servers = 10
	# unlimited power... err, requests
	max_requests_per_server = 0
	auto_limit_acct = no
}

tls {
	certificate_file = "${certdir}/server.pem"
	private_key_file = "${certdir}/server.key"
	tls_min_version = "1.0"
	tls_max_version = "1.3"
	cipher_list = "DEFAULT@SECLEVEL=0"
	random_file = "/dev/urandom"
}

# Requests

max_request_time = 30
cleanup_delay = 5
max_requests = 16384
hostname_lookups = no
# SPACENET: required!
proxy_requests = yes

# Logging

log {
	destination = stderr
	colourise = yes
	# don't log secrets, even in debug mode
	suppress_secrets = yes

	## please set the fields below to 'no'
	## when not debugging!
	# log authentication
	stripped_names = yes
	auth = no
	auth_accept = no
	auth_reject = no
	# log password attempts
	auth_badpass = no
	auth_goodpass = no

	## debug configuration for above
	#auth = yes
	#stripped_names = no
	#auth_accept = yes
	#auth_reject = yes
	#auth_badpass = yes
	#auth_goodpass = no
}

# Modules
modules {
	$INCLUDE modules.d/
}

# Policy
policy {
	$INCLUDE policy.d/
}

# Clients
$INCLUDE clients.d/
# Realms
$INCLUDE realms.d/
# Servers
$INCLUDE servers.d/


modules.d/

eap.revspace.conf

eap eap.outer {
	default_eap_type = ttls
	timer_expire = 60

	tls-config tls-config {
		certificate_file = ${tls.certificate_file}
		private_key_file = ${tls.private_key_file}
		tls_min_version = ${tls.tls_min_version}
		tls_max_version = ${tls.tls_max_version}
		cipher_list = ${tls.cipher_list}
		random_file = ${tls.random_file}
	}

	ttls {
		tls = tls-config
		virtual_server = server.inner-revspace
		default_eap_type = "gtc"
	}

	peap {
		tls = tls-config
		virtual_server = server.inner-revspace
		inner_eap_module = eap.inner-revspace
		default_eap_type = "gtc"
	}
}

eap eap.inner-revspace {
	default_eap_type = "gtc"
	timer_expire = 60

	gtc {
		auth_type = "PAP"
	}
}

ldap.revspace.conf

ldap ldap.revspace {
	server = "ldaps://ldap2.space.revspace.nl"
	identity = "cn=freeradius,ou=services,dc=space,dc=revspace,dc=nl"
	password = "<EXPUNGED>"
	base_dn = "dc=space,dc=revspace,dc=nl"
	user_dn = "RevSpace-LDAP-UserDn"

	tls {
		ca_path = "/etc/ssl/certs"
	}

	user {
		base_dn = "ou=people,dc=space,dc=revspace,dc=nl"
		scope = "one"
		filter = "(uid=%{%{Stripped-User-Name}:-%{User-Name}})"
	}

	group {
		base_dn = "ou=groups,dc=space,dc=revspace,dc=nl"
		scope = "one"
		filter = ""
		membership_filter = "(member=%{control:${..user_dn}})"
	}

	options {
		dereference = "always"
	}


	update {
		control:Password-With-Header += 'userPassword'
	}

	post-auth {
		update {}
	}

	accounting {}
}

realm.conf

# realm formats

#  'user@realm'
realm realm.email {
	format = suffix
	delimiter = "@"
	ignore_null = yes
}

#  'realm\user'
realm realm.ntdomain {
	format = prefix
	delimiter = "\\"
	ignore_null = yes
}


realms.d/

default.conf

# these entries are needed, but we don't do anything with them
realm LOCAL {
}

realm NULL {
}

revspace.conf

realm revspace.nl {
	# nothing here implies local handling
}

spacefed.conf

home_server nlnode1.spacefed.net {
	type = auth+acct
	ipv6addr = <REDACTED>
	port = 1812
	secret = "<EXPUNGED>"
	require_message_authenticator = yes
	response_window = 5
	zombie_period = 60
	revive_interval = 120
	status_check = status-server
	check_interval = 30
	num_answers_to_alive = 3
	coa {
		# initial retransmit interval (1..5)
		irt = 2
		# maximum retransmit timeout (1..30, 0 == no maximum)
		mrt = 16
		# maximum retransmit count (1..20, 0 == retransmit forever)
		mrc = 5
		# maximum retransmit duration (5..60)
		mrd = 30
	}
}

home_server_pool spacefed-pool {
	type = "client-balance"
	home_server = nlnode1.spacefed.net
}

realm DEFAULT {
	nostrip
	auth_pool = spacefed-pool
}


clients.d/

localhost.conf

# for debugging
client localhost {
	shortname = "localhost"
	ipaddr    = 127.0.0.1
	secret    = "<EXPUNGED>"
	require_message_authenticator = no
	nas_type  = "other"
}

lan.conf

# Ethernet
client lan.poeswitch {
	ipaddr          = 10.42.42.12
	secret          = "<EXPUNGED>"
	shortname       = "poeswitch"
}
# Wi-Fi
client lan.foundrymc1000 {
	ipaddr          = 10.42.62.1
	secret          = "<EXPUNGED>"
	shortname       = "foundrymc1000"
}
client lan.aruba {
	ipaddr          = 10.42.62.3
	secret          = "<EXPUNGED>"
	shortname       = "aruba radius proxy ip"
}

spacefed.conf

client spacefed.nlnode1v6 {
	ipaddr          = <REDACTED>
	secret          = "<EXPUNGED>"
	shortname       = nlnode1v6
}


servers.d/

outer.conf

# outer unencrypted server for PEAP/TTLS
server default {
	# both listen blocks are needed for every server!
	# ipaddr = * is broken

	# radius (1812)
	listen {
		type = auth
		ipv4addr = *
		port = 0  # use /etc/services
		virtual_server = "default"
	}
	listen {
		type = auth
		ipv6addr = ::
		port = 0  # use /etc/services
		virtual_server = "default"
	}
	# radius-acct (1813)
	listen {
		type = acct
		ipv4addr = *
		port = 0  # use /etc/services
	}
	listen {
		type = acct
		ipv6addr = ::
		port = 0  # use /etc/services
	}
	# radsec (2083)
	listen {
		type = auth+acct
		ipv4addr = *
		port = 2083
		proto = tcp
		tls = ${tls}
	}
	listen {
		type = auth+acct
		ipv6addr = ::
		port = 2083
		proto = tcp
		tls = ${tls}
	}

	# auth flow: start
	authorize {
		preprocess

		# this statement decides where the request should be proxied to,
		# through the `pre-proxy` & `post-proxy` flows, or if it should
		# be processed locally through the `authenticate` flow.
		realm.email

		if (!&Realm) {
			update reply {
				Reply-Message := "Please specify a realm to authenticate with."
			}
			reject
		}

		eap.outer
	}

	# auth flow: process local
	authenticate {
		eap.outer
	}

	# auth flow: process remote
	pre-proxy {
		# uncomment when we upgrade to FreeRADIUS 3.2.3/3.3+
		#eap.outer
	}
	post-proxy {
		eap.outer
	}

	# auth flow: end
	post-auth {
		eap.outer
	}


	# acct flow: start
	preacct {
		preprocess
		acct_unique
		realm.email
	}

	# acct flow: local
	accounting {
		attr_filter.accounting_response
	}
}

inner.revspace.conf

# inner encrypted server for EAP-TTLS/PEAP
server server.inner-revspace {
	# for debug purposes
	#listen {
	#	ipaddr = 127.0.0.1
	#	port = 18120
	#	type = auth
	#}


	# auth flow: start
	authorize {
		# split and lookup user and password
		realm.email
		if (Realm != "revspace.nl") {
			reject
		}
		ldap.revspace

		# authentication methods
		eap.inner-revspace
		pap
	}

	# auth flow: process local
	authenticate {
		# lookup user and password
		ldap.revspace

		# authentication methods
		eap.inner-revspace
		Auth-Type PAP {
			pap
		}
	}

	# auth flow: end
	post-auth {
		Post-Auth-Type REJECT {
			attr_filter.access_reject
		}
		ldap.revspace
		eap.inner-revspace
	}
}