8000 [Feature] [Platform] Cookie Auth (#1864) · arangodb/kube-arangodb@335922d · GitHub
[go: up one dir, main page]

Skip 8000 to content

Commit 335922d

Browse files
authored
[Feature] [Platform] Cookie Auth (#1864)
1 parent aa7f64e commit 335922d

35 files changed

+627
-214
lines changed

.golangci.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,18 @@ linters-settings:
143143
pkg: github.com/arangodb/kube-arangodb/pkg/util/k8sutil/tls
144144
- alias: pbEnvoyAuthV3
145145
pkg: github.com/envoyproxy/go-control-plane/envoy/service/auth/v3
146+
- alias: pbEnvoyBootstrapV3
147+
pkg: github.com/envoyproxy/go-control-plane/envoy/config/bootstrap/v3
148+
- alias: pbEnvoyClusterV3
149+
pkg: github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3
150+
- alias: pbEnvoyCoreV3
151+
pkg: github.com/envoyproxy/go-control-plane/envoy/config/core/v3
152+
- alias: pbEnvoyEndpointV3
153+
pkg: github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3
154+
- alias: pbEnvoyListenerV3
155+
pkg: github.com/envoyproxy/go-control-plane/envoy/config/listener/v3
156+
- alias: pbEnvoyRouteV3
157+
pkg: github.com/envoyproxy/go-control-plane/envoy/config/route/v3
146158
- alias: apps
147159
pkg: k8s.io/api/apps/v1
148160
- alias: batch

docs/api/ArangoDeployment.V1.md

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3092,14 +3092,34 @@ Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.
30923092

30933093
***
30943094

3095+
### .spec.gateway.cookiesSupport
3096+
3097+
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/deployment/v1/deployment_spec_gateway.go#L49)</sup>
3098+
3099+
CookiesSupport defines if Cookie based authentication via `X-ArangoDB-Token-JWT`
3100+
3101+
Default Value: `true`
3102+
3103+
***
3104+
3105+
### .spec.gateway.defaultTargetAuthentication
3106+
3107+
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/deployment/v1/deployment_spec_gateway.go#L53)</sup>
3108+
3109+
DefaultTargetAuthentication defines if default endpoints check authentication via envoy (Cookie and Header based auth)
3110+
3111+
Default Value: `true`
3112+
3113+
***
3114+
30953115
### .spec.gateway.dynamic
30963116

30973117
Type: `boolean` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/deployment/v1/deployment_spec_gateway.go#L41)</sup>
30983118

30993119
Dynamic setting enables/disables support dynamic configuration of the gateway in the cluster.
31003120
When enabled, gateway config will be reloaded by ConfigMap live updates.
31013121

3102-
Default Value: `false`
3122+
Default Value: `true`
31033123

31043124
***
31053125

@@ -3125,7 +3145,7 @@ By default, the image is determined by the operator.
31253145

31263146
### .spec.gateway.timeout
31273147

3128-
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/deployment/v1/deployment_spec_gateway.go#L50)</sup>
3148+
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.47/pkg/apis/deployment/v1/deployment_spec_gateway.go#L58)</sup>
31293149

31303150
Timeout defines default timeout for the upstream actions (if not overridden)
31313151

docs/cli/arangodb_operator_integration.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ Flags:
4444
--integration.config.v1.internal Defones if Internal access to service config.v1 is enabled (Env: INTEGRATION_CONFIG_V1_INTERNAL) (default true)
4545
--integration.config.v1.module strings Module in the reference <name>=<abs path> (Env: INTEGRATION_CONFIG_V1_MODULE)
4646
--integration.envoy.auth.v3 Enable EnvoyAuthV3 Integration Service (Env: INTEGRATION_ENVOY_AUTH_V3)
47+
--integration.envoy.auth.v3.extensions.cookie.jwt Defines if Cookie JWT extension is enabled (Env: INTEGRATION_ENVOY_AUTH_V3_EXTENSIONS_COOKIE_JWT) (default true)
48+
--integration.envoy.auth.v3.extensions.jwt Defines if JWT extension is enabled (Env: INTEGRATION_ENVOY_AUTH_V3_EXTENSIONS_JWT) (default true)
4749
--integration.envoy.auth.v3.external Defones if External access to service envoy.auth.v3 is enabled (Env: INTEGRATION_ENVOY_AUTH_V3_EXTERNAL)
4850
--integration.envoy.auth.v3.internal Defones if Internal access to service envoy.auth.v3 is enabled (Env: INTEGRATION_ENVOY_AUTH_V3_INTERNAL) (default true)
4951
--integration.scheduler.v1 SchedulerV1 Integration (Env: INTEGRATION_SCHEDULER_V1)

integrations/envoy/auth/v3/adb_helper.go

Lines changed: 12 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@ import (
2929

3030
pbAuthenticationV1 "github.com/arangodb/kube-arangodb/integrations/authentication/v1/definition"
3131
"github.com/arangodb/kube-arangodb/pkg/util"
32+
"github.com/arangodb/kube-arangodb/pkg/util/cache"
3233
)
3334

3435
const (
@@ -39,7 +40,12 @@ const (
3940
func NewADBHelper(client pbAuthenticationV1.AuthenticationV1Client) ADBHelper {
4041
return &adbHelper{
4142
client: client,
42-
cache: map[string]adbHelperToken{},
43+
cache: cache.NewCache(func(ctx context.Context, in string) (*pbAuthenticationV1.CreateTokenResponse, error) {
44+
return client.CreateToken(ctx, &pbAuthenticationV1.CreateTokenRequest{
45+
Lifetime: durationpb.New(DefaultLifetime),
46+
User: util.NewType(in),
47+
})
48+
}, DefaultTTL),
4349
}
4450
}
4551

@@ -48,14 +54,9 @@ type ADBHelper interface {
4854
Token(ctx context.Context, resp *AuthResponse) (string, bool, error)
4955
}
5056

51-
type adbHelperToken struct {
52-
TTL time.Time
53-
Token string
54-
}
55-
5657
type adbHelper struct {
5758
lock sync.Mutex
58-
cache map[string]adbHelperToken
59+
cache cache.Cache[string, *pbAuthenticationV1.CreateTokenResponse]
5960

6061
client pbAuthenticationV1.AuthenticationV1Client
6162
}
@@ -69,31 +70,12 @@ func (a *adbHelper) Token(ctx context.Context, resp *AuthResponse) (string, bool
6970
return "", false, nil
7071
}
7172

72-
v, ok := a.cache[resp.Username]
73-
if ok {
74-
// We received token
75-
if time.No 8000 w().Before(v.TTL) {
76-
return v.Token, true, nil
77-
}
78-
// Token has been expired
79-
delete(a.cache, resp.Username)
80-
}
81-
82-
// We did not receive token, create one
83-
auth, err := a.client.CreateToken(ctx, &pbAuthenticationV1.CreateTokenRequest{
84-
Lifetime: durationpb.New(DefaultLifetime),
85-
User: util.NewType(resp.Username),
86-
})
73+
token, err := a.cache.Get(ctx, resp.Username)
8774
if err != nil {
8875
return "", false, err
8976
}
9077

91-
a.cache[resp.Username] = adbHelperToken{
92-
TTL: time.Now().Add(DefaultTTL),
93-
Token: auth.GetToken(),
94-
}
95-
96-
return auth.GetToken(), true, nil
78+
return token.GetToken(), true, nil
9779
}
9880

9981
func (a *adbHelper) Validate(ctx context.Context, token string) (*AuthResponse, error) {
@@ -112,6 +94,7 @@ func (a *adbHelper) Validate(ctx context.Context, token string) (*AuthResponse,
11294
if det := resp.GetDetails(); det != nil {
11395
return &AuthResponse{
11496
Username: det.GetUser(),
97+
Token: util.NewType(token),
11598
}, nil
11699
}
117100
}

integrations/envoy/auth/v3/check.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -23,11 +23,18 @@ package v3
2323
import (
2424
"context"
2525

26+
pbEnvoyCoreV3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
2627
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
2728
)
2829

2930
type AuthResponse struct {
3031
Username string
32+
33+
Token *string
34+
35+
CustomResponse *pbEnvoyAuthV3.CheckResponse
36+
37+
Headers []*pbEnvoyCoreV3.HeaderValueOption
3138
}
3239

3340
type AuthRequestFunc func(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest, current *AuthResponse) (*AuthResponse, error)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package v3
22+
23+
import (
24+
"context"
25+
goHttp "net/http"
26+
27+
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
28+
)
29+
30+
const JWTAuthorizationCookieName = "X-ArangoDB-Token-JWT"
31+
32+
func (i *impl) checkADBJWTCookie(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest, current *AuthResponse) (*AuthResponse, error) {
33+
if current != nil {
34+
// Already authenticated
35+
return current, nil
36+
}
37+
38+
rawCookies := request.GetAttributes().GetRequest().GetHttp().GetHeaders()["cookie"]
39+
// Convert raw cookie string into map of http cookies
40+
header := goHttp.Header{}
41+
header.Add("Cookie", rawCookies)
42+
req := goHttp.Request{Header: header}
43+
cookies := req.Cookies()
44+
45+
for _, cookie := range cookies {
46+
if cookie != nil {
47+
if cookie.Valid() != nil {
48+
continue
49+
}
50+
if cookie.Name == JWTAuthorizationCookieName {
51+
resp, err := i.helper.Validate(ctx, cookie.Value)
52+
if err != nil {
53+
logger.Err(err).Warn("Auth failure")
54+
return nil, nil
55+
}
56+
57+
if resp == nil {
58+
return nil, nil
59+
}
60+
61+
resp.Headers = filterCookiesHeader(cookies, func(cookie *goHttp.Cookie) bool {
62+
return cookie.Valid() != nil
63+
}, func(cookie *goHttp.Cookie) bool {
64+
return cookie.Name == JWTAuthorizationCookieName
65+
})
66+
67+
return resp, nil
68+
}
69+
}
70+
}
71+
72+
return nil, nil
73+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package v3
22+
23+
import pbAuthenticationV1 "github.com/arangodb/kube-arangodb/integrations/authentication/v1/definition"
24+
25+
type Configuration struct {
26+
AuthClient pbAuthenticationV1.AuthenticationV1Client
27+
28+
Extensions ConfigurationExtensions
29+
}
30+
31+
type ConfigurationExtensions struct {
32+
JWT bool
33+
CookieJWT bool
34+
}

integrations/envoy/auth/v3/consts.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -37,4 +37,7 @@ const (
3737

3838
AuthUsernameHeader = "arangodb-platform-user"
3939
AuthAuthenticatedHeader = "arangodb-platform-authenticated"
40+
41+
AuthorizationHeader = "Authorization"
42+
CookieHeader = "Cookie"
4043
)

integrations/envoy/auth/v3/cookies.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package v3
22+
23+
import (
24+
goHttp "net/http"
25+
26+
pbEnvoyCoreV3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
27+
28+
"github.com/arangodb/kube-arangodb/pkg/util"
29+
)
30+
31+
func filterCookiesHeader(cookies []*goHttp.Cookie, filter ...func(cookie *goHttp.Cookie) bool) []*pbEnvoyCoreV3.HeaderValueOption {
32+
if len(cookies) == 0 {
33+
return nil
34+
}
35+
36+
filteredCookies := util.FilterList(cookies, util.MultiFilterList(filter...))
37+
38+
if len(filteredCookies) == 0 {
39+
return nil
40+
}
41+
42+
cookieStrings := util.FormatList(filteredCookies, func(a *goHttp.Cookie) string {
43+
return a.String()
44+
})
45+
46+
var r []*pbEnvoyCoreV3.HeaderValueOption
47+
48+
r = append(r, &pbEnvoyCoreV3.HeaderValueOption{
49+
Header: &pbEnvoyCoreV3.HeaderValue{
50+
Key: CookieHeader,
51+
},
52+
AppendAction: pbEnvoyCoreV3.HeaderValueOption_OVERWRITE_IF_EXISTS,
53+
KeepEmptyValue: false,
54+
})
55+
56+
for _, v := range cookieStrings {
57+
r = append(r, &pbEnvoyCoreV3.HeaderValueOption{
58+
Header: &pbEnvoyCoreV3.HeaderValue{
59+
Key: CookieHeader,
60+
Value: v,
61+
},
62+
AppendAction: pbEnvoyCoreV3.HeaderValueOption_APPEND_IF_EXISTS_OR_ADD,
63+
})
64+
}
65+
66+
return r
67+
}

0 commit comments

Comments
 (0)
0