Skip to content

Commit 96cec7e

Browse files
committed
Allow configuration of NGINX Plus API access
Add back removed comments Adjust comment
1 parent 7a08f11 commit 96cec7e

File tree

16 files changed

+595
-56
lines changed

16 files changed

+595
-56
lines changed

apis/v1alpha1/nginxproxy_types.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,23 @@ type NginxProxySpec struct {
4949
//
5050
// +optional
5151
Logging *NginxLogging `json:"logging,omitempty"`
52+
// NginxPlus specifies NGINX Plus additional settings.
53+
//
54+
// +optional
55+
NginxPlus *NginxPlus `json:"nginxPlus,omitempty"`
5256
// DisableHTTP2 defines if http2 should be disabled for all servers.
5357
// Default is false, meaning http2 will be enabled for all servers.
58+
DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
59+
}
60+
61+
// NginxPlus specifies NGINX Plus additional settings. These will only be applied if NGINX Plus is being used.
62+
type NginxPlus struct {
63+
// AllowedAddresses specifies IPAddresses or CIDR blocks to the allow list for accessing the NGINX Plus API.
5464
//
65+
//nolint:lll
5566
// +optional
56-
DisableHTTP2 bool `json:"disableHTTP2,omitempty"`
67+
// +kubebuilder:validation:items:XValidation:message="Address Type must be either CIDR or IPAddress",rule="(self.type=='CIDR' || self.type=='IPAddress')"
68+
AllowedAddresses []Address `json:"allowedAddresses,omitempty"`
5769
}
5870

5971
// Telemetry specifies the OpenTelemetry configuration.

apis/v1alpha1/zz_generated.deepcopy.go

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/gateway.nginx.org_nginxproxies.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,35 @@ spec:
8383
- emerg
8484
type: string
8585
type: object
86+
nginxPlus:
87+
description: NginxPlus specifies NGINX Plus additional settings.
88+
properties:
89+
allowedAddresses:
90+
description: AllowedAddresses specifies IPAddresses or CIDR blocks
91+
to the allow list for accessing the NGINX Plus API.
92+
items:
93+
description: Address is a struct that specifies address type
94+
and value.
95+
properties:
96+
type:
97+
description: Type specifies the type of address.
98+
enum:
99+
- CIDR
100+
- IPAddress
101+
- Hostname
102+
type: string
103+
value:
104+
description: Value specifies the address value.
105+
type: string
106+
required:
107+
- type
108+
- value
109+
type: object
110+
x-kubernetes-validations:
111+
- message: Address Type must be either CIDR or IPAddress
112+
rule: (self.type=='CIDR' || self.type=='IPAddress')
113+
type: array
114+
type: object
86115
rewriteClientIP:
87116
description: RewriteClientIP defines configuration for rewriting the
88117
client IP to the original client's IP.

deploy/crds.yaml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -668,6 +668,35 @@ spec:
668668
- emerg
669669
type: string
670670
type: object
671+
nginxPlus:
672+
description: NginxPlus specifies NGINX Plus additional settings.
673+
properties:
674+
allowedAddresses:
675+
description: AllowedAddresses specifies IPAddresses or CIDR blocks
676+
to the allow list for accessing the NGINX Plus API.
677+
items:
678+
description: Address is a struct that specifies address type
679+
and value.
680+
properties:
681+
type:
682+
description: Type specifies the type of address.
683+
enum:
684+
- CIDR
685+
- IPAddress
686+
- Hostname
687+
type: string
688+
value:
689+
description: Value specifies the address value.
690+
type: string
691+
required:
692+
- type
693+
- value
694+
type: object
695+
x-kubernetes-validations:
696+
- message: Address Type must be either CIDR or IPAddress
697+
rule: (self.type=='CIDR' || self.type=='IPAddress')
698+
type: array
699+
type: object
671700
rewriteClientIP:
672701
description: RewriteClientIP defines configuration for rewriting the
673702
client IP to the original client's IP.

internal/mode/static/nginx/conf/nginx-plus.conf

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -27,30 +27,6 @@ http {
2727
tcp_nopush on;
2828

2929
server_tokens off;
30-
31-
server {
32-
listen 127.0.0.1:8765;
33-
root /usr/share/nginx/html;
34-
access_log off;
35-
36-
allow 127.0.0.1;
37-
deny all;
38-
39-
location = /dashboard.html {}
40-
41-
location /api {
42-
api write=off;
43-
}
44-
}
45-
46-
server {
47-
listen unix:/var/run/nginx/nginx-plus-api.sock;
48-
access_log off;
49-
50-
location /api {
51-
api write=on;
52-
}
53-
}
5430
}
5531

