remove nfsnobody from examples and text

remove nfsnobody from examples and text

[[install-config-persistent-storage-pod-security-context]]
= Volume Security
{product-author}
{product-version}
:data-uri:
:icons:
:experimental:
:toc: macro
:toc-title:
:prewrap!:

toc::[]

== Overview

This topic provides a general guide on pod security as it relates to volume
security. For information on pod-level security in general, see
xref:../../admin_guide/manage_scc.adoc#admin-guide-manage-scc[Managing Security Context Constraints
(SCC)] and the
xref:../../architecture/additional_concepts/authorization.adoc#security-context-constraints[Security
Context Constraint] concept topic. For information on the {product-title}
persistent volume (PV) framework in general, see the
xref:../../architecture/additional_concepts/storage.adoc#architecture-additional-concepts-storage[Persistent Storage]
concept topic.

Accessing persistent storage requires coordination between the cluster and/or
storage administrator and the end developer. The cluster administrator creates
PVs, which abstract the underlying physical storage. The developer creates pods
and, optionally, PVCs, which bind to PVs, based on matching criteria, such as
capacity.

Multiple persistent volume claims (PVCs) within the same project can bind to the
same PV. However, once a PVC binds to a PV, that PV cannot be bound by a claim
outside of the first claim's project. If the underlying storage needs to be
accessed by multiple projects, then each project needs its own PV, which can
point to the same physical storage. In this sense, a bound PV is tied to a
project. For a detailed PV and PVC example, see the guide for
https://github.com/openshift/origin/tree/master/examples/wordpress[WordPress and
MySQL using NFS].

For the cluster administrator, granting pods access to PVs involves:

- knowing the group ID and/or user ID assigned to the actual storage,
- understanding SELinux considerations, and
- ensuring that these IDs are allowed in the range of legal IDs defined for the
project and/or the SCC that matches the requirements of the pod.

Group IDs, the user ID, and SELinux values are defined in the
`*SecurityContext*` section in a pod definition. Group IDs are global to the pod
and apply to all containers defined in the pod. User IDs can also be global, or
specific to each container. Four sections control access to volumes:

- xref:supplemental-groups[`*supplementalGroups*`]
- xref:fsgroup[`*fsGroup*`]
- xref:user-id[`*runAsUser*`]
- xref:selinuxoptions[`*seLinuxOptions*`]

[[sccs-defaults-allowed-ranges]]
== SCCs, Defaults, and Allowed Ranges

SCCs influence whether or not a pod is given a default user ID, `*fsGroup*` ID,
supplemental group ID, and SELinux label. They also influence whether or not IDs
supplied in the pod definition (or in the image) will be validated against a
range of allowable IDs. If validation is required and fails, then the pod will
also fail.

SCCs define strategies, such as `*runAsUser*`, `*supplementalGroups*`, and
`*fsGroup*`. These strategies help decide whether the pod is authorized.
Strategy values set to *RunAsAny* are essentially stating that the pod can do
what it wants regarding that strategy. Authorization is skipped for that
strategy and no {product-title} default is produced based on that strategy.
Therefore, IDs and SELinux labels in the resulting container are based on
container defaults instead of {product-title} policies.

For a quick summary of *RunAsAny*:

- Any ID defined in the pod definition (or image) is allowed.
- Absence of an ID in the pod definition (and in the image) results in the
container assigning an ID, which is *root* (0) for Docker.
- No SELinux labels are defined, so Docker will assign a unique label.

For these reasons, SCCs with *RunAsAny* for ID-related strategies should be
protected so that ordinary developers do not have access to the SCC. On the
other hand, SCC strategies set to *MustRunAs* or *MustRunAsRange* trigger ID
validation (for ID-related strategies), and cause default values to be supplied
by {product-title} to the container when those values are not supplied directly
in the pod definition or image.

SCCs may define the range of allowed IDs (user or groups). If range checking is
required (for example, using *MustRunAs*) and the allowable range is not defined
in the SCC, then the project determines the ID range. Therefore, projects
support ranges of allowable ID. However, unlike SCCs, projects do not define
strategies, such as `*runAsUser*`.

Allowable ranges are helpful not only because they define the boundaries for
container IDs, but also because the minimum value in the range becomes the
default value for the ID in question. For example, if the SCC ID strategy value
is *MustRunAs*, the minimum value of an ID range is *100*, and the ID is absent
from the pod definition, then 100 is provided as the default for this ID.

As part of pod admission, the SCCs available to a pod are examined (roughly, in
priority order followed by most restrictive) to best match the requests of the
pod. Setting a SCC's strategy type to *RunAsAny* is less restrictive, whereas a
type of *MustRunAs* is more restrictive. All of these strategies are evaluated.
To see which SCC was assigned to a pod, use the `oc get pod` command:

====
----
# oc get pod <pod_name> -o yaml
...
metadata:
  annotations:
    openshift.io/scc: nfs-scc <1>
  name: nfs-pod1 <2>
  namespace: default <3>
...
----
<1> Name of the SCC that the pod used (in this case, a custom SCC).
<2> Name of the pod.
<3> Name of the project. "Namespace" is interchangeable with "project" in
{product-title}. See
xref:../../architecture/core_concepts/projects_and_users.adoc#namespaces[Projects
and Users] for details.
====

It may not be immediately obvious which SCC was matched by a pod, so the command
above can be very useful in understanding the UID, supplemental groups, and
SELinux relabeling in a live container.

Any SCC with a strategy set to *RunAsAny* allows specific values for that
strategy to be defined in the pod definition (and/or image). When this applies
to the user ID (`*runAsUser*`) it is prudent to restrict access to the SCC to
prevent a container from being able to run as root.

Because pods often match the *restricted* SCC, it is worth knowing the security
this entails. The *restricted* SCC has the following characteristics:

- User IDs are constrained due to the `*runAsUser*` strategy being set to
*MustRunAsRange*. This forces user ID validation.
- Because a range of allowable user IDs is not defined in the SCC (see `oc export
scc restricted` for more details), the project's
`*openshift.io/sa.scc.uid-range*` range will be used for range checking and for
a default ID, if needed.
- A default user ID is produced when a user ID is not specified in the pod
definition and the matching SCC's `*runAsUser*` is set to *MustRunAsRange*.
- An SELinux label is required (`seLinuxContext` set to *MustRunAs*), which uses
the project's default MCS label.
- Arbitrary supplemental group IDs are allowed because no range checking is
required. This is a result of both the `*supplementalGroups*` and `*fsGroup*`
strategies being set to *RunAsAny*.
- Default supplemental groups are not produced for the running pod due to
*RunAsAny* for the two group strategies above. Therefore, if no groups are
defined in the pod definition (or in the image), the container(s) will have no
supplemental groups predefined.

The following shows the *default* project and a custom SCC (*my-custom-scc*),
which summarizes the interactions of the SCC and the project:

====
----
$ oc get project default -o yaml <1>
...
metadata:
  annotations: <2>
    openshift.io/sa.scc.mcs: s0:c1,c0 <3>
    openshift.io/sa.scc.supplemental-groups: 1000000000/10000 <4>
    openshift.io/sa.scc.uid-range: 1000000000/10000 <5>

$ oc get scc my-custom-scc -o yaml
...
fsGroup:
  type: MustRunAs <6>
  ranges:
  - min: 5000
    max: 6000
runAsUser:
  type: MustRunAsRange <7>
  uidRangeMin: 1000100000
  uidRangeMax: 1000100999
seLinuxContext: <8>
  type: MustRunAs
  SELinuxOptions: <9>
    user: <selinux-user-name>
    role: ...
    type: ...
    level: ...
supplementalGroups:
  type: MustRunAs <6>
  ranges:
  - min: 5000
    max: 6000
----
<1> *default* is the name of the project.
<2> Default values are only produced when the corresponding SCC strategy is not
*RunAsAny*.
<3> SELinux default when not defined in the pod definition or in the SCC.
<4> Range of allowable group IDs. ID validation only occurs when the SCC
strategy is *RunAsAny*. There can be more than one range specified, separated by
commas. See below for xref:volsec-rangeformats[supported formats].
<5> Same as *<4>* but for user IDs. Also, only a single range of user IDs is
supported.
<6> *MustRunAs* enforces group ID range checking and provides the container's
groups default. Based on this SCC definition, the default is 5000 (the minimum
ID value). If the range was omitted from the SCC, then the default would be
1000000000 (derived from the project). The other supported type, *RunAsAny*, does not
perform range checking, thus allowing any group ID, and produces no default
groups.
<7> *MustRunAsRange* enforces user ID range checking and provides a UID default.
Based on this SCC, the default UID is 1000100000 (the minimum value). If the minimum
and maximum range were omitted from the SCC, the default user ID would be
1000000000 (derived from the project). *MustRunAsNonRoot* and *RunAsAny* are
the other supported types. The range of allowed IDs can be defined to include
any user IDs required for the target storage.
<8> When set to *MustRunAs*, the container is created with the SCC's SELinux
options, or the MCS default defined in the project. A type of *RunAsAny*
indicates that SELinux context is not required, and, if not defined in the pod,
is not set in the container.
<9> The SELinux user name, role name, type, and labels can be defined here.
====

[[volsec-rangeformats]]
Two formats are supported for allowed ranges:

1. `M/N`, where `M` is the starting ID and `N` is the count, so the range becomes
`M` through (and including) `M+N-1`.

2. `M-N`, where `M` is again the starting ID and `N` is the ending ID. The default
group ID is the starting ID in the first range, which is `1000000000` in this
project. If the SCC did not define a minimum group ID, then the project's
default ID is applied.

[[supplemental-groups]]
== Supplemental Groups

[NOTE]
====
Read xref:sccs-defaults-allowed-ranges[SCCs, Defaults, and Allowed Ranges]
before working with supplemental groups.
====

[TIP]
====
It is generally preferable to use group IDs (supplemental or
xref:fsgroup[fsGroup]) to gain access to persistent storage versus using
xref:user-id[user IDs].
====

Supplemental groups are regular Linux groups. When a process runs in Linux, it
has a UID, a GID, and one or more supplemental groups. These attributes can be
set for a container's main process. The `*supplementalGroups*` IDs are typically
used for controlling access to shared storage, such as NFS and GlusterFS,
whereas xref:fsgroup[fsGroup] is used for controlling access to block storage,
such as Ceph RBD and iSCSI.

The {product-title} shared storage plug-ins mount volumes such that the POSIX
permissions on the mount match the permissions on the target storage. For
example, if the target storage's owner ID is *1234* and its group ID is *5678*, then
the mount on the host node and in the container will have those same IDs.
Therefore, the container's main process must match one or both of those IDs in
order to access the volume.

[[nfs-example]]
For example, consider the following NFS export.

On an {product-title} node:

[NOTE]
====
`showmount` requires access to the ports used by `rpcbind` and `rpc.mount` on
the NFS server
====

====
----
# showmount -e <nfs-server-ip-or-hostname>
Export list for f21-nfs.vm:
/opt/nfs  *
----
====

On the NFS server:

====
----
# cat /etc/exports
/opt/nfs *(rw,sync,root_squash)
...

# ls -lZ /opt/nfs -d
drwx------. 1000100001 5555 unconfined_u:object_r:usr_t:s0   /opt/nfs
----
====

