-
-
Notifications
You must be signed in to change notification settings - Fork 18.4k
nixos/nginx: validate config at build time #205561
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -241,7 +241,7 @@ let | |
|
|
||
| configPath = if cfg.enableReload | ||
| then "/etc/nginx/nginx.conf" | ||
| else configFile; | ||
| else finalConfigFile; | ||
|
|
||
| execCommand = "${cfg.package}/bin/nginx -c '${configPath}'"; | ||
|
|
||
|
|
@@ -391,6 +391,38 @@ let | |
| ); | ||
|
|
||
| mkCertOwnershipAssertion = import ../../../security/acme/mk-cert-ownership-assertion.nix; | ||
|
|
||
| snakeOilCert = pkgs.runCommand "nginx-config-validate-cert" { nativeBuildInputs = [ pkgs.openssl.bin ]; } '' | ||
| mkdir $out | ||
| openssl genrsa -des3 -passout pass:xxxxx -out server.pass.key 2048 | ||
| openssl rsa -passin pass:xxxxx -in server.pass.key -out $out/server.key | ||
| openssl req -new -key $out/server.key -out server.csr \ | ||
| -subj "/C=UK/ST=Warwickshire/L=Leamington/O=OrgName/OU=IT Department/CN=example.com" | ||
| openssl x509 -req -days 1 -in server.csr -signkey $out/server.key -out $out/server.crt | ||
| ''; | ||
| validatedConfigFile = pkgs.runCommand "validated-nginx.conf" { nativeBuildInputs = [ cfg.package ]; } '' | ||
| # nginx absolutely wants to read the certificates even when told to only validate config, so let's provide fake certs | ||
| sed ${configFile} \ | ||
| -e "s|ssl_certificate .*;|ssl_certificate ${snakeOilCert}/server.crt;|g" \ | ||
| -e "s|ssl_trusted_certificate .*;|ssl_trusted_certificate ${snakeOilCert}/server.crt;|g" \ | ||
| -e "s|ssl_certificate_key .*;|ssl_certificate_key ${snakeOilCert}/server.key;|g" \ | ||
|
Comment on lines
+406
to
+408
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure how robust the regex is. For using the nix options it is certainly enough. |
||
| > conf | ||
|
|
||
| LD_PRELOAD=${pkgs.libredirect}/lib/libredirect.so \ | ||
| NIX_REDIRECTS="/etc/resolv.conf=/dev/null" \ | ||
| nginx -t -c $(readlink -f ./conf) > out 2>&1 || true | ||
| if ! grep -q "syntax is ok" out; then | ||
| echo nginx config validation failed. | ||
| echo config was ${configFile}. | ||
| echo 'in case of false positive, set `services.nginx.validateConfig` to false.' | ||
| echo nginx output: | ||
| cat out | ||
| exit 1 | ||
| fi | ||
| cp ${configFile} $out | ||
| ''; | ||
|
|
||
| finalConfigFile = if cfg.validateConfig then validatedConfigFile else configFile; | ||
| in | ||
|
|
||
| { | ||
|
|
@@ -489,6 +521,15 @@ in | |
| ''; | ||
| }; | ||
|
|
||
| validateConfig = mkOption { | ||
| default = pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be |
||
| defaultText = literalExpression "pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform"; | ||
| type = types.bool; | ||
| description = lib.mdDoc '' | ||
| Validate the generated nginx config at build time. The check is not very robust and can be disabled in case of false positives. This is notably the case when cross-compiling or when using `include` with files outside of the store. | ||
| ''; | ||
| }; | ||
|
|
||
| additionalModules = mkOption { | ||
| default = []; | ||
| type = types.listOf (types.attrsOf types.anything); | ||
|
|
@@ -1027,7 +1068,7 @@ in | |
| }; | ||
|
|
||
| environment.etc."nginx/nginx.conf" = mkIf cfg.enableReload { | ||
| source = configFile; | ||
| source = finalConfigFile; | ||
| }; | ||
|
|
||
| # This service waits for all certificates to be available | ||
|
|
@@ -1046,7 +1087,7 @@ in | |
| # certs are updated _after_ config has been reloaded. | ||
| before = sslTargets; | ||
| after = sslServices; | ||
| restartTriggers = optionals (cfg.enableReload) [ configFile ]; | ||
| restartTriggers = optionals (cfg.enableReload) [ finalConfigFile ]; | ||
| # Block reloading if not all certs exist yet. | ||
| # Happens when config changes add new vhosts/certs. | ||
| unitConfig.ConditionPathExists = optionals (sslServices != []) (map (certName: certs.${certName}.directory + "/fullchain.pem") dependentCertNames); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we want to use runCommandLocal here. We probably don't want to cache or substitute this, or do we?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this certificate is only used during build, so reusing it or sharing it via a binary cache is not a problem