Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 63 additions & 5 deletions rest/tls/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ For more information on using TLS in your REST apis and other services [see our

This examples demonstrates a number of API Connect for GraphQL capabilities:
- Use of `@rest(tls:)`
- Use of schema level `@rest`
- stepzen service
- Simple ecmascript capability for reshaping data.
- config.yaml usage for `@rest` using process for clean CI/CD

## mTLS and certificates

Expand All @@ -22,26 +24,56 @@ When the tls entry is given the name of a configuration entry, you can provide
- `key` - the client certifcate key
The data should be in PEM format.

In our examples, we have two configuration: `selfsign` with a `ca` entry and `selfsignedmtls` with all three entries.
In our examples, we have two configuration: `myserver`(with a
selfsigned cert) with a `ca` entry and `mymtlsserver` requiring
mtls)with all three entries.

The same configuration entry is used
for both tls and server configuration, so you'll see
`@rest(tls:"myserver" configuration:"myserver")`.

If the tls `ca` was a shared private `ca`, you'd want to have a common
`tls` config entry for all servers so you'd probably put them into two
different configuration entries

TLS 1.2 and 1.3 are supported. TLS 1.0 and 1.1 are not supported.

### Schema `@rest`

You can definte a common `@rest(name:)` profile as a schema level definition to be shared as `@rest(use:)`.

This allows for common configuraiton to be creatd and shared.

```
schema
...
@rest(name: "commonserver", endpoint: "$url;", tls: "myserver" configuration: "myserver") {
query: Query
}
```
create a `commonserver` profile with endpoint, tls, and configuration.

When `@rest(use:"commonserver")` is encountered, those arguments will be applied.

Since there is only a single `@rest` definition, this is a contrivied example, but the utility should be clear especially for CI/CD.


## Try it out!

`rest_self` in tls.graphql provides an example of self signed certificates by pointing to the `selfsign` resource in config.yaml. That configuration contains `ca: STEPZEN_SERVER_CRT`
`rest_self` in tls.graphql provides an example of self signed certificates by pointing to the `myserver` resource in config.yaml. That configuration contains `ca: STEPZEN_SERVER_CRT`
During `stepzen deploy`, the `STEPZEN_SERVER_CRT` environment variable is expanded and the result will be a yaml that looks like:
```
configurationset:
- configuration:
name: selfsign
name: myserver
ca: |
-----BEGIN CERTIFICATE-----
MIIF5zCCA8+gAwIBAgIUS2BwtghuA7PREQ5AWzOeeT+tCe4wDQYJKoZIhvcNAQEL
...
-----END CERTIFICATE-----
```

The `selfsignedmtls` configuration contains an example mutual TLS configuration.
The `mymtlsserver` configuration contains an example mutual TLS configuration.

Two safe approaches are to set the environment variables from secrets or to have a `.env` file.

Expand Down Expand Up @@ -88,6 +120,14 @@ By default, `rest_self` uses `host.docker.internal` which works in most modern

For Podman, you may need to change this to `host.containers.internal` or `localhost` depending on your podman defaults. You may also need to modify your podman default configuration to allow for such access.

We apply a layer of indirection for the endpoint. The actual value is held in the configuation as `url` and that is actually obtained from the environment variable `STEPZEN_SERVER_URL`. This allows for CI/CD process to inject the root URL by setting the env variable.

Here, this can be done by running, replacing the `SERVER_URL` with the value appropriate to your container runtime toolset.
```
(cd tests; make env SERVER_URL="http://localhost:8443")
```
This won't overwrite an existing .env, so remove it if already exists.

### env variables

You can set `STEPZEN_*` env variables in .env or using export.
Expand Down Expand Up @@ -136,11 +176,29 @@ that it is as you expected.

You are looking for something that looks like:
```
"configuration":{"configurationset":[{"configuration":{"name":"selfsign","ca":
"configuration":{"configurationset":[{"configuration":{"name":"myserver","ca":
"-----BEGIN CERTIFICATE-----\nMIIF5zCCA8+gAwIBAgIUS2BwtghuA7PREQ5AWzOeeT+tCe4wDQYJKoZIhvcNAQEL\nBQAwbTE...
```
notice the '\n'. If you see spaces you've done something wrong upsteram.

