diff --git a/checks.d/nginx.py b/checks.d/nginx.py index e07d19d2cc..2344f73965 100644 --- a/checks.d/nginx.py +++ b/checks.d/nginx.py @@ -51,6 +51,7 @@ def check(self, instance): def _get_data(self, instance): url = instance.get('nginx_status_url') + ssl_validation = instance.get('ssl_validation', True) auth = None if 'user' in instance and 'password' in instance: @@ -63,7 +64,8 @@ def _get_data(self, instance): service_check_name = 'nginx.can_connect' service_check_tags = ['host:%s' % nginx_host, 'port:%s' % nginx_port] try: - r = requests.get(url, auth=auth, headers=headers(self.agentConfig)) + r = requests.get(url, auth=auth, headers=headers(self.agentConfig), + verify=ssl_validation) r.raise_for_status() except Exception: self.service_check(service_check_name, AgentCheck.CRITICAL, diff --git a/ci/nginx.rb b/ci/nginx.rb index 80d1d90963..f48ff136dd 100644 --- a/ci/nginx.rb +++ b/ci/nginx.rb @@ -24,7 +24,7 @@ def nginx_rootdir sh %(tar zxf $VOLATILE_DIR/nginx-#{nginx_version}.tar.gz\ -C $VOLATILE_DIR/nginx --strip-components=1) sh %(cd $VOLATILE_DIR/nginx\ - && ./configure --prefix=#{nginx_rootdir} --with-http_stub_status_module\ + && ./configure --prefix=#{nginx_rootdir} --with-http_stub_status_module --with-http_ssl_module\ && make -j $CONCURRENCY\ && make install) end @@ -33,6 +33,10 @@ def nginx_rootdir task before_script: ['ci:common:before_script'] do sh %(cp $TRAVIS_BUILD_DIR/ci/resources/nginx/nginx.conf\ #{nginx_rootdir}/conf/nginx.conf) + sh %(cp $TRAVIS_BUILD_DIR/ci/resources/nginx/testing.crt\ + #{nginx_rootdir}/conf/testing.crt) + sh %(cp $TRAVIS_BUILD_DIR/ci/resources/nginx/testing.key\ + #{nginx_rootdir}/conf/testing.key) sh %(#{nginx_rootdir}/sbin/nginx -g "pid #{ENV['VOLATILE_DIR']}/nginx.pid;") end @@ -46,6 +50,8 @@ def nginx_rootdir task before_cache: ['ci:common:before_cache'] do # Conf is regenerated at every run sh %(rm -f #{nginx_rootdir}/conf/nginx.conf) + sh %(rm -f #{nginx_rootdir}/conf/testing.cert) + sh %(rm -f #{nginx_rootdir}/conf/testing.key) end task cache: ['ci:common:cache'] diff --git a/ci/resources/nginx/nginx.conf b/ci/resources/nginx/nginx.conf index 060ca59c6e..7bf755e817 100644 --- a/ci/resources/nginx/nginx.conf +++ b/ci/resources/nginx/nginx.conf @@ -84,6 +84,28 @@ http { #} } + # HTTPS server + server { + listen 44442 ssl; + server_name localhost; + + location /https_nginx_status { + stub_status on; + access_log off; + allow 127.0.0.1; + deny all; + } + + ssl_certificate testing.crt; + ssl_certificate_key testing.key; + + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 5m; + + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + } + # another virtual host using mix of IP-, name-, and port-based configuration # #server { diff --git a/ci/resources/nginx/testing.crt b/ci/resources/nginx/testing.crt new file mode 100644 index 0000000000..63d7de0904 --- /dev/null +++ b/ci/resources/nginx/testing.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDGzCCAgOgAwIBAgIJANPtTQnZmjnPMA0GCSqGSIb3DQEBBQUAMCQxEDAOBgNV +BAoMB1Rlc3RpbmcxEDAOBgNVBAMMB1Rlc3RpbmcwHhcNMTUwNzIzMTg0MzAzWhcN +MTYwNzIyMTg0MzAzWjAkMRAwDgYDVQQKDAdUZXN0aW5nMRAwDgYDVQQDDAdUZXN0 +aW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA9EXrQeJEeuqIzdVP +NlrglH1E2RiPh5pALrprJTYVZTbGRcubB0wkEMED8TdQTIuZIt56DWFcz6/e9L8v +qexR9Vwa8u0vH9L4gJ4vOdSfiaPh66aRoGhlRaWzaqmbSjGN+06am0EWoLVqCS2+ +9jQ4lva+atCVFMkOenX3niBsKIVI4euEwU7rtQ+0PUJVmEjo6krWukdBEhozpCq6 +Zm2B5sqAEYz8hWQpAM6hM58xYL41lSGAV0Cmh37mXMMdIOcK1DY3/pUpCTS5TcSp +xCce61MEZhAHbfJlwJzHem5MSXgxoCzymT7/Ik08GYItAIo0Y0xg3Vhw8Je5pvHW +oz4fhQIDAQABo1AwTjAdBgNVHQ4EFgQUek/ZgsnuBl4acJ/srxIIkJDaUQ0wHwYD +VR0jBBgwFoAUek/ZgsnuBl4acJ/srxIIkJDaUQ0wDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQUFAAOCAQEASugib099pwRa3nNFwBslQIRFItk6M1izC3SKaTlhrgQl +cxI6Z7RrgpWVC7MEi4Spy+UICdpJh+b8o75XgZPrPgcL6wT0/UYXBGCGTed54RMH +X0OYIkvRQBVk8pm4IteWeQxMyCG+kGc9QTQ1M3KW+Rk2t5KP23bKBiZB986tBQgf +7uAyJdYU8gtrjJfPkxpWRoltDO53GG1GJOcVZrnIgSzzwP9TLW9PoiyLkBKcZWDJ +37y6Hq73qaPcTk8RV6Zayxbrc2CoxMTd9J09p1CTDBCpYTKBqwD+9wYykBdVHRr4 +BhuJBJNVqBflrncOUKkF+mQjUHc3fb2AiYjvyr2n4w== +-----END CERTIFICATE----- diff --git a/ci/resources/nginx/testing.key b/ci/resources/nginx/testing.key new file mode 100644 index 0000000000..5677d3cc08 --- /dev/null +++ b/ci/resources/nginx/testing.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQD0RetB4kR66ojN +1U82WuCUfUTZGI+HmkAuumslNhVlNsZFy5sHTCQQwQPxN1BMi5ki3noNYVzPr970 +vy+p7FH1XBry7S8f0viAni851J+Jo+HrppGgaGVFpbNqqZtKMY37TpqbQRagtWoJ +Lb72NDiW9r5q0JUUyQ56dfeeIGwohUjh64TBTuu1D7Q9QlWYSOjqSta6R0ESGjOk +KrpmbYHmyoARjPyFZCkAzqEznzFgvjWVIYBXQKaHfuZcwx0g5wrUNjf+lSkJNLlN +xKnEJx7rUwRmEAdt8mXAnMd6bkxJeDGgLPKZPv8iTTwZgi0AijRjTGDdWHDwl7mm +8dajPh+FAgMBAAECggEAaq9q22CGRiTO0Q8bxIKWWWQIwMRwU2o0I/R5PUxMteLh +X7RYJizEB6k1HpHo+TVzEX6XUea3EWIff0dM+uritMWgY37huQV8UThFKf3KG+Q+ +lJwwOB3ANVX0cV5YG2RfPWYMMkiQKGpzQEUBhSgzmwNzENW+dtCFCUkid6ZzdpI9 +UKqXhRj7c9FF5/24P9ERCkoIG0+L1SXynqduqCVnKy4UOgptsGryago4C9NA+RpF +UnYb8bEgkO4mSrr9ozzLkM3lz8XZhk0AmkKCsKw/PWJ+EJ/Ydy4A8/lF9MYjiqEv +AWip22O7WEvkQzhSg0ymGI8cSfwUdm7xqgvVWs4K9QKBgQD/oKA4TUYzFWzVWA7w +Evs4V5ImuHyuO5nJRKwJainct5LJVab300sM2LwPHxiZvnyExcFCT5vwuY/JxfWO +klShbP52GSB9oEFS58HaQg78YqAtuWnu1HtYbWFl4NZMLqLZV8PLWlbW+aMdl4FA +LGzsxgDHndBwFhEbR2HwVTferwKBgQD0oQ6M4O4SkJYOff30cpulSq/dhzW80rYd +03y/bLAfWjDONeVSuSh1iqMaQkntjeOmsmu7Rb+340kaTzkF3/dRbaTwQVkTOplY +XPxRWnuFEl1k1gGJitHbmz7xCDzC5SehsFCCts2NIDOXFoCOa6zus6KdYR7/mxem +vqzyGJTSCwKBgFJL+SkHH8GUdTxeJDkAM2bZMpFKtcE2KPWWKTjCuAV6CETPUXjZ +yoCxSiIoJbhhjh8Et4pMrOycIQGZvMuQqrRpraaBwmcPb9hsConk2IRCkEUIO2WL +fMZkOIYfE37lSMJmMf/G7sw5BF2jiBYL92lm+ZtKYG+lew5oNcy08s67AoGAcgxs +Vi2/kJQsAVGoBkEwY11wpF0XJpMuKLWioTQw4E0SF/F0mp6MSFB8Pg/Nm5zdF6hz +JXodKcQjHsr0kNKb4TC3BvPQbXCScWnYkK0YjS/ErvA/AzrfH/0+2Oy4NzzSv0UO +JALJzhPHOZdaFAwLMbY6CBlxdEWAP1MCGlRvfYUCgYEAl8iuq0NUrY3UCoUPSDnh +C51hAH2dJ9n7kFwgOt6X3DeHQOWUb9U3LRcrJqtHoLP2QB1nMu86/BkevOo6A/Wj +kr6GkcoxIw0Oec5k56ThQnyCAjQFiW8nRoyhbRR9nwK2gjOCsPHrceQoZjr3KbAl +aYMKjbhy0hJvt92vTqqD31c= +-----END PRIVATE KEY----- diff --git a/conf.d/nginx.yaml.example b/conf.d/nginx.yaml.example index b198722bb0..96d107be27 100644 --- a/conf.d/nginx.yaml.example +++ b/conf.d/nginx.yaml.example @@ -15,5 +15,6 @@ instances: # - instance:foo # # - nginx_status_url: http://example2.com:1234/nginx_status/ + # ssl_validation: False # tags: # - instance:bar diff --git a/tests/checks/integration/test_nginx.py b/tests/checks/integration/test_nginx.py index 8695724358..baa1ab3190 100644 --- a/tests/checks/integration/test_nginx.py +++ b/tests/checks/integration/test_nginx.py @@ -2,6 +2,7 @@ import unittest # 3p +import requests from nose.plugins.attrib import attr # project @@ -31,27 +32,77 @@ def setUp(self): 'nginx_status_url': 'http://localhost:44441/nginx_status/', 'tags': ['second'], }, + { + 'nginx_status_url': 'https://localhost:44442/https_nginx_status/', + 'tags': ['ssl_enabled'], + 'ssl_validation': True, + }, + { + 'nginx_status_url': 'https://localhost:44442/https_nginx_status/', + 'tags': ['ssl_disabled'], + 'ssl_validation': False, + }, ] } - def test_nginx(self): + def test_nginx_one_connection(self): nginx = load_check('nginx', self.config, self.agent_config) + + # Testing that connection will work with instance 0 nginx.check(self.config['instances'][0]) + + # Checking that only one metric is of type 'nginx.net.connections' r = nginx.get_metrics() self.assertEquals(len([t for t in r if t[0] == "nginx.net.connections"]), 1, r) + def test_nginx_tags(self): + nginx = load_check('nginx', self.config, self.agent_config) + + # Testing that connection will work with instance 1 nginx.check(self.config['instances'][1]) + + # Checking that 'tags' attribute of some result is equal to 'tags' attribute in config for instance 1 r = nginx.get_metrics() self.assertEquals(r[0][3].get('tags'), ['first_one']) + + # Checking that each 'nginx.can_connect' service check's 'tags' attribute match expected host/port from config service_checks = nginx.get_service_checks() can_connect = [sc for sc in service_checks if sc['check'] == 'nginx.can_connect'] for i in range(len(can_connect)): self.assertEquals(set(can_connect[i]['tags']), set(['host:localhost', 'port:44441']), service_checks) + def test_nginx_ssl_validation_enabled(self): + # Note: Throws an SSLError, because we're attempting to connect to an https endpoint with a self-signed + # certificate. In addition, this throws an InsecurePlatformWarning. Both of these are expected; + # versions of Python < 2.7.9 have restrictions in their ssl module limiting the configuration + # urllib3 can apply. (https://urllib3.readthedocs.org/en/latest/security.html#insecurerequestwarning) + nginx = load_check('nginx', self.config, self.agent_config) + + # Testing that connection will FAIL with instance 4 + self.assertRaises(requests.exceptions.SSLError, nginx.check, self.config['instances'][4]) + + def test_nginx_ssl_validation_disabled(self): + nginx = load_check('nginx', self.config, self.agent_config) + + # Testing that connection will work with instance 5 + nginx.check(self.config['instances'][5]) + + # Checking that 'tags' attribute of some result is equal to 'tags' attribute in config for instance 5 + r = nginx.get_metrics() + self.assertEquals(r[0][3].get('tags'), ['ssl_disabled']) + + # Checking that each 'nginx.can_connect' service check's 'tags' attribute match expected host/port from config + service_checks = nginx.get_service_checks() + can_connect = [sc for sc in service_checks if sc['check'] == 'nginx.can_connect'] + for i in range(len(can_connect)): + self.assertEquals(set(can_connect[i]['tags']), set(['host:localhost', 'port:44442']), service_checks) + def test_nginx_plus(self): test_data = Fixtures.read_file('nginx_plus_in.json') expected = eval(Fixtures.read_file('nginx_plus_out.python')) nginx = load_check('nginx', self.config, self.agent_config) parsed = nginx.parse_json(test_data) parsed.sort() + + # Check that the parsed test data is the same as the expected output self.assertEquals(parsed, expected)