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

Egress via Ingress VirtualServer Resource #3491

Merged
merged 19 commits into from
Apr 14, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
7d1ca30
Add ability for nginx service mesh to egress through a virtualserver …
chase-kiefer Jan 26, 2023
0ba0623
Add a description for the InternalRoute field in the VS CRD
chase-kiefer Feb 27, 2023
a9f6424
Add test case for nsmEgress being true in TestIsTLSEnabled
chase-kiefer Mar 7, 2023
4008dce
Merge branch 'main' into nsm-virtualserver-egress
ciarams87 Mar 9, 2023
8d32c11
Merge branch 'main' into nsm-virtualserver-egress
ciarams87 Mar 9, 2023
2328523
Update the isTLSEnabled function for clarity
chase-kiefer Mar 10, 2023
5f968d6
Reverse function params for isTLSEnabled
chase-kiefer Mar 10, 2023
a9a1e87
Merge branch 'main' into nsm-virtualserver-egress
ciarams87 Mar 16, 2023
43ce778
Add virtual server internal route validation and warning
chase-kiefer Mar 21, 2023
9dc96f5
Add refactored VS templates to avoid duplicate listen blocks
chase-kiefer Mar 28, 2023
458584c
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Mar 28, 2023
57aa6ab
Merge branch 'main' into nsm-virtualserver-egress
ciarams87 Mar 29, 2023
3362bab
Merge branch 'main' into nsm-virtualserver-egress
ciarams87 Mar 31, 2023
84f9d46
Add conditional to prevent SpiffeClientCerts being set for internal r…
chase-kiefer Apr 5, 2023
c5b4717
Fix unit tests
chase-kiefer Apr 5, 2023
4113a58
Merge branch 'main' into nsm-virtualserver-egress
tomasohaodha Apr 13, 2023
d30cdee
Merge branch 'main' into nsm-virtualserver-egress
vepatel Apr 13, 2023
7b216cf
Merge branch 'main' into nsm-virtualserver-egress
ciarams87 Apr 14, 2023
ae6aa50
Merge branch 'main' into nsm-virtualserver-egress
vepatel Apr 14, 2023
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
3 changes: 3 additions & 0 deletions deployments/common/crds/k8s.nginx.org_virtualservers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ spec:
type: string
ingressClassName:
type: string
internalRoute:
description: InternalRoute allows for the configuration of internal routing.
type: boolean
chase-kiefer marked this conversation as resolved.
Show resolved Hide resolved
policies:
type: array
items:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ spec:
type: string
ingressClassName:
type: string
internalRoute:
description: InternalRoute allows for the configuration of internal routing.
type: boolean
chase-kiefer marked this conversation as resolved.
Show resolved Hide resolved
policies:
type: array
items:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ spec:
|``upstreams`` | A list of upstreams. | [[]upstream](#upstream) | No |
|``routes`` | A list of routes. | [[]route](#virtualserverroute) | No |
|``ingressClassName`` | Specifies which Ingress Controller must handle the VirtualServer resource. | ``string`` | No |
|``internalRoute`` | Specifies if the VirtualServer resource is an internal route or not. | ``boolean`` | No |
|``http-snippets`` | Sets a custom snippet in the http context. | ``string`` | No |
|``server-snippets`` | Sets a custom snippet in server context. Overrides the ``server-snippets`` ConfigMap key. | ``string`` | No |
{{% /table %}}
Expand Down
17 changes: 9 additions & 8 deletions internal/configs/version2/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@ type UpstreamLabels struct {

// VirtualServerConfig holds NGINX configuration for a VirtualServer.
type VirtualServerConfig struct {
HTTPSnippets []string
LimitReqZones []LimitReqZone
Maps []Map
Server Server
SpiffeCerts bool
SplitClients []SplitClient
StatusMatches []StatusMatch
Upstreams []Upstream
HTTPSnippets []string
LimitReqZones []LimitReqZone
Maps []Map
Server Server
SpiffeCerts bool
InternalRouteServer bool
SplitClients []SplitClient
StatusMatches []StatusMatch
Upstreams []Upstream
}

// Upstream defines an upstream.
Expand Down
9 changes: 9 additions & 0 deletions internal/configs/version2/nginx-plus.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,17 @@ match {{ $m.Name }} {
{{ end }}

server {

{{ if $.InternalRouteServer }}
listen 443 ssl;
{{if not $s.DisableIPV6}}listen [::]:443 ssl;{{end}}
ssl_certificate /etc/nginx/secrets/spiffe_cert.pem;
ssl_certificate_key /etc/nginx/secrets/spiffe_key.pem;
chase-kiefer marked this conversation as resolved.
Show resolved Hide resolved

{{ else }}
listen 80{{ if $s.ProxyProtocol }} proxy_protocol{{ end }};
{{ if not $s.DisableIPV6 }}listen [::]:80{{ if $s.ProxyProtocol }} proxy_protocol{{ end }};{{ end }}
{{ end }}

server_name {{ $s.ServerName }};
status_zone {{ $s.StatusZone }};
Expand Down
10 changes: 9 additions & 1 deletion internal/configs/version2/nginx.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,17 @@ limit_req_zone {{ $z.Key }} zone={{ $z.ZoneName }}:{{ $z.ZoneSize }} rate={{ $z.

{{ $s := .Server }}
server {

{{ if $.InternalRouteServer }}
listen 443 ssl;
{{if not $s.DisableIPV6}}listen [::]:443 ssl;{{end}}
ssl_certificate /etc/nginx/secrets/spiffe_cert.pem;
ssl_certificate_key /etc/nginx/secrets/spiffe_key.pem;

{{ else }}
listen 80{{ if $s.ProxyProtocol }} proxy_protocol{{ end }};
{{ if not $s.DisableIPV6 }}listen [::]:80{{ if $s.ProxyProtocol }} proxy_protocol{{ end }};{{ end }}
{{ end }}

server_name {{ $s.ServerName }};

Expand Down Expand Up @@ -310,7 +319,6 @@ server {
{{ if $l.ProxyBufferSize }}
{{ $proxyOrGRPC }}_buffer_size {{ $l.ProxyBufferSize }};
{{ end }}

{{ if not $l.GRPCPass }}
proxy_http_version 1.1;
set $default_connection_header {{ if $l.HasKeepalive }}""{{ else }}close{{ end }};
Expand Down
15 changes: 11 additions & 4 deletions internal/configs/virtualserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,7 @@ type virtualServerConfigurator struct {
enableSnippets bool
warnings Warnings
spiffeCerts bool
enableInternalRoutes bool
oidcPolCfg *oidcPolicyCfg
isIPV6Disabled bool
}
Expand Down Expand Up @@ -273,6 +274,7 @@ func newVirtualServerConfigurator(
enableSnippets: staticParams.EnableSnippets,
warnings: make(map[runtime.Object][]string),
spiffeCerts: staticParams.NginxServiceMesh,
enableInternalRoutes: staticParams.EnableInternalRoutes,
oidcPolCfg: &oidcPolicyCfg{},
isIPV6Disabled: staticParams.DisableIPV6,
}
Expand Down Expand Up @@ -356,7 +358,7 @@ func (vsc *virtualServerConfigurator) GenerateVirtualServerConfig(
ups := vsc.generateUpstream(vsEx.VirtualServer, upstreamName, u, isExternalNameSvc, endpoints)
upstreams = append(upstreams, ups)

u.TLS.Enable = isTLSEnabled(u, vsc.spiffeCerts)
u.TLS.Enable = isTLSEnabled(u, vsc.spiffeCerts, vsEx.VirtualServer.Spec.InternalRoute)
crUpstreams[upstreamName] = u

if hc := generateHealthCheck(u, upstreamName, vsc.cfgParams); hc != nil {
Expand Down Expand Up @@ -385,7 +387,7 @@ func (vsc *virtualServerConfigurator) GenerateVirtualServerConfig(
_, isExternalNameSvc := vsEx.ExternalNameSvcs[GenerateExternalNameSvcKey(upstreamNamespace, u.Service)]
ups := vsc.generateUpstream(vsr, upstreamName, u, isExternalNameSvc, endpoints)
upstreams = append(upstreams, ups)
u.TLS.Enable = isTLSEnabled(u, vsc.spiffeCerts)
u.TLS.Enable = isTLSEnabled(u, vsc.spiffeCerts, vsEx.VirtualServer.Spec.InternalRoute)
crUpstreams[upstreamName] = u

if hc := generateHealthCheck(u, upstreamName, vsc.cfgParams); hc != nil {
Expand Down Expand Up @@ -677,7 +679,8 @@ func (vsc *virtualServerConfigurator) GenerateVirtualServerConfig(
VSName: vsEx.VirtualServer.Name,
DisableIPV6: vsc.isIPV6Disabled,
},
SpiffeCerts: vsc.spiffeCerts,
SpiffeCerts: vsc.spiffeCerts,
InternalRouteServer: vsEx.VirtualServer.Spec.InternalRoute,
}

return vsCfg, vsc.warnings
Expand Down Expand Up @@ -2452,7 +2455,11 @@ func generateProxySSLName(svcName, ns string) string {
return fmt.Sprintf("%s.%s.svc", svcName, ns)
}

func isTLSEnabled(u conf_v1.Upstream, spiffeCerts bool) bool {
func isTLSEnabled(u conf_v1.Upstream, spiffeCerts, spiffeEgress bool) bool {
lucacome marked this conversation as resolved.
Show resolved Hide resolved
if spiffeEgress {
return false
}

return u.TLS.Enable || spiffeCerts
}

Expand Down
126 changes: 125 additions & 1 deletion internal/configs/virtualserver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,119 @@ func TestGenerateVirtualServerConfigWithSpiffeCerts(t *testing.T) {
}
}

func TestGenerateVirtualServerConfigWithInternalRoutes(t *testing.T) {
t.Parallel()
virtualServerEx := VirtualServerEx{
VirtualServer: &conf_v1.VirtualServer{
ObjectMeta: meta_v1.ObjectMeta{
Name: "cafe",
Namespace: "default",
},
Spec: conf_v1.VirtualServerSpec{
Host: "cafe.example.com",
Upstreams: []conf_v1.Upstream{
{
Name: "tea",
Service: "tea-svc",
Port: 80,
TLS: conf_v1.UpstreamTLS{Enable: false},
},
},
Routes: []conf_v1.Route{
{
Path: "/",
Action: &conf_v1.Action{
Pass: "tea",
},
},
},
InternalRoute: true,
},
},
Endpoints: map[string][]string{
"default/tea-svc:80": {
"10.0.0.20:80",
},
},
}

baseCfgParams := ConfigParams{
ServerTokens: "off",
Keepalive: 16,
ServerSnippets: []string{"# server snippet"},
ProxyProtocol: true,
SetRealIPFrom: []string{"0.0.0.0/0"},
RealIPHeader: "X-Real-IP",
RealIPRecursive: true,
}

expected := version2.VirtualServerConfig{
Upstreams: []version2.Upstream{
{
UpstreamLabels: version2.UpstreamLabels{
Service: "tea-svc",
ResourceType: "virtualserver",
ResourceName: "cafe",
ResourceNamespace: "default",
},
Name: "vs_default_cafe_tea",
Servers: []version2.UpstreamServer{
{
Address: "10.0.0.20:80",
},
},
Keepalive: 16,
},
},
HTTPSnippets: []string{},
LimitReqZones: []version2.LimitReqZone{},
Server: version2.Server{
ServerName: "cafe.example.com",
StatusZone: "cafe.example.com",
VSNamespace: "default",
VSName: "cafe",
ProxyProtocol: true,
ServerTokens: "off",
SetRealIPFrom: []string{"0.0.0.0/0"},
RealIPHeader: "X-Real-IP",
RealIPRecursive: true,
Snippets: []string{"# server snippet"},
TLSPassthrough: true,
Locations: []version2.Location{
{
Path: "/",
ProxyPass: "http://vs_default_cafe_tea",
ProxyNextUpstream: "error timeout",
ProxyNextUpstreamTimeout: "0s",
ProxyNextUpstreamTries: 0,
HasKeepalive: true,
ProxySSLName: "tea-svc.default.svc",
ProxyPassRequestHeaders: true,
ProxySetHeaders: []version2.Header{{Name: "Host", Value: "$host"}},
ServiceName: "tea-svc",
},
},
},
SpiffeCerts: true,
InternalRouteServer: true,
}

isPlus := false
isResolverConfigured := false
staticConfigParams := &StaticConfigParams{TLSPassthrough: true, NginxServiceMesh: true, EnableInternalRoutes: true}
isWildcardEnabled := false
vsc := newVirtualServerConfigurator(&baseCfgParams, isPlus, isResolverConfigured, staticConfigParams, isWildcardEnabled)

result, warnings := vsc.GenerateVirtualServerConfig(&virtualServerEx, nil, nil)
if diff := cmp.Diff(expected, result); diff != "" {
t.Errorf("GenerateVirtualServerConfig() mismatch (-want +got):\n%s", diff)
}

if len(warnings) != 0 {
t.Errorf("GenerateVirtualServerConfig returned warnings: %v", vsc.warnings)
}
}

func TestGenerateVirtualServerConfigForVirtualServerWithSplits(t *testing.T) {
t.Parallel()
virtualServerEx := VirtualServerEx{
Expand Down Expand Up @@ -8110,6 +8223,7 @@ func TestIsTLSEnabled(t *testing.T) {
tests := []struct {
upstream conf_v1.Upstream
spiffeCert bool
nsmEgress bool
expected bool
}{
{
Expand Down Expand Up @@ -8148,10 +8262,20 @@ func TestIsTLSEnabled(t *testing.T) {
spiffeCert: false,
expected: true,
},
{
upstream: conf_v1.Upstream{
TLS: conf_v1.UpstreamTLS{
Enable: true,
},
},
nsmEgress: true,
spiffeCert: false,
expected: false,
},
}
ciarams87 marked this conversation as resolved.
Show resolved Hide resolved

for _, test := range tests {
result := isTLSEnabled(test.upstream, test.spiffeCert)
result := isTLSEnabled(test.upstream, test.spiffeCert, test.nsmEgress)
if result != test.expected {
t.Errorf("isTLSEnabled(%v, %v) returned %v but expected %v", test.upstream, test.spiffeCert, result, test.expected)
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/apis/configuration/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ type VirtualServerSpec struct {
ServerSnippets string `json:"server-snippets"`
Dos string `json:"dos"`
ExternalDNS ExternalDNS `json:"externalDNS"`
// InternalRoute allows for the configuration of internal routing.
InternalRoute bool `json:"internalRoute"`
}

// ExternalDNS defines externaldns sub-resource of a virtual server.
Expand Down