diff options
Diffstat (limited to '')
-rw-r--r-- | raddb/certs/realms/README.md | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/raddb/certs/realms/README.md b/raddb/certs/realms/README.md new file mode 100644 index 0000000..9f754fa --- /dev/null +++ b/raddb/certs/realms/README.md @@ -0,0 +1,235 @@ +# Multiple Certificate Chains + +As of version 3.0.24, FreeRADIUS supports loading multiple certificate +chains, keyed by a realm name. These chains are in _addition_ to the +default certificates loaded by the `tls` section. + +Loading multiple certificate chains means that the server can have +different identities. i.e. When a user `bob@example.com` requests +network access, the server can present an `example.com` certificate. +On the other hand, when a user `doug@example.org` requests network +access, the server cna present an `example.org` certificate. + +This functionality means that it is possible to configure only one +`eap` module, and then use multiple certificate chains. Previous +versions of the server required that the administrator configure +multiple EAP modules, one for each certificate being used. + +The selection can be performed in one of two ways. First, the +certificates can be loaded dynamically at run-time. Second, the +certificates can be pre-loaded for speed. + +## Dynamic Loading of Certificate Chains + +The server can dynamically load a certificate chain by setting a +special attribute. This has to be done _after_ the server has +received the EAP identity request, and _before_ the TLS session setup +has started. + +The simplest way to do this is via the following `unlang` statements: + +``` +authenticate { + ... + Auth-Type eap { + if ("%{unpack:&EAP-Message 4 byte}" == 1) { + update control { + TLS-Session-Cert-File := "${certdir}/realms/%{Realm}" + } + } + + eap + } + ... +} +``` + +This configuration looks at the `EAP-Message` attribute, and checks if +it is an EAP-Identity packet. If so, it then adds a special attribute +`TLS-Session-Cert-File`, with a value based on the `Realm`, from the +`User-Name`. That setting tells the server to look in the file for a +certificate. + +If the file is there, and contains a correctly formatted `PEM` +certificate chain, then it is loaded and used. + +If the file does not exist, or the file does not contain a correctly +formatted `PEM` certificate chain, then the user is rejected. + +### Format + +This file should contain the server certificate, followed by +intermediate certificates, in order. i.e. If we have a server +certificate signed by CA1, which is signed by CA2, which is signed by +a root CA, then the "certificate_file" should contain server.pem, +followed by CA1.pem, followed by CA2.pem. + +When using `ca_file` or `ca_dir`, the file should contain only the +server certificate. + +### Private Key + +The private should be placed in the same file as the other +certificates, but at the start. + +``` +private key +server cert +... +ca cert +``` + +The private key can also be placed into a separate file. The filename +should be placed into the `TLS-Session-Cert-Private-Key-File` +attribute. + +For simplicity, the private keys _should not_ have passwords. There +is essentially no security benefit to "securing" the key with a +password, and then placing the password into the file system, right +next to the private key. + +### Realms + +There is no need to place the certificates into files named for each +realm. However, it is by far and away the easiest way to manage these +certificate chains. + +For every realm which is handles this way, the `proxy.conf` file +should define a _local_ realm. That is, it should contain a +definition such as: + +``` +example.org { +} +``` + +This defines the realm `example.org`, and tells FreeRADIUS that there +are no home servers associated with the realm. + +The `suffix` module should also be configured, as per the default +configuration. i.e. list `suffix` in the `authorize` section _before_ +the `eap` module. + +### Caveats + +The root CA certificate for the server certificate should be located +in the `ca_dir`, along with other root CAs. If the root CA is not +there, then it *must* be included at the end of the file. + +These certificates will be loaded and parsed _for every matching +authentication request_. That limitation means that dynamic loading +of the certificates is likely be slow, and to severely impact +performance. The good news is that we can fix that with a little more +configuration. + +## Preloading Certificate Chains + +The server can also pre-load certificate chains. In the EAP module, +you can do: + +``` +eap { + ... + tls { + ... + realm_dir = ${certdir}/realms/ + ... + } + ... +} +``` + +Each file in that directory should be a `PEM` encoded certificate +chain, as described in the previous section. For safety, every file +*must* have a `.pem` as the filename extension. +e.g. `example.org.pem`. + +If there is a corresponding private key, it should be placed into a +`.key` file. e.g. `example.org.key`. + +These certificates will be loaded when the server starts, and cached +for the lifetime of the server. There is no way to reload these +certificates dynamically, the server must be restarted. + +Once the `realm_dir` configuration has been added, the selection of +certificates is identical to that described in the previous section. +Just set `TLS-Session-Cert-File`, and the server will figure it out. + +However, it is possible to dynamically add new certificate, and have +the server pick it up. In fact, as the process for choosing +certificates are the same, the server will do this automatically! + +## RadSec + +The above configuration applies to RadSec, too, as the `tls` +configuration in the server is for all TLS functionality, and not just +EAP. + +This means that the server can accept RadSec connections, and then +present different server certificates to different clients. + +For this functionality to work, the certificates for EAP and RadSec +*should* be in separate directories. + +### Clients + +RadSec clients can set the SNI to send in the `tls` subsection of the +`home_server` definition. Look for "SNI" in `sites-available/tls`, +and see the `hostname` configuration item for documentation. + +For example, an identity provider could host multiple sites, but +present itself with one public IP address. If the RadSec clients do +not use SNI, then they must be configured with the certificate of the +identity provider. + +When SNI is used, the RadSec clients can be configured with the +certificate of the hosted system that they're connecting to. This +ability means that there is no need to change certificates when +changing providers. In addition, there is no need to change the +configuration of all RadSec clients when the hosting system changes +its certifiates. Because the hosting system certificates are never +used. + +Instead, each hosted company is responsible for its own certificates, +and for its own RadSec clients. + +SNI also permits the use of a load balancer such as haproxy. That +load balancer can terminate the TLS connection, and then use SNI to +route the underlying RADIUS TCP traffic to a particular host. + +### Servers + +See the `realm_dir` configuration item in the `tls` subsection for the +location of the server certificates. + +If the server receives an SNI for a realm it does not recognize, it +will just use the default TLS configuration. + +If the realm is recognized (i.e. there is a file in +`${realm_dir}/%{TLS-Server-Name-Indication}.pem`, then that certificate will be chosen, and +present to the RadSec client. If there is no such file, then the +default TLS configuration is used. + +The current behavior is to _require_ that the server certificate is in +a file which taken from +`${realm_dir}/%{TLS-Server-Name-Indication}.pem`. Only the +`realm_dir` portion of the filename is configurable. The SNI portion +is taken from the TLS messages, and the `.pem` suffix is hard-coded in +the source code. + +Taking the filename from an untrusted source is fine here. The +standard (RFC 6066 Section 3) says that the Server Name Indication +field is a DNS "A label". Which means that there are a limited number +of characters allowed: + +* `.`, `-`, `a-Z`, `A-Z`, `0-9` + +If the SNI contain anything else, the TLS connection is rejected. + +Note that if session resumption is enabled for RadSec, the session +cache *must* also cache the `TLS-Server-Name-Indication` attribute. +The SNI is sent on resumption for TLS 1.2 and earlier, but it is not +sent for TLS 1.3. As such, the only way to select the right policy on +resumption is to check the value of the cached +TLS-Server-Name-Indication attribute. + |