Skip to content

Commit 2b63290

Browse files
Федорченко Олег Васильевичvany-egorov
authored andcommitted
add ClientAuthTLS to config. add server arg to fnNewServer in ServeGRPC. update server-base dump to print ClientAuthTLS. move client auth cfg for grpc in grpc struct. grpc.Dump to correct print clientAuthTLS. add mtls for http server. add warning for unsecure config. serverBase dump. server TLSConfig, add serverType for error msg.
1 parent 640aab2 commit 2b63290

8 files changed

Lines changed: 424 additions & 45 deletions

client-auth-tls-config.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package servers
2+
3+
import (
4+
"fmt"
5+
"io"
6+
7+
"github.com/go-x-pkg/dumpctx"
8+
)
9+
10+
type ClientAuthTLSConfig struct {
11+
// Enable/Disable client auth through mTLS
12+
Enable bool `json:"enable" yaml:"enable" bson:"enable"`
13+
// AuthType declares the policy the server will follow for
14+
// TLS Client Authentication.
15+
//
16+
// "NoClientCert" indicates that no client certificate should be requested
17+
// during the handshake, and if any certificates are sent they will not
18+
// be verified.
19+
//
20+
// "RequestClientCert" indicates that a client certificate should be requested
21+
// during the handshake, but does not require that the client send any
22+
// certificates.
23+
//
24+
// "RequireAnyClientCert" indicates that a client certificate should be requested
25+
// during the handshake, and that at least one certificate is required to be
26+
// sent by the client, but that certificate is not required to be valid.
27+
//
28+
// "VerifyClientCertIfGiven" indicates that a client certificate should be requested
29+
// during the handshake, but does not require that the client sends a
30+
// certificate. If the client does send a certificate it is required to be
31+
// valid.
32+
//
33+
// "RequireAndVerifyClientCert" indicates that a client certificate should be requested
34+
// during the handshake, and that at least one valid certificate is required
35+
// to be sent by the client.
36+
//
37+
// If ClientAuthTLS is set true, AuthType must be set.
38+
AuthType clientAuthTypeTLS `json:"authType" yaml:"authType" bson:"authType"`
39+
// CARoot certificate for clients certificates. Optional.
40+
TrustedCA string `json:"trustedCA" yaml:"trustedCA" bson:"trustedCA"`
41+
// If set, server will verifie Common Name of certificate given by client has in this list.
42+
// Otherwise server return Unauthtorized responce.
43+
ClientCommonNames []string `json:"clientCommonNames" yaml:"clientCommonNames" bson:"clientCommonNames"`
44+
}
45+
46+
func (c ClientAuthTLSConfig) dump(ctx *dumpctx.Ctx, w io.Writer) {
47+
fmt.Fprintf(w, "%smtls:\n", ctx.Indent())
48+
ctx.Wrap(func() {
49+
fmt.Fprintf(w, "%senable: %t\n", ctx.Indent(), c.Enable)
50+
fmt.Fprintf(w, "%sauthType: %s\n", ctx.Indent(), c.AuthType.SetedOrDefault())
51+
fmt.Fprintf(w, "%strustedCA: %s\n", ctx.Indent(), c.TrustedCA)
52+
fmt.Fprintf(w, "%sclientCommonNames: %s\n", ctx.Indent(), c.ClientCommonNames)
53+
})
54+
}

