# SSL

[Transportation Security Layer (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security) are a set of protocols designed to ensure secure communication across a network. Envoy's and Greymatter's filters allow for diverse types of TLS connections throughout the mesh. This document explains the different types of supported TLS and technical steps on how to configure them within Greymatter.

## One Way TLS

In One-Way TLS, only one certificate trust file is evaluated: either the client's or the server's. This can be configured with different values in the `cluster` vs. `domain` objects. Crucially, the `domain` configures TLS parameters (e.g. certificates, ssl types) for *incoming* requests whereas the `cluster` object controls TLS setting used for *outward* requests leaving the proxy.

* To validate *client* trust certificates, add the `"trust_file"` parameter to the *`domain`* object.
* To validate *server* trust certificates, add the `"trust_file"` parameter to the *`cluster`* object.

## mTLS / Re-Encrypt

Mutual TLS is a type of TLS communication where the server and client both verify each other's certificates during the TLS handshake, hence it is more secure than one way TLS. In its [current implementation in envoy](https://www.envoyproxy.io/docs/envoy/v1.13.0/intro/arch_overview/security/ssl), this is a form of [re-encryption](https://docs.openshift.com/container-platform/3.9/architecture/networking/routes.html#re-encryption-termination) where the incoming request context is terminated and the outgoing request is formed from a new certificate pair.

To add mTLS to your mesh, the following configuration needs to applied to each `domain` (incoming requests to the proxy)

```javascript
{
  ...,
  "ssl_config": {
      "protocols": [
        "TLSv1.2"
      ],
    "require_client_certs": true,
    "trust_file": "/etc/proxy/tls/sidecar/ca.crt",
    "cert_key_pairs": [
      {
        "certificate_path": "/etc/proxy/tls/sidecar/server.crt",
        "key_path": "/etc/proxy/tls/sidecar/server.key"
      }
    ]
  },
  "force_https": true,
}
```

and `cluster` (outgoing requests from the proxy):

```javascript
{
  ...,
  "ssl_config": {
      "protocols": [
        "TLSv1.2"
      ],
    "require_client_certs": true,
    "trust_file": "/etc/proxy/tls/sidecar/ca.crt",
    "cert_key_pairs": [
      {
        "certificate_path": "/etc/proxy/tls/sidecar/server.crt",
        "key_path": "/etc/proxy/tls/sidecar/server.key"
      }
    ]
  },
  "require_tls": true,
}
```

This forces each gm-proxy instance to serve https and validate incoming requests from a given certificate pair. For more information on SSL configuration parameters, see documentation for [cluster](https://github.com/greymatter-io/gm-control-api/blob/release-1.2/docs/mesh/objects/cluster.md#tls-configuration) and [domain](https://github.com/greymatter-io/gm-control-api/blob/release-1.2/docs/mesh/objects/domain.md#tls-configuration) TLS configs.

## Passthrough

SSL Passthrough differs from other methods for implementing TLS. Instead of handling encryption / decrypting at the proxy, the tls configuration is forwarded "as is." No [layer 7](https://en.wikipedia.org/wiki/OSI_model#Layer_7:_Application_Layer) actions are taken such as access control, redirects, blocking, or cookie / session management. The responsibility for this logic is deferred downstream to the workload.

At this writing, envoy does not support generic tls passthrough. It does support [tcp and grpc bridges](https://github.com/envoyproxy/envoy/issues/565#issuecomment-286212681) to connect directly to tcp or grpc servers directly. To enable this, see [documentation and examples](https://github.com/greymatter-io/gm-control-api/tree/release-1.2/docs/examples/network_filters/tcp_proxy) of setting up [Envoy's network filters](https://www.envoyproxy.io/docs/envoy/v1.10.0/configuration/network_filters/network_filters).

## Changing Protocols

A common use case of sidecars is to change the incoming protocol to something that can be used by the backed service. This gives assurance that upstream requests will be of a compatible type certain with each service's supported protocols.

### Origination

Origination occurs when a http context is "upgraded" to https. To enable origination, we first need to allow incoming http requests checks to pass validation. This can be done by updating the TLS options in the *domain* to look like the following:

```javascript
{
  ...,
  "ssl_config": {},
  "force_https": false
}
```

This removes TLS checks on incoming requests. Then, we need to configure outgoing requests to use a TLS context. This can be done by updating the *cluster* to look like the following:

```javascript
{
  ...,
  "ssl_config": {
      "protocols": [
        "TLSv1.2"
      ],
    "require_client_certs": true,
    "trust_file": "/etc/proxy/tls/sidecar/ca.crt",
    "cert_key_pairs": [
      {
        "certificate_path": "/etc/proxy/tls/sidecar/server.crt",
        "key_path": "/etc/proxy/tls/sidecar/server.key"
      }
    ]
  },
  "require_tls": true,
}
```

This ensures that outgoing requests from the proxy will use a TLS context from the provided certificates.

### Termination

Termination occurs when a https context is "downgraded" to http, the opposite of origination. To enable termination, we need to first ensure that incoming requests are validated with a TLS security context. This is done by updating the *domain* to use the following TLS configs:

```javascript
{
  ...,
  "ssl_config": {
      "protocols": [
        "TLSv1.2"
      ],
    "require_client_certs": true,
    "trust_file": "/etc/proxy/tls/sidecar/ca.crt",
    "cert_key_pairs": [
      {
        "certificate_path": "/etc/proxy/tls/sidecar/server.crt",
        "key_path": "/etc/proxy/tls/sidecar/server.key"
      }
    ]
  },
  "force_https": true,
}
```

Now, we need to tell each gm-proxy instance to use plain http for outgoing requests. This is done by removing TLS configs from the *cluster*:

```javascript
{
  ...,
  "ssl_config": {},
  "require_tls": false,
}
```

Incoming requests must now be TLS and outgoing requests from the proxy will be in plain http.

### X-Forwarded Proto

When making requests to services which change protocols, the header [`x-forwarded-proto`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto) should be set explicitly. Otherwise, if set implicitly, it will default to the original client protocol. When the upstream service receives the request, it will examine the `x-forwarded-proto` value and think the request is not the right protocol. The request will be rejected with a `301 redirect`. Here is an example of this workflow:

1. Instantiate a listener on `localhost:80` using TLS origination
2. Perform a request `curl http://localhost:80`. By default, the header is set as `x-forwarded-proto: http`
3. Sidecar receives the request, converts it to an SSL request, finds the correct cluster, and proxies the request.
4. The upstream service receives the request, performs the SSL handshake, reads the request, sees that `x-forward-proto: http`. The service is confused because it doesn't handle http and issues a `301 redirect` back.

There are two ways of ensuring that the right `x-forwarded-proto` header is set for outgoing requests:

* Specify `x-forwarded-proto` in each incoming request. This is not recommended for deployments or as a long term solution.
* Add `x-forwarded-proto` as a custom header in the *domain*. Here is an example of setting this for origination:

  ```javascript
  {
    ...,
    "custom_headers": [
      {
        "key": "x-forwarded-proto",
        "value": "https"
      }
    ]
  }
  ```

  Now, every outgoing request using this domain will include the header `"x-forwarded-proto: https"`.

## Multiple Listeners

Each type of TLS listed here can be combined with multiple [listeners](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/listeners/listeners#arch-overview-listeners) on one sidecar. For example, a sidecar handling both plaintext and encrypted traffic has two listeners. Each listener uses a different domain to control how to handle incoming requests:

* listener:`localhost:80` domain: configured to accept http requests
* listener:`localhost:443` domain: configured to accept https requests

After an incoming request is validated by the corresponding *domain*, it is routed to the corresponding *cluster*, using the cluster's specified TLS configuration.

Together, adding different types listeners and specifying the protocol for each cluster allows for powerful and dynamic configuration of TLS for each service (i.e. mTLS, one-way TLS, origination, etc).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://greymatter.gitbook.io/grey-matter-documentation/usage/fabric/security/ssl.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