The *_/opt/nfs/_* export is accessible by UID *1000100001* and the group *5555*. In
general, containers should not run as root. So, in this NFS example, containers
which are not run as UID *1000100001* and are not members the group *5555* will not
have access to the NFS export.

Often, the SCC matching the pod does not allow a specific user ID to be
specified, thus using supplemental groups is a more flexible way to grant
storage access to a pod. For example, to grant NFS access to the export above,
the group *5555* can be defined in the pod definition:

====
[source,yaml]
----
apiVersion: v1
kind: Pod
...
spec:
  containers:
  - name: ...
    volumeMounts:
    - name: nfs <1>
      mountPath: /usr/share/... <2>
  securityContext: <3>
    supplementalGroups: [5555] <4>
  volumes:
  - name: nfs <5>
    nfs:
      server: <nfs_server_ip_or_host>
      path: /opt/nfs <6>
----
<1> Name of the volume mount. Must match the name in the `*volumes*` section.
<2> NFS export path as seen in the container.
<3> Pod global security context. Applies to all containers inside the pod. Each
container can also define its `*securityContext*`, however group IDs are global
to the pod and cannot be defined for individual containers.
<4> Supplemental groups, which is an array of IDs, is set to 5555. This grants
group access to the export.
<5> Name of the volume. Must match the name in the `*volumeMounts*` section.
<6> Actual NFS export path on the NFS server.
====

All containers in the above pod (assuming the matching SCC or project allows the
group *5555*) will be members of the group *5555* and have access to the volume,
regardless of the container's user ID. However, the assumption above is
critical. Sometimes, the SCC does not define a range of allowable group IDs but
instead requires group ID validation (a result of `*supplementalGroups*` set to *MustRunAs*).
Note that this is *not* the case for the *_restricted_* SCC. The project will not likely
allow a group ID of *5555*, unless the project has been customized to access
this NFS export. So, in this scenario, the above pod will fail because its group
ID of *5555* is not within the SCC's or the project's range of allowed group
IDs.

[[scc-supplemental-groups]]
*Supplemental Groups and Custom SCCs*

To remedy the situation in xref:nfs-example[the previous example], a custom SCC
can be created such that:

- a minimum and max group ID are defined,
- ID range checking is enforced, and
- the group ID of *5555* is allowed.

It is often better to create a new SCC rather than modifying a predefined SCC, or
changing the range of allowed IDs in the predefined projects.

The easiest way to create a new SCC is to export an existing SCC and customize
the YAML file to meet the requirements of the new SCC. For example:

. Use the *restricted* SCC as a template for the new SCC:
+
----
$ oc export scc restricted > new-scc.yaml
----

. Edit the *_new-scc.yaml_* file to your desired specifications.

. Create the new SCC:
+
----
$ oc create -f new-scc.yaml
----

[NOTE]
====
The `oc edit scc` command can be used to modify an instantiated SCC.
====

Here is a fragment of a new SCC named *nfs-scc*:

====
----
$ oc export scc nfs-scc

allowHostDirVolumePlugin: false <1>
...
kind: SecurityContextConstraints
metadata:
  ...
  name: nfs-scc <2>
priority: 9 <3>
...
supplementalGroups:
  type: MustRunAs <4>
  ranges:
  -  min: 5000 <5>
     max: 6000
...
----
<1> The `allow*` bools are the same as for the *restricted* SCC.
<2> Name of the new SCC.
<3> Numerically larger numbers have greater priority. Nil or omitted is the lowest
priority. Higher priority SCCs sort before lower priority SCCs and thus have a
better chance of matching a new pod.
<4> `*supplementalGroups*` is a strategy and it is set to *MustRunAs*, which means
group ID checking is required.
<5> Multiple ranges are supported. The allowed group ID range here is 5000 through
5999, with the default supplemental group being 5000.
====

When the same pod shown earlier runs against this new SCC (assuming, of course,
the pod matches the new SCC), it will start because the group *5555*,
supplied in the pod definition, is now allowed by the custom SCC.

[[fsgroup]]
== fsGroup

[NOTE]
====
Read xref:sccs-defaults-allowed-ranges[SCCs, Defaults, and Allowed Ranges]
before working with supplemental groups.
====

[TIP]
====
It is generally preferable to use group IDs
(xref:supplemental-groups[supplemental] or `*fsGroup*`) to gain access to
persistent storage versus using xref:user-id[user IDs].
====

`*fsGroup*` defines a pod's "file system group" ID, which is added to the
container's supplemental groups. The `*supplementalGroups*` ID applies to shared
storage, whereas the `*fsGroup*` ID is used for block storage.

Block storage, such as Ceph RBD, iSCSI, and various cloud storage, is typically
dedicated to a single pod which has requested the block storage volume, either
directly or using a PVC. Unlike shared storage, block storage is taken over by a
pod, meaning that user and group IDs supplied in the pod definition (or image)
are applied to the actual, physical block device. Typically, block storage is
not shared.

A `*fsGroup*` definition is shown below in the following pod definition
fragment:

====
[source,yaml]
----
kind: Pod
...
spec:
  containers:
  - name: ...
  securityContext: <1>
    fsGroup: 5555 <2>
  ...
----
<1> As with `*supplementalGroups*`, `*fsGroup*` must be defined globally to the pod,
not per container.
<2> 5555 will become the group ID for the volume's group permissions and for all new
files created in the volume.
====

As with `*supplementalGroups*`, all containers in the above pod (assuming the
matching SCC or project allows the group *5555*) will be members of the group
*5555*, and will have access to the block volume, regardless of the container's
user ID. If the pod matches the *restricted* SCC, whose `*fsGroup*` strategy is
*RunAsAny*, then any `*fsGroup*` ID (including *5555*) will be accepted.
However, if the SCC has its `*fsGroup*` strategy set to *MustRunAs*, and *5555*
is not in the allowable range of `*fsGroup*` IDs, then the pod will fail to run.

[[scc-fsgroup]]
*fsGroups and Custom SCCs*

To remedy the situation in the previous example, a custom SCC can be created such that:

- a minimum and maximum group ID are defined,
- ID range checking is enforced,  and
- the group ID of *5555* is allowed.

It is better to create new SCCs versus modifying a predefined SCC, or changing
the range of allowed IDs in the predefined projects.

Consider the following fragment of a new SCC definition:

====
----
# oc export scc new-scc
...
kind: SecurityContextConstraints
...
fsGroup:
  type: MustRunAs <1>
  ranges: <2>
  - max: 6000
    min: 5000 <3>
...
----
<1> *MustRunAs* triggers group ID range checking, whereas *RunAsAny* does not
require range checking.
<2> The range of allowed group IDs is 5000 through, and including, 5999. Multiple
ranges are supported but not used. The allowed group ID range here is 5000 through 5999, with
the default `*fsGroup*` being 5000.
<3> The minimum value (or the entire range) can be omitted from the SCC, and thus
range checking and generating a default value will defer to the project's
`*openshift.io/sa.scc.supplemental-groups*` range. `*fsGroup*` and
`*supplementalGroups*` use the same group field in the project; there is not a
separate range for `*fsGroup*`.
====

When the pod shown above runs against this new SCC (assuming, of course, the pod
matches the new SCC), it will start because the group *5555*, supplied in
the pod definition, is allowed by the custom SCC. Additionally, the pod will
"take over" the block device, so when the block storage is viewed by a process
outside of the pod, it will actually have *5555* as its group ID.

A list of volumes supporting block ownership include:

* AWS Elastic Block Store
* OpenStack Cinder
* Ceph RBD
* GCE Persistent Disk
* iSCSI
* emptyDir
* gitRepo

[NOTE]
====
This list is potentially incomplete.
====

[[user-id]]
== User IDs

[NOTE]
====
Read xref:sccs-defaults-allowed-ranges[SCCs, Defaults, and Allowed Ranges]
before working with supplemental groups.
====

[TIP]
====
It is generally preferable to use group IDs
(xref:supplemental-groups[supplemental] or xref:fsgroup[fsGroup]) to gain
access to persistent storage versus using user IDs.
====

User IDs can be defined in the container image or in the pod definition. In the
pod definition, a single user ID can be defined globally to all containers, or
specific to individual containers (or both). A user ID is supplied as shown in
the pod definition fragment below:

[[pod-user-id-1000100001]]
====
[source,yaml]
----
spec:
  containers:
  - name: ...
    securityContext:
      runAsUser: 1000100001
----
====

ID 1000100001 in the above is container-specific and matches the owner ID on the
export. If the NFS export's owner ID was *54321*, then that number would be used
in the pod definition. Specifying `*securityContext*` outside of the container
definition makes the ID global to all containers in the pod.

Similar to group IDs, user IDs may be validated according to policies set in the
SCC and/or project. If the SCC's `*runAsUser*` strategy is set to *RunAsAny*,
then any user ID defined in the pod definition or in the image is allowed.

[WARNING]
====
This means even a UID of *0* (root) is allowed.
====

If, instead, the `*runAsUser*` strategy is set to *MustRunAsRange*, then a
supplied user ID will be validated against a range of allowed IDs. If the pod
supplies no user ID, then the default ID is set to the minimum value of the range of
allowable user IDs.

Returning to the earlier xref:nfs-example[NFS example], the container needs its
UID set to *1000100001*, which is shown in the pod fragment above. Assuming the
*default* project and the *restricted* SCC, the pod's requested user ID of
1000100001 will not be allowed, and therefore the pod will fail. The pod fails
because:

- it requests *1000100001* as its user ID,
- all available SCCs use *MustRunAsRange* for their `*runAsUser*` strategy, so UID
range checking is required, and
- *1000100001* is not included in the SCC or in the project's user ID range.

To remedy this situation, a new SCC can be created
with the appropriate user ID range. A new project could also be created with the
appropriate user ID range defined. There are also other, less-preferred options:

- The *restricted* SCC could be modified to include *1000100001* within its minimum and
maximum user ID range. This is not recommended as you should avoid modifying the
predefined SCCs if possible.
- The *restricted* SCC could be modified to use *RunAsAny* for the `*runAsUser*`
value, thus eliminating ID range checking. This is *_strongly_* not recommended, as
containers could run as root.
- The *default* project's UID range could be changed to allow a user ID of
*1000100001*. This is not generally advisable because only a single range of user IDs
can be specified, and thus other pods may not run if the range is altered.

[[scc-runasuser]]
*User IDs and Custom SCCs*

It is good practice to avoid modifying the predefined SCCs if possible. The
preferred approach is to create a custom SCC that better fits an organization's
security needs, or xref:../../dev_guide/projects.adoc#create-a-project[create a
new project] that supports the desired user IDs.

To remedy the situation in the previous example, a custom SCC can be created
such that:

- a minimum and maximum user ID is defined,
- UID range checking is still enforced, and
- the UID of *1000100001* is allowed.

For example:

====
----
$ oc export scc nfs-scc

allowHostDirVolumePlugin: false <1>
...
kind: SecurityContextConstraints
metadata:
  ...
  name: nfs-scc <2>
priority: 9 <3>
requiredDropCapabilities: null
runAsUser:
  type: MustRunAsRange <4>
  uidRangeMax: 1000100001 <5>
  uidRangeMin: 1000100001
...
----
<1> The `allowXX` bools are the same as for the *restricted* SCC.
<2> The name of this new SCC is *nfs-scc*.
<3> Numerically larger numbers have greater priority. Nil or omitted is the lowest
priority. Higher priority SCCs sort before lower priority SCCs, and thus have a
better chance of matching a new pod.
<4> The `*runAsUser*` strategy is set to *MustRunAsRange*, which means UID range
checking is enforced.
<5> The UID range is 1000100001 through 1000100001 (a range of one value).
====