5632
stream {

internal/mode/static/nginx/config/generator.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ const (
5858

5959
// mgmtIncludesFile is the path to the file containing the NGINX Plus mgmt config.
6060
mgmtIncludesFile = mainIncludesFolder + "/mgmt.conf"
61+
62+
// nginxPlusConfigFile is the path to the file containing the NGINX Plus API config.
63+
nginxPlusConfigFile = httpFolder + "/plus-api.conf"
6164
)
6265

6366
// ConfigFolders is a list of folders where NGINX configuration files are stored.
@@ -199,6 +202,7 @@ func (g GeneratorImpl) getExecuteFuncs(
199202
g.executeStreamUpstreams,
200203
executeStreamMaps,
201204
executeVersion,
205+
executePlusAPI,
202206
}
203207
}
204208

internal/mode/static/nginx/config/generator_test.go

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ func TestGenerate(t *testing.T) {
132132
graph.PlusReportClientSSLCertificate: []byte("cert"),
133133
graph.PlusReportClientSSLKey: []byte("key"),
134134
},
135+
NginxPlus: dataplane.NginxPlus{AllowedAddresses: []string{"127.0.0.3", "25.0.0.3"}},
135136
}
136137
g := NewWithT(t)
137138

@@ -144,7 +145,7 @@ func TestGenerate(t *testing.T) {
144145

145146
files := generator.Generate(conf)
146147

147-
g.Expect(files).To(HaveLen(17))
148+
g.Expect(files).To(HaveLen(18))
148149
arrange := func(i, j int) bool {
149150
return files[i].Path < files[j].Path
150151
}
@@ -155,6 +156,7 @@ func TestGenerate(t *testing.T) {
155156
/etc/nginx/conf.d/config-version.conf
156157
/etc/nginx/conf.d/http.conf
157158
/etc/nginx/conf.d/matches.json
159+
/etc/nginx/conf.d/plus-api.conf
158160
/etc/nginx/includes/http_snippet1.conf
159161
/etc/nginx/includes/http_snippet2.conf
160162
/etc/nginx/includes/main_snippet1.conf
@@ -196,65 +198,76 @@ func TestGenerate(t *testing.T) {
196198
g.Expect(httpCfg).To(ContainSubstring("include /etc/nginx/includes/http_snippet2.conf;"))
197199

198200
g.Expect(files[2].Path).To(Equal("/etc/nginx/conf.d/matches.json"))
199-
200201
g.Expect(files[2].Type).To(Equal(file.TypeRegular))
201202
expString := "{}"
202203
g.Expect(string(files[2].Content)).To(Equal(expString))
203204

205+
g.Expect(files[3].Path).To(Equal("/etc/nginx/conf.d/plus-api.conf"))
206+
g.Expect(files[3].Type).To(Equal(file.TypeRegular))
207+
httpCfg = string(files[3].Content)
208+
g.Expect(httpCfg).To(ContainSubstring("listen unix:/var/run/nginx/nginx-plus-api.sock;"))
209+
g.Expect(httpCfg).To(ContainSubstring("access_log off;"))
210+
g.Expect(httpCfg).To(ContainSubstring("listen 8765;"))
211+
g.Expect(httpCfg).To(ContainSubstring("root /usr/share/nginx/html;"))
212+
g.Expect(httpCfg).To(ContainSubstring("allow 127.0.0.3;"))
213+
g.Expect(httpCfg).To(ContainSubstring("allow 25.0.0.3;"))
214+
g.Expect(httpCfg).To(ContainSubstring("deny all;"))
215+
g.Expect(httpCfg).To(ContainSubstring("location = /dashboard.html {}"))
216+
204217
// snippet include files
205218
// content is not checked in this test.
206-
g.Expect(files[3].Path).To(Equal("/etc/nginx/includes/http_snippet1.conf"))
207-
g.Expect(files[4].Path).To(Equal("/etc/nginx/includes/http_snippet2.conf"))
208-
g.Expect(files[5].Path).To(Equal("/etc/nginx/includes/main_snippet1.conf"))
209-
g.Expect(files[6].Path).To(Equal("/etc/nginx/includes/main_snippet2.conf"))
219+
g.Expect(files[4].Path).To(Equal("/etc/nginx/includes/http_snippet1.conf"))
220+
g.Expect(files[5].Path).To(Equal("/etc/nginx/includes/http_snippet2.conf"))
221+
g.Expect(files[6].Path).To(Equal("/etc/nginx/includes/main_snippet1.conf"))
222+
g.Expect(files[7].Path).To(Equal("/etc/nginx/includes/main_snippet2.conf"))
210223

211-
g.Expect(files[7].Path).To(Equal("/etc/nginx/main-includes/deployment_ctx.json"))
212-
deploymentCtx := string(files[7].Content)
224+
g.Expect(files[8].Path).To(Equal("/etc/nginx/main-includes/deployment_ctx.json"))
225+
deploymentCtx := string(files[8].Content)
213226
g.Expect(deploymentCtx).To(ContainSubstring("\"integration\":\"ngf\""))
214227
g.Expect(deploymentCtx).To(ContainSubstring("\"cluster_id\":\"test-uid\""))
215228
g.Expect(deploymentCtx).To(ContainSubstring("\"installation_id\":\"test-uid-replicaSet\""))
216229
g.Expect(deploymentCtx).To(ContainSubstring("\"cluster_node_count\":1"))
217230

218-
g.Expect(files[8].Path).To(Equal("/etc/nginx/main-includes/main.conf"))
219-
mainConfStr := string(files[8].Content)
231+
g.Expect(files[9].Path).To(Equal("/etc/nginx/main-includes/main.conf"))
232+
mainConfStr := string(files[9].Content)
220233
g.Expect(mainConfStr).To(ContainSubstring("load_module modules/ngx_otel_module.so;"))
221234
g.Expect(mainConfStr).To(ContainSubstring("include /etc/nginx/includes/main_snippet1.conf;"))
222235
g.Expect(mainConfStr).To(ContainSubstring("include /etc/nginx/includes/main_snippet2.conf;"))
223236

224-
g.Expect(files[9].Path).To(Equal("/etc/nginx/main-includes/mgmt.conf"))
225-
mgmtConf := string(files[9].Content)
237+
g.Expect(files[10].Path).To(Equal("/etc/nginx/main-includes/mgmt.conf"))
238+
mgmtConf := string(files[10].Content)
226239
g.Expect(mgmtConf).To(ContainSubstring("usage_report endpoint=test-endpoint"))
227240
g.Expect(mgmtConf).To(ContainSubstring("license_token /etc/nginx/secrets/license.jwt"))
228241
g.Expect(mgmtConf).To(ContainSubstring("deployment_context /etc/nginx/main-includes/deployment_ctx.json"))
229242
g.Expect(mgmtConf).To(ContainSubstring("ssl_trusted_certificate /etc/nginx/secrets/mgmt-ca.crt"))
230243
g.Expect(mgmtConf).To(ContainSubstring("ssl_certificate /etc/nginx/secrets/mgmt-tls.crt"))
231244
g.Expect(mgmtConf).To(ContainSubstring("ssl_certificate_key /etc/nginx/secrets/mgmt-tls.key"))
232245

233-
g.Expect(files[10].Path).To(Equal("/etc/nginx/secrets/license.jwt"))
234-
g.Expect(string(files[10].Content)).To(Equal("license"))
246+
g.Expect(files[11].Path).To(Equal("/etc/nginx/secrets/license.jwt"))
247+
g.Expect(string(files[11].Content)).To(Equal("license"))
235248

236-
g.Expect(files[11].Path).To(Equal("/etc/nginx/secrets/mgmt-ca.crt"))
237-
g.Expect(string(files[11].Content)).To(Equal("ca"))
249+
g.Expect(files[12].Path).To(Equal("/etc/nginx/secrets/mgmt-ca.crt"))
250+
g.Expect(string(files[12].Content)).To(Equal("ca"))
238251

239-
g.Expect(files[12].Path).To(Equal("/etc/nginx/secrets/mgmt-tls.crt"))
240-
g.Expect(string(files[12].Content)).To(Equal("cert"))
252+
g.Expect(files[13].Path).To(Equal("/etc/nginx/secrets/mgmt-tls.crt"))
253+
g.Expect(string(files[13].Content)).To(Equal("cert"))
241254

242-
g.Expect(files[13].Path).To(Equal("/etc/nginx/secrets/mgmt-tls.key"))
243-
g.Expect(string(files[13].Content)).To(Equal("key"))
255+
g.Expect(files[14].Path).To(Equal("/etc/nginx/secrets/mgmt-tls.key"))
256+
g.Expect(string(files[14].Content)).To(Equal("key"))
244257

245-
g.Expect(files[14].Path).To(Equal("/etc/nginx/secrets/test-certbundle.crt"))
246-
certBundle := string(files[14].Content)
258+
g.Expect(files[15].Path).To(Equal("/etc/nginx/secrets/test-certbundle.crt"))
259+
certBundle := string(files[15].Content)
247260
g.Expect(certBundle).To(Equal("test-cert"))
248261

249-
g.Expect(files[15]).To(Equal(file.File{
262+
g.Expect(files[16]).To(Equal(file.File{
250263
Type: file.TypeSecret,
251264
Path: "/etc/nginx/secrets/test-keypair.pem",
252265
Content: []byte("test-cert\ntest-key"),
253266
}))
254267

255-
g.Expect(files[16].Path).To(Equal("/etc/nginx/stream-conf.d/stream.conf"))
256-
g.Expect(files[16].Type).To(Equal(file.TypeRegular))
257-
streamCfg := string(files[16].Content)
268+
g.Expect(files[17].Path).To(Equal("/etc/nginx/stream-conf.d/stream.conf"))
269+
g.Expect(files[17].Type).To(Equal(file.TypeRegular))
270+
streamCfg := string(files[17].Content)
258271
g.Expect(streamCfg).To(ContainSubstring("listen unix:/var/run/nginx/app.example.com-443.sock"))
259272
g.Expect(streamCfg).To(ContainSubstring("listen 443"))
260273
g.Expect(streamCfg).To(ContainSubstring("app.example.com unix:/var/run/nginx/app.example.com-443.sock"))
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package config
2+
3+
import (
4+
gotemplate "text/template"
5+
6+
"github.com/nginx/nginx-gateway-fabric/internal/framework/helpers"
7+
"github.com/nginx/nginx-gateway-fabric/internal/mode/static/state/dataplane"
8+
)
9+
10+
var plusAPITemplate = gotemplate.Must(gotemplate.New("plusAPI").Parse(plusAPITemplateText))
11+
12+
func executePlusAPI(conf dataplane.Configuration) []executeResult {
13+
result := executeResult{
14+
dest: nginxPlusConfigFile,
15+
data: helpers.MustExecuteTemplate(plusAPITemplate, conf.NginxPlus),
16+
}
17+
18+
return []executeResult{result}
19+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package config
2+
3+
const plusAPITemplateText = `
4+
server {
5+
listen unix:/var/run/nginx/nginx-plus-api.sock;
6+
access_log off;
7+
8+
location /api {
9+
api write=on;
10+
}
11+
}
12+
13+
server {
14+
listen 8765;
15+
root /usr/share/nginx/html;
16+
access_log off;
17+
{{ range $address := .AllowedAddresses }}
18+
allow {{ $address }};
19+
{{- end }}
20+
deny all;
21+
22+
location = /dashboard.html {}
23+
24+
location /api {
25+
api write=off;
26+
}
27+
}
28+
`
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package config
2+
3+
import (
4+
"strings"
5+
"testing"
6+
7+
. "github.com/onsi/gomega"
8+
9+
"github.com/nginx/nginx-gateway-fabric/internal/mode/static/state/dataplane"
10+
)
11+
12+
func TestExecutePlusAPI(t *testing.T) {
13+
t.Parallel()
14+
conf := dataplane.Configuration{
15+
NginxPlus: dataplane.NginxPlus{AllowedAddresses: []string{"127.0.0.1", "25.0.0.3"}},
16+
}
17+
18+
g := NewWithT(t)
19+
expSubStrings := map[string]int{
20+
"listen unix:/var/run/nginx/nginx-plus-api.sock;": 1,
21+
"access_log off;": 2,
22+
"api write=on;": 1,
23+
"listen 8765;": 1,
24+
"root /usr/share/nginx/html;": 1,
25+
"allow 127.0.0.1;": 1,
26+
"allow 25.0.0.3;": 1,
27+
"deny all;": 1,
28+
"location = /dashboard.html {}": 1,
29+
"api write=off;": 1,
30+
}
31+
32+
for expSubStr, expCount := range expSubStrings {
33+
res := executePlusAPI(conf)
34+
g.Expect(res).To(HaveLen(1))
35+
g.Expect(expCount).To(Equal(strings.Count(string(res[0].data), expSubStr)))
36+
}
37+
}

0 commit comments

Comments
 (0)