SnappyConfinement
Size: 13956
Comment:
|
Size: 17688
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 5: | Line 5: |
* '''Contributors''': [[LaunchpadHome:jdstrand|Jamie Strandboge]], [[LaunchpadHome:mdeslaur|Marc Deslauriers]] * '''Packages affected''': apparmor, apparmor-easyprof-ubuntu-snappy, click-apparmor, snappy-systemd * '''Status''': Beta |
* '''Contributors''': [[LaunchpadHome:jdstrand|Jamie Strandboge]], [[LaunchpadHome:tyhicks|Tyler Hicks]], [[LaunchpadHome:mdeslaur|Marc Deslauriers]] * '''Packages affected''': apparmor, ubuntu-core-security, click-apparmor, snappy * '''Status''': Alpha |
Line 10: | Line 10: |
Snappy confinement is an evolution of the [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement|security model for Ubuntu Touch]]. The basic concepts for confined applications and the !AppStore model pertain to snappy applications as well. In short, applications are confined using AppArmor by default and this is achieved through a simple template-based system where policy is extended through the use of policy groups. Please familiarize yourself with the following before proceeding: * http://www.ubuntu.com/snappy#core-tour * http://developer.ubuntu.com/snappy/filesystem-layout/ * http://developer.ubuntu.com/snappy/packaging-format-for-apps/ |
Snappy confinement is an evolution of the [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement|security model for Ubuntu Touch]]. The basic concepts for confined applications and the !AppStore model pertain to snappy applications as well. In short, applications are confined by default through the use of various technologies and this is achieved through a simple template-based system where policy is extended through the use of policy groups. It will be most helpful if you are familiar with: * https://developer.ubuntu.com/en/snappy/tutorials/using-snappy * https://developer.ubuntu.com/en/snappy/guides/filesystem-layout * https://developer.ubuntu.com/en/snappy/guides/packaging-format-apps |
Line 18: | Line 18: |
Snappy uses a simple packaging format that is an evolution of [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement/Manifest|click packaging]]. Snappy packages use a declarative [[http://developer.ubuntu.com/snappy/packaging-format-for-apps/|yaml syntax]] and defaults to using `default` !AppArmor template and the "networking" policy group. Apps may customize the default behavior in a number of ways via the yaml syntax. Under the hood, the [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement/Manifest|security manifest]] is used to describe the confinement of the app. Most apps do not need to specify anything for confinement and snappy will create a security manifest like the following:{{{ { "policy_vendor": "ubuntu-snappy", "policy_version": 1.3, "template": "default", "policy_groups": [ "networking" ] } }}} The defaults provided may change as the confinement needs evolve. The template policy is found in `/usr/share/apparmor/easyprof/ubuntu-snappy/templates/1.3/default` and the `networking` policy is found in `/usr/share/apparmor/easyprof/ubuntu-snappy/policy-groups/1.3/networking`. === "apparmor" hook === The `apparmor` hook is used to generate an !AppArmor profile based on what is in the snappy packaging yaml. Importantly, the profile name is unique to the application binary/writer and is achieved by using the concept of an ApplicationId. The APP_ID is the composition of the package name, the service/binary name and package version. The APP_ID takes the form of `<pkgname>_<appname>_<version>`. For example, if this is in packaging yaml:{{{ |
Snappy uses a simple packaging format that is an evolution of [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement/Manifest|click packaging]]. Snappy packages use a declarative [[https://developer.ubuntu.com/en/snappy/guides/packaging-format-apps/|yaml syntax]] and defaults to using `default` !AppArmor template and the "networking" policy group. Apps will be able to customize the default behavior in a number of ways via the yaml syntax. === Native snap format === ==== Security policy ==== Security policy in snappy will be by using a number of technologies including `apparmor`, `seccomp`, `cgroups`, etc. Internally, the security policy is generated based on what is in the snappy packaging yaml. Applications are tracked by the system by using the concept of an ApplicationId. The APP_ID is the composition of the package name, the service/binary name and package version. The APP_ID takes the form of `<pkgname>_<appname>_<version>`. For example, if this is in packaging yaml:{{{ |
Line 43: | Line 32: |
Then the APP_ID for the 'bar' service is `foo_bar_0.1`. Applications are launched under confinement by: * If unspecified, `snappy` will choose the `default` profile and `networking` policy group * Apps may choose to specify an alternate confinement binaries and services by specifying `security-template` and/or `security-policy-groups` in the yaml. Eg:{{{ ... services: - name: bar start: bin/bar |
Then the APP_ID for the 'bar' service is `foo_bar_0.1`. Notice, this is '<name>/<basename of binary/service name>'). The APP_ID is used throughout the system including in the enforcement of security policy. A launcher will be implemented that will: * setup cgroups (tag network traffic, block devices, memory*) * setup iptables (for internal app access) * drop privileges to uid of service * setup seccomp * setup various environment variables (eg, SNAP_APP_PATH, SNAP_APP_DATA_PATH, SNAP_APP_USER_DATA_PATH, SNAP_APP_TMPDIR, SNAP_OLD_PWD, SNAP_APP_ARCH and HOME). * chdir to SNAP_APP_PATH (the install directory) * exec the app under apparmor profile under default nice value The launcher will be used when lauching both services and using CLI binaries. The default policy allows ELF executables, python, perl and shell (with selected corresponding utilities from /bin and /usr/bin), disallows capabilities(7) and enforces application isolation as per the [[https://developer.ubuntu.com/en/snappy/guides/filesystem-layout/|snappy FHS]]. ===== AppArmor ===== Upon snap package install, the yaml is examined and `apparmor` profiles are generated for each service and binary and have names based on the APP_ID. `apparmor` profiles are template based and may be extended through policy groups, which are expressed in the yaml as `caps`. * If unspecified in the packaging yaml, `snappy` will choose the `default` template and `networking` policy group (this may change as snappy involves) * Apps may choose to specify an alternate confinement for binaries and services by specifying `caps` and/or `security-template` in the yaml. Eg:{{{ ... services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz |
Line 53: | Line 58: |
security-policy-groups: networking, something, etc }}} * For special circumstances, the packaging yaml may also use `apparmor` in its 'integration' section:{{{ ... services: - name: bar start: bin/bar |
caps: networking, something, etc }}} `apparmor` policy templates and policy groups are shipped on the snappy system and also via framework snaps. Apps that depend on a particular framework may reference the framework snap's policy templates and/or groups. Apps may also optionally specify `security-override` to specify high level overrides to use when `security-template’ and `caps’ are not sufficient. The path specified by `security-override` is a custom [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement/Manifest|security manifest]]. Use of this will trigger manual review in the Ubuntu store. Eg:{{{ services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-overrides: apparmor: path/to/security override }}} Furthermore, apps may also specify `security-policy` instead of using the template based policy to use hand-crafted `apparmor` policy. Use of this will trigger a manual review in the Ubuntu store. Eg:{{{ services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-policy: apparmor: meta/apparmor.profile }}} ===== Seccomp ===== Like with `apparmor` (see above), on snap package install the yaml is examined and seccomp filter lists are generated for each service and binary. These seccomp filter lists are template based and may be extended through policy groups, which are expressed in the yaml as `caps`. For simplicity, the seccomp policy groups and templates will have the same names as the corresponding `apparmor` policy groups and templates such that: * If unspecified in the packaging yaml, `snappy` will choose the `default` filter template and `networking` policy group (this may change as snappy involves) * Apps may choose to specify an alternate confinement for binaries and services by specifying `caps` and/or `security-template` Apps may also optionally specify `security-override` to specify high level overrides to use when `security-template` and `caps` are not sufficient. The path specified by `security-override` is a custom seccomp filter manifest. Use of this will trigger manual review in the Ubuntu store. Eg:{{{ services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-overrides: seccomp: path/to/filter override }}} Furthermore, apps may also specify `security-policy` instead of using the template based policy to use hand-crafted seccomp filters. Use of this will trigger a manual review in the Ubuntu store. Eg:{{{ services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-policy: seccomp: meta/seccomp-filter.list }}} ===== Cgroups ===== TBD: certain cgroups will be setup per app and there will be a mapping from the APP_ID to the cgroup id. This will be used to for example tag network traffic. ===== Privilege dropping ===== TBD: a mechanism will be provided for apps to drop privileges === Transitional click format (old) === At first, under the hood the `snappy build` command initially created a click format package using the [[https://developer.ubuntu.com/en/snappy/guides/packaging-format-apps/|yaml syntax]]. Eventually `snappy build` will create a native snap formatted package (see above) and not use the click format. This section describes the transition implementation. Upon package install: * the security policy is generated (running any click hooks, such as `aa-clickhook`) * launcher preparation is performed: * for services, a systemd service file is generated from the yaml (initially, `AppArmorProfile=<profilename>` is added to this service file, but eventually the launcher will be used) * for cli binaries, the binary will be registered with the system and added to the user's PATH (initially, a shell wrapper script is created in /apps/bin for each cli binary) ==== apparmor hook ==== Under the hood, the [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement/Manifest|security manifest]] is used to describe the `apparmor` confinement of the app. Most apps do not need to specify anything for confinement and snappy will create a security manifest like the following:{{{ { "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking" ] } }}} The defaults provided may change as the confinement needs evolve. The template policy is found in `/usr/share/apparmor/easyprof/templates/ubuntu-core/15.04/default` and the `networking` policy is found in `/usr/share/apparmor/easyprof/policy-groups/ubuntu-core/15.04/networking`. You may provide your own security json to extend security policy in various ways by using the `apparmor` integration section. Specifying `apparmor` may trigger a manual review in the store, and is not needed for normal Snappy apps, but instead is provided for trusted snappy applications. Eg:{{{ ... services: - name: bar start: bin/bar ports: required: 80/tcp |
Line 64: | Line 153: |
* `aa-clickhook` is run on package install and places the resulting profile in `/var/lib/apparmor/profiles`. * If the binary is a service, the snappy-systemd hook makes sure `/etc/systemd/system/<service>.service` has `AppArmorProfile=<profilename>` (in the above example, `AppArmorProfile=foo_bar_0.1`) such that the service starts under confinement. * If the binary is a cli binary, it will be launched under confinement via the '`bin-path` hook (see below) * apparmor policy templates and policy groups are usually shipped via the apparmor-easyprof-ubuntu-snappy package The default template allows ELF binaries, python, perl and shell (with selected corresponding utilities from /bin and /usr/bin), disallows capabilities(7) and enforces application isolation as per the [[|snappy FHS]]. === "apparmor-profile" hook === In addition to the above, a new `apparmor-profile` hook is provided to facilitate specialized, hand-crafted confinement. This hook is not allowed to !AppStore apps, but is provided for snappy framework and trusted snappy applications. |
With the above yaml, you can now create `meta/bar.apparmor` that contains:{{{ { "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking" ], "write_path": [ "/some/path" ] } }}} * upon snap install, the click security json is symlinked into `/var/lib/apparmor/clicks` * `aa-clickhook` is run on install and places the profile in `/var/lib/apparmor/profiles` (prefixed with 'click_') * `aa-clickhook` is shipped in click-apparmor * use of `apparmor` may trigger a manual review via the store (depending on the contents of the security json) * see the [[https://wiki.ubuntu.com/SecurityTeam/Specifications/ApplicationConfinement/Manifest#Click|click manifest]] documentation for details '''IMPORTANT''': due to a limitation in click, if you install an already installed snap with the same version, the click hooks may not be run. If you are trying to adjust policy, you may need to run '`sudo aa-clickhook -f`' to force regeneration of the profiles. ==== apparmor-profile hook ==== In addition to the above, specialized, hand-crafted confinement may be done via the `apparmor-profile` integration section. Specifying `apparmor-profile` will trigger a manual review in the store, and is not needed for normal Snappy apps, but instead is provided for snappy framework and trusted snappy applications. |
Line 80: | Line 184: |
ports: required: 80/tcp |
|
Line 86: | Line 192: |
* If the binary is a service, the snappy-systemd hook makes sure `/etc/systemd/system/<service>.service` has `AppArmorProfile=<profilename>` (in the above example, `AppArmorProfile=foo_bar_0.1`) such that the service starts under confinement. | * If the binary is a service, `snappy-systemd` makes sure `/etc/systemd/system/<service>.service` launches the service using `ubuntu-snapp-launch` (snappy-systemd temporarily sets `AppArmorProfile=<profilename>` instead of using the launcher) |
Line 90: | Line 196: |
To improve maintenace, the profile author doesn't have to worry about updating the profile name, the app name, where it is installed or package version and may instead use AppArmor variables in the policy. Example profile:{{{ | To improve maintenace, the profile author can use !AppArmor variables to avoid worrying about updating the profile name, the app name, where the app is installed or knowing the package version. Example profile:{{{ |
Line 127: | Line 233: |
ports: required: 80/tcp |
|
Line 132: | Line 240: |
You may not specify the `apparmor` and `apparmor-profile` hooks for the same <appname> (eg, specifying `"apparmor-profile": "meta/appname.profile"` and `"apparmor": "meta/appname.apparmor"` is an error). === "apparmor-policy" hook === The `apparmor-policy` hook is provided for frameworks to extend security policy (specifically, to add templates and/or policy groups) so that apps that specify the framework may then reference these template/policy groups to access any services/binaries that the framework exposes. Key ideas for snappy frameworks: * Frameworks extend Ubuntu Core in useful ways for apps to use * Frameworks are delivered via snaps * Because frameworks require additional privilege and are considered trusted (how much depends on what the framework offers), framework authors must partner with Canonical on framework design, security policy verification, acceptance in the store, etc * Frameworks are expected to provide significant functionality that is useful to a wide range of apps * Multiple snappy frameworks may be installed on the same system * The number of snappy frameworks is expected to be relatively low See the SnappyFrameworkConfinement for more details. === "bin-path" hook === If the yaml specifies 'binaries' then the `snappy-bin-path` hook will expose these binaries to the shell and other apps by launching apps via a specialized launcher that does the following: * chdir()s to the app install directory * sets up any environment * launches the app under confinement It does this by placing a symlink in `~/snappy-bin` pointing to the launcher. The launcher then queries the system to obtain the pkgname, version and profile name to launch the app under. The launcher will also `~/snappy-bin` is included as part of the user's PATH. The `snappy-bin-path` hook will create a very small shell script in `~/snappy-bin` to setup the environment, adjust the working directory and launch the binary under its !AppArmor profile. For example, consider the following snappy packaging yaml:{{{ name: foo version: 0.1 ... binaries: - name: bin/bar }}} The `snappy-bin-path` hook will create the ~/snappy-bin/foo-bar symlink (notice this is <name>-<basename of binary name>. When executing that symlink, the launcher will: * chdir() to /apps/foo/current * set TMPDIR="/var/lib/apps/foo/0.1", etc * run the app under the `foo_bar_0.1` profile Note, as of 2014-12-09, a shell script is temporarily being used instead of a symlink. }}} |
You may not specify the `apparmor` and `apparmor-profile` for the same <appname> (eg, specifying `"apparmor-profile": "meta/appname.profile"` and `"apparmor": "meta/appname.apparmor"` is an error). |
Line 177: | Line 249: |
start: bin/owncloud - name: baz start: bin/owncloud |
start: bin/bar - name: baz start: bin/baz |
Line 181: | Line 253: |
start: bin/owncloud | start: bin/norf |
Line 190: | Line 262: |
While the snappy packaging yaml is intentionally simple and straightforward for app developers, it can also quite flexible for those who need it. For example, consider the following yaml ('''TBD'''):{{{ | While the snappy packaging yaml is intentionally simple and straightforward for app developers, it can also quite flexible for those who need it. For example, consider the following yaml:{{{ |
Line 199: | Line 271: |
security-policy-groups: networking, extra | caps: networking, extra |
Line 206: | Line 278: |
security-policy-groups: networking, extra | caps: networking, extra |
Line 212: | Line 284: |
"policy_vendor": "ubuntu-snappy", "policy_version": 1.3, |
"policy_vendor": "ubuntu-core", "policy_version": 15.04, |
Line 222: | Line 294: |
"policy_vendor": "ubuntu-snappy", "policy_version": 1.3, |
"policy_vendor": "ubuntu-core", "policy_version": 15.04, |
Line 233: | Line 305: |
"policy_vendor": "ubuntu-snappy", "policy_version": 1.3, |
"policy_vendor": "ubuntu-core", "policy_version": 15.04, |
Line 243: | Line 315: |
"policy_vendor": "ubuntu-snappy", "policy_version": 1.3, |
"policy_vendor": "ubuntu-core", "policy_version": 15.04, |
Line 253: | Line 325: |
"policy_vendor": "ubuntu-snappy", "policy_version": 1.3, |
"policy_vendor": "ubuntu-core", "policy_version": 15.04, |
Line 289: | Line 361: |
=== Helpful commands === | === Helpful degugging commands === |
Line 294: | Line 366: |
* `sudo systemctl stop <app>.service` and `sudo systemctl start <app>.service` to stop and start services from /etc/systemd/system (ie, where the snappy-systemd hook puts the service files) | * `sudo systemctl stop <app>.service` and `sudo systemctl start <app>.service` to stop and start services from /etc/systemd/system (ie, where snappy-systemd puts the service files) |
Created: 2014-12-05
Created by: Jamie Strandboge
Contributors: Jamie Strandboge, Tyler Hicks, Marc Deslauriers
Packages affected: apparmor, ubuntu-core-security, click-apparmor, snappy
Status: Alpha
Introduction
Snappy confinement is an evolution of the security model for Ubuntu Touch. The basic concepts for confined applications and the AppStore model pertain to snappy applications as well. In short, applications are confined by default through the use of various technologies and this is achieved through a simple template-based system where policy is extended through the use of policy groups.
It will be most helpful if you are familiar with:
https://developer.ubuntu.com/en/snappy/tutorials/using-snappy
https://developer.ubuntu.com/en/snappy/guides/filesystem-layout
https://developer.ubuntu.com/en/snappy/guides/packaging-format-apps
Implementation summary
Snappy uses a simple packaging format that is an evolution of click packaging. Snappy packages use a declarative yaml syntax and defaults to using default AppArmor template and the "networking" policy group. Apps will be able to customize the default behavior in a number of ways via the yaml syntax.
Native snap format
Security policy
Security policy in snappy will be by using a number of technologies including apparmor, seccomp, cgroups, etc. Internally, the security policy is generated based on what is in the snappy packaging yaml. Applications are tracked by the system by using the concept of an ApplicationId. The APP_ID is the composition of the package name, the service/binary name and package version. The APP_ID takes the form of <pkgname>_<appname>_<version>. For example, if this is in packaging yaml:
name: foo version: 0.1 ... services: - name: bar start: bin/bar
Then the APP_ID for the 'bar' service is foo_bar_0.1. Notice, this is '<name>/<basename of binary/service name>'). The APP_ID is used throughout the system including in the enforcement of security policy.
A launcher will be implemented that will:
- setup cgroups (tag network traffic, block devices, memory*)
- setup iptables (for internal app access)
- drop privileges to uid of service
- setup seccomp
- setup various environment variables (eg, SNAP_APP_PATH, SNAP_APP_DATA_PATH, SNAP_APP_USER_DATA_PATH, SNAP_APP_TMPDIR, SNAP_OLD_PWD, SNAP_APP_ARCH and HOME).
- chdir to SNAP_APP_PATH (the install directory)
- exec the app under apparmor profile under default nice value
The launcher will be used when lauching both services and using CLI binaries. The default policy allows ELF executables, python, perl and shell (with selected corresponding utilities from /bin and /usr/bin), disallows capabilities(7) and enforces application isolation as per the snappy FHS.
AppArmor
Upon snap package install, the yaml is examined and apparmor profiles are generated for each service and binary and have names based on the APP_ID. apparmor profiles are template based and may be extended through policy groups, which are expressed in the yaml as caps.
If unspecified in the packaging yaml, snappy will choose the default template and networking policy group (this may change as snappy involves)
Apps may choose to specify an alternate confinement for binaries and services by specifying caps and/or security-template in the yaml. Eg:
... services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-template: nondefault caps: networking, something, etc
apparmor policy templates and policy groups are shipped on the snappy system and also via framework snaps. Apps that depend on a particular framework may reference the framework snap's policy templates and/or groups.
Apps may also optionally specify security-override to specify high level overrides to use when security-template’ and caps’ are not sufficient. The path specified by security-override is a custom security manifest. Use of this will trigger manual review in the Ubuntu store. Eg:
services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-overrides: apparmor: path/to/security override
Furthermore, apps may also specify security-policy instead of using the template based policy to use hand-crafted apparmor policy. Use of this will trigger a manual review in the Ubuntu store. Eg:
services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-policy: apparmor: meta/apparmor.profile
Seccomp
Like with apparmor (see above), on snap package install the yaml is examined and seccomp filter lists are generated for each service and binary. These seccomp filter lists are template based and may be extended through policy groups, which are expressed in the yaml as caps. For simplicity, the seccomp policy groups and templates will have the same names as the corresponding apparmor policy groups and templates such that:
If unspecified in the packaging yaml, snappy will choose the default filter template and networking policy group (this may change as snappy involves)
Apps may choose to specify an alternate confinement for binaries and services by specifying caps and/or security-template
Apps may also optionally specify security-override to specify high level overrides to use when security-template and caps are not sufficient. The path specified by security-override is a custom seccomp filter manifest. Use of this will trigger manual review in the Ubuntu store. Eg:
services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-overrides: seccomp: path/to/filter override
Furthermore, apps may also specify security-policy instead of using the template based policy to use hand-crafted seccomp filters. Use of this will trigger a manual review in the Ubuntu store. Eg:
services: - name: bar start: bin/bar caps: networking - name: baz start: bin/baz security-policy: seccomp: meta/seccomp-filter.list
Cgroups
TBD: certain cgroups will be setup per app and there will be a mapping from the APP_ID to the cgroup id. This will be used to for example tag network traffic.
Privilege dropping
TBD: a mechanism will be provided for apps to drop privileges
Transitional click format (old)
At first, under the hood the snappy build command initially created a click format package using the yaml syntax. Eventually snappy build will create a native snap formatted package (see above) and not use the click format. This section describes the transition implementation.
Upon package install:
the security policy is generated (running any click hooks, such as aa-clickhook)
- launcher preparation is performed:
for services, a systemd service file is generated from the yaml (initially, AppArmorProfile=<profilename> is added to this service file, but eventually the launcher will be used)
- for cli binaries, the binary will be registered with the system and added to the user's PATH (initially, a shell wrapper script is created in /apps/bin for each cli binary)
apparmor hook
Under the hood, the security manifest is used to describe the apparmor confinement of the app. Most apps do not need to specify anything for confinement and snappy will create a security manifest like the following:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking" ] }
The defaults provided may change as the confinement needs evolve. The template policy is found in /usr/share/apparmor/easyprof/templates/ubuntu-core/15.04/default and the networking policy is found in /usr/share/apparmor/easyprof/policy-groups/ubuntu-core/15.04/networking.
You may provide your own security json to extend security policy in various ways by using the apparmor integration section. Specifying apparmor may trigger a manual review in the store, and is not needed for normal Snappy apps, but instead is provided for trusted snappy applications. Eg:
... services: - name: bar start: bin/bar ports: required: 80/tcp integration: bar: apparmor: meta/bar.apparmor
With the above yaml, you can now create meta/bar.apparmor that contains:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking" ], "write_path": [ "/some/path" ] }
upon snap install, the click security json is symlinked into /var/lib/apparmor/clicks
aa-clickhook is run on install and places the profile in /var/lib/apparmor/profiles (prefixed with 'click_')
aa-clickhook is shipped in click-apparmor
use of apparmor may trigger a manual review via the store (depending on the contents of the security json)
see the click manifest documentation for details
IMPORTANT: due to a limitation in click, if you install an already installed snap with the same version, the click hooks may not be run. If you are trying to adjust policy, you may need to run 'sudo aa-clickhook -f' to force regeneration of the profiles.
apparmor-profile hook
In addition to the above, specialized, hand-crafted confinement may be done via the apparmor-profile integration section. Specifying apparmor-profile will trigger a manual review in the store, and is not needed for normal Snappy apps, but instead is provided for snappy framework and trusted snappy applications.
The aa-profile-hook works similarly to aa-clickhook:
The snappy packaging specifies to use 'apparmor-profile' in its 'integration' section, which specifies the profile. Eg:
... services: - name: bar start: bin/bar ports: required: 80/tcp integration: bar: apparmor-profile: meta/bar.profile
the profile should reference the AppArmor variables for CLICK_DIR, APP_PKGNAME, APP_APPNAME, APP_VERSION and for profile attachment, just like the apparmor template does with click-apparmor
aa-profile-hook is run on install and places the profile in /var/lib/apparmor/profiles (prefixed with 'profile_')
If the binary is a service, snappy-systemd makes sure /etc/systemd/system/<service>.service launches the service using ubuntu-snapp-launch (snappy-systemd temporarily sets AppArmorProfile=<profilename> instead of using the launcher)
aa-profile-hook is shipped in click-apparmor
use of apparmor-profile requires manual review via the store.
To improve maintenace, the profile author can use AppArmor variables to avoid worrying about updating the profile name, the app name, where the app is installed or knowing the package version. Example profile:
#include <tunables/global> # Specified profile variables ###VAR### ###PROFILEATTACH### (attach_disconnected) { #include <abstractions/base> #include <abstractions/nameservice> # Read-only for the install directory @{CLICK_DIR}/@{APP_PKGNAME}/ r, @{CLICK_DIR}/@{APP_PKGNAME}/@{APP_VERSION}/ r, @{CLICK_DIR}/@{APP_PKGNAME}/@{APP_VERSION}/** mrklix, # Writable home area owner @{HOMEDIRS}/apps/@{APP_PKGNAME}/ rw, owner @{HOMEDIRS}/apps/@{APP_PKGNAME}/** mrwklix, # Read-only system area for other versions /var/lib/apps/@{APP_PKGNAME}/ r, /var/lib/apps/@{APP_PKGNAME}/** mrkix, # Writable system area only for this version. /var/lib/apps/@{APP_PKGNAME}/@{APP_VERSION}/ w, /var/lib/apps/@{APP_PKGNAME}/@{APP_VERSION}/** wl, ... specialized confinement ...
Example yaml to use the profile:
name: foo version: 0.1 ... services: - name: bar start: bin/bar ports: required: 80/tcp integration: bar: apparmor-profile: meta/bar.profile
You may not specify the apparmor and apparmor-profile for the same <appname> (eg, specifying "apparmor-profile": "meta/appname.profile" and "apparmor": "meta/appname.apparmor" is an error).
Normal usage
As stated, the snappy packaging yaml does not have to do anything to specify the default confinement. Eg, the following yaml:
name: foo version: 0.1 ... services: - name: bar start: bin/bar - name: baz start: bin/baz - name: norf start: bin/norf
will create the following AppArmor profiles with default confinement:
- foo_bar_0.1
- foo_baz_0.1
- foo_norf_0.1
Advanced usage
While the snappy packaging yaml is intentionally simple and straightforward for app developers, it can also quite flexible for those who need it. For example, consider the following yaml:
name: foo version: 0.1 ... services: - name: normal-service start: bin/normal-service - name: extra-policy-group-service start: bin/extra-policy-group-service caps: networking, extra - name: non-default-template-service start: bin/non-default-template-service security-template: non-default binaries: - name: bin/normal-binary - name: extra-policy-group-binary caps: networking, extra
snappy will generate the following security manifests:
normal-service:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking" ] }
extra-policy-group-service:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking", "extra" ] }
non-default-template-service:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "non-default", "policy_groups": [ "networking" ] }
normal-binary:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking" ] }
extra-policy-group-binary:
{ "policy_vendor": "ubuntu-core", "policy_version": 15.04, "template": "default", "policy_groups": [ "networking", "extra" ] }
Which in turn creates the following AppArmor profiles:
- foo_normal-service_0.1
- foo_extra-policy-group-service_0.1
- foo_non-default-template-service_0.1
- foo_normal-binary_0.1
- foo_extra-policy-group-binary_0.1
Debugging
To check to see if you have any denials:
$ sudo journalctl --no-pager -k | grep DEN
A denial will look something like:
apparmor="DENIED" operation="mkdir" profile="foo_bar_0.1" name="/var/lib/foo" pid=637 comm="bar" requested_mask="c" denied_mask="c" fsuid=0 ouid=0
If there are no denials, AppArmor shouldn't be blocking the app.
If there are denials, you can unblock yourself by:
- modifying the profile in /var/lib/apparmor/profiles that corresponds to your app
reload the profile with:
$ sudo apparmor_parser -r /var/lib/apparmor/profiles/<profile>
Do note that the local modification will not be preserved on package update. If you believe you have found a bug, please file a bug against: https://bugs.launchpad.net/ubuntu/+source/apparmor/+filebug
Helpful degugging commands
sudo aa-clickhook -f will regenerate all the apparmor profiles in /var/lib/apparmor/profiles
sudo aa-profile-hook -f will regenerate all the apparmor-profile profiles in /var/lib/apparmor/profiles
sudo aa-status will show you the profiles loaded in the kernel and what processes are running under them
ps Z, ps Z <pid> and ps auxwwZ will show you normal ps output, but with the apparmor label the profile is running under
sudo systemctl stop <app>.service and sudo systemctl start <app>.service to stop and start services from /etc/systemd/system (ie, where snappy-systemd puts the service files)
- This is often helpful when developing your app or policy for it:
In one terminal launch (tail kernel log for AppArmor denials):
$ sudo journalctl -f -k | grep DEN
In another (service name is the filename in /etc/systemd/system):
$ sudo journalctl -f -u <service name>
Then launch the app with systemctl like above, or launch manually under confinement with:
$ aa-exec -p <profile name> -- /apps/<pkgname>/<version>/...
Future work
Confining snappy apps (particularly processes requiring root) may use AppArmor-wrapped user namespaces.
SecurityTeam/Specifications/SnappyConfinement (last edited 2016-11-17 16:29:21 by jdstrand)