Now, with `*runAsUser: 1000100001*` shown in the previous pod definition fragment,
the pod matches the new *nfs-scc* and is able to run with a UID of 1000100001.

[[selinuxoptions]]
== SELinux Options

All predefined SCCs, except for the *privileged* SCC, set the `*seLinuxContext*`
to *MustRunAs*. So the SCCs most likely to match a pod's requirements will force
the pod to use an SELinux policy. The SELinux policy used by the pod can be
defined in the pod itself, in the image, in the SCC, or in the project (which
provides the default).

SELinux labels can be defined in a pod's `*securityContext.seLinuxOptions*`
section, and supports `*user*`, `*role*`, `*type*`, and `*level*`:

[NOTE]
====
Level and MCS label are used interchangeably in this topic.
====

====
----
...
 securityContext: <1>
    seLinuxOptions:
      level: "s0:c123,c456" <2>
...
----
<1> `*level*` can be defined globally for the entire pod, or individually for each
container.
<2> SELinux level label.
====

Here are fragments from an SCC and from the *default* project:

====
----
$ oc export scc scc-name
...
seLinuxContext:
  type: MustRunAs <1>

# oc export project default
...
metadata:
  annotations:
    openshift.io/sa.scc.mcs: s0:c1,c0 <2>
...
----
<1> *MustRunAs* causes volume relabeling.
<2> If the label is not provided in the pod or in the SCC, then the default comes
from the project.
====

All predefined SCCs, except for the *privileged* SCC, set the `*seLinuxContext*`
to *MustRunAs*. This forces pods to use MCS labels, which can be defined in the
pod definition, the image, or provided as a default.

The SCC determines whether or not to require an SELinux label and can provide a
default label. If the `*seLinuxContext*` strategy is set to *MustRunAs* and the
pod (or image) does not define a label, {product-title} defaults to a label
chosen from the SCC itself or from the project.

If `*seLinuxContext*` is set to *RunAsAny*, then no
default labels are provided, and the container determines the final label. In
the case of Docker, the container will use a unique MCS label, which will not
likely match the labeling on existing storage mounts. Volumes which support
SELinux management will be relabeled so that they are accessible by the
specified label and, depending on how exclusionary the label is, only that
label.

This means two things for unprivileged containers:

- The volume will be given a `*type*` which is accessible by unprivileged
containers. This `*type*` is usually *svirt_sandbox_file_t*.
- If a `*level*` is specified, the volume will be labeled with the given MCS
label.

For a volume to be accessible by a pod, the pod must have both categories of the volume.
So a pod with *s0:c1,c2* will be able to access a volume with *s0:c1,c2*. A volume with
*s0* will be accessible by all pods.

If pods fail authorization, or if the storage mount is failing due to
permissions errors, then there is a possibility that SELinux enforcement is
interfering. One way to check for this is to run:

----
# ausearch -m avc --start recent
----

This examines the log file for AVC (Access Vector Cache) errors.

[[install-config-persistent-storage-pod-security-context]]
= Volume Security
{product-author}
{product-version}
:data-uri:
:icons:
:experimental:
:toc: macro
:toc-title:
:prewrap!:

toc::[]

== Overview

This topic provides a general guide on pod security as it relates to volume
security. For information on pod-level security in general, see
xref:../../admin_guide/manage_scc.adoc#admin-guide-manage-scc[Managing Security Context Constraints
(SCC)] and the
xref:../../architecture/additional_concepts/authorization.adoc#security-context-constraints[Security
Context Constraint] concept topic. For information on the {product-title}
persistent volume (PV) framework in general, see the
xref:../../architecture/additional_concepts/storage.adoc#architecture-additional-concepts-storage[Persistent Storage]
concept topic.

Accessing persistent storage requires coordination between the cluster and/or
storage administrator and the end developer. The cluster administrator creates
PVs, which abstract the underlying physical storage. The developer creates pods
and, optionally, PVCs, which bind to PVs, based on matching criteria, such as
capacity.

Multiple persistent volume claims (PVCs) within the same project can bind to the
same PV. However, once a PVC binds to a PV, that PV cannot be bound by a claim
outside of the first claim's project. If the underlying storage needs to be
accessed by multiple projects, then each project needs its own PV, which can
point to the same physical storage. In this sense, a bound PV is tied to a
project. For a detailed PV and PVC example, see the guide for
https://github.com/openshift/origin/tree/master/examples/wordpress[WordPress and
MySQL using NFS].

For the cluster administrator, granting pods access to PVs involves:

- knowing the group ID and/or user ID assigned to the actual storage,
- understanding SELinux considerations, and
- ensuring that these IDs are allowed in the range of legal IDs defined for the
project and/or the SCC that matches the requirements of the pod.

Group IDs, the user ID, and SELinux values are defined in the
`*SecurityContext*` section in a pod definition. Group IDs are global to the pod
and apply to all containers defined in the pod. User IDs can also be global, or
specific to each container. Four sections control access to volumes:

- xref:supplemental-groups[`*supplementalGroups*`]
- xref:fsgroup[`*fsGroup*`]
- xref:user-id[`*runAsUser*`]
- xref:selinuxoptions[`*seLinuxOptions*`]

[[sccs-defaults-allowed-ranges]]
== SCCs, Defaults, and Allowed Ranges

SCCs influence whether or not a pod is given a default user ID, `*fsGroup*` ID,
supplemental group ID, and SELinux label. They also influence whether or not IDs
supplied in the pod definition (or in the image) will be validated against a
range of allowable IDs. If validation is required and fails, then the pod will
also fail.

SCCs define strategies, such as `*runAsUser*`, `*supplementalGroups*`, and
`*fsGroup*`. These strategies help decide whether the pod is authorized.
Strategy values set to *RunAsAny* are essentially stating that the pod can do
what it wants regarding that strategy. Authorization is skipped for that
strategy and no {product-title} default is produced based on that strategy.
Therefore, IDs and SELinux labels in the resulting container are based on
container defaults instead of {product-title} policies.

For a quick summary of *RunAsAny*:

- Any ID defined in the pod definition (or image) is allowed.
- Absence of an ID in the pod definition (and in the image) results in the
container assigning an ID, which is *root* (0) for Docker.
- No SELinux labels are defined, so Docker will assign a unique label.

For these reasons, SCCs with *RunAsAny* for ID-related strategies should be
protected so that ordinary developers do not have access to the SCC. On the
other hand, SCC strategies set to *MustRunAs* or *MustRunAsRange* trigger ID
validation (for ID-related strategies), and cause default values to be supplied
by {product-title} to the container when those values are not supplied directly
in the pod definition or image.

SCCs may define the range of allowed IDs (user or groups). If range checking is
required (for example, using *MustRunAs*) and the allowable range is not defined
in the SCC, then the project determines the ID range. Therefore, projects
support ranges of allowable ID. However, unlike SCCs, projects do not define
strategies, such as `*runAsUser*`.

Allowable ranges are helpful not only because they define the boundaries for
container IDs, but also because the minimum value in the range becomes the
default value for the ID in question. For example, if the SCC ID strategy value
is *MustRunAs*, the minimum value of an ID range is *100*, and the ID is absent
from the pod definition, then 100 is provided as the default for this ID.

As part of pod admission, the SCCs available to a pod are examined (roughly, in
priority order followed by most restrictive) to best match the requests of the
pod. Setting a SCC's strategy type to *RunAsAny* is less restrictive, whereas a
type of *MustRunAs* is more restrictive. All of these strategies are evaluated.
To see which SCC was assigned to a pod, use the `oc get pod` command:

====
----
# oc get pod <pod_name> -o yaml
...
metadata:
  annotations:
    openshift.io/scc: nfs-scc <1>
  name: nfs-pod1 <2>
  namespace: default <3>
...
----
<1> Name of the SCC that the pod used (in this case, a custom SCC).
<2> Name of the pod.
<3> Name of the project. "Namespace" is interchangeable with "project" in
{product-title}. See
xref:../../architecture/core_concepts/projects_and_users.adoc#namespaces[Projects
and Users] for details.
====

It may not be immediately obvious which SCC was matched by a pod, so the command
above can be very useful in understanding the UID, supplemental groups, and
SELinux relabeling in a live container.

Any SCC with a strategy set to *RunAsAny* allows specific values for that
strategy to be defined in the pod definition (and/or image). When this applies
to the user ID (`*runAsUser*`) it is prudent to restrict access to the SCC to
prevent a container from being able to run as root.

Because pods often match the *restricted* SCC, it is worth knowing the security
this entails. The *restricted* SCC has the following characteristics:

- User IDs are constrained due to the `*runAsUser*` strategy being set to
*MustRunAsRange*. This forces user ID validation.
- Because a range of allowable user IDs is not defined in the SCC (see `oc export
scc restricted` for more details), the project's
`*openshift.io/sa.scc.uid-range*` range will be used for range checking and for
a default ID, if needed.
- A default user ID is produced when a user ID is not specified in the pod
definition due to `*runAsUser*` being set to *MustRunAsRange*.
- An SELinux label is required (`seLinuxContext` set to _MustRunAs_), which uses
the project's default MCS label.
- Arbitrary supplemental group IDs are allowed because no range checking is
required. This is a result of both the `*supplementalGroups*` and `*fsGroup*`
strategies being set to *RunAsAny*.
- Default supplemental groups are not produced for the running pod due to
*RunAsAny* for the two group strategies above. Therefore, if no groups are
defined in the pod definition (or in the image), the container(s) will have no
supplemental groups predefined.

The following shows the *default* project and a custom SCC (*my-custom-scc*),
which summarizes the interactions of the SCC and the project:

====
----
$ oc get project default -o yaml <1>
...
metadata:
  annotations: <2>
    openshift.io/sa.scc.mcs: s0:c1,c0 <3>
    openshift.io/sa.scc.supplemental-groups: 1000000000/10000 <4>
    openshift.io/sa.scc.uid-range: 1000000000/10000 <5>

$ oc get scc my-custom-scc -o yaml
...
fsGroup:
  type: MustRunAs <6>
  ranges:
  - min: 5000
    max: 6000
runAsUser:
  type: MustRunAsRange <7>
  uidRangeMin: 65534
  uidRangeMax: 65634
seLinuxContext: <8>
  type: MustRunAs
  SELinuxOptions: <9>
    user: <selinux-user-name>
    role: ...
    type: ...
    level: ...
supplementalGroups:
  type: MustRunAs <6>
  ranges:
  - min: 5000
    max: 6000