### Reserved environment variables

`STEPZEN_SERVER_URL` is used by the stepzen cli to identify the API Connect for GraphQL server and should be avoided to prevent stepzen cli issues.

Here's a full list of stepzen cli special variables you should avoid using.
```
STEPZEN_ENABLE_PERF
STEPZEN_DISABLE_ANALYTICS
STEPZEN_INTERACTIVE
STEPZEN_CONFIG_FILE
STEPZEN_DOCKER_IMAGE
STEPZEN_DOCKER_TAG
STEPZEN_DEPLOYMENT_TYPE
STEPZEN_ZENCTL_API_URL
STEPZEN_JSON2SDL_SERVER_URL
STEPZEN_CONFIG_CONTENT
STEPZEN_SEGMENT_PRODUCT
```

### Debugging
You can debug using stepzen request by adding `-H "stepzen-debug-level: 1"`
Expand Down
8 changes: 6 additions & 2 deletions rest/tls/config.yaml
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
# provide values through environment variables to mimimize secret exposure and
# adhere to clean ci/cd process. env variables/secrets should be injected
configurationset:
- configuration:
name: selfsign
name: myserver
ca: STEPZEN_SERVER_CRT
url: STEPZEN_SERVICE_URL
- configuration:
name: selfsignedmtls
name: mymtlsserver
ca: STEPZEN_SERVER_CRT
cert: STEPZEN_CLIENT_CRT
key: STEPZEN_CLIENT_KEY
url: STEPZEN_SERVICE_URL
4 changes: 3 additions & 1 deletion rest/tls/index.graphql
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
schema @sdl(files: ["tls.graphql"]) {
schema
@sdl(files: ["tls.graphql"])
@rest(name: "commonserver", endpoint: "$url;", tls: "myserver" configuration: "myserver") {
query: Query
}
9 changes: 8 additions & 1 deletion rest/tls/tests/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Makefile to build and validate a pair of *example* self-signed certificates for *simple* tests

# alternate endpoint settings for different container toolsets
# hostname: "https://host.docker.internal:8443"
# hostname: "https://localhost:8443"
# hostname: "https://host.rancher-desktop.internal:8443"
SERVER_URL:=https://host.docker.internal:8443

# enable to debug ssl server
# DEBUG:=-debug
all: client.crt server.crt env
Expand Down Expand Up @@ -27,6 +33,7 @@ clean:
env: ../.env

../.env: client.crt server.crt
( echo STEPZEN_CLIENT_CRT=\""`cat client.crt`"\"; \
( echo STEPZEN_SERVICE_URL=\"$(SERVER_URL)\"; \
echo STEPZEN_CLIENT_CRT=\""`cat client.crt`"\"; \
echo STEPZEN_CLIENT_KEY=\""`cat client.key`"\"; \
echo STEPZEN_SERVER_CRT=\""`cat server.crt`"\") > ../.env
13 changes: 8 additions & 5 deletions rest/tls/tls.graphql
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
type Query {
"""
typically, there will be a common set of server configurations that are shared among many
different `@rest` calls, so we actually specify the `@rest(tls:)` in a schema level
`@rest` definition called `commonserver` in index.graphql

`@rest(use:"commonserver")` picks up the `@rest(tls:)` and the `@rest(endpoint:)`

will contact localhost using host.docker.internal and 8443 and selfsign configuration
the ecmascript is used to repackage any content coming back (openssl s_server returns html)
"""
rest_self: JSON
@rest(
endpoint: "https://host.docker.internal:8443/"
# alternate endpoint settings for different container toolsets
# endpoint: "https://localhost:8443/"
# endpoint: "https://host.rancher-desktop.internal:8443/"
tls: "selfsign"
use: "commonserver"
path: "/path"
ecmascript: """
function transformREST(s) {
return JSON.stringify(
Expand Down