Skip to content

Commit

Permalink
Adding reloading of TLS certificates (runatlantis#2656)
Browse files Browse the repository at this point in the history
* Adding reloading of TLS certificates

* Update server/server.go

Co-authored-by: nitrocode <[email protected]>

* Adding test and test data

* Set minimum tls version

* Adding read header timeout

Co-authored-by: nitrocode <[email protected]>
  • Loading branch information
2 people authored and krrrr38 committed Dec 16, 2022
1 parent b9b625b commit d193678
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 2 deletions.
34 changes: 32 additions & 2 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package server

import (
"context"
"crypto/tls"
"flag"
"fmt"
"io"
Expand Down Expand Up @@ -112,6 +113,9 @@ type Server struct {
ProjectJobsErrorTemplate templates.TemplateWriter
SSLCertFile string
SSLKeyFile string
CertLastRefreshTime time.Time
KeyLastRefreshTime time.Time
SSLCert *tls.Certificate
Drainer *events.Drainer
WebAuthentication bool
WebUsername string
Expand Down Expand Up @@ -890,13 +894,15 @@ func (s *Server) Start() error {
s.ProjectCmdOutputHandler.Handle()
}()

server := &http.Server{Addr: fmt.Sprintf(":%d", s.Port), Handler: n} // nolint: gosec
tlsConfig := &tls.Config{GetCertificate: s.GetSSLCertificate, MinVersion: tls.VersionTLS12}

server := &http.Server{Addr: fmt.Sprintf(":%d", s.Port), Handler: n, TLSConfig: tlsConfig, ReadHeaderTimeout: 10 * time.Second}
go func() {
s.Logger.Info("Atlantis started - listening on port %v", s.Port)

var err error
if s.SSLCertFile != "" && s.SSLKeyFile != "" {
err = server.ListenAndServeTLS(s.SSLCertFile, s.SSLKeyFile)
err = server.ListenAndServeTLS("", "")
} else {
err = server.ListenAndServe()
}
Expand Down Expand Up @@ -1012,6 +1018,30 @@ var healthzData = []byte(`{
"status": "ok"
}`)

func (s *Server) GetSSLCertificate(*tls.ClientHelloInfo) (*tls.Certificate, error) {
certStat, err := os.Stat(s.SSLCertFile)
if err != nil {
return nil, fmt.Errorf("while getting cert file modification time: %w", err)
}

keyStat, err := os.Stat(s.SSLKeyFile)
if err != nil {
return nil, fmt.Errorf("while getting key file modification time: %w", err)
}

if s.SSLCert == nil || certStat.ModTime() != s.CertLastRefreshTime || keyStat.ModTime() != s.KeyLastRefreshTime {
cert, err := tls.LoadX509KeyPair(s.SSLCertFile, s.SSLKeyFile)
if err != nil {
return nil, fmt.Errorf("while loading tls cert: %w", err)
}

s.SSLCert = &cert
s.CertLastRefreshTime = certStat.ModTime()
s.KeyLastRefreshTime = keyStat.ModTime()
}
return s.SSLCert, nil
}

// ParseAtlantisURL parses the user-passed atlantis URL to ensure it is valid
// and we can use it in our templates.
// It removes any trailing slashes from the path so we can concatenate it
Expand Down
25 changes: 25 additions & 0 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package server_test

import (
"bytes"
"crypto/tls"
"errors"
"io"
"net/http"
Expand Down Expand Up @@ -163,6 +164,30 @@ func BenchmarkHealthz(b *testing.B) {
}
}

func TestGetCertificate(t *testing.T) {
s := server.Server{}
clientHelloInfo := &tls.ClientHelloInfo{}

// Initial certificate load
s.SSLCertFile = "../testdata/cert.pem"
s.SSLKeyFile = "../testdata/key.pem"
cert, err := s.GetSSLCertificate(clientHelloInfo)
Ok(t, err)

// Certificate reload
s.SSLCertFile = "../testdata/cert2.pem"
s.SSLKeyFile = "../testdata/key2.pem"
s.CertLastRefreshTime = s.CertLastRefreshTime.Add(-1 * time.Second)
s.KeyLastRefreshTime = s.KeyLastRefreshTime.Add(-1 * time.Second)
newCert, err := s.GetSSLCertificate(clientHelloInfo)

Ok(t, err)
Assert(
t,
!bytes.Equal(bytes.Join(cert.Certificate, nil), bytes.Join(newCert.Certificate, nil)),
"Certificate expected to rotate")
}

func TestParseAtlantisURL(t *testing.T) {
cases := []struct {
In string
Expand Down
21 changes: 21 additions & 0 deletions testdata/cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
-----BEGIN CERTIFICATE-----
MIIDiDCCAnACCQDOnvpjFkiR7TANBgkqhkiG9w0BAQsFADCBhTELMAkGA1UEBhMC
YXQxETAPBgNVBAgMCGF0bGFudGlzMREwDwYDVQQHDAhhdGxhbnRpczERMA8GA1UE
CgwIYXRsYW50aXMxETAPBgNVBAsMCGF0bGFudGlzMREwDwYDVQQDDAhhdGxhbnRp
czEXMBUGCSqGSIb3DQEJARYIYXRsYW50aXMwHhcNMjIxMTEwMTg1ODAwWhcNMjIx
MjEwMTg1ODAwWjCBhTELMAkGA1UEBhMCYXQxETAPBgNVBAgMCGF0bGFudGlzMREw
DwYDVQQHDAhhdGxhbnRpczERMA8GA1UECgwIYXRsYW50aXMxETAPBgNVBAsMCGF0
bGFudGlzMREwDwYDVQQDDAhhdGxhbnRpczEXMBUGCSqGSIb3DQEJARYIYXRsYW50
aXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ+d1Yhu2MBljro63h
bYJk3NgMjhiHQzvV2Uy9C6UnXZ0pELWa3utYx+rTAJUjOWxfed59qF2IGAAMWmm7
GQt/Apz0AMtU1uSYzQGYQkWVnAODKRtUC+nBrJYnW4r1zY1/duP74rVuLMFLWhlg
O7XPHbtQK5psYlXLmiyaljWpIMnj3pf/H1MUue+AD9yTpg+sRKscnbNsOVB8NV7Z
mfpeddTkNuQL1d1KqfzF6bKz+zbyrcBz+NHC1SmvCGViRie/nE7UDd5OyHA4WM21
CDfLvCJxmKG69nFDY8Z8EPu/WGWYndeG0piefdlFpZ8GQTpmxD7dgcZ6M3fnCIdX
Zvp/AgMBAAEwDQYJKoZIhvcNAQELBQADggEBAGlib941RVj17ynlH/MQ+R1x01a/
f0GrhHbM4N2IuwGZ77bS4f/yQMC5YJBDcBOog5v7bR3VM8rCNgYSlZDl2aBzBP+8
vXDjGQHr4AfV+dgM/6J7xdzQKpfFr7JCR421O9KOoI+rbuk4+HG2JpILR6H305XX
KOkiD3Ywbdvsng0gA3rMxKTTs0XWu8Rki7r227P5p73yNBOwLQHwiewAfDiASJ/P
UfzOEJjRHYe6ivz181HVQVn/4RJa1LbVtCVDk70VBA3N4tGHLb4eyeMcn/do1Hvg
8m//uN6x2s7TeswAEGCoj1LIhjHWIulAwlNCHIcXMguJqvubfhzlxmE601I=
-----END CERTIFICATE-----
22 changes: 22 additions & 0 deletions testdata/cert2.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDlDCCAnwCCQCGl++WdvHa4jANBgkqhkiG9w0BAQsFADCBizELMAkGA1UEBhMC
YXQxEjAQBgNVBAgMCWF0bGFudGlzMjESMBAGA1UEBwwJYXRsYW50aXMyMRIwEAYD
VQQKDAlhdGxhbnRpczIxEjAQBgNVBAsMCWF0bGFudGlzMjESMBAGA1UEAwwJYXRs
YW50aXMyMRgwFgYJKoZIhvcNAQkBFglhdGxhbnRpczIwHhcNMjIxMTEwMTkwNDIx
WhcNMjIxMjEwMTkwNDIxWjCBizELMAkGA1UEBhMCYXQxEjAQBgNVBAgMCWF0bGFu
dGlzMjESMBAGA1UEBwwJYXRsYW50aXMyMRIwEAYDVQQKDAlhdGxhbnRpczIxEjAQ
BgNVBAsMCWF0bGFudGlzMjESMBAGA1UEAwwJYXRsYW50aXMyMRgwFgYJKoZIhvcN
AQkBFglhdGxhbnRpczIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC+
6bvLyg+VlYT/SU7lXJc2Dmdtehe7C/yckNpl+Zjj/8nkNRYfqJ2g8iwHASOWO7+V
vdg91Ti6eC+OMjg54iSmd2rZQ6734I+hSo3C/l4alkOArjDumQPddynjMiOaB67u
S67+vyBwbQq10BxOgJOhY/wQnLBJhOUhWh+UrjnL1LsET6qQicLwTzt/1cWzXmYS
I8gTs0um+7r5WCB/Raf++KhboCtX3zEj6CV164ucEV65y2vQRIa7PQH+znCHGxbT
nnZdielbJPc0S2hVtL2cRqocKCdEYKY3co27Hgvt/M7byETyLbmxbMK1r4f4icr9
dyqKeY6aT+PxZ43nggYdAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAJTVkyx5SGnh
J5hKOgseJbh4AvwPB++jsrN+z5FE5A6WR/3zZA2bfUuit5uKLAQ0di3l03bZf+2l
zvxLmmeShOArzkaCQ0IRZdHl7rIaFHignikHnon1/fkBVqOoi+R0Hsn6GhVoQYo/
C7zxQYyM/57Yw1VOW9vheIhvNgomv4GxaztrGEVT5tG58j9BgKqKYOfsHz07rYXc
S2/iMML0xsgj5vXq9XiNJ0NVT3hD+LBnR5DZG64ITP9AgK22VeYKQrXiPWuzacKC
zn+ptHXFDeqofAS6UoelrQ4ZchIsc48IsWdIW5SI3FOfiao4R0l5T7BqToSyP5V2
DYLLTHTfIL4=
-----END CERTIFICATE-----
28 changes: 28 additions & 0 deletions testdata/key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDQ+d1Yhu2MBljr
o63hbYJk3NgMjhiHQzvV2Uy9C6UnXZ0pELWa3utYx+rTAJUjOWxfed59qF2IGAAM
Wmm7GQt/Apz0AMtU1uSYzQGYQkWVnAODKRtUC+nBrJYnW4r1zY1/duP74rVuLMFL
WhlgO7XPHbtQK5psYlXLmiyaljWpIMnj3pf/H1MUue+AD9yTpg+sRKscnbNsOVB8
NV7ZmfpeddTkNuQL1d1KqfzF6bKz+zbyrcBz+NHC1SmvCGViRie/nE7UDd5OyHA4
WM21CDfLvCJxmKG69nFDY8Z8EPu/WGWYndeG0piefdlFpZ8GQTpmxD7dgcZ6M3fn
CIdXZvp/AgMBAAECggEANjUaXaRiajgbSMSkjh1B/bfrsxYI9s1R8B718PPcW2HF
KqnS8eFxWw5As4srJH/4xKtwM1hBKtRO7uVlF8tfWArte73ZAKDdm2VSTJSkSDK4
FoXLOPn+IOcL7Bmq6ifv1GiaqvQb7ABgA5PTkUrr1lX4CMvGuuanKrFLcK4WLVCD
9+GHiduaV0BfTPA3RmszrA4zLOXlI+5zlGwGNb5pUz914i9Lk0feIYbOXRMx9M+U
FmDrKvasIXguUHGRWZ7D7ugV6j5/BTuCBjbzH6067YkA4NnXfiSKNTkedz+qTkGC
IJXUCPMDzy6TKbdPMx94OKot14f0qaGZx8zZ0taLAQKBgQDwfoT4gYKl+X/3X0aG
IZ5tSaLzAXKdlZ55W8YXCWDUX/b3YULGzILqEiS5RgnRIA0tGbtu3PMXtiol5Iff
e4ywSZGilvvPJBbw17l8iC3Y/rnHp6wlOhVusdjozBhOuc3CQj3k56p0OXyahmzN
eHp/zsOMimIeef2ZlskmvXZqjwKBgQDecx8VQoi8Ph8/IDD/2P6wIU73qv57AY8K
pRQqRX3zffEN6nr0Xnlb44Oy/zA/5/7FNcEF4D2jhPQF8zkOll5tf0HlbVAVIlfC
F5o8t0S05Uj5a6zAkc34bCV+oWwvCmxk5vCvDl2POAiO+dqYxom4bFsxRmMOf1VC
hh5YDXcpEQKBgQChc36XSnLINCipjIfO8nDmU6IWW6lzi4d5V5gzzPL5gHdO+jeX
OKLGu2l2DEP45fiSh4ziT2jPSVcgWzywVsRLcQhZS90+4a6Y/2oh5VZKMC/Ojo0t
7MGIr9K77pB/AZPVzxy4OKKhJhq1rnsKsdAjT07OYfSfGyyaWLUv0c/WlwKBgQDR
pYOk4LjHWHDQaIFljtexnSK0TgZaXUS3To8rq6Shh49YgyVwC12q2Uh0uQZ7JCU7
LYcGB6lv48yrkueyNMs3vRiYpiY0VNKKjP4CvOJW7kSRNQZx0rhgqWPI7U9tIhC4
I+KvyQUqBjAit51qIKsJEa38SY7vydfLw2TzrXUhUQKBgBgxh9csF9JQfMRKO1Nv
g5YWGFHdujl1Y2Qnf9nWHhQKy2wmCCoD0a0aRs6p0tyZXyqJfyBrPBEGF3VUONqf
OK1b5tSj3w+APFW0hNFQABE8lRYBA/Qq6dAf+pTnDF0+ak9DKzlafhFI7w0dOZU2
bYCXCqkOjIcnONDRDr04jE8c
-----END PRIVATE KEY-----
28 changes: 28 additions & 0 deletions testdata/key2.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC+6bvLyg+VlYT/
SU7lXJc2Dmdtehe7C/yckNpl+Zjj/8nkNRYfqJ2g8iwHASOWO7+Vvdg91Ti6eC+O
Mjg54iSmd2rZQ6734I+hSo3C/l4alkOArjDumQPddynjMiOaB67uS67+vyBwbQq1
0BxOgJOhY/wQnLBJhOUhWh+UrjnL1LsET6qQicLwTzt/1cWzXmYSI8gTs0um+7r5
WCB/Raf++KhboCtX3zEj6CV164ucEV65y2vQRIa7PQH+znCHGxbTnnZdielbJPc0
S2hVtL2cRqocKCdEYKY3co27Hgvt/M7byETyLbmxbMK1r4f4icr9dyqKeY6aT+Px
Z43nggYdAgMBAAECggEAKUNxsLFivu0LSvY4VEC3+hoQ5sut12LW3aw9WC8jiZwe
sfF7b6pNL51IQNdRLsaJOT9IPs0YLs2NUcmu92vWihhjgsQrTC5APRdVHqFGC68Q
tf5wWxG9kR+RcSbEJSWl/KFlGHCM/V/EIdnyVFFcF1T6BUkonStZLuVA0Cz8Fv7r
MO2mtmwtOcTAQaUqHSxdcq9ASmuh3QA9tUmn11oCjHwVbKrFrKNQW20vSn71pk4Z
UiXnppRi7tk1t+PJb4VIEdUTw3JYwtp/HRgnfQ8VFDxWxWDPL4hHkBU270i7oIr3
+DR0+A1eylCuKXO5Il75uMYs8mKjFyGCLFWoGWtW7QKBgQDlAva0FYrbDUFmdUjz
MCOVfOoPkaQB1bd9CK21b8HxGrcXbXwJzs/n2RV4GHZgodSADN2+fKvslpJofD3z
Cnim60MJ8WcxB8Ez+Jvfktap8Kox0qQEZPpIN9hQxBxcXaLL+9TcWvkYJwCDjy+7
LmfHEh9puECnxw5YAlHAreRCowKBgQDVaWB80Ehp9Q4McescrUtbsA0CYI3mkZgx
6YU44/+DqiQStwQLttaOXvI4HXUqTdQgi8wMIJN/EOkMeAA1tuyULXJK9dkEB1pm
zHF65USCr29g2hr/PsLckryKMtnyDGRW7YimXz8P03t5LfJ/M6Ovc7QJm6HSwCkS
FyxrvU3gPwKBgCcWlGk0bBjrcEg+qI7pnok7Yu/5Wdb+VW0/9/ZJ9v5iIvIau9so
s4/NG7793easeIrKp2aF/QpKwP6YhjJfjSxgZ3bg/039Ftr6ChDlDULAUyxh2aDu
Y1HERmWys2yIhuruNuzNkkqvDYVnASyfxRLTYw02Z8K7VRVsf+u1QoqlAoGBAJ6i
HNnKTPmN8apoh3aijhCSdakdsn0AHpyDU8btG4J4VyYeKoC2oRflFbGGnBAdGCA1
KjCdimX6YPEmxiknVwXyHjIAOxdWi+k78OKER3/I/kaE+Wpf8aLZ5BHqKL1WXsOK
/3eD9zFBZ1e1Qrsw3GxP2jUGHay1sBHFbfyME7YrAoGAXaa9GiSi/HjOgOS8nzGf
OzSl+I/fm651QjQ0tRVjVH777P3ZYyjdZNFYDb0x+fsvqTbkfkVtgeWuyoAVIwqy
BtWyvTYutjwwUi53oIpRBe3qhIWIQUZgyAwXVis8FChSv3aaCePij+Bwju6laIfj
+K5StCn2WaOE1d1akqF6C40=
-----END PRIVATE KEY-----

0 comments on commit d193678

Please sign in to comment.