----
<1> *default* is the name of the project.
<2> Default values are only produced when the corresponding SCC strategy is not
*RunAsAny*.
<3> SELinux default when not defined in the pod definition or in the SCC.
<4> Range of allowable group IDs. ID validation only occurs when the SCC
strategy is *RunAsAny*. There can be more than one range specified, separated by
commas. See below for xref:volsec-rangeformats[supported formats].
<5> Same as *<4>* but for user IDs. Also, only a single range of user IDs is
supported.
<6> *MustRunAs* enforces group ID range checking and provides the container's
groups default. Based on this SCC definition, the default is 5000 (the minimum
ID value). If the range was omitted from the SCC, then the default would be
1000000000 (derived from the project). The other supported type, *RunAsAny*, does not
perform range checking, thus allowing any group ID, and produces no default
groups.
<7> *MustRunAsRange* enforces user ID range checking and provides a UID default.
*Based on this SCC, the default UID is 65534 (the minimum value). If the minimum
*and maximum range were omitted from the SCC, the default user ID would be
*1000000000 (derived from the project). *MustRunAsNonRoot* and *RunAsAny* are
*the other supported types. The range of allowed IDs can be defined to include
*any user IDs required for the target storage.
<8> When set to *MustRunAs*, the container is created with the SCC's SELinux
options, or the MCS default defined in the project. A type of *RunAsAny*
indicates that SELinux context is not required, and, if not defined in the pod,
is not set in the container.
<9> The SELinux user name, role name, type, and labels can be defined here.
====

[[volsec-rangeformats]]
Two formats are supported for allowed ranges:

1. `M/N`, where `M` is the starting ID and `N` is the count, so the range becomes
`M` through (and including) `M+N-1`.

2. `M-N`, where `M` is again the starting ID and `N` is the ending ID. The default
group ID is the starting ID in the first range, which is `1000000000` in this
project. If the SCC did not define a minimum group ID, then the project's
default ID is applied.

[[supplemental-groups]]
== Supplemental Groups

[NOTE]
====
Read xref:sccs-defaults-allowed-ranges[SCCs, Defaults, and Allowed Ranges]
before working with supplemental groups.
====

[TIP]
====
It is generally preferable to use group IDs (supplemental or
xref:fsgroup[fsGroup]) to gain access to persistent storage versus using
xref:user-id[user IDs].
====

Supplemental groups are regular Linux groups. When a process runs in Linux, it
has a UID, a GID, and one or more supplemental groups. These attributes can be
set for a container's main process. The `*supplementalGroups*` IDs are typically
used for controlling access to shared storage, such as NFS and GlusterFS,
whereas xref:fsgroup[fsGroup] is used for controlling access to block storage,
such as Ceph RBD and iSCSI.

The {product-title} shared storage plug-ins mount volumes such that the POSIX
permissions on the mount match the permissions on the target storage. For
example, if the target storage's owner ID is *1234* and its group ID is *5678*, then
the mount on the host node and in the container will have those same IDs.
Therefore, the container's main process must match one or both of those IDs in
order to access the volume.

[[nfs-example]]
For example, consider the following NFS export.

On an {product-title} node:

[NOTE]
====
`showmount` requires access to the ports used by `rpcbind` and `rpc.mount` on
the NFS server
====

====
----
# showmount -e <nfs-server-ip-or-hostname>
Export list for f21-nfs.vm:
/opt/nfs  *
----
====

On the NFS server:

====
----
# cat /etc/exports
/opt/nfs *(rw,sync,root_squash)
...

# ls -lZ /opt/nfs -d
drwxrws---. nfsnobody 5555 unconfined_u:object_r:usr_t:s0   /opt/nfs

# id nfsnobody
uid=65534(nfsnobody) gid=65534(nfsnobody) groups=65534(nfsnobody)
----
====

[NOTE]
====
In the above, the owner is 65534 (*nfsnobody*), but the suggestions and examples in
this topic apply to any non-root owner.
====

The *_/opt/nfs/_* export is accessible by UID *65534* and the group *5555*. In
general, containers should not run as root, so in this NFS example, containers
which are not run as UID *65534* or are not members the group *5555* will not be
able to access the NFS export.

Often, the SCC matching the pod does not allow a specific user ID to be
specified, thus using supplemental groups is a more flexible way to grant
storage access to a pod. For example, to grant NFS access to the export above,
the group *5555* can be defined in the pod definition:

====
[source,yaml]
----
apiVersion: v1
kind: Pod
...
spec:
  containers:
  - name: ...
    volumeMounts:
    - name: nfs <1>
      mountPath: /usr/share/... <2>
  securityContext: <3>
    supplementalGroups: [5555] <4>
  volumes:
  - name: nfs <5>
    nfs:
      server: <nfs_server_ip_or_host>
      path: /opt/nfs <6>
----
<1> Name of the volume mount. Must match the name in the `*volumes*` section.
<2> NFS export path as seen in the container.
<3> Pod global security context. Applies to all containers in the pod. Each
container can also define its `*securityContext*`, however group IDs are global
to the pod and cannot be defined for individual containers.
<4> Supplemental groups, which is an array of IDs, is set to 5555. This grants
group access to the export.
<5> Name of the volume. Must match the name in the `*volumeMounts*` section.
<6> Actual NFS export path on the NFS server.
====

All containers in the above pod (assuming the matching SCC or project allows the
group *5555*) will be members of the group *5555* and have access to the volume,
regardless of the container's user ID. However, the assumption above is
critical. Sometimes, the SCC does not define a range of allowable group IDs but
requires group ID validation (due to `*supplementalGroups*` set to *MustRunAs*;
note this is not the case for the *restricted* SCC). The project will not likely
allow a group ID of *5555*, unless the project has been customized for access to
this NFS export. So in this scenario, the above pod will fail because its group
ID of *5555* is not within the SCC's or the project's range of allowed group
IDs.

[[scc-supplemental-groups]]
*Supplemental Groups and Custom SCCs*

To remedy the situation in xref:nfs-example[the previous example], a custom SCC
can be created such that:

- a minimum and max group ID are defined,
- ID range checking is enforced, and
- the group ID of *5555* is allowed.

It is better to create new SCCs versus modifying a predefined SCC, or changing
the range of allowed IDs in the predefined projects.

The easiest way to create a new SCC is to export an existing SCC and customize
the YAML file to meet the requirements of the new SCC. For example:

. Use the *restricted* SCC as a template for the new SCC:
+
----
$ oc export scc restricted > new-scc.yaml
----

. Edit the *_new-scc.yaml_* file to your desired specifications.

. Create the new SCC:
+
----
$ oc create -f new-scc.yaml
----

[NOTE]
====
The `oc edit scc` command can be used to modify an instantiated SCC.
====

Here is a fragment of a new SCC named *nfs-scc*:

====
----
$ oc export scc nfs-scc

allowHostDirVolumePlugin: false <1>
...
kind: SecurityContextConstraints
metadata:
  ...
  name: nfs-scc <2>
priority: 9 <3>
...
supplementalGroups:
  type: MustRunAs <4>
  ranges:
  -  min: 5000 <5>
     max: 6000
...
----
<1> The `allow*` bools are the same as for the *restricted* SCC.
<2> Name of the new SCC.
<3> Numerically larger numbers have greater priority. Nil or omitted is the lowest
priority. Higher priority SCCs sort before lower priority SCCs and thus have a
better chance of matching a new pod.
<4> `*supplementalGroups*` is a strategy and it is set to *MustRunAs*, which means
group ID checking is required.
<5> Multiple ranges are supported. The allowed group ID range here is 5000 through
5999, with the default supplemental group being 5000.
====

When the same pod shown earlier runs against this new SCC (assuming, of course,
the pod has access to the new SCC), it will start because the group *5555*,
supplied in the pod definition, is now allowed by the custom SCC.

[[fsgroup]]
== fsGroup

[NOTE]
====
Read xref:sccs-defaults-allowed-ranges[SCCs, Defaults, and Allowed Ranges]
before working with supplemental groups.
====

[TIP]
====
It is generally preferable to use group IDs
(xref:supplemental-groups[supplemental] or `*fsGroup*`) to gain access to
persistent storage versus using xref:user-id[user IDs].
====

`*fsGroup*` defines a pod's "file system group" ID, which is added to the
container's supplemental groups. The `*supplementalGroups*` ID applies to shared
storage, whereas the `*fsGroup*` ID is used for block storage.

Block storage, such as Ceph RBD, iSCSI, and various cloud storage, is typically
dedicated to a single pod which has requested the block storage volume, either
directly or using a PVC. Unlike shared storage, block storage is taken over by a
pod, meaning that user and group IDs supplied in the pod definition (or image)
are applied to the actual, physical block device. Typically, block storage is
not shared.

A `*fsGroup*` definition is shown below in the following pod definition
fragment:

====
[source,yaml]
----
kind: Pod
...
spec:
  containers:
  - name: ...
  securityContext: <1>
    fsGroup: 5555 <2>
  ...
----
<1> As with `*supplementalGroups*`, `*fsGroup*` must be defined globally to the pod,
not per container.
<2> 5555 will become the group ID for the volume's group permissions and for all new
files created in the volume.
====

As with `*supplementalGroups*`, all containers in the above pod (assuming the
matching SCC or project allows the group *5555*) will be members of the group
*5555*, and will have access to the block volume, regardless of the container's
user ID. If the pod matches the *restricted* SCC, whose `*fsGroup*` strategy is
*RunAsAny*, then any `*fsGroup*` ID (including *5555*) will be accepted.
However, if the SCC has its `*fsGroup*` strategy set to *MustRunAs*, and *5555*
is not in the allowable range of `*fsGroup*` IDs, then the pod will fail to run.

[[scc-fsgroup]]
*fsGroups and Custom SCCs*

To remedy the situation in the previous example, a custom SCC can be created such that:

- a minimum and maximum group ID are defined,
- ID range checking is enforced,  and
- the group ID of *5555* is allowed.

It is better to create new SCCs versus modifying a predefined SCC, or changing
the range of allowed IDs in the predefined projects.

Consider the following fragment of a new SCC definition:

====
----
# oc export scc new-scc
...
kind: SecurityContextConstraints
...
fsGroup:
  type: MustRunAs <1>
  ranges: <2>
  - max: 6000
    min: 5000 <3>
...
----
<1> *MustRunAs* triggers group ID range checking, whereas *RunAsAny* does not
require range checking.
<2> The range of allowed group IDs is 5000 through, and including, 5999. Multiple
ranges are supported. The allowed group ID range here is 5000 through 5999, with
the default `*fsGroup*` being 5000.
<3> The minimum value (or the entire range) can be omitted from the SCC, and thus
range checking and generating a default value will defer to the project's
`*openshift.io/sa.scc.supplemental-groups*` range. `*fsGroup*` and
`*supplementalGroups*` use the same group field in the project; there is not a
separate range for `*fsGroup*`.
====

When the pod shown above runs against this new SCC (assuming, of course, the pod
has access to the new SCC), it will start because the group *5555*, supplied in
the pod definition, is allowed by the custom SCC. Additionally, the pod will
"take over" the block device, so when the block storage is viewed by a process
outside of the pod, it will actually have *5555* as its group ID.

Currently the list of volumes which support block ownership (block) management
include:

* AWS Elastic Block Store
* OpenStack Cinder
* Ceph RBD
* GCE Persistent Disk
* iSCSI
* emptyDir
* gitRepo

[[user-id]]
== User IDs

[NOTE]
====
Read xref:sccs-defaults-allowed-ranges[SCCs, Defaults, and Allowed Ranges]
before working with supplemental groups.
====

[TIP]
====
It is generally preferable to use group IDs
(xref:supplemental-groups[supplemental] or xref:fsgroup[fsGroup]) to gain
access to persistent storage versus using user IDs.
====

User IDs can be defined in the container image or in the pod definition. In the
pod definition, a single user ID can be defined globally to all containers, or
specific to individual containers (or both). A user ID is supplied as shown in
the pod definition fragment below:

