/etc/at.allow decides, on its own, who is even allowed to queue a job with at or batch, and its mere presence overrides whatever at.deny says. This guide restricts access with an allow-list, checks which policy the installed tools will actually use, and rolls the change back safely if needed. It follows the at.allow(5) behaviour installed with package at version 3.2.5-2.1ubuntu3 on this machine.
Allow about ten minutes. You need a shell, access to the account policy you are changing, and a clear list of Unix usernames. Reading the files is ordinarily unprivileged. Creating or editing files under /etc normally needs elevated privileges, so check the change before and after using sudo.
Start with read-only checks. None of these submit a job or change either access file:
$ dpkg-query -W -f='${Package} ${Version}\n' at
at 3.2.5-2.1ubuntu3
$ at -V
at version 3.2.5
$ for f in /etc/at.allow /etc/at.deny; do
> if test -e "$f"; then
> printf '%s exists\n' "$f"
> sed -n '1,40p' "$f"
> else
> printf '%s absent\n' "$f"
> fi
> done
The final command may report a file as absent, or that your account cannot read it. Do not infer the policy from a missing line alone. The decisive order is: does /etc/at.allow exist, then what does it contain, then fall back to the deny file.
Checkpoint: write down whether /etc/at.allow exists. If it does, the contents of /etc/at.deny change nothing.
/etc/at.allow is an allow-list. When it exists, only usernames written in that file may use at or batch, one complete username per line.
Whitespace is not permitted by the manual. Keep the file simple: no commas, comments, leading spaces, trailing spaces or group names. For example:
alice
operator
deploy
If /etc/at.allow does not exist, the command checks /etc/at.deny instead. Users named there are blocked, and everyone else is allowed, so an empty at.deny allows every user. If neither file exists, only the superuser may submit jobs.
These are three different states, not three spellings of the same policy.
Before changing access, confirm the usernames with the people who own those accounts: a misspelt name silently fails to grant access. This is a security-sensitive change, since it controls who can schedule commands for later execution.
Use an editor with elevated privileges:
$ sudoedit /etc/at.allow
Replace the file contents with the exact usernames that should be permitted, one per line. For example:
alice
operator
Save the file and exit the editor. Do not add a comment to explain the list: the documented format is a plain list of usernames with no whitespace.
Checkpoint: inspect the saved file and reject accidental blank decoration or spaces.
$ sudo sed -n 'l' /etc/at.allow
alice$
operator$
The dollar signs mark the end of each line. Your output should show the intended names with no leading or trailing spaces. This command only prints the policy; it does not alter it.
The access files are consulted whenever a user submits through at or batch. To test a real user, open a shell as that account and attempt a harmless submission, but only if your change window allows a queued job. Never use a command that writes secrets, stops a service or changes data.
For a read-only policy check, first confirm the account name and file state:
$ id -un
alice
$ sudo cat /etc/at.allow
alice
operator
A listed username is the expected match, but it is not a substitute for testing the installed at command in your own environment. If a user is rejected, check the exact account name from id -un, line endings, and whether another process replaced the file. Do not add the user to both files as a guess: at.allow takes precedence whenever it exists.
Remember that permission to submit a job is not permission to run arbitrary work safely. The job later runs with the submitting user's account context, subject to the system's normal permissions and atd's behaviour. Review submitted commands separately.
Removing /etc/at.allow is a policy change, not a harmless cleanup. Decide first whether the fallback you want is a deny-list or superuser-only. Keep a recoverable copy in a root-readable location approved by your change process, then remove the file with an elevated command:
$ sudo cp --preserve=mode,ownership /etc/at.allow /etc/at.allow.backup
$ sudo rm /etc/at.allow
This removes the active allow-list. The backup is not consulted by at. If /etc/at.deny exists, its rules now apply; if it does not, only the superuser is allowed.
To restore the previous policy, replace the active file from the backup after checking its contents:
$ sudo sed -n 'l' /etc/at.allow.backup
$ sudo cp --preserve=mode,ownership /etc/at.allow.backup /etc/at.allow
Warning: rm is irreversible unless you have that backup or another known copy. Do not run it as part of a first test. If the file gets removed accidentally, restore it before letting users submit jobs under an unintended fallback policy.
An empty at.allow is not the same as an absent at.allow. The empty file permits nobody, while the absent file makes the system consult at.deny instead. An empty at.deny has the opposite effect: every user is allowed.
Do not confuse scheduled jobs with cron entries. This policy controls who may submit one-off jobs through at or batch; it does not describe existing jobs, edit crontabs or stop atd. Changing the access file also does not remove jobs already submitted: review those through your normal at administration process if access has been withdrawn.
Finally, avoid testing with a real destructive command. A policy test should prove who may submit, not that a dangerous payload can run.
at package and version were recorded.