Skip to content

Commit

Permalink
chore(docs): add doc on non-http ingress (#1166)
Browse files Browse the repository at this point in the history
## Description

Documents the resources/configuration necessary to allow non-http
ingress into a UDS Cluster (with Istio).

## Related Issue

Fixes #748

## Type of change

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [x] Other (security config, docs update, etc)

## Steps to Validate

While the doc can be read and reviewed, I stepped through this on k3d
with an example pod to validate my own docs. The steps I used are
included below for convenience/reference. These should align with the
doc 1:1, just subsituting real workloads/values where needed instead of
the example ones.

<details>

Create a folder + file for a new bundle,
`bundles/base-ssh/uds-bundle.yaml`. The file contents should be:

```yaml
kind: UDSBundle
metadata:
  name: base-ssh
  version: "dev"

packages:
  - name: init
    repository: ghcr.io/zarf-dev/packages/init
    ref: v0.45.0

  - name: core-base
    repository: ghcr.io/defenseunicorns/packages/private/uds/core-base
    ref: 0.33.1-unicorn
    overrides:
      istio-tenant-gateway:
        gateway:
          values:
            - path: "service.ports"
              value:
                - name: status-port
                  port: 15021
                  protocol: TCP
                  targetPort: 15021
                - name: http2
                  port: 80
                  protocol: TCP
                  targetPort: 80
                - name: https
                  port: 443
                  protocol: TCP
                  targetPort: 443
                - name: tcp-ssh
                  port: 2022
                  protocol: TCP
                  targetPort: 22
```

Run the below commands to deploy core with a pod listening for SSH
connections:

```console
# The extra args here allow us to expose port 2022 on the host and map it into the ingress gateway
uds zarf package deploy oci://defenseunicorns/uds-k3d:0.11.0 --set K3D_EXTRA_ARGS='-p 2022:2022@server:*' --set NGINX_EXTRA_PORTS='[2022]' --confirm

# Create our bundle
uds create bundles/base-ssh --confirm

# Deploy our bundle (note that the architecture may be different for you)
uds deploy bundles/base-ssh/uds-bundle-base-ssh-arm64-dev.tar.zst --confirm

# Create our gateway
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: ssh-gateway
  namespace: istio-tenant-gateway
spec:
  selector:
    app: tenant-ingressgateway
  servers:
    - hosts:
      - ssh.uds.dev
      port:
        name: tcp-ssh
        number: 22
        protocol: TCP
EOF

# Create our virtualservice
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: ssh
  namespace: uds-dev-stack
spec:
  gateways:
    - istio-tenant-gateway/ssh-gateway
  hosts:
    - ssh.uds.dev
  tcp:
    - match:
        - port: 22
      route:
        - destination:
            host: ssh-service.uds-dev-stack.svc.cluster.local
            port:
              number: 22
EOF

# Note that this assumes you have a public key setup at ~/.ssh/id_rsa.pub
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: docker-ssh-pod
  namespace: uds-dev-stack
  labels:
    app: docker-ssh
    zarf.dev/agent: ignore
spec:
  containers:
  - name: docker-ssh
    image: serversideup/docker-ssh:latest
    ports:
    - containerPort: 2222
    env:
    - name: AUTHORIZED_KEYS
      value: "$(cat ~/.ssh/id_rsa.pub)"
EOF

# Create a service for our pod
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
  name: ssh-service
  namespace: uds-dev-stack
  labels:
    app: docker-ssh
spec:
  selector:
    app: docker-ssh
  ports:
  - protocol: TCP
    port: 22
    targetPort: 2222
  type: ClusterIP
EOF

# Note that this assumes you have the private key at ~/.ssh/id_rsa
ssh -p 2022 -i ~/.ssh/id_rsa tunnel@ssh.uds.dev
```

</details>

## Checklist before merging

- [x] Test, docs, adr added or updated as needed
- [x] [Contributor
Guide](https://github.com/defenseunicorns/uds-template-capability/blob/main/CONTRIBUTING.md)
followed

---------

Co-authored-by: Noah <40781376+noahpb@users.noreply.github.com>
  • Loading branch information
mjnagel and noahpb authored Jan 10, 2025
1 parent 0f9552a commit 0783525
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 0 deletions.
5 changes: 5 additions & 0 deletions docs/reference/configuration/ingress.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ UDS Core provides a few Istio [Gateway](https://istio.io/latest/docs/reference/c
2. **(Required)** Admin Gateway - This gateway provides ingress to admin-related applications that are not for use by the default end user. By default, UDS Core deploys a few services on this gateway, such as the Admin Keycloak interface. This gateway is typically accessible to admins of the applications deployed on top of UDS Core. *Since the Admin and Tenant Gateways are logically separated, it is possible to have different security controls on each gateway.*
3. **(Optional)** Passthrough Gateway - This gateway allows mesh ingress without TLS termination performed by Istio. This could be useful for applications that need to (or currently) handle their own TLS termination. This gateway used to be a default component of UDS Core but is no longer deployed by default. To deploy this gateway, you must specify `istio-passthrough-gateway` as an `optionalComponent` in your UDS Bundle configuration.

:::note
The default gateways provided with UDS Core only support HTTP/HTTPS ingress. If you need other TCP ingress for a service (ex: SSH ingress) this can be done by adding additional resources/configuration to UDS Core (see [this document](https://uds.defenseunicorns.com/reference/configuration/non-http-ingress/) for a guide). UDP Ingress is [not currently supported with Istio](https://github.com/istio/istio/issues/1430) and would need to be managed via a separate ingress path.
:::

### Enable Passthrough Gateway

In order to enable the Passthrough Gateway, you must specify `istio-passthrough-gateway` as an `optionalComponent` in your UDS Bundle configuration. Here is an example of how to do this:
Expand Down Expand Up @@ -129,3 +133,4 @@ packages:
values:
- path: tls.credentialName
value: tenant-gateway-tls-secret # Reference to the Kubernetes secret for the tenant gateway's TLS certificate
```
121 changes: 121 additions & 0 deletions docs/reference/configuration/non-http-ingress.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
---
title: Non-HTTP(s) Istio Ingress
---

As noted in the [Istio Ingress document](https://uds.defenseunicorns.com/reference/configuration/ingress/), UDS Core by default provides gateway configuration to handle HTTP(s) ingress traffic only. This document provides example configuration and resources to setup ingress for a non-http service (using SSH for the example below). Note that while this example uses port 22 and the SSH protocol this same process should work for an TCP port/protocol that your service is listening on.

## UDS Core Configuration

In order to allow ingress for a non-HTTP service you first need to configure the UDS Core loadbalancers to accept traffic on a different port. This can be done via an override to the configuration for the admin or tenant loadbalancers, as shown in the example below for the tenant loadbalancer to add port 22:

```yaml
- name: core
repository: ghcr.io/defenseunicorns/packages/uds/core
ref: x.x.x
overrides:
istio-tenant-gateway:
gateway:
values:
- path: "service.ports"
value:
# Default ports for status, http, and https
- name: status-port
port: 15021
protocol: TCP
targetPort: 15021
- name: http2
port: 80
protocol: TCP
targetPort: 80
- name: https
port: 443
protocol: TCP
targetPort: 443
# Any additional ports required for ingress
- name: tcp-ssh
port: 2022 # The external port that is exposed
protocol: TCP
targetPort: 22 # The port to route to on the Gateway
```
Note that you _MUST_ include the default list of ports (as shown above) to ensure that HTTP traffic and liveness checks continue to function as expected. You can choose any `port` and `targetPort` for your additional configuration that you want.

## Gateway Custom Resource

In order to allow exposing services through the newly opened loadbalancer port you must also create an [Istio Gateway](https://istio.io/latest/docs/reference/config/networking/gateway/) custom resource that specifies the hosts and port that you want to configure the gateway to accept requests for. The below example shows how to do this for `example.uds.dev` on our SSH port of 22:

```yaml
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: example-ssh-gateway
# This must be the namespace of the ingressgateway you configured the port for
namespace: istio-tenant-gateway
spec:
selector:
app: tenant-ingressgateway
servers:
- hosts:
# This should be the host you expect to hit with requests
- example.uds.dev
port:
name: tcp-ssh
# This must match the `targetPort` you added to the port list above
number: 22
protocol: TCP
```
## VirtualService Custom Resource
Now that the loadbalancer and Istio Gateway are configured for the right ports and host, you will just need to add a route (`VirtualService`) to ensure traffic is directed to the right cluster service when requests come to your host and port. The example below does this for our `example.uds.dev` host:

```yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: example-ssh
# This must be in the namespace of your application
namespace: example
spec:
gateways:
# This must match the namespace/name of the Gateway you created
- istio-tenant-gateway/example-ssh-gateway
hosts:
- example.uds.dev
tcp:
- match:
# This must match the Gateway port number you added above
- port: 22
route:
- destination:
# This should be the full cluster service address
host: example.example.svc.cluster.local
port:
# This is the port on the service you want to route to
number: 22
```

Assuming you are running with strict network policies you will also need to add a network policy to allow ingress on this same port. You can do this in the Package CR like the example below:

```yaml
spec:
network:
allow:
- direction: Ingress
selector:
app: example
# These must line up with the gateway you chose
remoteNamespace: istio-tenant-gateway
remoteSelector:
app: tenant-ingressgateway
# This must line up with the port exposed on the pod
port: 22
description: "SSH Ingress"
...
```

With these steps complete you should be able to hit your application over the port you configured on the configured host, so in our case we should be able to run:

```console
ssh -p 2022 user@example.uds.dev
```

0 comments on commit 0783525

Please sign in to comment.