/
main.go
187 lines (161 loc) · 5.54 KB
/
main.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// Copyright 2020 Comcast Cable Communications Management, LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package ssl-handshake-check implements an SSL TLS handshake checker for Kuberhealthy
// It verifies that a domain's SSL cert is valid, and does not expire in the next 60 days
package main
import (
"context"
"fmt"
"net/url"
"os"
"strconv"
"time"
"github.com/Comcast/kuberhealthy/v2/pkg/checks/external/checkclient"
"github.com/Comcast/kuberhealthy/v2/pkg/checks/external/nodeCheck"
"github.com/Comcast/kuberhealthy/v2/pkg/checks/external/ssl_util"
"github.com/Comcast/kuberhealthy/v2/pkg/kubeClient"
log "github.com/sirupsen/logrus"
"k8s.io/client-go/kubernetes"
)
var (
kubeConfigFile = os.Getenv("KUBECONFIG")
checkTimeout time.Duration
checkNamespace string
domainName string
portNum string
selfSigned string
selfSignedBool bool
ctx context.Context
)
type Checker struct {
client *kubernetes.Clientset
domainName string
portNum string
selfSignedBool bool
}
func init() {
// Set the check time limit to default
checkTimeout = time.Duration(time.Second * 20)
// Get the deadline time in Unix from the environment variable
timeDeadline, err := checkclient.GetDeadline()
if err != nil {
log.Infoln("There was an issue getting the check deadline:", err.Error())
}
checkTimeout = timeDeadline.Sub(time.Now().Add(time.Second * 5))
log.Infoln("Check time limit set to: ", checkTimeout)
domainName = os.Getenv("DOMAIN_NAME")
if len(domainName) == 0 {
log.Error("ERROR: The DOMAIN_NAME environment variable has not been set.")
return
}
portNum = os.Getenv("PORT")
if len(portNum) == 0 {
log.Error("ERROR: The PORT environment variable has not been set.")
return
}
selfSigned = os.Getenv("SELF_SIGNED")
if len(selfSigned) == 0 {
log.Error("ERROR: The SELF_SIGNED environment variable has not been set.")
return
}
selfSignedBool, _ = strconv.ParseBool(selfSigned)
// set debug mode for nodeCheck pkg
nodeCheck.EnableDebugOutput()
}
func main() {
// create context
nodeCheckTimeout := time.Minute * 1
nodeCheckCtx, _ := context.WithTimeout(context.Background(), nodeCheckTimeout.Round(10))
client, err := kubeClient.Create(kubeConfigFile)
if err != nil {
log.Fatalln("Unable to create kubernetes client", err)
}
// wait for the node to join the worker pool
waitForNodeToJoin(nodeCheckCtx)
shc := New()
var cancelFunc context.CancelFunc
nodeCheckCtx, cancelFunc = context.WithTimeout(context.Background(), checkTimeout)
err = shc.runHandshake(nodeCheckCtx, cancelFunc, client)
if err != nil {
log.Errorln("Error completing SSL handshake check for", domainName+":", err)
}
}
func New() *Checker {
return &Checker{
domainName: domainName,
portNum: portNum,
selfSignedBool: selfSignedBool,
}
}
// runHandshake runs the SSL handshake check for the specified host and port number from ssl_util package
func (shc *Checker) runHandshake(ctx context.Context, cancel context.CancelFunc, client *kubernetes.Clientset) error {
doneChan := make(chan error)
runTimeout := time.After(checkTimeout)
go func(doneChan chan error) {
err := shc.doChecks()
doneChan <- err
}(doneChan)
select {
case <-ctx.Done():
log.Println("Cancelling check and shutting down due to interrupt.")
return reportKHFailure("Cancelling check and shutting down due to interrupt.")
case <-runTimeout:
cancel()
log.Println("Cancelling check and shutting down due to timeout.")
return reportKHFailure("Failed to complete SSL handshake in time. Timeout was reached.")
case err := <-doneChan:
cancel()
if err != nil {
log.Errorln("Error when doing SSL handshake:", err)
return reportKHFailure(err.Error())
}
return reportKHSuccess()
}
}
func (shc *Checker) doChecks() error {
siteURL, err := url.Parse("https://" + domainName + ":" + portNum)
if err != nil {
return err
}
// create a cert pool for this check
certPool, err := ssl_util.CreatePool()
if err != nil {
return fmt.Errorf("error creating cert pool for ssl checks: %w", err)
}
return ssl_util.SSLHandshakeWithCertPool(siteURL, certPool)
}
// reportKHSuccess reports success to Kuberhealthy servers and verifies the report successfully went through
func reportKHSuccess() error {
err := checkclient.ReportSuccess()
if err != nil {
log.Error("Error reporting success status to Kuberhealthy servers: ", err)
return err
}
log.Info("Successfully reported success status to Kuberhealthy servers")
return err
}
// reportKHFailure reports failure to Kuberhealthy servers and verifies the report successfully went through
func reportKHFailure(errorMessage string) error {
err := checkclient.ReportFailure([]string{errorMessage})
if err != nil {
log.Error("Error reporting failure status to Kuberhealthy servers: ", err)
return err
}
log.Info("Successfully reported failure status to Kuberhealthy servers")
return nil
}
func waitForNodeToJoin(ctx context.Context) {
// Check if Kuberhealthy is reachable.
err := nodeCheck.WaitForKuberhealthy(ctx)
if err != nil {
log.Errorln("Failed to reach Kuberhealthy:", err.Error())
}
}