[[pod-user-id-65534]]
====
[source,yaml]
----
spec:
  containers:
  - name: ...
    securityContext:
      runAsUser: 65534
----
====

ID 65534 in the above is container-specific and matches the owner ID on the
export. If the NFS export's owner ID was *54321*, then that number would be used
in the pod definition. Specifying `*securityContext*` outside of the container
definition makes the ID global to all containers in the pod.

Similar to group IDs, user IDs may be validated according to policies set in the
SCC and/or project. If the SCC's `*runAsUser*` strategy is set to *RunAsAny*,
then any user ID defined in the pod definition or in the image is allowed.

[WARNING]
====
This means even a UID of *0* (root) is allowed.
====

If, instead, the `*runAsUser*` strategy is set to *MustRunAsRange*, then a
supplied user ID will be validated against a range of allowed IDs. If the pod
supplies no user ID, then the default ID is the minimum value of the range of
allowable user IDs.

Returning to the earlier xref:nfs-example[NFS example], the container needs its
UID set to *65534*, which is shown in the pod fragment above. Assuming the
*default* project and the *restricted* SCC, the pod's requested user ID of
*65534* will *not* be allowed, and therefore the pod will fail. The pod fails
because:

- it requests *65534* as its user ID,
- all available SCCs use *MustRunAsRange* for their `*runAsUser*` strategy, so UID
range checking is required, and
- *65534* is not included in the SCC or project's user ID range.

To address this situation, the recommended path would be to create a new SCC
with the appropriate user ID range. A new project could also be created with the
appropriate user ID range defined. There are other, less-preferred options:

- The *restricted* SCC could be modified to include *65534* within its minimum and
maximum user ID range. This is not recommended as you should avoid modifying the
predefined SCCs if possible.
- The *restricted* SCC could be modified to use *RunAsAny* for the `*runAsUser*`
value, thus eliminating ID range checking. This is strongly not recommended, as
containers could run as root.
- The *default* project's UID range could be changed to allow a user ID of
*65534*. This is not generally advisable because only a single range of user IDs
can be specified.

[[scc-runasuser]]
*User IDs and Custom SCCs*

It is good practice to avoid modifying the predefined SCCs if possible. The
preferred approach is to create a custom SCC that better fits an organization's
security needs, or xref:../../dev_guide/projects.adoc#create-a-project[create a
new project] that supports the desired user IDs.

To remedy the situation in the previous example, a custom SCC can be created
such that:

- a minimum and maximum user ID is defined,
- UID range checking is still enforced, and
- the UID of *65534* will be allowed.

For example:

====
----
$ oc export scc nfs-scc

allowHostDirVolumePlugin: false <1>
...
kind: SecurityContextConstraints
metadata:
  ...
  name: nfs-scc <2>
priority: 9 <3>
requiredDropCapabilities: null
runAsUser:
  type: MustRunAsRange <4>
  uidRangeMax: 65534 <5>
  uidRangeMin: 65534
...
----
<1> The `allow*` bools are the same as for the *restricted* SCC.
<2> The name of this new SCC is *nfs-scc*.
<3> Numerically larger numbers have greater priority. Nil or omitted is the lowest
priority. Higher priority SCCs sort before lower priority SCCs, and thus have a
better chance of matching a new pod.
<4> The `*runAsUser*` strategy is set to *MustRunAsRange*, which means UID range
checking is enforced.
<5> The UID range is 65534 through 65534 (a range of one value).
====

Now, with `*runAsUser: 65534*` shown in the previous pod definition fragment,
the pod matches the new *nfs-scc* and is able to run with a UID of 65534.

[[selinuxoptions]]
== SELinux Options

All predefined SCCs, except for the *privileged* SCC, set the `*seLinuxContext*`
to *MustRunAs*. So the SCCs most likely to match a pod's requirements will force
the pod to use an SELinux policy. The SELinux policy used by the pod can be
defined in the pod itself, in the image, in the SCC, or in the project (which
provides the default).

SELinux labels can be defined in a pod's `*securityContext.seLinuxOptions*`
section, and supports `*user*`, `*role*`, `*type*`, and `*level*`:

[NOTE]
====
Level and MCS label are used interchangeably in this topic.
====

====
----
...
 securityContext: <1>
    seLinuxOptions:
      level: "s0:c123,c456" <2>
...
----
<1> `*level*` can be defined globally for the entire pod, or individually for each
container.
<2> SELinux level label.
====

Here are fragments from an SCC and from the *default* project:

====
----
$ oc export scc scc-name
...
seLinuxContext:
  type: MustRunAs <1>

# oc export project default
...
metadata:
  annotations:
    openshift.io/sa.scc.mcs: s0:c1,c0 <2>
...
----
<1> *MustRunAs* causes volume relabeling.
<2> If the label is not provided in the pod or in the SCC, then the default comes
from the project.
====

All predefined SCCs, except for the *privileged* SCC, set the `*seLinuxContext*`
to *MustRunAs*. This forces pods to use MCS labels, which can be defined in the
pod definition, the image, or provided as a default.

The SCC determines whether or not to require an SELinux label and can provide a
default label. If the `*seLinuxContext*` strategy is set to *MustRunAs* and the
pod (or image) does not define a label, {product-title} defaults to a label
chosen from the SCC itself or from the project.

If `*seLinuxContext*` is set to *RunAsAny*, then no
default labels are provided, and the container determines the final label. In
the case of Docker, the container will use a unique MCS label, which will not
likely match the labeling on existing storage mounts. Volumes which support
SELinux management will be relabeled so that they are accessible by the
specified label and, depending on how exclusionary the label is, only that
label.

This means two things for unprivileged containers:

- The volume will be given a `*type*` which is accessible by unprivileged
containers. This `*type*` is usually *svirt_sandbox_file_t*.
- If a `*level*` is specified, the volume will be labeled with the given MCS
label.

For a volume to be accessible by a pod, the pod must have both categories of the volume.
So a pod with *s0:c1,c2* will be able to access a volume with *s0:c1,c2*. A volume with
*s0* will be accessible by all pods.

If pods fail authorization, or if the storage mount is failing due to
permissions errors, then there is a possibility that SELinux enforcement is
interfering. One way to check for this is to run:

----
# ausearch -m avc --start recent
----

This examines the log file for AVC (Access Vector Cache) errors.


Update 2015-11-25-11-10-Bitmask-usage.adoc

= 1+1 = 10. Bitmask usage
:hp-image: cover_lines.jpg
:hp-tags: bitmask

Цікаво, наскільки розповсюджене зараз, в час "панування" високорівневих мов програмування та великих об"ємів пам"яті, використання побітових операцій (bitwise) та бітових масок (bitmask)? Мені чомусь здавалось, що двійкова система счислення може бути корисною для тих, хто займається низько-рівневим програмуванням (ніколи не зустрічала таких людей, але сподіваюсь, що вони існують), ну або для написання якогось хитрого ресурсозберігаючого алгоритму (людей, що займаються такими речами для роботи, а не для хобі, я теж, нажаль, не зустрічала). Яким же було моє здивування, коли на одному проекті я побачила в коді операцію на зразок наступної: +

	if (Request.PermissionMask & (8) > 0)
		{...}

Невже! Невже шкільні знання з двійкової системи счислення стануть в нагоді для роботи! Як виявиться пізніше, на двох моїх минулих звичайнісіньких корпоративних проектах використовувались бітові маски. Одним з них була програма написана років так 15 назад (ну тут можна зрозуміти, може на час написання не було інших варіантів просто і там ніхто не думав про те, що код має бути зрозумілим і self-descriptive), але інший проект був відносно новим. Ні в тому, ні в іншому випадку проблеми економії пам"яті та проблеми обробки великих об"ємів даних не було.

== Bitmask

Спробую пояснити своє здивування. Спочатку розповім, що таке бітова маска. Bitmask - це спосіб представити характеристики об"єкту за допомогою цифр 0 та 1 (ну, тому що це *бітова* маска). Можна думати про бітову маску як про шифр: +

- Кожна цифра в числі відповідає за заздалегідь визначену властивість;
- 0 може значити, наприклад, що певна властивість в об"єкті відсутня, а 1 - що присутня.

