..
      Licensed under the Apache License, Version 2.0 (the "License"); you may
      not use this file except in compliance with the License. You may obtain
      a copy of the License at

          http://www.apache.org/licenses/LICENSE-2.0

      Unless required by applicable law or agreed to in writing, software
      distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
      WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
      License for the specific language governing permissions and limitations
      under the License.

      Convention for heading levels in Open vSwitch documentation:

      =======  Heading 0 (reserved for the title in a document)
      -------  Heading 1
      ~~~~~~~  Heading 2
      +++++++  Heading 3
      '''''''  Heading 4

      Avoid deeper levels because they do not render well.

=======================================
Encrypt Open vSwitch Tunnels with IPsec
=======================================

This document gives detailed description on the OVS IPsec tunnel and its
configuration modes.  If you want to follow a step-by-step guide to run and
test IPsec tunnel, please refer to :doc:`/tutorials/ipsec`.

Overview
--------

Why do encryption?
~~~~~~~~~~~~~~~~~~

OVS tunnel packets are transported from one machine to another. Along the path,
the packets are processed by physical routers and physical switches.  There are
risks that these physical devices might read or write the contents of the
tunnel packets. IPsec encrypts IP payload and prevents the malicious party
sniffing or manipulating the tunnel traffic.

OVS IPsec
~~~~~~~~~

OVS IPsec aims to provide a simple interface for user to add encryption on OVS
tunnels. It supports GRE, GENEVE, and VXLAN tunnels. The IPsec configuration is
done by setting options of the tunnel interface and other_config of
Open_vSwitch. You can choose different authentication methods and plaintext
tunnel policies based on your requirements.

OVS does not currently provide any support for IPsec encryption for traffic not
encapsulated in a tunnel.

Configuration
-------------

Authentication Methods
~~~~~~~~~~~~~~~~~~~~~~

Hosts of the IPsec tunnel need to authenticate each other to build a secure
channel. There are three authentication methods:

1) You can use a pre-shared key (PSK) to do authentication. In both hosts, set
   the same PSK value. This PSK is like your password. You should never reveal
   it to untrusted parties. This method is easier to use but less secure than
   the certificate-based methods::

      $ ovs-vsctl add-port br0 ipsec_gre0 -- \
                  set interface ipsec_gre0 type=gre \
                                     options:remote_ip=2.2.2.2 \
                                     options:psk=swordfish

2) You can use a self-signed certificate to do authentication. In each host,
   generate a certificate and the paired private key. Copy the certificate of
   the remote host to the local host and configure the OVS as following::

      $ ovs-vsctl set Open_vSwitch . \
                  other_config:certificate=/path/to/local_cert.pem \
                  other_config:private_key=/path/to/priv_key.pem
      $ ovs-vsctl add-port br0 ipsec_gre0 -- \
                  set interface ipsec_gre0 type=gre \
                                 options:remote_ip=2.2.2.2 \
                                 options:remote_cert=/path/to/remote_cert.pem

   `local_cert.pem` is the certificate of the local host. `priv_key.pem`
   is the private key of the local host. `priv_key.pem` needs to be stored in
   a secure location. `remote_cert.pem` is the certificate of the remote host.

   .. note::

      OVS IPsec requires x.509 version 3 certificate with the subjectAltName
      DNS field setting the same string as the common name (CN) field. You can
      follow the tutorial in :doc:`/tutorials/ipsec` and use ovs-pki(8) to
      generate compatible certificate and key.

      (Before OVS version 2.10.90, ovs-pki(8) did not generate x.509 v3
      certificates, so if your existing PKI was generated by an older version,
      it is not suitable for this purpose.)

