8000 feat: Add initial support for SSL termination for TransportServer by ciarams87 · Pull Request #3462 · nginx/kubernetes-ingress · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
6 changes: 6 additions & 0 deletions deployments/common/crds/k8s.nginx.org_transportservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ spec:
type: string
streamSnippets:
type: string
tls:
description: TLS defines TLS configuration for a TransportServer.
type: object
properties:
secret:
type: string
upstreamParameters:
description: UpstreamParameters defines parameters for an upstream.
type: object
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ spec:
type: string
streamSnippets:
type: string
tls:
description: TLS defines TLS configuration for a TransportServer.
type: object
properties:
secret:
type: string
upstreamParameters:
description: UpstreamParameters defines parameters for an upstream.
type: object
Expand Down
16 changes: 16 additions & 0 deletions docs/content/configuration/transportserver-resource.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ The TransportServer resource defines load balancing configuration for TCP, UDP,
listener:
name: dns-tcp
protocol: TCP
tls:
secret: cafe-secret
upstreams:
- name: dns-app
service: dns-service
Expand Down Expand Up @@ -82,6 +84,7 @@ The TransportServer resource defines load balancing configuration for TCP, UDP,
| ---| ---| ---| --- |
|``listener`` | The listener on NGINX that will accept incoming connections/datagrams. | [listener](#listener) | Yes |
|``host`` | The host (domain name) of the server. Must be a valid subdomain as defined in RFC 1123, such as ``my-app`` or ``hello.example.com``. Wildcard domains like ``*.example.com`` are not allowed. Required for TLS Passthrough load balancing. | ``string`` | No |
|``tls`` | The TLS termination configuration. Not supported for TLS Passthrough load balancing. | [tls](#tls) | No |
|``upstreams`` | A list of upstreams. | [[]upstream](#upstream) | Yes |
|``upstreamParameters`` | The upstream parameters. | [upstreamParameters](#upstreamparameters) | No |
|``action`` | The action to perform for a client connection/datagram. | [action](#action) | Yes |
Expand Down Expand Up @@ -110,6 +113,19 @@ listener:
|``protocol`` | The protocol of the listener. | ``string`` | Yes |
{{% /table %}}

### TLS

The tls field defines TLS configuration for a TransportServer. Please note the current implementation supports TLS termination on multiple ports, where each application owns a dedicated port - the Ingress Controller terminates TLS connections on each port, where each application uses its own cert/key, and routes connections to appropriate application (service) based on that incoming port (any TLS connection regardless of the SNI on a port will be routed to the application that corresponds to that port). An example configuration is shown below:
```yaml
secret: cafe-secret
```

{{% table %}}
|Field | Description | Type | Required |
| ---| ---| ---| --- |
|``secret`` | The name of a secret with a TLS certificate and key. The secret must belong to the same namespace as the TransportServer. The secret must be of the type ``kubernetes.io/tls`` and contain keys named ``tls.crt`` and ``tls.key`` that contain the certificate and private key as described [here](https://kubernetes.io/docs/concepts/services-networking/ingress/#tls). | ``string`` | No |
{{% /table %}}

### Upstream

The upstream defines a destination for the TransportServer. For example:
Expand Down
46 changes: 45 additions & 1 deletion internal/configs/transportserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import (
"fmt"
"strings"

api_v1 "k8s.io/api/core/v1"

"github.com/nginxinc/kubernetes-ingress/internal/configs/version2"
"github.com/nginxinc/kubernetes-ingress/internal/k8s/secrets"
conf_v1alpha1 "github.com/nginxinc/kubernetes-ingress/pkg/apis/configuration/v1alpha1"
)

Expand All @@ -18,6 +21,7 @@ type TransportServerEx struct {
PodsByIP map[string]string
ExternalNameSvcs map[string]bool
DisableIPV6 bool
SecretRefs map[string]*secrets.SecretReference
}

func (tsEx *TransportServerEx) String() string {
Expand All @@ -38,14 +42,20 @@ func newUpstreamNamerForTransportServer(transportServer *conf_v1alpha1.Transport

// generateTransportServerConfig generates a full configuration for a TransportServer.
func generateTransportServerConfig(transportServerEx *TransportServerEx, listenerPort int, isPlus bool, isResolverConfigured bool) (*version2.TransportServerConfig, Warnings) {
warnings := newWarnings()

upstreamNamer := newUpstreamNamerForTransportServer(transportServerEx.TransportServer)

upstreams, warnings := generateStreamUpstreams(transportServerEx, upstreamNamer, isPlus, isResolverConfigured)
upstreams, w := generateStreamUpstreams(transportServerEx, upstreamNamer, isPlus, isResolverConfigured)
warnings.Add(w)

healthCheck, match := generateTransportServerHealthCheck(transportServerEx.TransportServer.Spec.Action.Pass,
upstreamNamer.GetNameForUpstream(transportServerEx.TransportServer.Spec.Action.Pass),
transportServerEx.TransportServer.Spec.Upstreams)

sslConfig, w := generateSSLConfig(transportServerEx.TransportServer, transportServerEx.TransportServer.Spec.TLS, transportServerEx.TransportServer.Namespace, transportServerEx.SecretRefs)
warnings.Add(w)

var proxyRequests, proxyResponses *int
var connectTimeout, nextUpstreamTimeout string
var nextUpstream bool
Expand Down Expand Up @@ -97,6 +107,7 @@ func generateTransportServerConfig(transportServerEx *TransportServerEx, listene
HealthCheck: healthCheck,
ServerSnippets: serverSnippets,
DisableIPV6: transportServerEx.DisableIPV6,
SSL: sslConfig,
},
Match: match,
Upstreams: upstreams,
Expand All @@ -112,6 +123,39 @@ func generateUnixSocket(transportServerEx *TransportServerEx) string {
return ""
}

func generateSSLConfig(ts *conf_v1alpha1.TransportServer, tls *conf_v1alpha1.TLS, namespace string, secretRefs map[string]*secrets.SecretReference) (*version2.StreamSSL, Warnings) {
if tls == nil {
return &version2.StreamSSL{Enabled: false}, nil
}

warnings := newWarnings()
sslEnabled := true

secretRef := secretRefs[fmt.Sprintf("%s/%s", namespace, tls.Secret)]
var secretType api_v1.SecretType
if secretRef.Secret != nil {
secretType = secretRef.Secret.Type
}
name := secretRef.Path
if secretType != "" && secretType != api_v1.SecretTypeTLS {
errMsg := fmt.Sprintf("TLS secret %s is of a wrong type '%s', must be '%s'. SSL termination will not be enabled for this server.", tls.Secret, secretType, api_v1.SecretTypeTLS)
warnings.AddWarning(ts, errMsg)
sslEnabled = false
} else if secretRef.Error != nil {
errMsg := fmt.Sprintf("TLS secret %s is invalid: %v. SSL termination will not be enabled for this server.", tls.Secret, secretRef.Error)
warnings.AddWarning(ts, errMsg)
sslEnabled = false
}

ssl := version2.StreamSSL{
Enabled: sslEnabled,
Certificate: name,
CertificateKey: name,
}

return &ssl, warnings
}

func generateStreamUpstreams(transportServerEx *TransportServerEx, upstreamNamer *upstreamNamer, isPlus bool, isResolverConfigured bool) ([]version2.StreamUpstream, Warnings) {
warnings := newWarnings()
var upstreams []version2.StreamUpstream
Expand Down
Loading
0