AppArmor is a Mandatory Access Control (MAC) system which confines programs to a limited set of resources. AppArmor confinement is provided via profiles loaded into the kernel. AppArmor can be set to either enforce the profile or complain when profile rules are violated.
For this tutorial, we will generate an AppArmor profile for certspotter. certspotter is a new utility in Ubuntu as of 17.10 and no profile yet exists. certspotter monitors certificate transparency logs to see if new certificates have been generated for domains listed in a watchlist. Users of certspotter are encouraged to set up a cron job to regularly monitor new entries. I want to use this useful utility, but I haven’t had a chance to browse the source code, so I want to limit what it can do on my system.
Ready? Let’s get started!
AppArmor profiles are simple text files. Absolute paths as well as file globbing can be used when specifying file access. Most file access rules specify the type of access which is allowed: ‘r’ (read), ‘w’ (write), ’m' (memory map as executable), ‘k’ (file locking), ‘l’ (creation hard links), and ‘ix’ to execute another program with the new program inheriting policy. Other file access rules also exist such as ‘Px’ (execute under another profile, after cleaning the environment), ‘Cx’ (execute under a child profile, after cleaning the environment), and ‘Ux’ (execute unconfined, after cleaning the environment).
AppArmor supports access controls for:
In addition:
@{HOME}
can be defined and manipulated outside the profile (#include <tunables/global>
for @{PROC}
and @{HOME}
)@{HOME}/bin/bad.sh
is denied with auditing due to audit deny @{HOME}/bin/** mrwkl,
even though general access to @{HOME}
is permitted with @{HOME}/** rw,
)#include <abstractions/base>
, #include <abstractions/nameservice>
, #include <abstractions/user-tmp>
)To get started, let’s install some useful AppArmor utilities and the application that we want to confine:
sudo apt install apparmor-easyprof apparmor-notify apparmor-utils certspotter
The easiest way to get started is to create a skeleton profile, set AppArmor to complain mode for your target and then use the aa-logprof
tool to evaluate the denials.
We’ll use aa-easyprof
to generate the skeleton policy; let’s see what it generates (be sure to specify the absolute path to the application):
$ aa-easyprof /usr/bin/certspotter
# vim:syntax=apparmor
# AppArmor policy for certspotter
# ###AUTHOR###
# ###COPYRIGHT###
# ###COMMENT###
#include <tunables/global>
# No template variables specified
"/usr/bin/certspotter" {
#include <abstractions/base>
# No abstractions specified
# No policy groups specified
# No read paths specified
# No write paths specified
}
Looks pretty basic, so let’s write that output into the profile file (the name of the file can be anything; it is the contents of the file which matter):
$ aa-easyprof /usr/bin/certspotter > usr.bin.certspotter
$ sudo mv usr.bin.certspotter /etc/apparmor.d
and then load the profile into the kernel:
$ sudo apparmor_parser -r /etc/apparmor.d/usr.bin.certspotter
Trying to run certspotter, results in an immediate (safe) crash.
$ certspotter
certspotter: /home/testuser/.certspotter/watchlist: open /home/testuser/.certspotter/watchlist permission denied
This basic profile doesn’t allow certspotter access to resources it needs, so let’s look at the AppArmor denial messages to see what went wrong.
AppArmor denials are logged to /var/log/syslog
(or /var/log/audit/audit.log
for non-DBus policy violations if auditd is installed). The kernel will rate limit AppArmor denials which can cause problems while profiling. You can avoid this by installing auditd or by adjusting rate limiting in the kernel:
$ sudo sysctl -w kernel.printk_ratelimit=0
Another way to to view AppArmor denials is by using the aa-notify tool. aa-notify is a very simple program that will report any new AppArmor denials by consulting /var/log/syslog
(or /var/log/audit/audit.log
if auditd is installed). For example,
$ /usr/bin/aa-notify -s 1 -v
will show any AppArmor denials within the last day.
We are going to take the easy route to develop this profile and use the aa-logprof
tool to evaluate the log entries that AppArmor makes in complain mode, so let’s set the AppArmor profile for certspotter to complain mode for this policy so that we can see what is happening.
$ sudo aa-complain certspotter
Now let’s try running certspotter again:
$ certspotter
It immediately starts generating AppArmor entries in the logs that look like this:
Feb 23 13:34:24 tutorials audit[18643]: AVC apparmor="ALLOWED" operation="recvmsg" profile="/usr/bin/certspotter" pid=18643 comm="certspotter" laddr=10.0.2.15 lport=46314 faddr=10.0.2.16 fport=443 family="inet" sock_type="stream" protocol=6 requested_mast="receive" denied_mask="receive"
because we haven’t yet created the profile rules to allow it to access the network.
The aa-logprof
tool will parse the AppArmor messages and suggest policy rules which would permit certspotter to run under confinement.
$ sudo aa-logprof
Reading log entries from /var/log/syslog.
Updating AppArmor profiles in /etc/apparmor.d.
Complain-mode changes:
Profile: /usr/bin/certspotter
Path: /proc/sys/net/core/somaxconn
New Mode: r
Severity: 6
[1 - /proc/sys/net/core/somaxconn r,]
(A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xtension / (N) ew / Audi(t) / Abo(r)t / (F)inish
A
There is no problem with letting certspotter read this file which specifies the maximum number of open socket connections, so we type A to allow it.
Profile: /usr/bin/certspotter
Path: /etc/nsswitch.conf
New Mode: r
Severity: unknown
[1 - #include <abstractions/nameservice>]
2 - /etc/nsswitch.conf r,
(A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xtension / (N) ew / Audi(t) / Abo(r)t / (F)inish
A
certspotter uses the network to retrieve information from the certificate transparency logs. We have the choice to either specifically allow this first network related access or to use the existing nameservice abstraction which grants common access patterns. You can review the details of the abstraction in /etc/apparmor.d/abstractions/nameservice
. This access pattern makes sense for certspotter, so let’s allow it.
Profile: /usr/bin/certspotter
Path: /proc/sys/kernel/hostname
New Mode: r
Severity: 6
[1 - /proc/sys/kernel/hostname r,]
(A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xtension / (N) ew / Audi(t) / Abo(r)t / (F)inish
A
We don’t have a problem with certspotter knowing the system’s hostname, so let’s Allow it.
Profile: /usr/bin/certspotter
Path: /home/testuser/.certspotter/watchlist
New Mode: r
Severity: 4
[1 - /home/*/.certspotter/watchlist r,]
2 - /home/testuser/.certspotter/watchlist r,
(A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xtension / (N) ew / Audi(t) / Abo(r)t / (F)inish
A
certspotter reads the watchlist to determine which domains to monitor. We want certspotter to work for all users of the system and not just ourselves, so suggested rule 1 is better than rule 2. However we also know that certspotter uses the .certspotter
directory to write information that it discovers, its lock file and other data, so this ‘r’ rule will be insufficient. Additionally, we would prefer to use the @{HOME}
tunable rather than the globbed path. For now, let’s accept it as a placeholder and take a TODO to touch it up later.
Profile: /usr/bin/certspotter
Path: /home/testuser/.certspotter/version
New Mode: r
Severity: 4
[1 - /home/*/.certspotter/version r,]
2 - /home/testuser/.certspotter/version r,
(A)llow / [(D)eny] / (I)gnore / (G)lob / Glob with (E)xtension / (N) ew / Audi(t) / Abo(r)t / (F)inish
I
When we touch up the watchlist rule, we should cover all of these entries about files in $HOME/.certspotter
, so we will Ignore these suggested rules for now.
<rule suggestions for other files in $HOME/.certspotter omitted>
Enforce-mode changes:
= Change Local Profiles =
The following local profiles were changed. Would you like to save them?
[1 - /usr/bin/certspotter]
(S)ave Changes / Save Selec(t)ed Profile / [(V)iew Changes] / View Change b/w (C)lean profiles / Abo(r)t
S
When you Save the profile, aa-logprof
automatically causes the profile to be reloaded which immediately silences all of the AppArmor messages about certspotter using the network.
Let’s go back and touch up the profile to allow certspotter to read and write from the $HOME/.certspotter
directory.
$ sudo vi /etc/apparmor.d/usr.bin.certspotter
let’s change the /home/*/.certspotter/watchlist r,
line to owner @{HOME}/.certspotter/** rw,
. The **
glob means certspotter can now read and write to all files, directories and all paths under the current user’s .certspotter
directory in their home directory. You can take this opportunity to touch up the ###AUTHOR###
, ###COPYRIGHT###
, and ###COMMENT###
placeholders with your preferred information. Reload the policy once again:
$ sudo apparmor_parser -r /etc/apparmor.d/usr.bin.certspotter
We’re feeling especially paranoid today, so we are going to add in a few rules to ensure that certspotter can’t exfiltrate some of the data from $HOME
. While AppArmor profiles are default-deny by default, adding explicit deny rules can guard against profile mistakes:
deny @{HOME}/Documents/ rw,
deny @{HOME}/Private/ rw,
deny @{HOME}/Pictures/ rw,
deny @{HOME}/Videos/ rw,
deny @{HOME}/fake/ rw,
deny @{HOME}/.config/ rw,
deny @{HOME}/.ssh/ rw,
deny @{HOME}/.bashrc rw,
The fake directory doesn’t exist on this system, but the policy rule is still valid and AppArmor will enforce rules on it if it ever gets created someday. Remember when specifying a directory itself to use the trailing ‘/'; this is how AppArmor tells the difference between a file and a directory.
Don’t forget to reload the policy!
$ sudo apparmor_parser -r /etc/apparmor.d/usr.bin.certspotter
Ok, let’s restart certspotter and see if it works:
$ /usr/bin/certspotter
It seems to be working with no new denials being generated, so let’s take AppArmor out of complain mode for this profile and set it to enforcing:
$ sudo aa-enforce certspotter
And that’s it! You have generated your first AppArmor profile. You should probably ask someone else to review the final profile to make sure that privilege hasn’t been over granted. Hop into #apparmor on OFTC to ask questions. Submit a pull request to add your profile into the extras directory in the [AppArmor project on Gitlab] (https://gitlab.com/apparmor/apparmor/tree/master/profiles/apparmor/profiles/extras) so that other AppArmor users benefit from your work.
For more details about AppArmor profile rules and AppArmor utilities, see the AppArmor man pages
For detailed information, check out the AppArmor Wiki especially the Policy page
For more description of AppArmor profile development see Application isolation with AppArmor
For more information about certspotter, see CertSpotter