3) You can also use CA-signed certificate to do authentication. First, you need
   to create a CA certificate and sign each host certificate with the CA key
   (please see :doc:`/tutorials/ipsec`). Copy the CA certificate to each
   host and configure the OVS as following::

      $ ovs-vsctl set Open_vSwitch . \
                  other_config:certificate=/path/to/local_cert.pem \
                  other_config:private_key=/path/to/priv_key.pem \
                  other_config:ca_cert=/path/to/ca_cert.pem
      $ ovs-vsctl add-port br0 ipsec_gre0 -- \
                  set interface ipsec_gre0 type=gre \
                                     options:remote_ip=2.2.2.2 \
                                     options:remote_name=remote_cn

   `ca_cert.pem` is the CA certificate.  You need to set `remote_cn` as the
   common name (CN) of the remote host's certificate so that only the
   certificate with the expected CN can be trusted in this connection. It is
   preferable to use this method than 2) if there are many remote hosts since
   you don't have to copy every remote certificate to the local host.

   .. note::

      When using certificate-based authentication, you should not set psk in
      the interface options. When using psk-based authentication, you should
      not set certificate, private_key, ca_cert, remote_cert, and remote_name.

Plaintext Policies
~~~~~~~~~~~~~~~~~~

When an IPsec tunnel is configured in this database, multiple independent
components take responsibility for implementing it.  ``ovs-vswitchd`` and its
datapath handle packet forwarding to the tunnel and a separate daemon pushes
the tunnel's IPsec policy configuration to the kernel or other entity that
implements it.  There is a race: if the former configuration completes before
the latter, then packets sent by the local host over the tunnel can be
transmitted in plaintext.  Using this setting, OVS users can avoid this
undesirable situation.

1) The default setting allows unencrypted packets to be sent before IPsec
   completes negotiation::

     $ ovs-vsctl add-port br0 ipsec_gre0 -- \
                  set interface ipsec_gre0 type=gre \
                                     options:remote_ip=2.2.2.2 \
                                     options:psk=swordfish

   This setting should be used only and only if tunnel configuration is static
   and/or if there is firewall that can drop the plain packets that
   occasionally leak the tunnel unencrypted on OVSDB (re)configuration events.

2) Setiing ipsec_skb_mark drops unencrypted packets by using skb_mark of
   tunnel packets::

     $ ovs-vsctl set Open_vSwitch . other_config:ipsec_skb_mark=0/1
     $ ovs-vsctl add-port br0 ipsec_gre0 -- \
                 set interface ipsec_gre0 type=gre \
                                    options:remote_ip=2.2.2.2 \
                                    options:psk=swordfish

   OVS IPsec drops unencrypted packets which carry the same skb_mark as
   `ipsec_skb_mark`. By setting the ipsec_skb_mark as 0/1, OVS IPsec prevents
   all unencrypted tunnel packets leaving the host since the default skb_mark
   value for tunnel packets are 0. This affects all OVS tunnels including those
   without IPsec being set up. You can install OpenFlow rules to enable
   those non-IPsec tunnels by setting the skb_mark of the tunnel traffic as
   non-zero value.

3) Setting `ipsec_skb_mark` as 1/1 only drops tunnel packets with skb_mark
   value being 1::

     $ ovs-vsctl set Open_vSwitch . other_config:ipsec_skb_mark=1/1
     $ ovs-vsctl add-port br0 ipsec_gre0 -- \
                 set interface ipsec_gre0 type=gre \
                                    options:remote_ip=2.2.2.2 \
                                    options:psk=swordfish

   Opposite to 2), this setting passes through unencrypted tunnel packets by
   default. To drop unencrypted IPsec tunnel traffic, you need to explicitly
   set skb_mark to a non-zero value for those tunnel traffic by installing
   OpenFlow rules.

Bug Reporting
-------------

If you think you may have found a bug with security implications, like

1) IPsec protected tunnel accepted packets that came unencrypted; OR
2) IPsec protected tunnel allowed packets to leave unencrypted

then please report such bugs according to :doc:`/internals/security`.

If the bug does not have security implications, then report it according to
instructions in :doc:`/internals/bugs`.
