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

Add TLS redirect support in Virtualserver #748

Merged
merged 2 commits into from
Nov 1, 2019
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
25 changes: 23 additions & 2 deletions docs/virtualserver-and-virtualserverroute.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ This document is the reference documentation for the resources. To see additiona
- [Prerequisites](#prerequisites)
- [VirtualServer Specification](#virtualserver-specification)
- [VirtualServer.TLS](#virtualservertls)
- [VirtualServer.TLS.Redirect](#virtualservertlsredirect)
- [VirtualServer.Route](#virtualserverroute)
- [VirtualServerRoute Specification](#virtualserverroute-specification)
- [VirtualServerRoute.Subroute](#virtualserverroutesubroute)
Expand All @@ -26,8 +27,8 @@ This document is the reference documentation for the resources. To see additiona
- [Header](#header)
- [Action](#action)
- [Split](#split)
- [Condition](#condition)
- [Match](#match)
- [Condition](#condition)
- [Using VirtualServer and VirtualServerRoute](#using-virtualserver-and-virtualserverroute)
- [Validation](#validation)
- [Customization via ConfigMap](#customization-via-configmap)
Expand Down Expand Up @@ -76,12 +77,30 @@ spec:
The tls field defines TLS configuration for a VirtualServer. For example:
```yaml
secret: cafe-secret
redirect:
code: 302
basedOn: x-forwarded-proto
```

| 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 VirtualServer. The secret must 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). If the secret doesn't exist, NGINX will break any attempt to establish a TLS connection to the host of the VirtualServer. | `string` | Yes |
| `redirect` | The redirect configuration of the TLS for a VirtualServer. | [`tls.redirect`](#VirtualServerTLSRedirect) | No |

### VirtualServer.TLS.Redirect

The redirect field configures a TLS redirect for a VirtualServer:
```yaml
enable: true
code: 301
basedOn: scheme
```

| Field | Description | Type | Required |
| ----- | ----------- | ---- | -------- |
| `enable` | Enables a TLS redirect for a VirtualServer. The default is `False`. | `boolean` | No |
| `code` | The status code of a redirect. The allowed values are: `301`, `302`, `307`, `308`. The default is `301`. | `int` | No |
| `basedOn` | The attribute of a request that NGINX will evaluate to send a redirect. The allowed values are `scheme` (the scheme of the request) or `x-forwarded-proto` (the `X-Forwarded-Proto` header of the request). The default is `scheme`. | `string` | No |

### VirtualServer.Route

Expand Down Expand Up @@ -205,7 +224,7 @@ next-upstream-timeout: 5s
next-upstream-tries: 10
client-max-body-size: 2m
tls:
enable: True
enable: true
```

**Note**: The WebSocket protocol is supported without any additional configuration.
Expand Down Expand Up @@ -535,3 +554,5 @@ You can customize the NGINX configuration for VirtualServer and VirtualServerRou
* `hsts-max-age`
* `hsts-include-subdomains`
* `hsts-behind-proxy`
* `redirect-to-https`
* `ssl-redirect`
41 changes: 23 additions & 18 deletions internal/configs/version2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,28 +32,27 @@ type UpstreamServer struct {

// Server defines a server.
type Server struct {
ServerName string
StatusZone string
ProxyProtocol bool
SSL *SSL
RedirectToHTTPSBasedOnXForwarderProto bool
ServerTokens string
RealIPHeader string
SetRealIPFrom []string
RealIPRecursive bool
Snippets []string
InternalRedirectLocations []InternalRedirectLocation
Locations []Location
HealthChecks []HealthCheck
ServerName string
StatusZone string
ProxyProtocol bool
SSL *SSL
ServerTokens string
RealIPHeader string
SetRealIPFrom []string
RealIPRecursive bool
Snippets []string
InternalRedirectLocations []InternalRedirectLocation
Locations []Location
HealthChecks []HealthCheck
TLSRedirect *TLSRedirect
}

// SSL defines SSL configuration for a server.
type SSL struct {
HTTP2 bool
Certificate string
CertificateKey string
Ciphers string
RedirectToHTTPS bool
HTTP2 bool
Certificate string
CertificateKey string
Ciphers string
}

// Location defines a location.
Expand Down Expand Up @@ -99,6 +98,12 @@ type HealthCheck struct {
Match string
}

// TLSRedirect defines a redirect in a Server.
type TLSRedirect struct {
Code int
BasedOn string
}

// SessionCookie defines a session cookie for an upstream.
type SessionCookie struct {
Enable bool
Expand Down
12 changes: 3 additions & 9 deletions internal/configs/version2/nginx-plus.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,11 @@ server {
{{ if $ssl.Ciphers }}
ssl_ciphers {{ $ssl.Ciphers }};
{{ end }}

{{ if $ssl.RedirectToHTTPS }}
if ($scheme = http) {
return 301 https://$host$request_uri;
}
{{ end }}
{{ end }}

{{ if $s.RedirectToHTTPSBasedOnXForwarderProto }}
if ($http_x_forwarded_proto = 'http') {
return 301 https://$host$request_uri;
{{ with $s.TLSRedirect }}
if ({{ .BasedOn }} = 'http') {
return {{ .Code }} https://$host$request_uri;
}
{{ end }}

Expand Down
12 changes: 3 additions & 9 deletions internal/configs/version2/nginx.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,11 @@ server {
{{ if $ssl.Ciphers }}
ssl_ciphers {{ $ssl.Ciphers }};
{{ end }}

{{ if $ssl.RedirectToHTTPS }}
if ($scheme = http) {
return 301 https://$host$request_uri;
}
{{ end }}
{{ end }}

{{ if $s.RedirectToHTTPSBasedOnXForwarderProto }}
if ($http_x_forwarded_proto = 'http') {
return 301 https://$host$request_uri;
{{ with $s.TLSRedirect }}
if ({{ .BasedOn }} = 'http') {
return {{ .Code }} https://$host$request_uri;
}
{{ end }}

Expand Down
24 changes: 13 additions & 11 deletions internal/configs/version2/templates_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,20 @@ var virtualServerCfg = VirtualServerConfig{
StatusZone: "example.com",
ProxyProtocol: true,
SSL: &SSL{
HTTP2: true,
Certificate: "cafe-secret.pem",
CertificateKey: "cafe-secret.pem",
Ciphers: "NULL",
RedirectToHTTPS: true,
HTTP2: true,
Certificate: "cafe-secret.pem",
CertificateKey: "cafe-secret.pem",
Ciphers: "NULL",
},
RedirectToHTTPSBasedOnXForwarderProto: true,
ServerTokens: "off",
SetRealIPFrom: []string{"0.0.0.0/0"},
RealIPHeader: "X-Real-IP",
RealIPRecursive: true,
Snippets: []string{"# server snippet"},
TLSRedirect: &TLSRedirect{
BasedOn: "$scheme",
Code: 301,
},
ServerTokens: "off",
SetRealIPFrom: []string{"0.0.0.0/0"},
RealIPHeader: "X-Real-IP",
RealIPRecursive: true,
Snippets: []string{"# server snippet"},
InternalRedirectLocations: []InternalRedirectLocation{
{
Path: "/split",
Expand Down
56 changes: 38 additions & 18 deletions internal/configs/virtualserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ func (vsc *virtualServerConfigurator) generateEndpointsForUpstream(owner runtime
func (vsc *virtualServerConfigurator) GenerateVirtualServerConfig(virtualServerEx *VirtualServerEx, tlsPemFileName string) (version2.VirtualServerConfig, Warnings) {
vsc.clearWarnings()
ssl := generateSSLConfig(virtualServerEx.VirtualServer.Spec.TLS, tlsPemFileName, vsc.cfgParams)
tlsRedirectConfig := generateTLSRedirectConfig(virtualServerEx.VirtualServer.Spec.TLS)

// crUpstreams maps an UpstreamName to its conf_v1alpha1.Upstream as they are generated
// necessary for generateLocation to know what Upstream each Location references
Expand Down Expand Up @@ -289,19 +290,19 @@ func (vsc *virtualServerConfigurator) GenerateVirtualServerConfig(virtualServerE
Maps: maps,
StatusMatches: statusMatches,
Server: version2.Server{
ServerName: virtualServerEx.VirtualServer.Spec.Host,
StatusZone: virtualServerEx.VirtualServer.Spec.Host,
ProxyProtocol: vsc.cfgParams.ProxyProtocol,
SSL: ssl,
RedirectToHTTPSBasedOnXForwarderProto: vsc.cfgParams.RedirectToHTTPS,
ServerTokens: vsc.cfgParams.ServerTokens,
SetRealIPFrom: vsc.cfgParams.SetRealIPFrom,
RealIPHeader: vsc.cfgParams.RealIPHeader,
RealIPRecursive: vsc.cfgParams.RealIPRecursive,
Snippets: vsc.cfgParams.ServerSnippets,
InternalRedirectLocations: internalRedirectLocations,
Locations: locations,
HealthChecks: healthChecks,
ServerName: virtualServerEx.VirtualServer.Spec.Host,
StatusZone: virtualServerEx.VirtualServer.Spec.Host,
ProxyProtocol: vsc.cfgParams.ProxyProtocol,
SSL: ssl,
ServerTokens: vsc.cfgParams.ServerTokens,
SetRealIPFrom: vsc.cfgParams.SetRealIPFrom,
RealIPHeader: vsc.cfgParams.RealIPHeader,
RealIPRecursive: vsc.cfgParams.RealIPRecursive,
Snippets: vsc.cfgParams.ServerSnippets,
InternalRedirectLocations: internalRedirectLocations,
Locations: locations,
HealthChecks: healthChecks,
TLSRedirect: tlsRedirectConfig,
},
}

Expand Down Expand Up @@ -771,16 +772,35 @@ func generateSSLConfig(tls *conf_v1alpha1.TLS, tlsPemFileName string, cfgParams
}

ssl := version2.SSL{
HTTP2: cfgParams.HTTP2,
Certificate: name,
CertificateKey: name,
Ciphers: ciphers,
RedirectToHTTPS: cfgParams.SSLRedirect,
HTTP2: cfgParams.HTTP2,
Certificate: name,
CertificateKey: name,
Ciphers: ciphers,
}

return &ssl
}

func generateTLSRedirectConfig(tls *conf_v1alpha1.TLS) *version2.TLSRedirect {
if tls == nil || tls.Redirect == nil || !tls.Redirect.Enable {
return nil
}

redirect := &version2.TLSRedirect{
Code: generateIntFromPointer(tls.Redirect.Code, 301),
BasedOn: generateTLSRedirectBasedOn(tls.Redirect.BasedOn),
}

return redirect
}

func generateTLSRedirectBasedOn(basedOn string) string {
if basedOn == "x-forwarded-proto" {
return "$http_x_forwarded_proto"
}
return "$scheme"
}

func createEndpointsFromUpstream(upstream version2.Upstream) []string {
var endpoints []string

Expand Down
Loading