client-auth-type-tls.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package servers
2+
3+
import (
4+
"crypto/tls"
5+
"encoding/json"
6+
"fmt"
7+
)
8+
9+
const (
10+
strNoClientCert = "NoClientCert"
11+
strRequestClientCert = "RequestClientCert"
12+
strRequireAnyClientCert = "RequireAnyClientCert"
13+
strVerifyClientCertIfGiven = "VerifyClientCertIfGiven"
14+
strRequireAndVerifyClientCert = "RequireAndVerifyClientCert"
15+
)
16+
17+
type clientAuthTypeTLS tls.ClientAuthType
18+
19+
const clientAuthTypeTLSDefault clientAuthTypeTLS = clientAuthTypeTLS(tls.NoClientCert)
20+
const clientAuthTypeTLSUnknown clientAuthTypeTLS = -1
21+
22+
func (c clientAuthTypeTLS) String() string {
23+
switch tls.ClientAuthType(c) {
24+
case tls.NoClientCert:
25+
return strNoClientCert
26+
case tls.RequestClientCert:
27+
return strRequestClientCert
28+
case tls.RequireAnyClientCert:
29+
return strRequireAnyClientCert
30+
case tls.VerifyClientCertIfGiven:
31+
return strVerifyClientCertIfGiven
32+
case tls.RequireAndVerifyClientCert:
33+
return strRequireAndVerifyClientCert
34+
case tls.ClientAuthType(clientAuthTypeTLSUnknown):
35+
return "unknown"
36+
default:
37+
return "undefined"
38+
}
39+
}
40+
41+
func (c clientAuthTypeTLS) SetedOrDefault() string {
42+
if c.isDefined() {
43+
return c.String()
44+
}
45+
return versionTLSDefault.String()
46+
}
47+
48+
func (c clientAuthTypeTLS) isDefined() bool {
49+
switch tls.ClientAuthType(c) {
50+
case tls.NoClientCert:
51+
return true
52+
case tls.RequestClientCert:
53+
return true
54+
case tls.RequireAnyClientCert:
55+
return true
56+
case tls.VerifyClientCertIfGiven:
57+
return true
58+
case tls.RequireAndVerifyClientCert:
59+
return true
60+
default:
61+
return false
62+
}
63+
}
64+
65+
func (c clientAuthTypeTLS) setedOrDefault() clientAuthTypeTLS {
66+
if c.isDefined() {
67+
return c
68+
}
69+
return clientAuthTypeTLSDefault
70+
}
71+
72+
func (c *clientAuthTypeTLS) unmarshal(fn func(interface{}) error) error {
73+
var raw string
74+
75+
if err := fn(&raw); err != nil {
76+
return fmt.Errorf("error unmarshal client authType: %w", err)
77+
}
78+
79+
if *c = newClientAuthTypeTLS(raw); *c == clientAuthTypeTLSUnknown {
80+
return fmt.Errorf("error unmarshal client authType: %s", clientAuthTypeTLSUnknown)
81+
}
82+
83+
return nil
84+
}
85+
86+
func (c clientAuthTypeTLS) MarshalJSON() ([]byte, error) {
87+
return []byte(fmt.Sprintf("%q", c.String())), nil
88+
}
89+
90+
func (c clientAuthTypeTLS) MarshalYAML() (interface{}, error) {
91+
return c.String(), nil
92+
}
93+
94+
func (c *clientAuthTypeTLS) UnmarshalJSON(data []byte) error {
95+
return c.unmarshal(func(c interface{}) error { return json.Unmarshal(data, c) })
96+
}
97+
98+
func (c *clientAuthTypeTLS) UnmarshalYAML(unmarshal func(interface{}) error) error {
99+
return c.unmarshal(unmarshal)
100+
}
101+
102+
func newClientAuthTypeTLS(raw string) clientAuthTypeTLS {
103+
switch raw {
104+
case strNoClientCert:
105+
return clientAuthTypeTLS(tls.NoClientCert)
106+
case strRequestClientCert:
107+
return clientAuthTypeTLS(tls.RequestClientCert)
108+
case strRequireAnyClientCert:
109+
return clientAuthTypeTLS(tls.RequireAnyClientCert)
110+
case strVerifyClientCertIfGiven:
111+
return clientAuthTypeTLS(tls.VerifyClientCertIfGiven)
112+
case strRequireAndVerifyClientCert:
113+
return clientAuthTypeTLS(tls.RequireAndVerifyClientCert)
114+
default:
115+
return clientAuthTypeTLSUnknown
116+
}
117+
}

listen-serve.go

