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 additional mgmt config parameters #6921

Merged
merged 14 commits into from
Dec 6, 2024
Merged
1 change: 1 addition & 0 deletions build/scripts/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ if [ -z "${BUILD_OS##*plus*}" ]; then
cp -a /code/internal/configs/oidc/* /etc/nginx/oidc/
mkdir -p /etc/nginx/state_files/
mkdir -p /etc/nginx/reporting/
mkdir -p /etc/nginx/secrets/mgmt/
PLUS=-plus
fi

Expand Down
9 changes: 6 additions & 3 deletions charts/nginx-ingress/templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,8 @@ Expand the name of the configmap used for NGINX Agent.
Expand the name of the mgmt configmap.
*/}}
{{- define "nginx-ingress.mgmtConfigName" -}}
{{- if .Values.controller.mgmt.customConfigMap -}}
{{ .Values.controller.mgmt.customConfigMap }}
{{- if .Values.controller.mgmt.configMapName -}}
{{ .Values.controller.mgmt.configMapName }}
{{- else -}}
{{- default (printf "%s-mgmt" (include "nginx-ingress.fullname" .)) -}}
{{- end -}}
Expand All @@ -127,7 +127,11 @@ Expand the name of the mgmt configmap.
Expand license token secret name.
*/}}
{{- define "nginx-ingress.licenseTokenSecretName" -}}
{{- if hasKey .Values.controller.mgmt "licenseTokenSecretName" -}}
{{- .Values.controller.mgmt.licenseTokenSecretName -}}
{{- else }}
{{- fail "Error: When using Nginx Plus, 'controller.mgmt.licenseTokenSecretName' must be set." }}
{{- end -}}
{{- end -}}

