generated from wisdom-oss/microservice-template
-
Notifications
You must be signed in to change notification settings - Fork 0
/
init.go
217 lines (189 loc) · 6.29 KB
/
init.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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
package main
import (
"crypto/x509"
"encoding/pem"
"errors"
"io"
"os"
_ "github.com/joho/godotenv/autoload"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwk"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/rs/zerolog/pkgerrors"
"microservice/internal/config"
_ "microservice/internal/db" // side effect import to connect to the database and parse the sql queries from it's embed
"microservice/oidc"
"microservice/resources"
"microservice/utils"
_ "github.com/wisdom-oss/go-healthcheck/client"
)
// init is executed at every startup of the microservice and is always executed
// before main
func init() {
configureLogger()
loadCertificates()
validateOIDCEnvironment()
}
// configureLogger handles the configuration of the logger used in the
// microservice. it reads the logging level from the `LOG_LEVEL` environment
// variable and sets it according to the parsed logging level. if an invalid
// value is supplied or no level is supplied, the service defaults to the
// `INFO` level
func configureLogger() {
// set the time format to unix timestamps to allow easier machine handling
zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
// allow the logger to create an error stack for the logs
zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack
// now use the environment variable `LOG_LEVEL` to determine the logging
// level for the microservice.
rawLoggingLevel, isSet := os.LookupEnv("LOG_LEVEL")
// if the value is not set, use the info level as default.
var loggingLevel zerolog.Level
if !isSet {
loggingLevel = zerolog.InfoLevel
} else {
// now try to parse the value of the raw logging level to a logging
// level for the zerolog package
var err error
loggingLevel, err = zerolog.ParseLevel(rawLoggingLevel)
if err != nil {
// since an error occurred while parsing the logging level, use info
loggingLevel = zerolog.InfoLevel
log.Warn().Msg("unable to parse value from environment. using info")
}
}
// since now a logging level is set, configure the logger
zerolog.SetGlobalLevel(loggingLevel)
}
func validateOIDCEnvironment() {
clientID, isSet := os.LookupEnv("OIDC_CLIENT_ID")
if !isSet {
log.Fatal().Msg("OIDC_CLIENT_ID environment variable not set")
}
clientSecret, isSet := os.LookupEnv("OIDC_CLIENT_SECRET")
if !isSet {
log.Fatal().Msg("OIDC_CLIENT_SECRET environment variable not set")
}
issuer, isSet := os.LookupEnv("OIDC_ISSUER")
if !isSet {
log.Fatal().Msg("OIDC_ISSUER environment variable not set")
}
err := oidc.ExternalProvider.Configure(issuer, clientID, clientSecret, "")
if err != nil {
log.Fatal().Err(err).Msg("unable to configure external OIDC provider information")
}
}
func loadCertificates() {
// test if the certificates are already present
var tries int
loadCerts:
signingCertificate, err := os.Open(config.SigningCertificateFilePath)
if err != nil {
if tries >= 3 {
log.Fatal().Err(err).Msg("unable to open certificate file after three tries")
}
tries++
if errors.Is(err, os.ErrNotExist) {
err = utils.GenerateCertificates()
if err != nil {
log.Fatal().Err(err).Msg("unable to generate certificates")
}
goto loadCerts
}
}
encryptionCertificate, err := os.Open(config.EncryptionCertificateFilePath)
if err != nil {
if tries >= 3 {
log.Fatal().Err(err).Msg("unable to open certificate file after three tries")
}
tries++
if errors.Is(err, os.ErrNotExist) {
err = utils.GenerateCertificates()
if err != nil {
log.Fatal().Err(err).Msg("unable to generate certificates")
}
goto loadCerts
}
}
defer signingCertificate.Close()
certificateContents, err := io.ReadAll(signingCertificate)
if err != nil {
log.Fatal().Err(err).Msg("unable to read certificate file")
}
privateKeyBlock, _ := pem.Decode(certificateContents)
if privateKeyBlock.Type != "EC PRIVATE KEY" {
log.Fatal().Msg("unsupported private key type")
}
ecdsaPrivateKey, err := x509.ParseECPrivateKey(privateKeyBlock.Bytes)
if err != nil {
log.Fatal().Err(err).Msg("unable to parse ECDSA private key")
}
privateKey, err := jwk.FromRaw(ecdsaPrivateKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to create jwk private key")
}
err = jwk.AssignKeyID(privateKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to set private key key id")
}
err = privateKey.Set(jwk.KeyUsageKey, "sig")
if err != nil {
log.Fatal().Err(err).Msg("unable to set private key usage type")
}
err = privateKey.Set(jwk.AlgorithmKey, jwa.ES256)
if err != nil {
log.Fatal().Err(err).Msg("unable to set private key algorithm")
}
publicKey, err := jwk.PublicKeyOf(privateKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to parse public key")
}
resources.PublicSigningKey = publicKey
resources.PrivateSigningKey = privateKey
defer encryptionCertificate.Close()
certificateContents, err = io.ReadAll(encryptionCertificate)
if err != nil {
log.Fatal().Err(err).Msg("unable to read certificate file")
}
privateKeyBlock, _ = pem.Decode(certificateContents)
if privateKeyBlock.Type != "EC PRIVATE KEY" {
log.Fatal().Msg("unsupported private key type")
}
ecdsaPrivateKey, err = x509.ParseECPrivateKey(privateKeyBlock.Bytes)
if err != nil {
log.Fatal().Err(err).Msg("unable to parse ECDSA private key")
}
privateKey, err = jwk.FromRaw(ecdsaPrivateKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to create jwk private key")
}
err = jwk.AssignKeyID(privateKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to set private key key id")
}
err = privateKey.Set(jwk.KeyUsageKey, "enc")
if err != nil {
log.Fatal().Err(err).Msg("unable to set private key usage type")
}
err = privateKey.Set(jwk.AlgorithmKey, jwa.ES256)
if err != nil {
log.Fatal().Err(err).Msg("unable to set private key algorithm")
}
publicKey, err = jwk.PublicKeyOf(privateKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to parse public key")
}
resources.PublicEncryptionKey = publicKey
resources.PrivateEncryptionKey = privateKey
resources.KeySet = jwk.NewSet()
err = resources.KeySet.AddKey(resources.PublicEncryptionKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to add public encryption key to key set")
}
err = resources.KeySet.AddKey(resources.PublicSigningKey)
if err != nil {
log.Fatal().Err(err).Msg("unable to add public signing key to key set")
}
log.Info().Msg("loaded certificates")
}