mirror of
https://gitlab.com/apparmor/apparmor.git
synced 2025-03-04 08:24:42 +01:00
AppArmorNamespaces: add initial markdown conversion
parent
7f1db399ac
commit
2b4ae5a9c2
1 changed files with 491 additions and 0 deletions
491
AppArmorNamespaces.md
Normal file
491
AppArmorNamespaces.md
Normal file
|
@ -0,0 +1,491 @@
|
|||
Required Versions
|
||||
=================
|
||||
|
||||
- AppArmor 2.3 with 2.6.??? kernel
|
||||
- Limitations
|
||||
- Limited experimental flat namespace support. Only partially like documented here
|
||||
|
||||
<!-- -->
|
||||
|
||||
- AppArmor 2.5 with 2.6.??? kernel
|
||||
- Limitations
|
||||
- Hierarchical namespaces, no stacking, basic creation/deletion via profile load and removal
|
||||
- View == current namespace
|
||||
|
||||
<!-- -->
|
||||
|
||||
- 2.11 with AppArmor 3.5-beta1 - (Ubuntu 16.04)
|
||||
- Limitations
|
||||
- View == current namespace
|
||||
- stacking is buggy without backported patches
|
||||
- No mkdir/rmdir namespace interface
|
||||
- apparmor/policy is not virtualized
|
||||
- /sys/module/apparmor/parameters/\* are not virtualized
|
||||
|
||||
<!-- -->
|
||||
|
||||
- 2.11 with AppArmor 3.6-beta1 - (Ubuntu 16.10)
|
||||
- Limitations
|
||||
- View == current namespace
|
||||
- apparmor/policy is not virtualized
|
||||
- /sys/module/apparmor/parameters/\* are not virtualized
|
||||
|
||||
<!-- -->
|
||||
|
||||
- AppArmor 4
|
||||
- Limitations
|
||||
- In development
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
AppArmor policy namespaces allow separating AppArmor profiles into
|
||||
different logical groups that provide the scope for the profile's
|
||||
names, variables and attachments. In addition they provide a
|
||||
mechanism for control over profile management and are the basis for
|
||||
how confinement is viewed.
|
||||
|
||||
Policy namespaces serve 4 main purposes
|
||||
|
||||
- providing alternate namespaces for profile names to aid in profile management and avoid name collisions
|
||||
- providing better control over who/what can manage policy, or specific pieces of policy
|
||||
- providing a view that defines what policy is visible
|
||||
- providing a scope for which profiles interact during mediation
|
||||
|
||||
A few examples
|
||||
|
||||
Example 1: LXD
|
||||
--------------
|
||||
|
||||
The lxd container management system can set up a new policy namespace as part of its container configuration. The
|
||||
container is free to load policy into the policy namespace without affecting system policy even when the container's
|
||||
profiles have the same names as those in the system policy. The confinement scope of the policy in the container is
|
||||
limited to that of the tasks within the container (ie, they're scoped to have no effect on other system tasks). For
|
||||
the tasks within the container, the policy within the container looks like system policy (the actual system policy
|
||||
is not even visible to these tasks).
|
||||
|
||||
- The *control* is set to allow the container to manage the policy in the namespace
|
||||
- The *view* is that of the policy namespace itself
|
||||
- The *scope* is that of the policy namespace itself
|
||||
|
||||
Example 2: snapd confinement (planned)
|
||||
--------------------------------------
|
||||
|
||||
The snappy system consists of applications called 'snaps' and snapd which, among other things, manages the
|
||||
application sandbox for installed snaps. When AppArmor is available, snapd uses it as the main component for
|
||||
confinement and generates per-snap policy for each snap's exposed commands. snapd is thus allowed to manage the
|
||||
snap's Apparmor policy, but it is not allowed to manage system policy. Because snapped applications must be able to
|
||||
interact with system policy in controlled ways, their policy is written with system policy in mind.
|
||||
|
||||
- The *control* is set to allow snapd to manage the policy namespace
|
||||
- The *view* is set to that of the system policy namespace
|
||||
- The *scope* is set to that of the system policy namespace
|
||||
|
||||
Example 3: user confinement (roles)
|
||||
-----------------------------------
|
||||
|
||||
Sometimes it is desirable to limit specific users' access to certain files and resources while at the same time
|
||||
allowing users to reuse available application profiles without modification (for applications the user is allowed
|
||||
to access). A policy namespace can be used to manage the user policy such that the profiles within this namespace
|
||||
can coexist with system policy, therefore allowing use of application profiles where system application policy is
|
||||
also visible and available.
|
||||
|
||||
|
||||
- The *control* is set to that of the system
|
||||
- The *view* is set to that of the system
|
||||
- The *scope* is that of the policy namespace itself so the system application policy does not need to be changed for unique user confinements
|
||||
|
||||
Example 4: user defined policy
|
||||
------------------------------
|
||||
|
||||
If enabled, it is possible to allow users to define their own application policy and load it into the system.
|
||||
This policy is only applied to the users' own tasks such that system policy can remain unmodified. In general, this
|
||||
would also allow the user to view what system policy is being applied so that the use of user policy does not
|
||||
change the regular behavior of the system.
|
||||
|
||||
- The *control* is set to allow the user to manage the policy of the namespace
|
||||
- The *view* is that of the system policy namespace so that the user can see both system and user policy
|
||||
- The *scope* is that of the policy namespace itself, so that the user policy does not affect system policy
|
||||
|
||||
Example 5: application privilege separation
|
||||
-------------------------------------------
|
||||
|
||||
If enabled, it is possible to allow an application to define its own policy and load it into a custom namespace.
|
||||
This policy only applies to the parts of the application that the application deliberately separates. The
|
||||
application is then free to choose what the privilege-separated component can view of its confinement.
|
||||
The *control* is set to allow the application to manage its policy namespace
|
||||
|
||||
##### Option 1:
|
||||
|
||||
- The *view* is set to the parent namespace so the privilege-separated components can view the confinement stack.
|
||||
- The *scope* is set to that of the parent namespace so that policy is authored from the view of the system.
|
||||
|
||||
##### Option 2:
|
||||
|
||||
- The *view* is set to the parent namespace so the privilege-separated components can view the confinement stack.
|
||||
- The *scope* is set to that of the application namespace so the policy does not interact with system policy.
|
||||
|
||||
##### Option 3:
|
||||
|
||||
The *view* and scope are set to the application namespace so that the privilege-separated component can only
|
||||
view its own confinement and its policy does not interact with the rest of the system.
|
||||
|
||||
##### Option 4:
|
||||
|
||||
For the application policy one of options 1-3 is chosen. A new sub-namespace is setup within the application namespace
|
||||
with its *view* and *scope* set to the new sub-namespace. The privilege-separated part of the application is
|
||||
transitioned into a stack of the application policy and *unconfined* in the sub-namespace. This blocks the
|
||||
privilege-separated components of the application from even being able to view their own confinement.
|
||||
|
||||
It is important to understand that policy namespaces are not in and of
|
||||
themselves sufficient to cover each of these situations and are meant
|
||||
to be used in conjunction with [stacking](AppArmorStacking). Each of
|
||||
these will be covered in depth in different sections.
|
||||
|
||||
Creating a policy namespace
|
||||
===========================
|
||||
|
||||
There are three basic ways to create a policy namespace, by specifying
|
||||
the namespace in policy, by forcing a profile to be loaded into
|
||||
namespace, and by creating a namespace directory in apparmorfs. Each
|
||||
method covers a different use case???..
|
||||
|
||||
Specifying the namespace as part of policy
|
||||
------------------------------------------
|
||||
|
||||
Policy can be authored so that profiles can specify the namespace
|
||||
they belong in. This is done by specifying the namespace name along
|
||||
with the profile. When the profile is loaded the namespace will be
|
||||
created with default values if needed.
|
||||
|
||||
```
|
||||
:foo:/does/not/exist {
|
||||
#include <includes/base>
|
||||
...
|
||||
}
|
||||
|
||||
profile :foo:/does/not/exist {
|
||||
#include <includes/base>
|
||||
...
|
||||
}
|
||||
|
||||
:foo:unattached {
|
||||
#include <includes/base>
|
||||
...
|
||||
}
|
||||
|
||||
profile :foo:unattached2 {
|
||||
#include <includes/base>
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
This method of namespace creation is appropriate when policy from
|
||||
different namespaces need to interact (see scopes). Or when the parent
|
||||
namespace needs to setup a child namespace and its base policy.
|
||||
|
||||
Namespaces can also be created using a namespace block, which allows
|
||||
declaring the namespace and setting some of its control parameters.
|
||||
|
||||
```
|
||||
namespace foo {
|
||||
profile one {
|
||||
...
|
||||
}
|
||||
}
|
||||
profile :foo:two {
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
When using namespace blocks, their profiles do not need to be declared
|
||||
within the block as long as the namespace is declared as part of
|
||||
its name.
|
||||
|
||||
Forced loading of a profile into a namespace
|
||||
--------------------------------------------
|
||||
|
||||
The apparmor\_parser can be used to force a profile or profiles into
|
||||
a specified namespace at load time.
|
||||
|
||||
```
|
||||
apparmor_parser -n name-of-namespace -r /path/to/profile
|
||||
```
|
||||
|
||||
This technique is useful for when a profile needs to be replicated
|
||||
into another namespace without modifications (useful for testing ..).
|
||||
|
||||
Creating a namespace with mkdir
|
||||
-------------------------------
|
||||
|
||||
A namespace can be made with using the filesystem mkdir command in
|
||||
the securityfs apparmor/policy/namespaces directory, which is usually
|
||||
mounted at /sys/kernel/security/. Making the full path
|
||||
|
||||
```
|
||||
/sys/kernel/security/apparmor/policy/namespaces/
|
||||
```
|
||||
|
||||
This will make a namespace with the specified name and default
|
||||
properties, which can be changed before policy is loaded.
|
||||
|
||||
This method is most useful for loading binary policy blobs like what
|
||||
is done for checkpoint restore functionality.
|
||||
|
||||
Caveats with loading policy namespaces via files:
|
||||
|
||||
- you also cannot (currently) specify namespace scope or namespace view in the policy
|
||||
- you should specify only one namespace per profile file (ie, you shouldn't use \`profile :foo:...\` with \`profile :bar:...\`) for predictable policy behavior (because you can't yet specify the namespace view, the sibling namespaces can't interact)
|
||||
- you cannot specify parent and child namespaces within the same profile file
|
||||
|
||||
TODO:
|
||||
|
||||
- using raw\_data interface??? At a different point where we can get more indepth???
|
||||
|
||||
Attributes of a policy namespace
|
||||
================================
|
||||
|
||||
Each policy namespace consists of a:
|
||||
|
||||
- unique set of variables
|
||||
- unique unconfined profile
|
||||
- unique default profile
|
||||
- set of profiles that can be applied
|
||||
- set of controls for who can manipulate the namespace.
|
||||
|
||||
name
|
||||
----
|
||||
|
||||
Each policy namespace is named using alpha-numeric chararacters and
|
||||
begins and ends with a **:** (the character set may be broadened in
|
||||
the future somewhat, but the first character will always need to be
|
||||
alpha-numeric). The beginning and ending colons (**:**) are technically
|
||||
not part of the name (they are a prefix and separator) but the name is
|
||||
always shown with the colons to disambiguate them from profile names.
|
||||
|
||||
```
|
||||
:namespace:
|
||||
:jail1:
|
||||
```
|
||||
|
||||
The namespace's name when combined with a profile name is known as
|
||||
the fully-qualified path. The fully-qualified path is calculated by
|
||||
concatenating the profile name to the namespace name using the prefix
|
||||
and suffix **:** affixed with an optional separator in between.
|
||||
|
||||
```
|
||||
:namespace:profile_name # ssh style (recommended)
|
||||
:namespace:/profile/name # ssh style
|
||||
:namespace://profie_name # url style ie :// as separator
|
||||
:namespace:///profile/name # notice **///** always parses as the separator (**//**) first then **/**
|
||||
:namespace://profile//child # fully qualified name of a child profile
|
||||
```
|
||||
|
||||
The maximum length for the namespace's name is technically unlimited
|
||||
but best practice says to keep them short since they often appear with
|
||||
profile names as fully-qualified path and different parts of the system
|
||||
have hard limits that might interfere with long fully-qualified paths.
|
||||
|
||||
Examples:
|
||||
|
||||
- The proc interface used for introspecting tasks is limited to a PAGE\_SIZE
|
||||
- Cipso labeling for networking is limited to 40 characters
|
||||
- ...
|
||||
|
||||
### Why do namespace names need to begin with a *:*
|
||||
|
||||
When AppArmor profile names are used as an attachment, they can have
|
||||
any character or pattern that a filename may have which greatly limits
|
||||
how namespace names can be expressed. In addition, non-attaching
|
||||
profile names put their own constraints on how the namespace's name
|
||||
can be expressed. Because of these limitations, a unique leading
|
||||
character is used (the *:*) to indicate the beginning of a namespace
|
||||
name. The same technique is also used to indicate [instances, stacks,
|
||||
delegation, and variants](AppArmorProfileSpec).
|
||||
|
||||
The trailing *:* separates the namespace name from the profile name
|
||||
and the optional */* and *//* separators are provided as a convenience
|
||||
for those familiar with ssh and protocol urls.
|
||||
|
||||
view
|
||||
----
|
||||
|
||||
The view determines what other namespaces and their corresponding
|
||||
policy are visible to the profiles (and the tasks that they confine)
|
||||
in this namespace. This is discussed further in [AppArmor Policy
|
||||
Namespace Views](AppArmorPolicyView).
|
||||
|
||||
scope
|
||||
-----
|
||||
|
||||
The scope of the namespace determines which policy from other
|
||||
namespaces may interact with policy in this namespace. This
|
||||
is discussed further in [AppArmor Policy Namespace Scope of
|
||||
Mediation](AppArmorPolicyScope).
|
||||
|
||||
unconfined profile
|
||||
------------------
|
||||
|
||||
Each namespace gets its own unique unconfined profile that is used to
|
||||
track tasks assigned to or created withing the namespace that should
|
||||
not be confined.
|
||||
|
||||
default profile
|
||||
---------------
|
||||
|
||||
Each namespace has a default profile that is assigned to tasks when
|
||||
no other profile in the namespace has an attachment that matches. The
|
||||
standard default profile is the unconfined profile.
|
||||
|
||||
Note: as of AppArmor 3.5, setting the default profile to something
|
||||
other than unconfined is considered experimental. The default profile
|
||||
can only be applied to the root system policy namespace via a grub
|
||||
kernel parameter.
|
||||
|
||||
lifetime
|
||||
--------
|
||||
|
||||
The lifetime controls whether a namespace should be automatically
|
||||
removed from the system based on certain conditions:
|
||||
|
||||
- *persistent* - the namespace remains loaded until it is explicitly removed from the system
|
||||
- *profiles* - if all the namespace's profiles are removed, the namespace is removed
|
||||
- *tasks* - if all tasks assigned to the namespace exit, the namespace is removed
|
||||
- *in-use* - only remove when nothing is using the namespace (eg profiles, tasks, ...)
|
||||
|
||||
variables
|
||||
---------
|
||||
|
||||
TODO
|
||||
|
||||
controls
|
||||
--------
|
||||
|
||||
TODO
|
||||
|
||||
Referencing profiles and profile transitions within a policy namespace
|
||||
======================================================================
|
||||
|
||||
NEEDS REVIEW AND MORE EXAMPLES
|
||||
|
||||
- inherit from current profile relative to current namespace: \`/foo ix,\`
|
||||
- transition to sibling profile relative to current namespace: \`/foo Px -> sibling,\`
|
||||
- transition to child profile relative to current namespace: \`/foo Cx -> child,\`
|
||||
- transition to profile in another namespace: \`/foo Px -> :other-ns:foo,\`
|
||||
|
||||
Policy Namespaces are Hierarchical
|
||||
==================================
|
||||
|
||||
AppArmor policy namespaces are arranged in a tree structure with the
|
||||
system policy namespace at the root. The system policy namespace
|
||||
can have children namespaces, which in turn can have their own
|
||||
children. Like profiles names, namespace names can be expressed as
|
||||
a path using **//** as a component separator.
|
||||
|
||||
Examples:
|
||||
|
||||
```
|
||||
:parent//child:
|
||||
:parent//child//grand_child:
|
||||
```
|
||||
|
||||
Policy Namespace names are Relative to the View
|
||||
===============================================
|
||||
|
||||
AppArmor policy is authored and introspected from the point of view
|
||||
of a task's confinement.
|
||||
|
||||
When authoring policy
|
||||
---------------------
|
||||
|
||||
When a profile specifies a profile (or label) without specifying a
|
||||
namespace the reference is relative to the namespace the profile is
|
||||
in. Eg, given:
|
||||
|
||||
```
|
||||
:ns1:A
|
||||
:ns1:B
|
||||
```
|
||||
|
||||
with profile `:ns1:B` having the transition
|
||||
|
||||
```
|
||||
px /** -> A,
|
||||
```
|
||||
|
||||
the profile `*A*` referenced is for the profile `:ns1:A`
|
||||
|
||||
Furthermore, when a profile specifies a profile (or label) with an
|
||||
explicit namespace prefix, the profile name is then always relative
|
||||
to the [namespace view](AppArmorPolicyView).
|
||||
|
||||
When viewing policy
|
||||
-------------------
|
||||
|
||||
When viewing a task's confinement, the name reported will always
|
||||
be relative to the [namespace view](AppArmorPolicyView). If the
|
||||
viewed namespace of the target is the same as the task doing
|
||||
the viewing then the namespace name will not be reported. If
|
||||
the namespaces differ then visibility and view virtualization
|
||||
considerations will be enforced (see [view](AppArmorPolicyView) and
|
||||
[visibility](AppArmorNamespaces#Policy_Namespace_Visibility)).
|
||||
|
||||
### Policy Namespace Visibility
|
||||
|
||||
Policy namespace visibility is determined by the [namespace
|
||||
view](AppArmorPolicyView) and namespace hierarchy. Parent namespaces
|
||||
can view their descendants (children, grand children, ...) but the
|
||||
full namespace hierarchy may not be visible to all tasks: descendant
|
||||
namespaces may or may not be able to view parent or sibling namespaces
|
||||
dependent on the [namespace view](AppArmorPolicyView).
|
||||
|
||||
Further discussion of visibility will occur in the section on
|
||||
[namespace views](AppArmorPolicyView).
|
||||
|
||||
Profile transitions between namespaces
|
||||
--------------------------------------
|
||||
|
||||
????
|
||||
====
|
||||
|
||||
relative vs abs ns path
|
||||
|
||||
root ns is not express via a name
|
||||
|
||||
ns: refers to a namespace within the current root ns
|
||||
|
||||
When the View is not the current namespace
|
||||
------------------------------------------
|
||||
|
||||
In AppArmor 4 it is possible to have the view be a namespace that is
|
||||
different from the current namespace. When this occurs the view will
|
||||
be an ancestor of the current namespace, and the view will affect
|
||||
what profiles and namespaces are used when directly referenced.
|
||||
|
||||
For transitions and management when no namespace is specified the
|
||||
current namespace is used and if a namespace is specified then it is
|
||||
from the view.
|
||||
|
||||
`:: is the namespace of the view`
|
||||
|
||||
`No equiv of file path ..`
|
||||
|
||||
`If you want the root of the view, or ns that is not a descendent the must specify abs path for view root `
|
||||
|
||||
how to do relative vs abs ns path
|
||||
|
||||
### Simulating flat namespaces by setting the view
|
||||
|
||||
While AppArmor namespaces are hierarchical they can simulate a flat
|
||||
set of namespaces by setting up a *root* namespace that is only used
|
||||
to provide the a view for its children namespaces, no policy will
|
||||
be loaded to the root namespace. A set of children namespaces are
|
||||
then created under the *root* namespace and policy is loaded into
|
||||
the children namespaces. Policy within a child namespace that does
|
||||
not reference policy outside of the specific child namespace does
|
||||
not use a namespace prefix. When a namespace prefix is used it will
|
||||
reference one of sibling namespaces.
|
||||
|
||||
```
|
||||
TODO example
|
||||
```
|
Loading…
Add table
Reference in a new issue