rsync, Part I
Using rsync with SSH is the easiest way to use rsync securely with authenticated users, in a way that both requires and protects the use of real users' accounts. But as I mentioned earlier in the “SFTP and SSH” section [of the book, see Sidebar], SSH doesn't lend itself easily to anonymous access. What if you want to set up a public file server that supports rsync-optimized file transfers?
This is quite easy to do. Create a simple /etc/rsyncd.conf file, and run rsync with the --daemon flag (i.e., rsync --daemon). The devil, however, is in the details. You should configure /etc/rsyncd.conf very carefully if your server will be connected to the Internet or any other untrusted network. Let's discuss how.
rsyncd.conf has a simple syntax; global options are listed at the beginning without indentation. Modules, which are groups of options specific to a particular filesystem path, are indicated by a square-bracketed module name followed by indented options.
Option lines each consist of the name of the option, an equal sign and one or more values. If the option is boolean, allowable values are yes or no (don't be misled by the rsyncd.conf(5) man page, which in some cases refers to true and false). If the option accepts multiple values, these should be comma-space delimited, for example, option1, option2.
Listing 1 is part of a sample rsyncd.conf file that illustrates some options particularly useful for tightening security. Although I created it for this purpose, it's a real configuration file and syntactically complete. Let's dissect it.
As advertised, the global options are listed at the top. The first option set also happens to be the only global-only option: syslog facility, motd file, log file, pid file and socket options may be used only as global settings, not in module settings. Of these, only syslog facility has direct security ramifications. Like the ProFTPD directive SyslogFacility, rsync's syslog facility can be used to specify which syslog facility rsync should log to if you don't want it to use daemon, its default.
For detailed descriptions of the other global-only options, see the rsyncd.conf(5) man page; I won't cover them here, as they don't directly affect system security, and their default settings are fine for most situations, anyhow.
All other allowable rsyncd.conf options can be used as global options, in modules or both. If an option appears in both the global section and in a module, the module setting overrides the global setting for transactions involving that module. In general, global options replace default values, and module-specific options override both default and global options.
The second group of options falls into the category of module-specific options.
use chroot = yes: if use chroot is set to yes, rsync will chroot itself to the module's path prior to any file transfer, preventing or at least hindering certain types of abuses and attacks. This has the trade-off of requiring that rsync --daemon be started by root, but by also setting the uid and gid options, you can minimize the amount of the time rsync uses its root privileges. The default setting is yes.
uid = nobody: the uid option lets you specify with which user's privileges rsync should operate during file transfers, and it therefore affects which permissions will be applicable when rsync attempts to read or write a file on a client's behalf. You may specify either a user name or a numeric user ID. The default is -2, which is nobody on many systems, but not on mine, which is why uid is defined explicitly.
gid = nobody: the gid option lets you specify with which group's privileges rsync should operate during file transfers, and it therefore affects (along with uid) which permissions apply when rsync attempts to read or write a file on a client's behalf. You may specify either a user name or a numeric user ID; the default is -2 (nobody on many systems).
max connections = 20: this limits the number of concurrent connections to a given module (not the total for all modules, even if set globally). If specified globally, this value will be applied to each module that doesn't contain its own max connections setting. The default value is zero, which places no limit on concurrent connections. I do not recommend leaving it at zero, as this makes Denial-of-Service (DoS) attacks easier.
timeout = 600: the timeout also defaults to zero, which in this case also means “no limit”. Since timeout controls how long (in seconds) rsync will wait for idle transactions to become active again, this also represents a DoS exposure and should likewise be set globally (and per module, when a given module needs a different value for some reason).
read only = yes: the last option defined globally is read-only, which specifies that the module in question is read-only, i.e., that no files or directories may be uploaded to the specified directory, only downloaded. The default value is yes.
The third group of options defines the module [public]. These, as you can see, are indented. When rsync parses rsyncd.conf downward, it considers each option below a module name to belong to that module until it reaches either another square-bracketed module name or the end of the file. Let's examine each of the module [public]'s options, one at a time.
[public]: this is the name of the module. No arguments or other modifiers belong here: just the name you wish to call this module, in this case public.
path = /home/public_rsync: the path option is mandatory for each module, as it defines which directory the module will allow files to be read from or written to. If you set the global option use_chroot to yes, this is the directory rsync will chroot to prior to any file transfer.
comment = Nobody home but us tarballs: this string will be displayed whenever a client requests a list of available modules. By default there is no comment.
hosts allow = near.echo-echo-echo.org, 10.18.3.12 and hosts deny = *.echo-echo-echo.org, 10.16.3.0/24: you may, if you wish, use the hosts allow and hosts deny options to define Access Control Lists (ACLs). Each accepts a comma-delimited list of FQDNs or IP addresses from which you wish to explicitly allow or deny connections. By default, neither option is set, which is equivalent to “allow all”. If you specify an FQDN, which may contain the wildcard *, rsync will attempt to reverse-resolve all connecting clients' IP addresses to names prior to matching them against the ACL.
rsync's precise interpretation of each of these options depends on whether the other is present. If only hosts allow is specified, then any client whose IP or name matches will be allowed to connect, and all others will be denied. If only hosts deny is specified, then any client whose IP or name matches will be denied, and all others will be allowed to connect.
If, however, both hosts allow and hosts deny are present, hosts allow will be parsed first, and if the client's IP or name matches, the transaction will be passed.
If the IP or name in question didn't match hosts allow, then hosts deny will be parsed, and if the client matches there, the transaction will be dropped.
If the client's IP or name matches neither, it will be allowed.
In this example, both options are set. They would be interpreted as follows:
Requests from 10.18.3.12 will be allowed, but requests from any other IP in the range 10.16.3.1 through 10.16.3.254 will be denied.
Requests from the host near.echo-echo-echo.org will be allowed, but everything else from the echo-echo-echo.org domain will be rejected. Everything else will be allowed.
ignore nonreadable = yes: any remote file for which the client's rsync process does not have read permissions (see the uid and gid options) will not be compared against the client's local copy thereof. This probably enhances performance more significantly than security; as a means of access control, the underlying file permissions are more important.
refuse options = checksum: the refuse options option tells the server-side rsync process to ignore the specified options if specified by the client. Of rsync's command-line options, only checksum has an obvious security ramification. It tells rsync to calculate CPU-intensive MD5 checksums in addition to its normal rolling checksums, so blocking this option reduces certain DoS opportunities. Although the compress option has a similar exposure, you can use the dont compress option to refuse it rather than the refuse options option.
dont compress = *: you can specify certain files and directories that should not be compressed via the dont compress option. If you wish to reduce the chances of compression being used in a DoS attempt, you also can specify that nothing be compressed by using an asterisk (*), as in our example.
This simple example should get you started offering files for download by rsync. Next month, we'll cover setting up rsync modules (directories) at the filesystem level to accept anonymous uploads and authenticate users.
Mick Bauer (firstname.lastname@example.org) is a network security consultant for Upstream Solutions, Inc., based in Minneapolis, Minnesota. He is the author of the O'Reilly book Building Secure Servers with Linux, composer of the “Network Engineering Polka” and a proud parent (of children).