feature/jenkins-proxy (#182)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/182 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
		
							
								
								
									
										1
									
								
								Jenkins/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Jenkins/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | .generated | ||||||
							
								
								
									
										2
									
								
								Jenkins/Jenkinsfile
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								Jenkins/Jenkinsfile
									
									
									
									
										vendored
									
									
								
							| @@ -6,7 +6,7 @@ pipeline { | |||||||
|     } |     } | ||||||
|     agent { |     agent { | ||||||
|         dockerfile { |         dockerfile { | ||||||
|             filename 'Jenkins/agent/Dockerfile' |             filename 'Jenkins/jenkins-agent/Dockerfile' | ||||||
|             args """--user root --network ${params.AGENT_NETWORK} |             args """--user root --network ${params.AGENT_NETWORK} | ||||||
|                     --volume /var/run/docker.sock:/var/run/docker.sock |                     --volume /var/run/docker.sock:/var/run/docker.sock | ||||||
|                     --memory=8g --cpus=${params.AGENT_CPUS}""" |                     --memory=8g --cpus=${params.AGENT_CPUS}""" | ||||||
|   | |||||||
							
								
								
									
										157
									
								
								Jenkins/Makefile
									
									
									
									
									
								
							
							
						
						
									
										157
									
								
								Jenkins/Makefile
									
									
									
									
									
								
							| @@ -1,54 +1,169 @@ | |||||||
| DOCKER := docker | include .env | ||||||
|  | export | ||||||
|  |  | ||||||
| SOCKET := /var/run/docker.sock | SOCKET := /var/run/docker.sock | ||||||
| VOLUME := jenkins_home | VOLUME := jenkins_home | ||||||
|  |  | ||||||
| .PHONY: build run bash init-pw unprotected protected start stop rm purge | CERTBOT_CONF := $(PWD)/.generated/certbot/lib/conf | ||||||
|  | CERTBOT_WWW := $(PWD)/.generated/certbot/lib/www | ||||||
|  | CERTBOT_LOG := $(PWD)/.generated/certbot/log | ||||||
|  | NGINX_LOG := $(PWD)/.generated/certbot/nginx/log | ||||||
|  |  | ||||||
| # building the Jenkins image | .PHONY: provision \ | ||||||
|  | 	build run bash init-pw unprotected protected start stop rm purge \ | ||||||
|  | 	nginx-prepare nginx-proxy nginx-start nginx-letsencrypt-init nginx-letsencrypt-timer nginx-restart nginx-stop | ||||||
|  |  | ||||||
|  | ## lists all documented targets | ||||||
|  | help: | ||||||
|  | 	@awk '/^##/ {sub(/^## /, "", $$0); desc=$$0; next} /^[a-zA-Z0-9][^:]*:/ { \ | ||||||
|  | 		print "\033[1m" $$1 "\033[0m"; \ | ||||||
|  | 		print "    " desc "\n" \ | ||||||
|  | 	}' $(MAKEFILE_LIST) | ||||||
|  |  | ||||||
|  | ## initially, run this once to provision te nginx | ||||||
|  | provision: nginx-prepare nginx-letsencrypt-init nginx-letsencrypt-timer nginx-start build start | ||||||
|  |  | ||||||
|  | ## removes all generated files | ||||||
|  | clean: nginx-stop stop | ||||||
|  | 	rm -rf .generated/ | ||||||
|  |  | ||||||
|  | ## builds the Jenkins image | ||||||
| build: | build: | ||||||
| 	$(DOCKER) build -t jenkins-docker . | 	docker build -t jenkins-docker . | ||||||
|  |  | ||||||
| # initially running the Jenkins container | ## manually running the Jenkins container | ||||||
| run: | run: | ||||||
| 	$(DOCKER) run --detach \ | 	docker run --detach \ | ||||||
| 		--dns 8.8.8.8 \ | 		--dns 8.8.8.8 \ | ||||||
| 		--network bridge \ | 		--network bridge \ | ||||||
| 		--publish 8080:8080 --publish 50000:50000 \ | 		--publish 8090:8080 --publish 50000:50000 \ | ||||||
| 		--volume $(SOCKET):/var/run/docker.sock \ | 		--volume $(SOCKET):/var/run/docker.sock \ | ||||||
| 		--volume $(VOLUME):/var/jenkins_home \ | 		--volume $(VOLUME):/var/jenkins_home \ | ||||||
| 		--restart unless-stopped \ | 		--restart unless-stopped \ | ||||||
| 		--name jenkins jenkins-docker | 		--name jenkins jenkins-docker | ||||||
|  |  | ||||||
| # (re-) starts the Jenkins container | ## manually starts the Jenkins container (again) | ||||||
| start: | start: | ||||||
| 	$(DOCKER) start jenkins | 	docker start jenkins | ||||||
|  |  | ||||||
| # opens a bash within the Jenkins container | ## opens a bash within the Jenkins container | ||||||
| bash: | bash: | ||||||
| 	$(DOCKER) exec -it jenkins bash | 	docker exec -it jenkins bash | ||||||
|  |  | ||||||
| # prints the inital password of a newly setup Jenkins | ## prints the initial password of a newly setup Jenkins | ||||||
| init-pw: | init-pw: | ||||||
| 	$(DOCKER) exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword | 	docker exec -it jenkins sh -c '\ | ||||||
|  |     		while [ ! -f /var/jenkins_home/secrets/initialAdminPassword ]; do \ | ||||||
|  |     			sleep 1; \ | ||||||
|  |     		done; \ | ||||||
|  |     		cat /var/jenkins_home/secrets/initialAdminPassword \ | ||||||
|  |     	' | ||||||
|  |  | ||||||
| # disables security for the Jenkins, allows login without credentials | ## disables security for the Jenkins => allows login to Jenkins without credentials | ||||||
| unprotected: | unprotected: | ||||||
| 	docker exec -it jenkins sed -i 's|<useSecurity>true</useSecurity>|<useSecurity>false</useSecurity>|' /var/jenkins_home/config.xml | 	docker exec -it jenkins sed -i 's|<useSecurity>true</useSecurity>|<useSecurity>false</useSecurity>|' /var/jenkins_home/config.xml | ||||||
| 	docker exec -it jenkins grep useSecurity /var/jenkins_home/config.xml | 	docker exec -it jenkins grep useSecurity /var/jenkins_home/config.xml | ||||||
|  |  | ||||||
| # enables security for the Jenkins, requires login with credentials | ## enables security for the Jenkins => Jenkins requires login with credentials | ||||||
| protected: | protected: | ||||||
| 	docker exec -it jenkins sed -i 's|<useSecurity>true</useSecurity>|<useSecurity>true</useSecurity>|' /var/jenkins_home/config.xml | 	docker exec -it jenkins sed -i 's|<useSecurity>true</useSecurity>|<useSecurity>true</useSecurity>|' /var/jenkins_home/config.xml | ||||||
| 	docker exec -it jenkins grep useSecurity /var/jenkins_home/config.xml | 	docker exec -it jenkins grep useSecurity /var/jenkins_home/config.xml | ||||||
|  |  | ||||||
| # stops the Jenkins container | ## stops the Jenkins container | ||||||
| stop: | stop: | ||||||
| 	$(DOCKER) stop jenkins | 	docker stop jenkins | ||||||
|  |  | ||||||
| # removes the Jenkins container | ## removes the Jenkins container | ||||||
| rm: stop | rm: stop | ||||||
| 	$(DOCKER) rm jenkins | 	docker rm jenkins | ||||||
|  |  | ||||||
| # purges the Jenkins volume (finally deletes the configuration) | ## purges the Jenkins volume (finally deletes the configuration) | ||||||
| purge: rm | purge: rm | ||||||
| 	$(DOCKER) volume rm $(VOLUME) | 	docker volume rm $(VOLUME) | ||||||
|  |  | ||||||
|  | # (internal) generates the files for nginx-proxy and certbot | ||||||
|  | nginx-prepare: | ||||||
|  | 	mkdir -p $(CERTBOT_WWW) $(CERTBOT_LOG) $(CERTBOT_CONF)/live/$(SERVER_NAME) $(NGINX_LOG) | ||||||
|  | 	chmod 755 $(CERTBOT_WWW) $(CERTBOT_LOG) $(CERTBOT_CONF)/live/$(SERVER_NAME) $(NGINX_LOG) | ||||||
|  | 	sed -e 's/%SERVER_NAME/$(SERVER_NAME)/g' <nginx-proxy/nginx.conf >.generated/nginx.conf | ||||||
|  | 	cp nginx-proxy/options-ssl-nginx.conf $(CERTBOT_CONF)/options-ssl-nginx.conf | ||||||
|  | 	chmod 644 $(CERTBOT_CONF)/options-ssl-nginx.conf | ||||||
|  | 	test -f $(CERTBOT_CONF)/ssl-dhparams.pem || curl -o $(CERTBOT_CONF)/ssl-dhparams.pem \ | ||||||
|  | 		https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem | ||||||
|  | 	chmod 644 $(CERTBOT_CONF)/ssl-dhparams.pem | ||||||
|  | 	openssl req -x509 -nodes -newkey rsa:2048 \ | ||||||
|  | 	  -keyout $(CERTBOT_CONF)/live/$(SERVER_NAME)/privkey.pem \ | ||||||
|  | 	  -out /$(CERTBOT_CONF)/live/$(SERVER_NAME)/fullchain.pem \ | ||||||
|  | 	  -subj "/CN=dummy" | ||||||
|  |  | ||||||
|  | ## opens a bash within the Nginx-proxy container | ||||||
|  | nginx-bash: | ||||||
|  | 	docker exec -it nginx bash | ||||||
|  |  | ||||||
|  | # (internal) fetches an initial certificate from letsencrypt | ||||||
|  | nginx-letsencrypt-init: nginx-start | ||||||
|  | 	# wait for nginx actually running (could be improved) | ||||||
|  | 	@sleep 5 | ||||||
|  | 	# delete the previous (dummy) config to avoid file creation with suffix -0001 etc. | ||||||
|  | 	rm -rf $(CERTBOT_CONF)/etc/letsencrypt/live/$(SERVER_NAME) \ | ||||||
|  |        $(CERTBOT_CONF)/etc/letsencrypt/archive/$(SERVER_NAME) \ | ||||||
|  |        $(CERTBOT_CONF)/etc/letsencrypt/renewal/$(SERVER_NAME).conf | ||||||
|  |     # request the certificate via letsencrypt | ||||||
|  | 	docker run --rm \ | ||||||
|  | 	  -v $(CERTBOT_CONF):/etc/letsencrypt \ | ||||||
|  | 	  -v $(CERTBOT_WWW):/var/www/certbot \ | ||||||
|  | 	  -v $(CERTBOT_LOG):/var/log/letsencrypt \ | ||||||
|  | 	  certbot/certbot \ | ||||||
|  | 	  certonly --webroot --webroot-path /var/www/certbot \ | ||||||
|  | 	  --email $(EMAIL) --cert-name $(SERVER_NAME) \ | ||||||
|  | 	  -d $(SERVER_NAME) --rsa-key-size 4096 \ | ||||||
|  | 	  --agree-tos --force-renewal | ||||||
|  | 	# restart nginx | ||||||
|  | 	docker stop nginx || true | ||||||
|  | 	docker start nginx | ||||||
|  |  | ||||||
|  | ## opens a shell in the letsencrypt certbot | ||||||
|  | nginx-letsencrypt-sh: | ||||||
|  | 	docker run -it --rm \ | ||||||
|  | 	  -v $(CERTBOT_CONF):/etc/letsencrypt \ | ||||||
|  | 	  -v $(CERTBOT_WWW):/var/www/certbot \ | ||||||
|  | 	  -v $(CERTBOT_LOG):/var/log/letsencrypt \ | ||||||
|  | 	  --entrypoint /bin/sh \ | ||||||
|  | 	  certbot/certbot | ||||||
|  |  | ||||||
|  | # (internal) installs the letsencrypt certbot timer for automatic renewal | ||||||
|  | nginx-letsencrypt-timer: | ||||||
|  | 	@mkdir -p $(HOME)/.config/systemd/user | ||||||
|  | 	@cp nginx-proxy/nginx-letsencrypt-renew.timer $(HOME)/.config/systemd/user/nginx-letsencrypt-renew.timer | ||||||
|  | 	@cp nginx-proxy/nginx-letsencrypt-renew.service $(HOME)/.config/systemd/user/nginx-letsencrypt-renew.service | ||||||
|  | 	systemctl --user daemon-reload | ||||||
|  | 	systemctl --user enable --now nginx-letsencrypt-renew.timer | ||||||
|  |  | ||||||
|  | ## renews the cert, if already renewable - this is also called from the timer | ||||||
|  | nginx-letsencrypt-renew: | ||||||
|  | 	docker run --rm \ | ||||||
|  | 	  -v $(CERTBOT_CONF):/etc/letsencrypt \ | ||||||
|  | 	  -v $(CERTBOT_WWW):/var/www/certbot \ | ||||||
|  | 	  -v $(CERTBOT_LOG):/var/log/letsencrypt \ | ||||||
|  | 	  certbot/certbot renew -q | ||||||
|  |  | ||||||
|  | ## starts the nginx proxy server | ||||||
|  | nginx-start: nginx-stop | ||||||
|  | 	docker run -d --name nginx \ | ||||||
|  | 	  --publish 8080:80 \ | ||||||
|  | 	  --publish 8443:443 \ | ||||||
|  | 	  --network bridge \ | ||||||
|  | 	  -v $(CERTBOT_CONF):/etc/letsencrypt \ | ||||||
|  | 	  -v $(CERTBOT_WWW):/var/www/certbot \ | ||||||
|  | 	  -v $(NGINX_LOG):/var/log/nginx \ | ||||||
|  | 	  -v $(PWD)/.generated/nginx.conf:/etc/nginx/nginx.conf \ | ||||||
|  | 	  nginx | ||||||
|  |  | ||||||
|  | ## restarts the nginx proxy server | ||||||
|  | nginx-restart: nginx-stop nginx-start | ||||||
|  |  | ||||||
|  | ## stops the nginx proxy server | ||||||
|  | nginx-stop: | ||||||
|  | 	docker stop nginx || true | ||||||
|  | 	docker rm nginx || true | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								Jenkins/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								Jenkins/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | # Jenkins Build+Test-Pipeline with NGINX HTTPS-Proxy and Letsencrypt | ||||||
|  |  | ||||||
|  | The scripts work in a Hostsharing Managed Docker environment. | ||||||
|  |  | ||||||
|  | Requires a .env file like this in the current directory:  | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | SERVER_NAME=jenkins.example.org | ||||||
|  | EMAIL=contact@example.org | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Then run `make provision` to initialize everything. | ||||||
|  |  | ||||||
|  | Run `make help` for more information. | ||||||
|  |  | ||||||
|  | WARNING: Provisioning does not really work yet, needs some manual restarts. | ||||||
							
								
								
									
										8
									
								
								Jenkins/nginx-proxy/nginx-letsencrypt-renew.service
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								Jenkins/nginx-proxy/nginx-letsencrypt-renew.service
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Renew Let's Encrypt certs via Make | ||||||
|  |  | ||||||
|  | [Service] | ||||||
|  | Type=oneshot | ||||||
|  | WorkingDirectory=%h/hs.hsadmin.ng/Jenkins | ||||||
|  | ExecStart=/usr/bin/make nginx-letsencrypt-renew | ||||||
|  |  | ||||||
							
								
								
									
										11
									
								
								Jenkins/nginx-proxy/nginx-letsencrypt-renew.timer
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								Jenkins/nginx-proxy/nginx-letsencrypt-renew.timer
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | [Unit] | ||||||
|  | Description=Run cert renew Make target at ~5 AM daily | ||||||
|  |  | ||||||
|  | [Timer] | ||||||
|  | OnCalendar=05:05 | ||||||
|  | RandomizedDelaySec=20m | ||||||
|  | Persistent=true | ||||||
|  |  | ||||||
|  | [Install] | ||||||
|  | WantedBy=timers.target | ||||||
|  |  | ||||||
							
								
								
									
										40
									
								
								Jenkins/nginx-proxy/nginx.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								Jenkins/nginx-proxy/nginx.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | |||||||
|  | events {} | ||||||
|  |  | ||||||
|  | http { | ||||||
|  |     server { | ||||||
|  |         listen 80; | ||||||
|  |         server_name %SERVER_NAME; | ||||||
|  |  | ||||||
|  |         # directly answer initial certbot request | ||||||
|  |         location /.well-known/acme-challenge/ { | ||||||
|  |             root /var/www/certbot; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         # forward all other HTTP-requests to HTTPS | ||||||
|  |         location / { | ||||||
|  |             return 301 https://$host$request_uri; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     server { | ||||||
|  |         listen 443 ssl; | ||||||
|  |         server_name %SERVER_NAME; | ||||||
|  |  | ||||||
|  |         ssl_certificate /etc/letsencrypt/live/%SERVER_NAME/fullchain.pem; | ||||||
|  |         ssl_certificate_key /etc/letsencrypt/live/%SERVER_NAME/privkey.pem; | ||||||
|  |         include /etc/letsencrypt/options-ssl-nginx.conf; | ||||||
|  |  | ||||||
|  |         location /.well-known/acme-challenge/ { | ||||||
|  |             root /var/www/certbot; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         location / { | ||||||
|  |             proxy_pass http://%SERVER_NAME:8090; | ||||||
|  |             proxy_set_header Host $host; | ||||||
|  |             proxy_set_header X-Real-IP $remote_addr; | ||||||
|  |             proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; | ||||||
|  |             proxy_set_header X-Forwarded-Proto $scheme; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										7
									
								
								Jenkins/nginx-proxy/options-ssl-nginx.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								Jenkins/nginx-proxy/options-ssl-nginx.conf
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | ssl_session_cache shared:le_nginx_SSL:1m; | ||||||
|  | ssl_session_timeout 1440m; | ||||||
|  | ssl_protocols TLSv1.2 TLSv1.3; | ||||||
|  | ssl_prefer_server_ciphers off; | ||||||
|  |  | ||||||
|  | ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:..."; | ||||||
|  | ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; | ||||||
		Reference in New Issue
	
	Block a user