diff --git a/nginx/default b/nginx/default index 6ea04f95..02bf98e7 100644 --- a/nginx/default +++ b/nginx/default @@ -1,7 +1,10 @@ server { listen 80 default_server; server_name build.servo.org; + ssl_certificate /etc/letsencrypt/live/build.servo.org/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/build.servo.org/privkey.pem; + listen 443 ssl; location / { proxy_pass http://localhost:8010/; diff --git a/nginx/init.sls b/nginx/init.sls index 86990817..c583b003 100644 --- a/nginx/init.sls +++ b/nginx/init.sls @@ -6,6 +6,8 @@ nginx: - watch: - pkg: nginx - file: /etc/nginx/sites-available/default + - require: + - cmd: create-cert {% endif %} /etc/nginx/sites-available/default: @@ -19,3 +21,40 @@ nginx: file.symlink: - target: /etc/nginx/sites-available/default +certbot: + pkgrepo.managed: + - ppa: certbot/certbot + pkg.installed: + - pkgs: + - certbot + - python-certbot-nginx + +/root/renew.sh: + file.managed: + - source: salt://nginx/renew.sh + - template: jinja + - user: root + - group: root + - mode: 644 + +bash /root/renew.sh: + cron.present: + - identifier: build-cert-renew + - user: root + - minute: 40 + - hour: 2 + - dayweek: 1 + - require: + - pkg: certbot + - file: /root/renew.sh + +create-cert: + cmd.run: + - name: | + mkdir -p /etc/letsencrypt/live/build.servo.org && + openssl req -x509 -newkey rsa:4096 -new -nodes -days 365 \ + -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=build.servo.org" \ + -keyout /etc/letsencrypt/live/build.servo.org/privkey.pem \ + -out /etc/letsencrypt/live/build.servo.org/fullchain.pem + - user: root + - creates: /etc/letsencrypt/live/build.servo.org/fullchain.pem \ No newline at end of file diff --git a/nginx/renew.sh b/nginx/renew.sh new file mode 100644 index 00000000..67d9aa8b --- /dev/null +++ b/nginx/renew.sh @@ -0,0 +1,9 @@ +sleep ${RANDOM:0:2}m +certbot renew +if [ $? -ne 0 ] ; then + # Create a new issue reporting the failure + curl --user "servo-wpt-sync" \ + --pass '{{ pillar["wpt-sync"]["upstream-wpt-sync-token"] }}' \ + --data '{"title": "Cert renewal cron job failed"}' \ + https://api.github.com/repos/servo/saltfs/issues +fi diff --git a/tests/sls/nginx/serving.py b/tests/sls/nginx/serving.py index 0334b9bc..286b4973 100644 --- a/tests/sls/nginx/serving.py +++ b/tests/sls/nginx/serving.py @@ -1,12 +1,16 @@ import urllib.request import urllib.error +import ssl from tests.util import Failure, Success -def run(): +def check_url(url): + # We use a self-signed certificate for automated testing. + ssl._create_default_https_context = ssl._create_unverified_context + try: - urllib.request.urlopen('http://localhost/') + urllib.request.urlopen(url) except urllib.error.URLError as e: # Can call e.read() if there was a response but the HTTP status code # indicated error; the method is unavailable if a connection could not @@ -16,8 +20,20 @@ def run(): # Also, we're 'expecting' a string for e.reason (for the connection # refused error case), but it may be another exception instance. if not hasattr(e, 'read'): - return Failure("Nginx is not serving requests:", str(e.reason)) + return False, str(e.reason) # No need to catch HTTPError or ContentTooShortError specially here + return True, None + + +def run(): + result, err = check_url('http://localhost/') + if not result: + return Failure("Nginx is not serving HTTP requests:", err) + + result, err = check_url('https://localhost/') + if not result: + return Failure("Nginx is not serving HTTPS requests:", err) + return Success("Nginx is serving requests")