{{/*
Expand Down Expand Up @@ -393,7 +397,6 @@ volumeMounts:
{{ include "nginx-ingress.volumeMountEntries" . }}
{{- end -}}
{{- end -}}

{{- define "nginx-ingress.volumeMountEntries" -}}
{{- if eq (include "nginx-ingress.readOnlyRootFilesystem" .) "true" }}
- mountPath: /etc/nginx
Expand Down
32 changes: 30 additions & 2 deletions charts/nginx-ingress/templates/controller-configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ data:
{{ include "nginx-ingress.agentConfiguration" . | indent 4 }}
{{- end }}
---
{{- if and .Values.controller.nginxplus (eq (.Values.controller.mgmt.customConfigMap | default "") "") }}
{{- if .Values.controller.nginxplus }}
apiVersion: v1
kind: ConfigMap
metadata:
Expand All @@ -44,8 +44,36 @@ metadata:
{{ toYaml .Values.controller.config.annotations | indent 4 }}
{{- end }}
data:
license-token-secret-name: {{ include "nginx-ingress.licenseTokenSecretName" . }}
license-token-secret-name: {{ required "When using Nginx Plus, 'controller.mgmt.licenseTokenSecretName' cannot be empty " (include "nginx-ingress.licenseTokenSecretName" . ) }}
{{- if hasKey .Values.controller.mgmt "sslVerify" }}
ssl-verify: {{ quote .Values.controller.mgmt.sslVerify }}
{{- end }}
{{- if hasKey .Values.controller.mgmt "enforceInitialReport" }}
enforce-initial-report: {{ quote .Values.controller.mgmt.enforceInitialReport }}
{{- end }}
{{- if hasKey .Values.controller.mgmt "usageReport" }}
{{- if hasKey .Values.controller.mgmt.usageReport "endpoint" }}
usage-report-endpoint: {{ quote .Values.controller.mgmt.usageReport.endpoint }}
{{- end }}
{{- if hasKey .Values.controller.mgmt.usageReport "interval" }}
usage-report-interval: {{ quote .Values.controller.mgmt.usageReport.interval }}
{{- end }}
{{- end }}
{{- if hasKey .Values.controller.mgmt "sslTrustedCertificateSecretName" }}
ssl-trusted-certificate-secret-name: {{ quote .Values.controller.mgmt.sslTrustedCertificateSecretName }}
{{- end }}
{{- if hasKey .Values.controller.mgmt "sslCertificateSecretName" }}
ssl-certificate-secret-name: {{ quote .Values.controller.mgmt.sslCertificateSecretName}}
{{- end }}
{{- if hasKey .Values.controller.mgmt "resolver" }}
{{- if hasKey .Values.controller.mgmt.resolver "addresses" }}
resolver-addresses: {{ join "," .Values.controller.mgmt.resolver.addresses | quote }}
{{- end }}
{{- if hasKey .Values.controller.mgmt.resolver "ipv6" }}
resolver-ipv6: {{ quote .Values.controller.mgmt.resolver.ipv6 }}
{{- end }}
{{- if hasKey .Values.controller.mgmt.resolver "valid" }}
resolver-valid: {{ quote .Values.controller.mgmt.resolver.valid }}
{{- end }}
{{- end }}
{{- end }}
88 changes: 88 additions & 0 deletions charts/nginx-ingress/values.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,42 @@
"license"
]
},
"sslCertificateSecretName": {
"type": "string",
"default": "",
"title": "The sslCertificateSecretName Schema",
"examples": [
"ssl-certificate"
]
},
"usageReport": {
"type": "object",
"default": {},
"title": "The usageReport Schema",
"properties": {
"endpoint": {
"type": "string",
"title": "The endpoint of the usageReport",
"default": "",
"examples": [
"",
"product.connect.nginx.com",
"nginx-mgmt.local"
]
},
"interval": {
"type": "string",
"pattern": "^[0-9]+[mhd]$",
"default": "1h",
"title": "The usage report interval Schema",
"examples": [
"1m",
"1h",
"24h"
]
}
}
},
"enforceInitialReport": {
"type": "boolean",
"default": false,
Expand All @@ -117,6 +153,58 @@
true,
false
]
},
"sslVerify": {
"type": "boolean",
"default": true,
"title": "The sslVerify Schema",
"examples": [
true,
false
]
},
"resolver": {
"type": "object",
"default": {},
"title": "The resolver Schema",
"properties": {
"addresses": {
"type": "array",
"default": [],
"title": "List of resolver addresses/fqdns"
},
"valid": {
"type": "string",
"pattern": "^[0-9]+[smhdwMy]$",
"title": "A valid nginx time",
"examples": [
"1m",
"5d"
]
},
"ipv6": {
"type": "boolean",
"title": "turn on or off ipv6 support",
"default": false
}
}
},
"sslTrustedCertificateSecretName": {
"type": "string",
"default": "ssl-trusted-cert",
"title": "The sslTrustedCertificateSecretName Schema",
"examples": [
"ssl-trusted-cert",
"certificate-secret"
]
},
"configMapName": {
"type": "string",
"default": "",
"title": "The configMap Schema",
"examples": [
""
]
}
},
"examples": [
Expand Down
25 changes: 25 additions & 0 deletions charts/nginx-ingress/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,31 @@ controller:
## Enables the 180-day grace period for sending the initial usage report
# enforceInitialReport: false

# usageReport:
# endpoint: "product.connect.nginx.com" # Endpoint for usage report
# interval: 1h

## Configures the ssl_verify directive in the mgmt block
# sslVerify: true

## Configures the resolver directive in the mgmt block
# resolver:
# ipv6: true
# valid: 1s
# addresses:
# - kube-dns.kube-system.svc.cluster.local

## Secret containing TLS client certificate
# sslCertificateSecretName: ssl-certificate # kubernetes.io/tls secret type

## Secret containing trusted CA certificate
# sslTrustedCertificateSecretName: ssl-trusted-cert

# configMapName allows changing the name of the MGMT config map
# the name should not include a namespace
# configMapName: ""


## Timeout in milliseconds which the Ingress Controller will wait for a successful NGINX reload after a change or at the initial start.
nginxReloadTimeout: 60000

Expand Down
60 changes: 56 additions & 4 deletions cmd/nginx-ingress/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ func main() {
if err := processLicenseSecret(kubeClient, nginxManager, mgmtCfgParams, controllerNamespace); err != nil {
logEventAndExit(ctx, eventRecorder, pod, secretErrorReason, err)
}

if err := processTrustedCertSecret(kubeClient, nginxManager, mgmtCfgParams, controllerNamespace); err != nil {
logEventAndExit(ctx, eventRecorder, pod, secretErrorReason, err)
}

if err := processClientAuthSecret(kubeClient, nginxManager, mgmtCfgParams, controllerNamespace); err != nil {
logEventAndExit(ctx, eventRecorder, pod, secretErrorReason, err)
}

}

templateExecutor, templateExecutorV2 := createTemplateExecutors(ctx)
Expand Down Expand Up @@ -204,7 +213,7 @@ func main() {
AppProtectBundlePath: appProtectBundlePath,
}

mustProcessNginxConfig(staticCfgParams, cfgParams, mgmtCfgParams, templateExecutor, nginxManager)
mustWriteNginxMainConfig(staticCfgParams, cfgParams, mgmtCfgParams, templateExecutor, nginxManager)

if *enableTLSPassthrough {
var emptyFile []byte
Expand Down Expand Up @@ -323,6 +332,44 @@ func main() {
}
}

func processClientAuthSecret(kubeClient *kubernetes.Clientset, nginxManager nginx.Manager, mgmtCfgParams *configs.MGMTConfigParams, controllerNamespace string) error {
if mgmtCfgParams.Secrets.ClientAuth == "" {
return nil
}

clientAuthSecretNsName := controllerNamespace + "/" + mgmtCfgParams.Secrets.ClientAuth

secret, err := getAndValidateSecret(kubeClient, clientAuthSecretNsName, api_v1.SecretTypeTLS)
if err != nil {
return fmt.Errorf("error trying to get the client auth secret %v: %w", clientAuthSecretNsName, err)
}

bytes := configs.GenerateCertAndKeyFileContent(secret)
nginxManager.CreateSecret(fmt.Sprintf("mgmt/%s", configs.ClientAuthCertSecretFileName), bytes, nginx.ReadWriteOnlyFileMode)
return nil
}

func processTrustedCertSecret(kubeClient *kubernetes.Clientset, nginxManager nginx.Manager, mgmtCfgParams *configs.MGMTConfigParams, controllerNamespace string) error {
if mgmtCfgParams.Secrets.TrustedCert == "" {
return nil
}

trustedCertSecretNsName := controllerNamespace + "/" + mgmtCfgParams.Secrets.TrustedCert

secret, err := getAndValidateSecret(kubeClient, trustedCertSecretNsName, secrets.SecretTypeCA)
if err != nil {
return fmt.Errorf("error trying to get the trusted cert secret %v: %w", trustedCertSecretNsName, err)
}

caBytes, crlBytes := configs.GenerateCAFileContent(secret)
nginxManager.CreateSecret(fmt.Sprintf("mgmt/%s", configs.CACrtKey), caBytes, nginx.ReadWriteOnlyFileMode)
if _, hasCRL := secret.Data[configs.CACrlKey]; hasCRL {
mgmtCfgParams.Secrets.TrustedCRL = secret.Name
nginxManager.CreateSecret(fmt.Sprintf("mgmt/%s", configs.CACrlKey), crlBytes, nginx.ReadWriteOnlyFileMode)
}
return nil
}

func mustCreateConfigAndKubeClient(ctx context.Context) (*rest.Config, *kubernetes.Clientset) {
l := nl.LoggerFromContext(ctx)
var config *rest.Config
Expand Down Expand Up @@ -666,9 +713,9 @@ func createGlobalConfigurationValidator() *cr_validation.GlobalConfigurationVali
return cr_validation.NewGlobalConfigurationValidator(forbiddenListenerPorts)
}

// mustProcessNginxConfig calls internally os.Exit
// mustWriteNginxMainConfig calls internally os.Exit
// if can't generate a valid NGINX config.
func mustProcessNginxConfig(staticCfgParams *configs.StaticConfigParams, cfgParams *configs.ConfigParams, mgmtCfgParams *configs.MGMTConfigParams, templateExecutor *version1.TemplateExecutor, nginxManager nginx.Manager) {
func mustWriteNginxMainConfig(staticCfgParams *configs.StaticConfigParams, cfgParams *configs.ConfigParams, mgmtCfgParams *configs.MGMTConfigParams, templateExecutor *version1.TemplateExecutor, nginxManager nginx.Manager) {
l := nl.LoggerFromContext(cfgParams.Context)
ngxConfig := configs.GenerateNginxMainConfig(staticCfgParams, cfgParams, mgmtCfgParams)
content, err := templateExecutor.ExecuteMainConfigTemplate(ngxConfig)
Expand Down Expand Up @@ -701,7 +748,6 @@ func getSocketClient(sockPath string) *http.Client {
}

// getAndValidateSecret gets and validates a secret.
// nolint:unparam
func getAndValidateSecret(kubeClient *kubernetes.Clientset, secretNsName string, secretType api_v1.SecretType) (secret *api_v1.Secret, err error) {
ns, name, err := k8s.ParseNamespaceName(secretNsName)
if err != nil {
Expand All @@ -722,7 +768,13 @@ func getAndValidateSecret(kubeClient *kubernetes.Clientset, secretNsName string,
if err != nil {
return nil, err
}
case secrets.SecretTypeCA:
err = secrets.ValidateCASecret(secret)
if err != nil {
return nil, err
}
}

return secret, nil
}

Expand Down
3 changes: 3 additions & 0 deletions examples/shared-examples/nginx-plus-secret/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# NGINX Plus Secret

Refer to the [Create License Secret](https://docs.nginx.com/nginx-ingress-controller/installation/installing-nic/create-license-secret/) docs to download and create a License Secret
7 changes: 7 additions & 0 deletions examples/shared-examples/nginx-plus-secret/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config-mgmt
namespace: nginx-ingress
data:
license-token-secret-name: "license-token"
12 changes: 11 additions & 1 deletion internal/configs/config_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,22 @@ type Listener struct {

// MGMTSecrets holds mgmt block secret names
type MGMTSecrets struct {
License string
License string
ClientAuth string
TrustedCert string
TrustedCRL string
}

// MGMTConfigParams holds mgmt block parameters.
type MGMTConfigParams struct {
Context context.Context
SSLVerify *bool
ResolverAddresses []string
ResolverIPV6 *bool
ResolverValid string
EnforceInitialReport *bool
Endpoint string
Interval string
Secrets MGMTSecrets
}

Expand Down Expand Up @@ -236,6 +245,7 @@ func NewDefaultConfigParams(ctx context.Context, isPlus bool) *ConfigParams {
func NewDefaultMGMTConfigParams(ctx context.Context) *MGMTConfigParams {
return &MGMTConfigParams{
Context: ctx,
SSLVerify: nil,
EnforceInitialReport: nil,
Secrets: MGMTSecrets{},
}
Expand Down
Loading
Loading