-
Notifications
You must be signed in to change notification settings - Fork 590
/
credentials.go
238 lines (214 loc) · 6.41 KB
/
credentials.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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package kongstate
import (
"fmt"
"github.com/kong/go-kong/kong"
"github.com/mitchellh/mapstructure"
)
var redactedString = kong.String("REDACTED")
// KeyAuth represents a key-auth credential.
type KeyAuth struct {
kong.KeyAuth
}
// HMACAuth represents a HMAC credential.
type HMACAuth struct {
kong.HMACAuth
}
// JWTAuth represents a JWT credential.
type JWTAuth struct {
kong.JWTAuth
}
// BasicAuth represents a basic authentication credential.
type BasicAuth struct {
kong.BasicAuth
}
// ACLGroup represents an ACL associated with a consumer. Due to ACL implementation in Kong being similar to
// credentials, ACLs are treated as credentials, too.
type ACLGroup struct {
kong.ACLGroup
}
// Oauth2Credential represents an OAuth2 client configuration including credentials.
type Oauth2Credential struct {
kong.Oauth2Credential
}
// MTLSAuth represents an MTLS auth credential
type MTLSAuth struct {
kong.MTLSAuth
}
func NewKeyAuth(config interface{}) (*KeyAuth, error) {
var res KeyAuth
err := decodeCredential(config, &res.KeyAuth)
if err != nil {
return nil, fmt.Errorf("failed to decode key-auth credential: %w", err)
}
// TODO we perform these validity checks here because passing credentials without these fields will panic deck
// later on. Ideally this should not be handled in the controller, but we cannot currently handle it elsewhere
// (i.e. in deck or go-kong) without entering a sync failure loop that cannot actually report the problem
// piece of configuration. if we can address those limitations, we should remove these checks.
// See https://github.com/Kong/deck/pull/223 and https://github.com/Kong/kubernetes-ingress-controller/issues/532
// for more discussion.
if res.Key == nil {
return nil, fmt.Errorf("key-auth is invalid: no key")
}
return &res, nil
}
func NewHMACAuth(config interface{}) (*HMACAuth, error) {
var res HMACAuth
err := decodeCredential(config, &res.HMACAuth)
if err != nil {
return nil, fmt.Errorf("failed to decode hmac-auth credential: %w", err)
}
if res.Username == nil {
return nil, fmt.Errorf("hmac-auth is invalid: no username")
}
return &res, nil
}
func NewJWTAuth(config interface{}) (*JWTAuth, error) {
var res JWTAuth
err := decodeCredential(config, &res.JWTAuth)
if err != nil {
return nil, fmt.Errorf("failed to process JWT credential: %v", err)
}
// This is treated specially because only this
// field might be omitted by user under the expectation
// that Kong will insert the default.
// If we don't set it, decK will detect a diff and PUT this
// credential everytime it performs a sync operation, which
// leads to unnecessary cache invalidations in Kong.
if res.Algorithm == nil || *res.Algorithm == "" {
res.Algorithm = kong.String("HS256")
}
if res.Key == nil {
return nil, fmt.Errorf("jwt-auth for is invalid: no key")
}
return &res, nil
}
func NewBasicAuth(config interface{}) (*BasicAuth, error) {
var res BasicAuth
err := decodeCredential(config, &res.BasicAuth)
if err != nil {
return nil, fmt.Errorf("failed to decode basic-auth credential: %w", err)
}
if res.Username == nil {
return nil, fmt.Errorf("basic-auth is invalid: no username")
}
return &res, nil
}
func NewACLGroup(config interface{}) (*ACLGroup, error) {
var res ACLGroup
err := decodeCredential(config, &res.ACLGroup)
if err != nil {
return nil, fmt.Errorf("failed to process ACL group: %v", err)
}
if res.Group == nil {
return nil, fmt.Errorf("acl is invalid: no group")
}
return &res, nil
}
func NewOauth2Credential(config interface{}) (*Oauth2Credential, error) {
var res Oauth2Credential
err := decodeCredential(config, &res.Oauth2Credential)
if err != nil {
return nil, fmt.Errorf("failed to decode oauth2 credential: %w", err)
}
if res.ClientID == nil {
return nil, fmt.Errorf("oauth2 is invalid: no client_id")
}
if res.Name == nil {
return nil, fmt.Errorf("oauth2 is invalid: no name")
}
return &res, nil
}
func NewMTLSAuth(config interface{}) (*MTLSAuth, error) {
var res MTLSAuth
err := decodeCredential(config, &res.MTLSAuth)
if err != nil {
return nil, fmt.Errorf("failed to decode mTLS credential: %w", err)
}
if res.SubjectName == nil {
return nil, fmt.Errorf("mtls-auth is invalid: no subject_name")
}
return &res, nil
}
// SanitizedCopy returns a shallow copy with sensitive values redacted best-effort.
func (c *KeyAuth) SanitizedCopy() *KeyAuth {
return &KeyAuth{
kong.KeyAuth{
// Consumer field omitted
CreatedAt: c.CreatedAt,
ID: c.ID,
Key: redactedString,
Tags: c.Tags,
},
}
}
// SanitizedCopy returns a shallow copy with sensitive values redacted best-effort.
func (c *HMACAuth) SanitizedCopy() *HMACAuth {
return &HMACAuth{
kong.HMACAuth{
// Consumer field omitted
CreatedAt: c.CreatedAt,
ID: c.ID,
Username: c.Username,
Secret: redactedString,
Tags: c.Tags,
},
}
}
// SanitizedCopy returns a shallow copy with sensitive values redacted best-effort.
func (c *JWTAuth) SanitizedCopy() *JWTAuth {
return &JWTAuth{
kong.JWTAuth{
// Consumer field omitted
CreatedAt: c.CreatedAt,
ID: c.ID,
Algorithm: c.Algorithm,
Key: c.Key, // despite field name, "key" is an identifier
RSAPublicKey: c.RSAPublicKey,
Secret: redactedString,
Tags: c.Tags,
},
}
}
// SanitizedCopy returns a shallow copy with sensitive values redacted best-effort.
func (c *BasicAuth) SanitizedCopy() *BasicAuth {
return &BasicAuth{
kong.BasicAuth{
// Consumer field omitted
CreatedAt: c.CreatedAt,
ID: c.ID,
Username: c.Username,
Password: redactedString,
Tags: c.Tags,
},
}
}
// SanitizedCopy returns a shallow copy with sensitive values redacted best-effort.
func (c *Oauth2Credential) SanitizedCopy() *Oauth2Credential {
return &Oauth2Credential{
kong.Oauth2Credential{
// Consumer field omitted
CreatedAt: c.CreatedAt,
ID: c.ID,
Name: c.Name,
ClientID: c.ClientID,
ClientSecret: redactedString,
RedirectURIs: c.RedirectURIs,
Tags: c.Tags,
},
}
}
func decodeCredential(credConfig interface{},
credStructPointer interface{}) error {
decoder, err := mapstructure.NewDecoder(
&mapstructure.DecoderConfig{TagName: "json",
Result: credStructPointer,
})
if err != nil {
return fmt.Errorf("failed to create a decoder: %w", err)
}
err = decoder.Decode(credConfig)
if err != nil {
return fmt.Errorf("failed to decode credential: %w", err)
}
return nil
}