github.com/projectcontour/contour@v1.28.2/site/content/docs/main/guides/fips.md (about)

     1  ---
     2  title: FIPS 140-2 in Contour
     3  ---
     4  
     5  The [Federal Information Processing Standard (FIPS) 140-2][0] publication describes United States government approved security requirements for cryptographic modules.
     6  Software that is validated by an accredited [Cryptographic Module Validation Program (CVMP) laboratory][1] can be suitable for use in applications for US governmental departments or in industries subject to US Federal regulations.
     7  
     8  As a full application is not often tested by a CVMP laboratory, we cannot say that Contour is FIPS validated.
     9  Rather, Contour can be built and configured in a manner that adheres to the standards FIPS 140-2 establishes.
    10  
    11  For a fully FIPS compliant deployment of Contour a few things are required:
    12  - Contour must be compiled with a FIPS validated cryptographic module
    13  - Envoy must be compiled with a FIPS validated cryptographic module
    14  - Contour must be configured to use FIPS approved cryptographic algorithms
    15  
    16  This guide will run through an example of the process for building and configuring Contour and Envoy for adherence to FIPS 140-2.
    17  Specifically, we will show how Contour and Envoy can be built with the FIPS validated BoringCrypto module of BoringSSL and configured to use FIPS approved TLS ciphers.
    18  
    19  Please note that this guide makes no guarantees about Contour FIPS 140-2 approval, validation, or the like.
    20  Interested parties should still evaluate the processes given as example here and the suitability for their purposes.
    21  The Contour project does not have any plans to distribute any binaries compiled in the manner described by this guide.
    22  
    23  ## Notes on BoringCrypto
    24  
    25  This guide shows how Contour and Envoy can be built with [BoringSSL][2] as the cryptographic module.
    26  BoringSSL is Google's fork of OpenSSL and as a whole is not FIPS validated, but a specific core library called BoringCrypto is.
    27  For more detailed information about BoringCrypto see [this document][3].
    28  
    29  We are using BoringSSL/BoringCrypto in this example because Contour is written in Go and there is an open source [BoringCrypto flavor of Go][4] readily available.
    30  In addition, Envoy uses BoringSSL at its core and already has well defined build processes for building in a FIPS compliant mode.
    31  
    32  One could possibly perform the same sort of operations with another library with FIPS 140-2 a validated cryptographic module (e.g. OpenSSL).
    33  However, that is out of the scope of this guide and interested users will have to come up with their own solutions for that use case, possibly using this document as a template.
    34  
    35  ## Building Contour
    36  
    37  In this section we will describe how the [`projectcontour/contour`][5] container image can be compiled and linked to BoringCrypto for FIPS compliance.
    38  We will be modifying the standard build process by setting up some dependencies and passing additional arguments to the same `make` target used to build the standard, non-FIPS image distributed by the project.
    39  
    40  You will need some software downloaded and installed on the computer you are performing the Contour FIPS build on:
    41  - Contour source code checked out to the version you would like to build
    42  - [GNU Make][6]
    43  - [Docker][7]
    44  
    45  The Contour [Dockerfile][8] uses a multistage build that performs compilation in an image that contains the necessary build tools and dependencies and then exports compiled artifacts to a final image.
    46  In order to minimize the `projectcontour/contour` image footprint, the final output image only consists of a single layer, containing a lone file: the statically compiled `contour` binary.
    47  The standard Contour build uses the upstream `golang` image as a build base, however we will have to swap that out to build Contour with BoringCrypto.
    48  
    49  ### Go 1.19 and higher
    50  
    51  Starting with Go 1.19, you can simply add [`BUILD_GOEXPERIMENT=boringcrypto`][18] and some related arguments to enable integrating BoringCrypto for standard Go.
    52  
    53  ```bash
    54  make container \
    55    BUILD_GOEXPERIMENT=boringcrypto \
    56    BUILD_CGO_ENABLED=1 \
    57    BUILD_EXTRA_GO_LDFLAGS="-linkmode=external -extldflags=-static"
    58  ```
    59  
    60  ### Go 1.18 and lower
    61  
    62  For the Go version under 1.19, we can use the Google-provided Go implementation that has patches on top of standard Go to enable integrating BoringCrypto.
    63  This is available to us in the [`goboring/golang`][9] container image we can use as a build base. 
    64  Note that the latest version of  [`goboring/golang`][9] image on the Docker hub is `1.16.7b7`, find more versions [here][19] and pull the images on Google Artifact Registry following [this document][20].
    65  
    66  In addition, to ensure we can statically compile the `contour` binary when it is linked with the BoringCrypto C library, we must pass some additional arguments to the `make container` target.
    67  
    68  To perform the Contour image build with BoringCrypto, change directories to where you have the Contour source code checked out and run the following (replacing `<goboring-version-tag>` with the appropriate version of Go and BoringCrypto, see [here][10] for version specifics):
    69  
    70  ```bash
    71  make container BUILD_CGO_ENABLED=1 BUILD_BASE_IMAGE=goboring/golang:<goboring-version-tag> BUILD_EXTRA_GO_LDFLAGS="-linkmode=external -extldflags=-static"
    72  ```
    73  
    74  The command above can be broken down as follows:
    75  - `make container` invokes the container image build target
    76  - `BUILD_CGO_ENABLED=1` ensures `cgo` is enabled in the Contour compilation process
    77  - `BUILD_BASE_IMAGE=goboring/golang:<goboring-version-tag>` ensures we use the BoringCrypto flavor of Go
    78  - `BUILD_EXTRA_GO_LDFLAGS` contains the additional linker flags we need to perform a static build
    79    - `-linkmode=external` tells the Go linker to use an external linker
    80    - `-extldflags=-static"` passes the `-static` flag to the external link to ensure a statically linked executable is produced
    81  
    82  The container image build process should fail before export of the `contour` binary to the final image if the compiled binary is not statically linked.
    83  
    84  ### Validation
    85  
    86  To be fully sure the produced `contour` binary has been compiled with BoringCrypto you must remove the `-s` flag from the base Contour `Makefile` to stop stripping symbols and run through the build process above.
    87  Then you will be able to inspect the `contour` binary with `go tool nm` to check for symbols containing the string `_Cfunc__goboringcrypto_`. 
    88  Also, you can use the program [rsc.io/goversion][21]. It will report the crypto implementation used by a given binary when invoked with the `-crypto` flag.
    89  
    90  Once you have a `projectcontour/contour` image built, you can re-tag it if needed, push the image to a registry, and reference it in a Contour deployment to use it!
    91  
    92  ## Building Envoy
    93  
    94  Envoy has support for building in a FIPS compliant mode as [documented here][11].
    95  The upstream project does not distribute a FIPS compliant Envoy container image, but combining the documented process with the processes for building the Envoy executable and container image, we can produce one.
    96  
    97  Again we will need the Envoy source code checked out to the version to build and Docker installed on your computer.
    98  The simplest way to build Envoy without having to learn [Bazel][12] and set up a C++ toolchain on your computer is to build using the Envoy build container image which contains the necessary tools pre-installed.
    99  Note that if you do build with FIPS mode outside of the build container, you can only do so on a Linux-amd64 architecture.
   100  
   101  We can first compile the Envoy binary by running the following in a `bash` shell from the Envoy source directory:
   102  
   103  ```bash
   104  BAZEL_BUILD_EXTRA_OPTIONS="--define boringssl=fips" ENVOY_DOCKER_BUILD_DIR=<envoy-output-dir> ./ci/run_envoy_docker.sh './ci/do_ci.sh bazel.release //test/exe:envoy_static_test'
   105  ```
   106  
   107  *This command mimics the Envoy release CI process with the target `bazel.release` but differs in only running a single test for brevity. You may omit the `//test/exe:envoy_static_test` test entirely to run the full suite of Envoy tests.*
   108  
   109  Replace `<envoy-output-dir>` with a directory you would like the build output to be placed on your host computer.
   110  
   111  Once that build completes, you should have a file named `release.tar.zst` in your specified output directory.
   112  This file is a [Zstandard](https://github.com/facebook/zstd) compressed archive containing the compiled Envoy release and debug binaries.
   113  If you would like to build an image with Envoy according to your own specifications, you can unpack the resulting archive and you will find a stripped Envoy binary in the root and an unstripped Envoy binary with debug info in the `dbg` directory.
   114  
   115  To build an image matching the canonical Envoy upstream release image ([`envoyproxy/envoy`][13]), run the following:
   116  
   117  *Note: You will need a recent version of Docker/BuildKit that supports Zstandard decompression.*
   118  
   119  ```bash
   120  # Make ./linux/amd64 directories.
   121  mkdir -p ./linux/amd64
   122  # Copy Zstandard archive from build step.
   123  cp -a <envoy-output-dir>/envoy/x64/bin/release.tar.zst ./linux/amd64/release.tar.zst
   124  # Run the Docker image build.
   125  docker build -f ./ci/Dockerfile-envoy --target envoy .
   126  ```
   127  
   128  Once you have an image built, you can tag it as needed, push the image to a registry, and use it in an Envoy deployment.
   129  
   130  ## Configuring TLS Ciphers
   131  
   132  Now that we have Contour and Envoy compiled with BoringCrypto, we can turn our attention to ensuring encrypted communication paths in Contour are configured to use FIPS approved cryptographic algorithms.
   133  Using a FIPS flavor of Envoy will do most of the heavy lifting here without any user configuration needed.
   134  
   135  The critical communication paths and how they are set up to be FIPS compliant are enumerated below:
   136  - Contour -> k8s API
   137    - Contour uses [`client-go`][14] to communicate with the k8s API
   138    - `client-go` uses the default Golang cipher suites configuration
   139    - When compiled with BoringCrypto Go, this set of ciphers is FIPS compliant and not configurable by users
   140  - Envoy -> Contour xDS Server, extension services, upstream services
   141    - A FIPS compliant build of Envoy will choose FIPS approved TLS ciphers when negotiating TLS 1.2 as documented [here][15]
   142    - The set of ciphers is not configurable
   143  - TLS client -> Envoy
   144    - As of [Contour 1.13.0][16], the ciphers Envoy will accept as a server when negotiating TLS 1.2 are configurable
   145    - The [default set of ciphers Contour configures][17] includes some ciphers that are not FIPS approved
   146    - Users must configure FIPS approved ciphers from the list [here][15]
   147  
   148  [0]: https://csrc.nist.gov/publications/detail/fips/140/2/final
   149  [1]: https://csrc.nist.gov/projects/testing-laboratories
   150  [2]: https://boringssl.googlesource.com/boringssl/
   151  [3]: https://boringssl.googlesource.com/boringssl/+/master/crypto/fipsmodule/FIPS.md
   152  [4]: https://go.googlesource.com/go/+/dev.boringcrypto/README.boringcrypto.md
   153  [5]: https://hub.docker.com/r/projectcontour/contour
   154  [6]: https://www.gnu.org/software/make/
   155  [7]: https://www.docker.com/
   156  [8]: {{< param github_url >}}/blob/main/Dockerfile
   157  [9]: https://hub.docker.com/r/goboring/golang/
   158  [10]: https://go.googlesource.com/go/+/dev.boringcrypto/misc/boring/README.md#version-strings
   159  [11]: https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/security/ssl.html#fips-140-2
   160  [12]: https://bazel.build/
   161  [13]: https://hub.docker.com/r/envoyproxy/envoy
   162  [14]: https://github.com/kubernetes/client-go
   163  [15]: https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/transport_sockets/tls/v3/common.proto#envoy-v3-api-field-extensions-transport-sockets-tls-v3-tlsparameters-cipher-suites
   164  [16]: https://github.com/projectcontour/contour/releases/tag/v1.13.0
   165  [17]: https://pkg.go.dev/github.com/projectcontour/contour/pkg/config#pkg-variables
   166  [18]: https://pkg.go.dev/internal/goexperiment@go1.19
   167  [19]: https://go-boringcrypto.storage.googleapis.com/
   168  [20]: https://go.googlesource.com/go/+/dev.boringcrypto/misc/boring/README.md#releases
   169  [21]: https://godoc.org/rsc.io/goversion