Для кращого розуміння, створимо бітові маски для кольорів. Є три базових кольори - червоний, жовтий та синій. Змішуючи ці кольори ми можемо отримати всі інші (я тут маю на увазі базові кольори для художників, живих людей, а не представлення кольору в комп"ютерах).

|===
|Червоний|Жовтий|Синій|
|0|0|1| Синій
|0|1|0| Жовтий
|1|0|0| Червоний
|0|1|1| Зелений
|1|1|0| Помаранчевий
|1|0|1| Фіолетовий
|===

Отримали такі двійкові коди: +

	1 - синій
    10 - жовтий
    100 - червоний
    11 - зелений
    110 - помаранчевий
    101 - фіолетовий

Зазвичай, якщо вирішують користуватись бітовими масками, то такі двійкові коди переводять в звичну для нас десяткову систему счислення:

|===
||2|1|0|
|синій|0|0|1|1 * 2^0^ = 1
|жовтий|0|1|0| 1 * 2^1^ = 2
|червоний|1|0|0| 1 * 2^2^ = 4
|зелений|0|1|1| 1 * 2^0^ + 1 * 2^1^ = 3
|помаранчевий|1|1|0| 1 * 2^1^ + 1 * 2^2^ = 6
|фіолетовий|1|0|1| 1 * 2^0^ + 1 * 2^2^ = 5
|===

Тепер, коди до наших кольорів виглядають так:

	1 - синій
    2 - жовтий
    4 - червоний
    3 - зелений
    6 - помаранчевий
    5 - фіолетовий

Якщо проаналізувати, то побачимо, що всі базові кольори є степенями 2, всі інші кольори, що ми отримали в результаті змішування є сумою відповідних базових кольорів, так фіолетовий = синій + червоний: +

	5 = 1 + 4

Окрім цих властивостей, ще в програмах, такі "зашифровані" об"єкти розшифровуються бітовими операціями (bitwise), в основному операндом & (AND). Так, наприклад, якщо нам потрібно вибрати серед всієї множини наших кольорів тільки ті кольори, де був застосований синій колір, то ми виконаємо таку операцію:

	color = {1, 2, 4, 3, 6, 5} - наша множина всіх кольорів
	color & 1 > 0  = {1, 3, 5} - множина кольорів, в яких є синій колір (синій, зелений, фіолетовий)

Опишу детальніше, як ми це отримали:

Ми застосовуємо логічне AND до кожної пари бітів, які стоять на однакових позиціях у двійкових представленнях кольорів. Якщо обидва відповідних біта рівні 1, результуючий двійковий розряд дорівнює 1 (true), якщо ж хоча б один біт з пари дорівнює 0, результуючий двійковий розряд дорівнює 0 (false).

|===
|0|0|#1#| Синій
|0|1|0| Жовтий
|1|0|0| Червоний
|0|1|#1#| Зелений
|1|1|0| Помаранчевий
|1|0|#1#| Фіолетовий
|===
***
|===
|0|0|#1#| Синій
|===
***
|===
|0|0|*1*| Синій
|[line-through]*0*|[line-through]*0*|[line-through]*0*| [line-through]*Жовтий*
|[line-through]*0*|[line-through]*0*|[line-through]*0*| [line-through]*Червоний*
|0|0|*1*| Зелений
|[line-through]*0*|[line-through]*0*|[line-through]*0*| [line-through]*Помаранчевий*
|0|0|*1*| Фіолетовий
|===

Результат операції AND для жовтого, червоного та помаранчевого кольорів однаковий - 000, а значить вони не ввійшли в результуючий набір.

Як бачите, застосування бітових масок є цікавим та дає нам можливість в одному числі зберігати багато інформації - по одному біту на характеристику об"єкта. Але, це не  робить програму легкою для розуміння та подальшої підтримки, особливо, якщо розробник не задокументував свій шифр =)

На сьогодні все, а в наступному пості я розповім про те, як можна удосконалити рішення, якщо ви, все ж таки, вирішили скористатись bitmask у своєму проекті.

icon:heart-o[size=2x]

= 1+1 = 10. Bitmask usage
:hp-image: cover_lines.jpg
:hp-tags: bitmask

Цікаво, наскільки розповсюджене зараз, в час "панування" високорівневих мов програмування та великих об"ємів пам"яті, використання побітових операцій (bitwise) та бітових масок (bitmask)? Мені чомусь здавалось, що двійкова система счислення може бути корисною для тих, хто займається низько-рівневим програмуванням (ніколи не зустрічала таких людей, але сподіваюсь, що вони існують), ну або для написання якогось хитрого ресурсозберігаючого алгоритму (людей, що займаються такими речами для роботи, а не для хобі, я теж, нажаль, не зустрічала). Яким же було моє здивування, коли на одному проекті я побачила в коді операцію на зразок наступної: +

	if (Request.PermissionMask & (8) > 0)
		{...}

Невже! Невже шкільні знання з двійкової системи счислення стануть в нагоді для роботи! Як виявиться пізніше, на двох моїх минулих звичайнісіньких корпоративних проектах використовувались бітові маски. Одним з них була програма написана років так 15 назад (ну тут можна зрозуміти, може на час написання не було інших варіантів просто і там ніхто не думав про те, що код має бути зрозумілим і self-descriptive), але інший проект був відносно новим. Ні в тому, ні в іншому випадку проблеми економії пам"яті та проблеми обробки великих об"ємів даних не було.

== Bitmask

Спробую пояснити своє здивування. Спочатку розповім, що таке бітова маска. Bitmask - це спосіб представити характеристики об"єкту за допомогою цифр 0 та 1 (ну, тому що це *бітова* маска). Можна думати про бітову маску як про шифр: +

- Кожна цифра в числі відповідає за заздалегідь визначену властивість;
- 0 може значити, наприклад, що певна властивість в об"єкті відсутня, а 1 - що присутня.

Для кращого розуміння, створимо бітові маски для кольорів. Є три базових кольори - червоний, жовтий та синій. Змішуючи ці кольори ми можемо отримати всі інші (я тут маю на увазі базові кольори для художників, живих людей, а не представлення кольору в комп"ютерах).

|===
|Червоний|Жовтий|Синій|
|0|0|1| Синій
|0|1|0| Жовтий
|1|0|0| Червоний
|0|1|1| Зелений
|1|1|0| Помаранчевий
|1|0|1| Фіолетовий
|===

Отримали такі двійкові коди: +

	1 - синій
    10 - жовтий
    100 - червоний
    11 - зелений
    110 - помаранчевий
    101 - фіолетовий

Зазвичай, якщо вирішують користуватись бітовими масками, то такі двійкові коди переводять в звичну для нас десяткову систему счислення:

|===
||2|1|0|
|синій|0|0|1|1 * 2^0^ = 1
|жовтий|0|1|0| 1 * 2^1^ = 2
|червоний|1|0|0| 1 * 2^2^ = 4
|зелений|0|1|1| 1 * 2^0^ + 1 * 2^1^ = 3
|помаранчевий|1|1|0| 1 * 2^1^ + 1 * 2^2^ = 6
|фіолетовий|1|0|1| 1 * 2^0^ + 1 * 2^2^ = 5
|===

Тепер, коди до наших кольорів виглядають так:

	1 - синій
    2 - жовтий
    4 - червоний
    3 - зелений
    6 - помаранчевий
    5 - фіолетовий

Якщо проаналізувати, то побачимо, що всі базові кольори є степенями 2, всі інші кольори, що ми отримали в результаті змішування є сумою відповідних базових кольорів, так фіолетовий = синій + червоний: +

	5 = 1 + 4

Окрім цих властивостей, ще в програмах, такі "зашифровані" об"єкти розшифровуються бітовими операціями (bitwise), в основному операндом & (AND). Так, наприклад, якщо нам потрібно вибрати серед всієї множини наших кольорів тільки ті кольори, де був застосований синій колір, то ми виконаємо таку операцію:

	color = {1, 2, 4, 3, 6, 5} - наша множина всіх кольорів
	color & 1 = {1, 3, 5} - множина кольорів, в яких є синій колір (синій, зелений, фіолетовий)

Опишу детальніше, як ми це отримали:

Ми застосовуємо логічне AND до кожної пари бітів, які стоять на однакових позиціях у двійкових представленнях кольорів. Якщо обидва відповідних біта рівні 1, результуючий двійковий розряд дорівнює 1 (true), якщо ж хоча б один біт з пари дорівнює 0, результуючий двійковий розряд дорівнює 0 (false).

|===
|0|0|#1#| Синій
|0|1|0| Жовтий
|1|0|0| Червоний
|0|1|#1#| Зелений
|1|1|0| Помаранчевий
|1|0|#1#| Фіолетовий
|===
***
|===
|0|0|#1#| Синій
|===
***
|===
|0|0|*1*| Синій
|[line-through]*0*|[line-through]*0*|[line-through]*0*| [line-through]*Жовтий*
|[line-through]*0*|[line-through]*0*|[line-through]*0*| [line-through]*Червоний*
|0|0|*1*| Зелений
|[line-through]*0*|[line-through]*0*|[line-through]*0*| [line-through]*Помаранчевий*
|0|0|*1*| Фіолетовий
|===

Як бачите, застосування бітових масок є цікавим та дає нам можливість в одному числі зберігати багато інформації - по одному біту на характеристику об"єкта. Але, це не  робить програму легкою для розуміння та подальшої підтримки, особливо, якщо розробник не задокументував свій шифр =)

На сьогодні все, а в наступному пості я розповім про те, як можна удосконалити рішення, якщо ви, все ж таки, вирішили скористатись bitmask у своєму проекті.

icon:heart-o[size=2x]


Update 2016-03-12-Follow-Your-Madness.adoc

= Follow Your Madness
:hp-tags: Self Improvement, Soft Skills, Confidence
:hp-image: covers/cover-01.jpg

= Follow Your Madness
:hp-tags: Self Improvement, Soft Skills, Confidence
:hp-image: /covers/cover-01.jpg


Update 2016-09-03-CME-New-Release-VPN.adoc

= CME New Release VPN

This guide is written to help others go through the process of configuring a system to connect to the Chicago Mercantile Exchange's New Release environment over a self-hosted VPN connection. It's meant not to be an in-depth explanation of all terms and concepts, but rather a guide/map to go from a new router to having a working connection.

== Step 1: Router

You will need a router with built-in ISAKMP and IPSEC capabilities. One of the low cost options is to go with an 800 series Cisco router such as the 871W which you can pick up on Ebay for $50 to $60 and it includes wireless capabilities.

For those readers who are not networking experts or Cisco CCNAs, there are many acronyms that are used. A few of them are briefly explained here.
* ISAKMP - This is part of the security mechanism and is a subset of IKE.  http://networkengineering.stackexchange.com/questions/1/whats-the-difference-between-ike-and-isakmp
* GRE - Generic Routing Encapsulation. This allows multicast traffic to be sent over the VPN tunnel. http://www.cisco.com/c/en/us/support/docs/ip/ip-multicast/43584-mcast-over-gre.html
* PIM - Protocol Independent Multicast. You'll need to "enable multicast routing" and "pim sparse-mode" on the router for the multicast traffic. http://www.cisco.com/c/en/us/td/docs/ios/solutions_docs/ip_multicast/White_papers/mcst_ovr.html
* VLAN - Virtual LAN. Note that on the 871W, you can not assign a specific IP or DHCP group to the physical interfaces. You must assign the interfaces to be part of a VLAN and then the VLAN can be assigned a DHCP pool for IP assignment.
* Advanced Security or Advanced IP - Cisco offers two flavors of software to run on their routers. The "PIM" capabilities are in the Advanced IP package, not the Advanced Security package despite the need for a VPN tunnel! Make sure you are running a package with the K9 designator because it has AES/3DES encryption.
* ACL - Access Lists. These allow you to choose what traffic can and can not go through your router.
* NAT - Network Address Translation. This is a technology that allows your router to create a sub network and, through the use of differing ports, pass the traffic through one (public) IP. "ip nat inside" tells the vlan to NAT ip that are connected to it, and "ip nat outside" tells the interface (you would execute this command on your WAN port) to NAT traffic to the outside world.
* dot1Q - This is to tell your wireless interface to use a specific vlan. For example "encapsulation dot1Q 10 native" uses vlan 10.

== Step 2: Hardware
In addition to the 800 series Router, to get started, you'll need a so-called "Rollover Cable". http://www.ebay.com/sch/i.html?_nkw=cisco+rollover+usb&_sacat=0
This allows you to configure the router over a serial protocol. Use putty to connect, and choose Serial for the method. For my setup, it was COM3 and 9600 baud.
To connect to CME you'll need to have two physical interfaces available on your server. One for public IP traffic, and the other for CME New Release traffic.

== Step 3: Big Picture
Create two VLANs, one for public IP traffic ("Vlan 10"), and the other for CME New Release traffic ("Vlan 20"). For wireless models, you'll add the wireless connection to be part of Vlan 10.  Assign two of the fast ethernet ports to vlan 10, and the other two to Vlan 20. This will allow you to have two physical connections to public IP and two to New Release. You can always attach a switch to a vlan 10 port to expand access to other devices.  To have the appropriate IPs assigned to each VLAN, you'll create two DHCP pools for which IPs can come. On the vlan 10, you can stay with the traditional 192.168.1.x range and on vlan 20, you must use the range that the CME assigns you.

Note for Wireless users: In order to get wireless working propertly, you'll need to create a "bridge group". At a high level, this allows you to bridge the physical interface with the wireless interface into the same group. Note: don't assign an IP address range to vlan 10, just tell it to be part of the bridge group and with "no ip address". Then, in the bridge group configuration, you will assign the IP range for which the DHCP pool exits. However, for vlan 20 (because it's not part of a bridge group with a wireless interface), you will assign an ip range that matches what CME tells you.

== Step 4: Configure Router

Once you connect to the router, there will be a few key commands that you'll use over and over:

"write erase" -- This will erase the "running-config" and the "startup-config". These are the file names of the two configuration files on the router.
"copy running-config startup-config" -- This will copy the configuration that you have created to be the one run when the router is rebooted.
"enable" -- This will bring the router into priviledged mode so you can issue basic show commands.
"config t" -- This will bring the router into global configuration mode where you can actually change settings.
"exit" -- Go back up one "level" in your configuration. For example if you are configuring a sub-interface and want to return back to the interface level, just type exit.
"shut" -- Brings down an interface.
"no XXXX" -- Removes or takes away a command. For example, if you type "no shut", then it will bring UP an interface. Likewise, "no ip pim sparse-mode" will REMOVE the "ip pim sparse-mode" from the configuration.

Execute "write erase" first (to restore factory configuration).
Next, "enable" to go into priviledged mode.
Then, "show running-config" to see what the initial configuration looks like.
Lastly, "config t" so you can start changing settings (you should see the '#' prompt which means you can now issue commands).

Once you are in this mode, type in the commands from the attached configuration file.

== Step 5: Configure Linux

In order to get this to work properly, you will need to: 1. diable RP filtering, 2. configure your firewall properly (or just turn it off), and 3. add the appropriate routing table entries so that traffic to CME goes to the correct interface. On the commands that follow, the interface for CME is enp3s0 (change it to match yours).

Routing table:
route add -net 69.50.112.0 netmask 255.255.255.0 gw 10.249.71.1 dev enp3s0

To see if multicast traffic is coming in on the interface:
tcpdump -i enp3s0 -s0 -vv net 224.0.28.0/24

== Useful Links:
http://stevehardie.com/2013/05/cisco-877w-configure-wireless-and-wired-on-single-subnet/
https://supportforums.cisco.com/discussion/11801006/does-configuring-two-vlans-cisco-871-router-divides-bandwidth-internet-half
https://supportforums.cisco.com/discussion/10567086/change-ip-router-cisco-871

== Sample Router Configuration

[%hardbreaks]

version 12.4
no service pad
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname Router
!
boot-start-marker
boot-end-marker
!
!
no aaa new-model
!
resource policy
!
ip cef
!
!
no ip dhcp use vrf connected
ip dhcp excluded-address 10.249.71.64 10.249.71.255
!
ip dhcp pool vlan1pool
   network 10.249.71.0 255.255.255.0
   default-router 10.249.71.1
   dns-server 8.8.8.8
!
!
ip multicast-routing
!
!
!
!
!
!
crypto isakmp policy 2
 encr 3des
 hash md5
 authentication pre-share
crypto isakmp key XXXXXXXXXXXXXXXXXXXXX
!
!
crypto ipsec transform-set cmevpn esp-3des esp-md5-hmac
!
crypto map cmevpn 1 ipsec-isakmp
 set peer XXX.XXX.XXX.XXX
 set transform-set cmevpn
 match address 100
!
bridge irb
!
!
!
interface Tunnel0
 ip address XXX.XXX.XXX.XXX 255.255.255.252
 ip pim sparse-mode
 tunnel source XXX.XXX.XXX.XXX
 tunnel destination XXX.XXX.XXX.XXX
!
interface Loopback0
 ip address 10.249.0.229 255.255.255.255
!
interface FastEthernet0
!
interface FastEthernet1
!
interface FastEthernet2
!
interface FastEthernet3
!
interface FastEthernet4
 ip address dhcp
 ip nat outside
 ip virtual-reassembly
 duplex auto
 speed auto
 crypto map cmevpn
!
interface Dot11Radio0
 no ip address
 !
 broadcast-key vlan 1 change 45
 !
 !
 encryption vlan 1 mode ciphers tkip
 !
 ssid YOUR_SSID_NAME
    vlan 1
    authentication open
    authentication key-management wpa
    guest-mode
    wpa-psk ascii 0 YOUR_SSID_PASSWORD
 !
 speed basic-1.0 basic-2.0 basic-5.5 6.0 9.0 basic-11.0 12.0 18.0 24.0 36.0 48.0 54.0
 station-role root
 no cdp enable
!
interface Dot11Radio0.1
 encapsulation dot1Q 1 native
 no cdp enable
 bridge-group 1
 bridge-group 1 subscriber-loop-control
 bridge-group 1 spanning-disabled
 bridge-group 1 block-unknown-source
 no bridge-group 1 source-learning
 no bridge-group 1 unicast-flooding
!
interface Vlan1
 no ip address
 ip access-group 102 in
 bridge-group 1
 bridge-group 1 spanning-disabled
!
interface BVI1
 ip address 10.249.71.1 255.255.255.0
 ip nat inside
 ip virtual-reassembly
!
ip route 10.249.254.1 255.255.255.255 FastEthernet4
ip route 69.50.112.0 255.255.255.128 Tunnel0
ip route 69.50.112.128 255.255.255.128 FastEthernet4
ip route 69.50.112.254 255.255.255.255 Tunnel0
!
!
no ip http server
no ip http secure-server
ip pim rp-address XXX.XXX.XXX.XXX
ip mroute 69.50.112.0 255.255.255.128 Tunnel0
ip nat inside source list 1 interface FastEthernet4 overload
!
access-list 1 permit 10.249.71.0 0.0.0.255

= CME New Release VPN

This guide is written to help others go through the process of configuring a system to connect to the Chicago Mercantile Exchange's New Release environment over a self-hosted VPN connection. It's meant not to be an in-depth explanation of all terms and concepts, but rather a guide/map to go from a new router to having a working connection.

== Step 1: Router

You will need a router with built-in ISAKMP and IPSEC capabilities. One of the low cost options is to go with an 800 series Cisco router such as the 871W which you can pick up on Ebay for $50 to $60 and it includes wireless capabilities.

For those readers who are not networking experts or Cisco CCNAs, there are many acronyms that are used. A few of them are briefly explained here.
ISAKMP - This is part of the security mechanism and is a subset of IKE.  http://networkengineering.stackexchange.com/questions/1/whats-the-difference-between-ike-and-isakmp

GRE - Generic Routing Encapsulation. This allows multicast traffic to be sent over the VPN tunnel. http://www.cisco.com/c/en/us/support/docs/ip/ip-multicast/43584-mcast-over-gre.html

PIM - Protocol Independent Multicast. You'll need to "enable multicast routing" and "pim sparse-mode" on the router for the multicast traffic. http://www.cisco.com/c/en/us/td/docs/ios/solutions_docs/ip_multicast/White_papers/mcst_ovr.html

VLAN - Virtual LAN. Note that on the 871W, you can not assign a specific IP or DHCP group to the physical interfaces. You must assign the interfaces to be part of a VLAN and then the VLAN can be assigned a DHCP pool for IP assignment.
Advanced Security or Advanced IP - Cisco offers two flavors of software to run on their routers. The "PIM" capabilities are in the Advanced IP package, not the Advanced Security package despite the need for a VPN tunnel! Make sure you are running a package with the K9 designator because it has AES/3DES encryption.
ACL - Access Lists. These allow you to choose what traffic can and can not go through your router.
NAT - Network Address Translation. This is a technology that allows your router to create a sub network and, through the use of differing ports, pass the traffic through one (public) IP. "ip nat inside" tells the vlan to NAT ip that are connected to it, and "ip nat outside" tells the interface (you would execute this command on your WAN port) to NAT traffic to the outside world.
dot1Q - This is to tell your wireless interface to use a specific vlan. For example "encapsulation dot1Q 10 native" uses vlan 10.

== Step 2: Hardware
In addition to the 800 series Router, to get started, you'll need a so-called "Rollover Cable". http://www.ebay.com/sch/i.html?_nkw=cisco+rollover+usb&_sacat=0
This allows you to configure the router over a serial protocol. Use putty to connect, and choose Serial for the method. For my setup, it was COM3 and 9600 baud.
To connect to CME you'll need to have two physical interfaces available on your server. One for public IP traffic, and the other for CME New Release traffic.

== Step 3: Big Picture
Create two VLANs, one for public IP traffic ("Vlan 10"), and the other for CME New Release traffic ("Vlan 20"). For wireless models, you'll add the wireless connection to be part of Vlan 10.  Assign two of the fast ethernet ports to vlan 10, and the other two to Vlan 20. This will allow you to have two physical connections to public IP and two to New Release. You can always attach a switch to a vlan 10 port to expand access to other devices.  To have the appropriate IPs assigned to each VLAN, you'll create two DHCP pools for which IPs can come. On the vlan 10, you can stay with the traditional 192.168.1.x range and on vlan 20, you must use the range that the CME assigns you.

Note for Wireless users: In order to get wireless working propertly, you'll need to create a "bridge group". At a high level, this allows you to bridge the physical interface with the wireless interface into the same group. Note: don't assign an IP address range to vlan 10, just tell it to be part of the bridge group and with "no ip address". Then, in the bridge group configuration, you will assign the IP range for which the DHCP pool exits. However, for vlan 20 (because it's not part of a bridge group with a wireless interface), you will assign an ip range that matches what CME tells you.

== Step 4: Configure Router

Once you connect to the router, there will be a few key commands that you'll use over and over:

"write erase" -- This will erase the "running-config" and the "startup-config". These are the file names of the two configuration files on the router.
"copy running-config startup-config" -- This will copy the configuration that you have created to be the one run when the router is rebooted.
"enable" -- This will bring the router into priviledged mode so you can issue basic show commands.
"config t" -- This will bring the router into global configuration mode where you can actually change settings.
"exit" -- Go back up one "level" in your configuration. For example if you are configuring a sub-interface and want to return back to the interface level, just type exit.
"shut" -- Brings down an interface.
"no XXXX" -- Removes or takes away a command. For example, if you type "no shut", then it will bring UP an interface. Likewise, "no ip pim sparse-mode" will REMOVE the "ip pim sparse-mode" from the configuration.

Execute "write erase" first (to restore factory configuration).
Next, "enable" to go into priviledged mode.
Then, "show running-config" to see what the initial configuration looks like.
Lastly, "config t" so you can start changing settings (you should see the '#' prompt which means you can now issue commands).

Once you are in this mode, type in the commands from the attached configuration file.

== Step 5: Configure Linux

In order to get this to work properly, you will need to: 1. diable RP filtering, 2. configure your firewall properly (or just turn it off), and 3. add the appropriate routing table entries so that traffic to CME goes to the correct interface. On the commands that follow, the interface for CME is enp3s0 (change it to match yours).

Routing table:
route add -net 69.50.112.0 netmask 255.255.255.0 gw 10.249.71.1 dev enp3s0

To see if multicast traffic is coming in on the interface:
tcpdump -i enp3s0 -s0 -vv net 224.0.28.0/24

== Useful Links:
http://stevehardie.com/2013/05/cisco-877w-configure-wireless-and-wired-on-single-subnet/
https://supportforums.cisco.com/discussion/11801006/does-configuring-two-vlans-cisco-871-router-divides-bandwidth-internet-half
https://supportforums.cisco.com/discussion/10567086/change-ip-router-cisco-871

== Sample Router Configuration

[%hardbreaks]

version 12.4
no service pad
service timestamps debug datetime msec
service timestamps log datetime msec
no service password-encryption
!
hostname Router
!
boot-start-marker
boot-end-marker
!
!
no aaa new-model
!
resource policy
!
ip cef
!
!
no ip dhcp use vrf connected
ip dhcp excluded-address 10.249.71.64 10.249.71.255
!
ip dhcp pool vlan1pool
   network 10.249.71.0 255.255.255.0
   default-router 10.249.71.1
   dns-server 8.8.8.8
!
!
ip multicast-routing
!
!
!
!
!
!
crypto isakmp policy 2
 encr 3des
 hash md5
 authentication pre-share
crypto isakmp key XXXXXXXXXXXXXXXXXXXXX
!
!
crypto ipsec transform-set cmevpn esp-3des esp-md5-hmac
!
crypto map cmevpn 1 ipsec-isakmp
 set peer XXX.XXX.XXX.XXX
 set transform-set cmevpn
 match address 100
!
bridge irb
!
!
!
interface Tunnel0
 ip address XXX.XXX.XXX.XXX 255.255.255.252
 ip pim sparse-mode
 tunnel source XXX.XXX.XXX.XXX
 tunnel destination XXX.XXX.XXX.XXX
!
interface Loopback0
 ip address 10.249.0.229 255.255.255.255
!
interface FastEthernet0
!
interface FastEthernet1
!
interface FastEthernet2
!
interface FastEthernet3
!
interface FastEthernet4
 ip address dhcp
 ip nat outside
 ip virtual-reassembly
 duplex auto
 speed auto
 crypto map cmevpn
!
interface Dot11Radio0
 no ip address
 !
 broadcast-key vlan 1 change 45
 !
 !
 encryption vlan 1 mode ciphers tkip
 !
 ssid YOUR_SSID_NAME
    vlan 1
    authentication open
    authentication key-management wpa
    guest-mode
    wpa-psk ascii 0 YOUR_SSID_PASSWORD
 !
 speed basic-1.0 basic-2.0 basic-5.5 6.0 9.0 basic-11.0 12.0 18.0 24.0 36.0 48.0 54.0
 station-role root
 no cdp enable
!
interface Dot11Radio0.1
 encapsulation dot1Q 1 native
 no cdp enable
 bridge-group 1
 bridge-group 1 subscriber-loop-control
 bridge-group 1 spanning-disabled
 bridge-group 1 block-unknown-source
 no bridge-group 1 source-learning
 no bridge-group 1 unicast-flooding
!
interface Vlan1
 no ip address
 ip access-group 102 in
 bridge-group 1
 bridge-group 1 spanning-disabled
!
interface BVI1
 ip address 10.249.71.1 255.255.255.0
 ip nat inside
 ip virtual-reassembly
!
ip route 10.249.254.1 255.255.255.255 FastEthernet4
ip route 69.50.112.0 255.255.255.128 Tunnel0
ip route 69.50.112.128 255.255.255.128 FastEthernet4
ip route 69.50.112.254 255.255.255.255 Tunnel0
!
!
no ip http server
no ip http secure-server
ip pim rp-address XXX.XXX.XXX.XXX
ip mroute 69.50.112.0 255.255.255.128 Tunnel0
ip nat inside source list 1 interface FastEthernet4 overload
!
access-list 1 permit 10.249.71.0 0.0.0.255


Delete 2015-02-09-Test.adoc

Delete 2015-02-09-Test.adoc


Delete 2015-05-14-Yeah.adoc

Delete 2015-05-14-Yeah.adoc


Delete the file at '_posts/2017-06-12-Test.adoc'

= Test
// See https://hubpress.gitbooks.io/hubpress-knowledgebase/content/ for information about the parameters.
// :hp-image: /covers/cover.png
// :published_at: 2019-01-31
// :hp-tags: HubPress, Blog, Open_Source,
// :hp-alt-title: My English Title

test blog


PR17978 Follow-up - fix command

PR17978 Follow-up - fix command

// Module included in the following assemblies:
//
// * installing/install_config/installing-restricted-networks-preparations.adoc
// * openshift_images/samples-operator-alt-registry.adoc

ifeval::["{context}" == "installing-restricted-networks-preparations"]
:restrictednetwork:
endif::[]

ifeval::["{context}" == "samples-operator-alt-registry"]
:samplesoperatoraltreg:
endif::[]

[id="installation-restricted-network-samples_{context}"]
= Using Samples Operator imagestreams with alternate or mirrored registries

Most imagestreams in the OpenShift namespace managed by the Samples Operator
point to images located in the Red Hat registry at link:registry.redhat.io[registry.redhat.io].
ifdef::restrictednetwork[]
Mirroring
will not apply to these imagestreams.
endif::[]
The `jenkins`, `jenkins-agent-maven`, and `jenkins-agent-nodejs` imagestreams
come from the install payload and are managed by the Samples
ifdef::restrictednetwork[]
Operator, so no further mirroring procedures are needed for those imagestreams.
endif::[]
ifdef::samplesoperatoraltreg[]
Operator.
endif::[]

[NOTE]
====
The `cli`, `installer`, `must-gather`, and `tests` imagestreams, while
part of the install payload, are not managed by the Samples Operator. These are
not addressed in this procedure.
====

.Prerequisites
* Access to the cluster as a user with the `cluster-admin` role.
* Create a pull secret for your mirror registry.

.Procedure

. Access the images of a specific imagestream to mirror, for example:
+
----
$ oc get is <imagestream> -n openshift -o json | jq .spec.tags[].from.name | grep registry.redhat.io
----
+
. Mirror images from link:registry.redhat.io[registry.redhat.io] associated with any imagestreams you need
ifdef::restrictednetwork[]
in the restricted network environment into one of the defined mirrors, for example:
endif::[]
ifdef::configsamplesoperator[]
into your defined preferred registry, for example:
endif::[]
+
----
$ oc image mirror registry.redhat.io/rhscl/ruby-25-rhel7:latest ${MIRROR_ADDR}/rhscl/ruby-25-rhel7:latest
----
+
. Add the required trusted CAs for the mirror in the cluster’s image
configuration object:
+
----
$ oc create configmap registry-config --from-file=${MIRROR_ADDR_HOSTNAME}..5000=$path/ca.crt -n openshift-config
$ oc patch image.config.openshift.io/cluster --patch '{"spec":{"additionalTrustedCA":{"name":"registry-config"}}}' --type=merge
----
+
. Update the `samplesRegistry` field in the Samples Operator configuration object
to contain the `hostname` portion of the mirror location defined in the mirror
configuration:
+
----
$ oc get configs.samples.operator.openshift.io -n openshift-cluster-samples-operator
----
+
[NOTE]
====
This is required because the imagestream import process does not use the mirror or search mechanism at this time.
====
+
. Add any imagestreams that are not mirrored into the `skippedImagestreams` field
of the Samples Operator configuration object. Or if you do not want to support
any of the sample imagestreams, set the Samples Operator to `Removed` in the
Samples Operator configuration object.
+
[NOTE]
====
Any unmirrored imagestreams that are not skipped, or if the Samples Operator is
not changed to `Removed`, will result in the Samples Operator reporting a
`Degraded` status two hours after the imagestream imports start failing.
====
+
Many of the templates in the OpenShift namespace
reference the imagestreams. So using `Removed` to purge both the imagestreams
and templates will eliminate the possibility of attempts to use them if they
are not functional because of any missing imagestreams.

ifeval::["{context}" == "installing-restricted-networks-preparations"]
:!restrictednetwork:
endif::[]

ifeval::["{context}" == "samples-operator-alt-registry"]
:!samplesoperatoraltreg:
endif::[]

// Module included in the following assemblies:
//
// * installing/install_config/installing-restricted-networks-preparations.adoc
// * openshift_images/samples-operator-alt-registry.adoc

ifeval::["{context}" == "installing-restricted-networks-preparations"]
:restrictednetwork:
endif::[]

ifeval::["{context}" == "samples-operator-alt-registry"]
:samplesoperatoraltreg:
endif::[]

[id="installation-restricted-network-samples_{context}"]
= Using Samples Operator imagestreams with alternate or mirrored registries

Most imagestreams in the OpenShift namespace managed by the Samples Operator
point to images located in the Red Hat registry at link:registry.redhat.io[registry.redhat.io].
ifdef::restrictednetwork[]
Mirroring
will not apply to these imagestreams.
endif::[]
The `jenkins`, `jenkins-agent-maven`, and `jenkins-agent-nodejs` imagestreams
come from the install payload and are managed by the Samples
ifdef::restrictednetwork[]
Operator, so no further mirroring procedures are needed for those imagestreams.
endif::[]
ifdef::samplesoperatoraltreg[]
Operator.
endif::[]

[NOTE]
====
The `cli`, `installer`, `must-gather`, and `tests` imagestreams, while
part of the install payload, are not managed by the Samples Operator. These are
not addressed in this procedure.
====

.Prerequisites
* Access to the cluster as a user with the `cluster-admin` role.
* Create a pull secret for your mirror registry.

.Procedure

. Access the images of a specific imagestream to mirror, for example:
+
----
$ oc get is <imagestream> -n openshift -o json | jq .spec.tags[].from.name | grep registry.redhat.io
----
+
. Mirror images from link:registry.redhat.io[registry.redhat.io] associated with any imagestreams you need
ifdef::restrictednetwork[]
in the restricted network environment into one of the defined mirrors, for example:
endif::[]
ifdef::configsamplesoperator[]
into your defined preferred registry, for example:
endif::[]
+
----
$ oc image mirror registry.redhat.io/rhscl/ruby-25-rhel7:latest ${MIRROR_ADDR}/rhscl/ruby-25-rhel7:latest
----
+
. Add the required trusted CAs for the mirror in the cluster’s image
configuration object:
+
----
$ oc create configmap registry-config --from-file={MIRROR_ADDR}=$path/ca.crt -n openshift-config
$ oc patch image.config.openshift.io/cluster --patch '{"spec":{"additionalTrustedCA":{"name":"registry-config"}}}' --type=merge
----
+
. Update the `samplesRegistry` field in the Samples Operator configuration object
to contain the `hostname` portion of the mirror location defined in the mirror
configuration:
+
----
$ oc get configs.samples.operator.openshift.io -n openshift-cluster-samples-operator
----
+
[NOTE]
====
This is required because the imagestream import process does not use the mirror or search mechanism at this time.
====
+
. Add any imagestreams that are not mirrored into the `skippedImagestreams` field
of the Samples Operator configuration object. Or if you do not want to support
any of the sample imagestreams, set the Samples Operator to `Removed` in the
Samples Operator configuration object.
+
[NOTE]
====
Any unmirrored imagestreams that are not skipped, or if the Samples Operator is
not changed to `Removed`, will result in the Samples Operator reporting a
`Degraded` status two hours after the imagestream imports start failing.
====
+
Many of the templates in the OpenShift namespace
reference the imagestreams. So using `Removed` to purge both the imagestreams
and templates will eliminate the possibility of attempts to use them if they
are not functional because of any missing imagestreams.

ifeval::["{context}" == "installing-restricted-networks-preparations"]
:!restrictednetwork:
endif::[]

ifeval::["{context}" == "samples-operator-alt-registry"]
:!samplesoperatoraltreg:
endif::[]


BZ-1715395: Updated block volume support.

// Module included in the following assemblies:
//
// * storage/understanding-persistent-storage.adoc
//
// This module should only be present in openshift-enterprise and
// openshift-origin distributions.

[id="block-volume-support_{context}"]
= Block volume support

You can statically provision raw block volumes by including API fields
in your PV and PVC specifications.

The following table displays which volume plug-ins support block volumes.

.Block volume support
[cols="1,1,1", width="100%",options="header"]
|===
|Volume Plug-in  |Manually provisioned  |Dynamically provisioned
|AWS EBS  | ✅ | ✅
|Fibre Channel | ✅ |
|HostPath | |
|iSCSI | ✅ |
|NFS | |
|VMWare vSphere  | ✅ | ✅
|===

// Module included in the following assemblies:
//
// * storage/understanding-persistent-storage.adoc
//
// This module should only be present in openshift-enterprise and
// openshift-origin distributions.

[id="block-volume-support_{context}"]
= Block volume support

You can statically provision raw block volumes by including API fields
in your PV and PVC specifications. This functionality is only available for
manually provisioned PVs.