Lines changed: 25 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,24 @@ func (it iterator) ServeHTTP(fnNewHandler func(Server) http.Handler, fnArgs ...A
178178
} else {
179179
inet := l.Server.(*ServerINET)
180180

181-
if inet.TLS.Enable {
182-
if err := server.ServeTLS(l.Listener, inet.TLS.CertFile, inet.TLS.KeyFile); err != nil {
183-
fnOnErr(fmt.Errorf("starting https (%s) server failed: %w", addr, err))
184-
}
185-
} else {
186-
if err := server.Serve(l.Listener); err != nil {
187-
fnOnErr(fmt.Errorf("starting http (%s) server failed: %w", addr, err))
181+
tlsConfig, err := inet.newTLSConfig()
182+
183+
if err != nil {
184+
fnOnErr(err)
185+
return
186+
}
187+
188+
if tlsConfig != nil {
189+
l.Listener = tls.NewListener(l.Listener, tlsConfig)
190+
server.TLSConfig = tlsConfig
191+
}
192+
193+
if err := server.Serve(l.Listener); err != nil {
194+
serverType := "http"
195+
if inet.TLS.Enable {
196+
serverType = "https"
188197
}
198+
fnOnErr(fmt.Errorf("starting %s (%s) server failed: %w", serverType, addr, err))
189199
}
190200
}
191201
}(l)
@@ -223,7 +233,7 @@ func (it iterator) ServeHTTP(fnNewHandler func(Server) http.Handler, fnArgs ...A
223233
}
224234
}
225235

226-
func (it iterator) ServeGRPC(fnNewServer func(opts ...grpc.ServerOption) *grpc.Server, fnArgs ...Arg) error {
236+
func (it iterator) ServeGRPC(fnNewServer func(s Server, opts ...grpc.ServerOption) *grpc.Server, fnArgs ...Arg) error {
227237
it = it.FilterListener()
228238

229239
cfg := args{}
@@ -268,26 +278,18 @@ func (it iterator) ServeGRPC(fnNewServer func(opts ...grpc.ServerOption) *grpc.S
268278

269279
fnLog(log.Info, "%s gRPC server starting on %s", runLogPrefix(l), addr)
270280

271-
if inet.TLS.Enable {
272-
cert, err := tls.LoadX509KeyPair(inet.TLS.CertFile, inet.TLS.KeyFile)
273-
if err != nil {
274-
fnOnErr(fmt.Errorf("error load x509 key pair (:cert %q :key %q): %w",
275-
inet.TLS.CertFile, inet.TLS.KeyFile, err))
276-
return
277-
}
278-
279-
tlsConfig := &tls.Config{
280-
Certificates: make([]tls.Certificate, 1),
281-
}
282-
283-
tlsConfig.Certificates[0] = cert
281+
tlsConfig, err := inet.newTLSConfig()
282+
if err != nil {
283+
fnOnErr(err)
284+
return
285+
}
284286

287+
if tlsConfig != nil {
285288
opt := grpc.Creds(credentials.NewTLS(tlsConfig))
286-
287289
opts = append(opts, opt)
288290
}
289291

290-
server := fnNewServer(opts...)
292+
server := fnNewServer(s, opts...)
291293

292294
if inet.GRPC.Reflection {
293295
reflection.Register(server)

server-base.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,15 +88,19 @@ func (s *ServerBase) defaultize() error {
8888
}
8989

9090
func (s *ServerBase) Dump(ctx *dumpctx.Ctx, w io.Writer) {
91-
fmt.Fprintf(w, "%sgrpc:\n", ctx.Indent())
92-
ctx.Wrap(func() {
93-
fmt.Fprintf(w, "%sreflection: %t\n", ctx.Indent(), s.GRPC.Reflection)
94-
})
91+
if s.Kind().Has(KindGRPC) {
92+
fmt.Fprintf(w, "%sgrpc:\n", ctx.Indent())
93+
ctx.Wrap(func() {
94+
fmt.Fprintf(w, "%sreflection: %t\n", ctx.Indent(), s.GRPC.Reflection)
95+
})
96+
}
9597

96-
fmt.Fprintf(w, "%shttp:\n", ctx.Indent())
97-
ctx.Wrap(func() {
98-
fmt.Fprintf(w, "%sreadHeaderTimeout: %s\n", ctx.Indent(), s.HTTP.ReadHeaderTimeout)
99-
})
98+
if s.Kind().Has(KindHTTP) {
99+
fmt.Fprintf(w, "%shttp:\n", ctx.Indent())
100+
ctx.Wrap(func() {
101+
fmt.Fprintf(w, "%sreadHeaderTimeout: %s\n", ctx.Indent(), s.HTTP.ReadHeaderTimeout)
102+
})
103+
}
100104

101105
fmt.Fprintf(w, "%spprof:\n", ctx.Indent())
102106
ctx.Wrap(func() {

0 commit comments

Comments
 (0)