Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document custom ssl certificate #404

Merged
merged 12 commits into from
Dec 15, 2022
3 changes: 3 additions & 0 deletions .github/workflows/markdown.links.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
},
{
"pattern": "http://localstack:4566"
},
{
"pattern": "(.*)localhost.localstack.cloud(.*)"
}
],
"httpHeaders": [
Expand Down
130 changes: 130 additions & 0 deletions content/en/references/custom-tls-certificates.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
title: Custom TLS certificates
weight: 99
tags:
- ssl
description: >
How to use custom TLS certificates with LocalStack
---

# Background

LocalStack sometimes performs on-demand fetching of resources from the public internet.
This requires that LocalStack is able to access public URLs.
If there is a proxy server in your network that uses a non-standard TLS certificate, LocalStack will not be able to download any files on demand.
You may see errors in the logs relating to TLS such as "unable to get local issuer certificate".

# Solution

There are three options when running LocalStack:

1. [creating a custom Docker image]({{< ref "#creating-a-custom-docker-image" >}}),
2. [using init hooks]({{< ref "#custom-ssl-certificates-with-init-hooks" >}}) or
3. [when running in host mode]({{< ref "#custom-ssl-certificates-with-host-mode" >}}).

They all can be summarised as:

1. get your proxy's custom certificate into the system certificate store, and
2. configure [`requests`](https://pypi.python.org/pypi/requests) to use the custom certificate, and
3. configure [`curl`](https://curl.se/) to use the custom certificate.

## Creating a custom docker image

If you run LocalStack in a docker container (which includes using [the CLI]({{< ref "/getting-started#localstack-cli" >}}), [docker]({{< ref "/getting-started/#docker" >}}), [docker-compose]({{< ref "/getting-started/#docker-compose" >}}), [cockpit]({{< ref "/getting-started/#localstack-cockpit" >}}) or [helm]({{< ref "/getting-started/#helm" >}})), to include a custom TLS root certificate a new docker image should be created.

Create a `Dockerfile` containing the following commands:

```docker
FROM localstack/localstack:latest
# or if using the pro image:
FROM localstack/localstack-pro:latest

COPY <your custom certificate.crt> /usr/local/share/ca-certificates/cert-bundle.crt
RUN update-ca-certificates
ENV CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
ENV REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
```

and build the image:

{{< command >}}
$ docker build -t <image name> .
{{< / command >}}

{{< alert title="Information" color="primary">}}
**Note**: Certificate files **must** end in `.crt` to be included in the system certificate store.
If your certificate file ends with `.pem`, you can rename it to end in `.crt`.
{{< / alert>}}

### Starting LocalStack with the custom image

LocalStack now needs to be configured to use this custom image. The workflow is different depending on how you start localstack.

{{< tabpane >}}
{{< tab header="CLI" lang="bash" >}}
IMAGE_NAME=<image name> localstack start
{{< /tab >}}
{{< tab header="Docker" lang="bash" >}}
docker run <docker arguments> <image name>
{{< /tab >}}
{{< tab header="docker-compose.yml" lang="yml" >}}
services:
localstack:
image: <image name>
# the rest of your configuration
{{< /tab >}}
{{< / tabpane >}}

## Custom TLS certificates with init hooks

It is recommended to create a `boot` init hook. Create a directory on your local system that includes

* the certificate you wish to copy, and
* the following shell script:

```bash
#!/bin/bash

set -euo pipefail

cp /etc/localstack/init/boot.d/<your certificate file>.crt /usr/local/share/ca-certificates
update-ca-certificates
```

Then run LocalStack with the environment variables

* `REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt`, and
* `CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt`, and

and follow the instructions fn the [init hooks documentation]({{< ref "init-hooks" >}}) for configuring LocalStack to use the hook directory as a `boot` hook.

## Custom TLS certificates with host mode

### Linux

On linux the custom certificate should be added to your `ca-certificates` bundle. For example on Debian based systems (as root):

{{< command >}}
# cp <your custom certificate.crt> /usr/local/share/ca-certificates
# update-ca-certificates
{{< / command >}}

Then run LocalStack with the environment variables `REQUESTS_CA_BUNDLE` and `CURL_CA_BUNDLE`:

{{< command >}}
$ CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt localstack start --host
{{< / command >}}

### macos

On macos the custom certificate should be added to your keychain. See [this Apple support article](https://support.apple.com/en-gb/guide/keychain-access/kyca2431/mac) for more information.

Then run LocalStack with the environment variables `REQUESTS_CA_BUNDLE` and `CURL_CA_BUNDLE`:

{{< command >}}
$ CURL_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt localstack start --host
{{< / command >}}

### Windows

Currently host mode does not work with Windows. If you are using WSL2 you should follow the [Linux]({{< ref "#linux" >}}) steps above.
2 changes: 2 additions & 0 deletions content/en/references/init-hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,3 +146,5 @@ services:
DOCKER_FLAGS='-v /path/to/init-aws.sh:/etc/localstack/init/ready.d/init-aws.sh' localstack start
{{< /tab >}}
{{< /tabpane >}}

Another use for init hooks can be seen when [adding custom TLS certificates to LocalStack]({{< ref "custom-tls-certificates#custom-tls-certificates-with-init-hooks" >}}).
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ You can configure the local endpoint URL under which LocalStack is accessible fr

## Connecting to a LocalStack instance on a different machine

To ensure that the Web user interface can connect with your running LocalStck instance, you would need to configure the endpoint URL so that the server's SSL certificate matches the hostname/IP address of the endpoint URL. This situation arises when users configure the endpoint URL to be something like `https://myhost:4566` or use an IP address like `https://1.2.3.4:4566`. Websites with an `https://...` URL can only request other endpoints using HTTPS (i.e., not on `http://`). Additionally, while requesting an HTTPS page, the SSL certificate must match the hostname (i.e., `localhost.localstack.cloud` in our case).
To ensure that the Web user interface can connect with your running LocalStack instance, you would need to configure the endpoint URL so that the server's SSL certificate matches the hostname/IP address of the endpoint URL. This situation arises when users configure the endpoint URL to be something like `https://myhost:4566` or use an IP address like `https://1.2.3.4:4566`. Websites with an `https://...` URL can only request other endpoints using HTTPS (i.e., not on `http://`). Additionally, while requesting an HTTPS page, the SSL certificate must match the hostname (i.e., `localhost.localstack.cloud` in our case).

To navigate this, we recommend you create a local TCP proxy server. The proxy server could listen on `127.0.0.1:4566` and forward all requests to your target endpoint where the LocalStack instance is running. You could leave the configuration in the Web user interface to use the default value, `https://localhost.localstack.cloud:4566`. We recommend [simpleproxy](https://manpages.ubuntu.com/manpages/trusty/man1/simpleproxy.1.html) or [proxy.py](https://github.com/abhinavsingh/proxy.py) as a way to implement this.

Expand Down