1
0
Fork 0
mirror of https://github.com/arangodb/kube-arangodb.git synced 2024-12-14 11:57:37 +00:00

[Feature] [Gateway] ArangoDB AuthIntegration (#1715)

This commit is contained in:
Adam Janikowski 2024-09-03 17:50:59 +02:00 committed by GitHub
parent 81dfd87566
commit fb2ac883ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 792 additions and 47 deletions

View file

@ -23,6 +23,7 @@
- (Feature) Integration Service TLS - (Feature) Integration Service TLS
- (Feature) (Gateway) SNI and Authz support - (Feature) (Gateway) SNI and Authz support
- (Maintenance) Bump Examples to ArangoDB 3.12 - (Maintenance) Bump Examples to ArangoDB 3.12
- (Feature) (Gateway) ArangoDB JWT Auth Integration
## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23) ## [1.2.42](https://github.com/arangodb/kube-arangodb/tree/1.2.42) (2024-07-23)
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries - (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries

View file

@ -1,7 +1,7 @@
// //
// DISCLAIMER // DISCLAIMER
// //
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany // Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -21,8 +21,6 @@
package cmd package cmd
import ( import (
"fmt"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/arangodb/kube-arangodb/pkg/version" "github.com/arangodb/kube-arangodb/pkg/version"
@ -38,6 +36,5 @@ var cmdVersion = &cobra.Command{
} }
func versionRun(cmd *cobra.Command, args []string) { func versionRun(cmd *cobra.Command, args []string) {
v := version.GetVersionV1() println(version.GetVersionV1().String())
println(fmt.Sprintf("Version: %s %s, Build: %s, Go: %s, Build Date: %s", v.Edition.Title(), v.Version, v.Build, v.GoVersion, v.BuildDate))
} }

View file

@ -16,6 +16,12 @@ Deployment specifies the ArangoDeployment object name
*** ***
### .spec.destination.authentication.type
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec_destination_authentication.go#L28)</sup>
***
### .spec.destination.path ### .spec.destination.path
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec_destination.go#L36)</sup> Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec_destination.go#L36)</sup>
@ -131,6 +137,12 @@ UID keeps the information about object UID
*** ***
### .status.target.authentication.type
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_authentication.go#L26)</sup>
***
### .status.target.destinations\[int\].host ### .status.target.destinations\[int\].host
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_destination.go#L38)</sup> Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_destination.go#L38)</sup>
@ -145,7 +157,7 @@ Type: `integer` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.
### .status.target.path ### .status.target.path
Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target.go#L37)</sup> Type: `string` <sup>[\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target.go#L40)</sup>
Path specifies request path override Path specifies request path override

View file

@ -0,0 +1,46 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v3
import (
"context"
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
)
type AuthResponse struct {
Username string
}
type AuthRequestFunc func(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest, current *AuthResponse) (*AuthResponse, error)
func MergeAuthRequest(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest, requests ...AuthRequestFunc) (*AuthResponse, error) {
var resp *AuthResponse
for _, r := range requests {
if v, err := r(ctx, request, resp); err != nil {
return nil, err
} else {
resp = v
}
}
return resp, nil
}

View file

@ -0,0 +1,60 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v3
import (
"context"
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
pbAuthenticationV1 "github.com/arangodb/kube-arangodb/integrations/authentication/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util/strings"
)
func (i *impl) checkADBJWT(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest, current *AuthResponse) (*AuthResponse, error) {
if current != nil {
// Already authenticated
return current, nil
}
if auth, ok := request.GetAttributes().GetRequest().GetHttp().GetHeaders()["authorization"]; ok {
parts := strings.SplitN(auth, " ", 2)
if len(parts) == 2 {
if strings.ToLower(parts[0]) == "bearer" {
resp, err := i.authClient.Validate(ctx, &pbAuthenticationV1.ValidateRequest{
Token: parts[1],
})
if err != nil {
logger.Err(err).Warn("Auth failure")
return nil, nil
}
if err == nil && resp.GetIsValid() {
// All went fine!
return &AuthResponse{
Username: resp.GetDetails().GetUser(),
}, nil
}
}
}
}
return nil, nil
}

View file

@ -22,4 +22,18 @@ package v3
const ( const (
Name = "envoy.auth.v3" Name = "envoy.auth.v3"
AuthConfigKeywordTrue = "true"
AuthConfigKeywordFalse = "false"
AuthConfigNamespace = "platform.arangodb.com"
AuthConfigAuthNamespace = "auth." + AuthConfigNamespace
AuthConfigTypeKey = AuthConfigNamespace + "/type"
AuthConfigTypeValue = "ArangoDBPlatform"
AuthConfigAuthRequiredKey = AuthConfigAuthNamespace + "/required"
AuthUsernameHeader = "arangodb-platform-user"
AuthAuthenticatedHeader = "arangodb-platform-authenticated"
) )

View file

@ -22,15 +22,23 @@ package v3
import ( import (
"context" "context"
"net/http"
corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
"google.golang.org/grpc" "google.golang.org/grpc"
pbAuthenticationV1 "github.com/arangodb/kube-arangodb/integrations/authentication/v1/definition"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/errors/panics"
"github.com/arangodb/kube-arangodb/pkg/util/svc" "github.com/arangodb/kube-arangodb/pkg/util/svc"
) )
func New() svc.Handler { func New(authClient pbAuthenticationV1.AuthenticationV1Client) svc.Handler {
return &impl{} return &impl{
authClient: authClient,
}
} }
var _ pbEnvoyAuthV3.AuthorizationServer = &impl{} var _ pbEnvoyAuthV3.AuthorizationServer = &impl{}
@ -38,6 +46,8 @@ var _ svc.Handler = &impl{}
type impl struct { type impl struct {
pbEnvoyAuthV3.UnimplementedAuthorizationServer pbEnvoyAuthV3.UnimplementedAuthorizationServer
authClient pbAuthenticationV1.AuthenticationV1Client
} }
func (i *impl) Name() string { func (i *impl) Name() string {
@ -53,10 +63,84 @@ func (i *impl) Register(registrar *grpc.Server) {
} }
func (i *impl) Check(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest) (*pbEnvoyAuthV3.CheckResponse, error) { func (i *impl) Check(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest) (*pbEnvoyAuthV3.CheckResponse, error) {
logger.Info("Request Received") resp, err := panics.RecoverO1(func() (*pbEnvoyAuthV3.CheckResponse, error) {
return i.check(ctx, request)
})
if err != nil {
var v DeniedResponse
if errors.As(err, &v) {
return v.GetCheckResponse()
}
return nil, err
}
return resp, nil
}
func (i *impl) check(ctx context.Context, request *pbEnvoyAuthV3.CheckRequest) (*pbEnvoyAuthV3.CheckResponse, error) {
ext := request.GetAttributes().GetContextExtensions()
if v, ok := ext[AuthConfigTypeKey]; !ok || v != AuthConfigTypeValue {
return nil, DeniedResponse{
Code: http.StatusBadRequest,
Message: &DeniedMessage{
Message: "Auth plugin is not enabled for this request",
},
}
}
authenticated, err := MergeAuthRequest(ctx, request, i.checkADBJWT)
if err != nil {
return nil, err
}
if util.Optional(ext, AuthConfigAuthRequiredKey, AuthConfigKeywordFalse) == AuthConfigKeywordTrue && authenticated == nil {
return nil, DeniedResponse{
Code: http.StatusUnauthorized,
Message: &DeniedMessage{
Message: "Unauthorized",
},
}
}
if authenticated != nil {
return &pbEnvoyAuthV3.CheckResponse{
HttpResponse: &pbEnvoyAuthV3.CheckResponse_OkResponse{
OkResponse: &pbEnvoyAuthV3.OkHttpResponse{
Headers: []*corev3.HeaderValueOption{
{
Header: &corev3.HeaderValue{
Key: AuthUsernameHeader,
Value: authenticated.Username,
},
AppendAction: corev3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
},
{
Header: &corev3.HeaderValue{
Key: AuthAuthenticatedHeader,
Value: "true",
},
AppendAction: corev3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
},
},
},
},
}, nil
}
return &pbEnvoyAuthV3.CheckResponse{ return &pbEnvoyAuthV3.CheckResponse{
HttpResponse: &pbEnvoyAuthV3.CheckResponse_OkResponse{ HttpResponse: &pbEnvoyAuthV3.CheckResponse_OkResponse{
OkResponse: &pbEnvoyAuthV3.OkHttpResponse{}, OkResponse: &pbEnvoyAuthV3.OkHttpResponse{
Headers: []*corev3.HeaderValueOption{
{
Header: &corev3.HeaderValue{
Key: AuthAuthenticatedHeader,
Value: "false",
},
AppendAction: corev3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
},
},
},
}, },
}, nil }, nil
} }

View file

@ -0,0 +1,85 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v3
import (
"encoding/json"
"fmt"
corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
typev3 "github.com/envoyproxy/go-control-plane/envoy/type/v3"
status "google.golang.org/genproto/googleapis/rpc/status"
)
type DeniedMessage struct {
Message string `json:"message,omitempty"`
}
type DeniedResponse struct {
Code int32
Headers map[string]string
Message *DeniedMessage
}
func (d DeniedResponse) Error() string {
return fmt.Sprintf("Request denied with code: %d", d.Code)
}
func (d DeniedResponse) GetCheckResponse() (*pbEnvoyAuthV3.CheckResponse, error) {
var resp pbEnvoyAuthV3.DeniedHttpResponse
for k, v := range d.Headers {
resp.Headers = append(resp.Headers, &corev3.HeaderValueOption{
Header: &corev3.HeaderValue{
Key: k,
Value: v,
},
AppendAction: corev3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
})
}
if data := d.Message; data != nil {
z, err := json.Marshal(data)
if err != nil {
return nil, err
}
resp.Body = string(z)
resp.Headers = append(resp.Headers, &corev3.HeaderValueOption{
Header: &corev3.HeaderValue{
Key: "content/type",
Value: "application/json",
},
AppendAction: corev3.HeaderValueOption_OVERWRITE_IF_EXISTS_OR_ADD,
})
}
resp.Status = &typev3.HttpStatus{
Code: typev3.StatusCode(d.Code),
}
return &pbEnvoyAuthV3.CheckResponse{
HttpResponse: &pbEnvoyAuthV3.CheckResponse_DeniedResponse{DeniedResponse: &resp},
Status: &status.Status{
Code: d.Code,
}}, nil
}

View file

@ -22,6 +22,7 @@ package v3
import ( import (
"context" "context"
"net/http"
"testing" "testing"
pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3" pbEnvoyAuthV3 "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
@ -35,7 +36,7 @@ import (
func Client(t *testing.T, ctx context.Context) pbEnvoyAuthV3.AuthorizationClient { func Client(t *testing.T, ctx context.Context) pbEnvoyAuthV3.AuthorizationClient {
local := svc.NewService(svc.Configuration{ local := svc.NewService(svc.Configuration{
Address: "127.0.0.1:0", Address: "127.0.0.1:0",
}, New()) }, New(nil))
start := local.Start(ctx) start := local.Start(ctx)
@ -44,7 +45,7 @@ func Client(t *testing.T, ctx context.Context) pbEnvoyAuthV3.AuthorizationClient
return client return client
} }
func Test_AllowAll(t *testing.T) { func Test_DenyHeader(t *testing.T) {
ctx, c := context.WithCancel(context.Background()) ctx, c := context.WithCancel(context.Background())
defer c() defer c()
@ -53,8 +54,28 @@ func Test_AllowAll(t *testing.T) {
resp, err := client.Check(ctx, &pbEnvoyAuthV3.CheckRequest{}) resp, err := client.Check(ctx, &pbEnvoyAuthV3.CheckRequest{})
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, resp.Validate()) require.NoError(t, resp.Validate())
require.NotNil(t, resp.Status)
require.NotNil(t, resp.HttpResponse)
require.NotNil(t, tests.CastAs[*pbEnvoyAuthV3.CheckResponse_DeniedResponse](t, resp.GetHttpResponse()).DeniedResponse)
require.EqualValues(t, http.StatusBadRequest, tests.CastAs[*pbEnvoyAuthV3.CheckResponse_DeniedResponse](t, resp.GetHttpResponse()).DeniedResponse.GetStatus().GetCode())
}
func Test_AllowAll(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
client := Client(t, ctx)
resp, err := client.Check(ctx, &pbEnvoyAuthV3.CheckRequest{
Attributes: &pbEnvoyAuthV3.AttributeContext{
ContextExtensions: map[string]string{
AuthConfigTypeKey: AuthConfigTypeValue,
},
},
})
require.NoError(t, err)
require.NoError(t, resp.Validate())
require.Nil(t, resp.Status) require.Nil(t, resp.Status)
require.NotNil(t, resp.HttpResponse) require.NotNil(t, resp.HttpResponse)
require.NotNil(t, tests.CastAs[*pbEnvoyAuthV3.CheckResponse_OkResponse](t, resp.GetHttpResponse()).OkResponse) require.NotNil(t, tests.CastAs[*pbEnvoyAuthV3.CheckResponse_OkResponse](t, resp.GetHttpResponse()).OkResponse)
require.Nil(t, resp.DynamicMetadata)
} }

View file

@ -0,0 +1,62 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1alpha1
import (
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
type ArangoRouteSpecAuthenticationType string
const (
ArangoRouteSpecAuthenticationTypeRequired ArangoRouteSpecAuthenticationType = "required"
ArangoRouteSpecAuthenticationTypeOptional ArangoRouteSpecAuthenticationType = "optional"
)
func (a *ArangoRouteSpecAuthenticationType) Get() ArangoRouteSpecAuthenticationType {
if a == nil {
return ArangoRouteSpecAuthenticationTypeOptional
}
switch v := *a; v {
case ArangoRouteSpecAuthenticationTypeOptional, ArangoRouteSpecAuthenticationTypeRequired:
return v
}
return ""
}
func (a *ArangoRouteSpecAuthenticationType) Validate() error {
switch v := a.Get(); v {
case ArangoRouteSpecAuthenticationTypeOptional, ArangoRouteSpecAuthenticationTypeRequired:
return nil
default:
return errors.Errorf("Invalid AuthType: %s", v)
}
}
func (a *ArangoRouteSpecAuthenticationType) Hash() string {
if a == nil {
return ""
}
return util.SHA256FromString(string(*a))
}

View file

@ -34,6 +34,9 @@ type ArangoRouteSpecDestination struct {
// Path defines service path used for overrides // Path defines service path used for overrides
Path *string `json:"path,omitempty"` Path *string `json:"path,omitempty"`
// Authentication defines auth methods
Authentication *ArangoRouteSpecDestinationAuthentication `json:"authentication,omitempty"`
} }
func (a *ArangoRouteSpecDestination) GetService() *ArangoRouteSpecDestinationService { func (a *ArangoRouteSpecDestination) GetService() *ArangoRouteSpecDestinationService {
@ -68,6 +71,14 @@ func (a *ArangoRouteSpecDestination) GetTLS() *ArangoRouteSpecDestinationTLS {
return a.TLS return a.TLS
} }
func (a *ArangoRouteSpecDestination) GetAuthentication() *ArangoRouteSpecDestinationAuthentication {
if a == nil || a.Authentication == nil {
return nil
}
return a.Authentication
}
func (a *ArangoRouteSpecDestination) Validate() error { func (a *ArangoRouteSpecDestination) Validate() error {
if a == nil { if a == nil {
a = &ArangoRouteSpecDestination{} a = &ArangoRouteSpecDestination{}
@ -77,6 +88,7 @@ func (a *ArangoRouteSpecDestination) Validate() error {
shared.ValidateOptionalInterfacePath("service", a.Service), shared.ValidateOptionalInterfacePath("service", a.Service),
shared.ValidateOptionalInterfacePath("schema", a.Schema), shared.ValidateOptionalInterfacePath("schema", a.Schema),
shared.ValidateOptionalInterfacePath("tls", a.TLS), shared.ValidateOptionalInterfacePath("tls", a.TLS),
shared.ValidateOptionalInterfacePath("authentication", a.Authentication),
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())), shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),
); err != nil { ); err != nil {
return err return err

View file

@ -0,0 +1,47 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1alpha1
import (
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
)
type ArangoRouteSpecDestinationAuthentication struct {
Type *ArangoRouteSpecAuthenticationType `json:"type,omitempty"`
}
func (a *ArangoRouteSpecDestinationAuthentication) GetType() ArangoRouteSpecAuthenticationType {
if a == nil {
return ArangoRouteSpecAuthenticationTypeOptional
}
return a.Type.Get()
}
func (a *ArangoRouteSpecDestinationAuthentication) Validate() error {
if a == nil {
return nil
}
return shared.WithErrors(
shared.ValidateOptionalInterfacePath("type", a.Type),
)
}

View file

@ -33,6 +33,9 @@ type ArangoRouteStatusTarget struct {
// TLS Keeps target TLS Settings (if not nil, TLS is enabled) // TLS Keeps target TLS Settings (if not nil, TLS is enabled)
TLS *ArangoRouteStatusTargetTLS `json:"TLS,omitempty"` TLS *ArangoRouteStatusTargetTLS `json:"TLS,omitempty"`
// Authentication specifies the authentication details
Authentication ArangoRouteStatusTargetAuthentication `json:"authentication,omitempty"`
// Path specifies request path override // Path specifies request path override
Path string `json:"path,omitempty"` Path string `json:"path,omitempty"`
} }
@ -61,5 +64,5 @@ func (a *ArangoRouteStatusTarget) Hash() string {
if a == nil { if a == nil {
return "" return ""
} }
return util.SHA256FromStringArray(a.Destinations.Hash(), a.TLS.Hash(), a.Path) return util.SHA256FromStringArray(a.Destinations.Hash(), a.TLS.Hash(), a.Path, a.Authentication.Hash())
} }

View file

@ -0,0 +1,34 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package v1alpha1
import "github.com/arangodb/kube-arangodb/pkg/util"
type ArangoRouteStatusTargetAuthentication struct {
Type ArangoRouteSpecAuthenticationType `json:"type,omitempty"`
}
func (a *ArangoRouteStatusTargetAuthentication) Hash() string {
if a == nil {
return ""
}
return util.SHA256FromStringArray(a.Type.Hash())
}

View file

@ -26,7 +26,7 @@
package v1alpha1 package v1alpha1
import ( import (
v2alpha1 "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" deploymentv1 "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
v1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1" v1 "github.com/arangodb/kube-arangodb/pkg/apis/shared/v1"
runtime "k8s.io/apimachinery/pkg/runtime" runtime "k8s.io/apimachinery/pkg/runtime"
intstr "k8s.io/apimachinery/pkg/util/intstr" intstr "k8s.io/apimachinery/pkg/util/intstr"
@ -147,6 +147,11 @@ func (in *ArangoRouteSpecDestination) DeepCopyInto(out *ArangoRouteSpecDestinati
*out = new(string) *out = new(string)
**out = **in **out = **in
} }
if in.Authentication != nil {
in, out := &in.Authentication, &out.Authentication
*out = new(ArangoRouteSpecDestinationAuthentication)
(*in).DeepCopyInto(*out)
}
return return
} }
@ -160,6 +165,27 @@ func (in *ArangoRouteSpecDestination) DeepCopy() *ArangoRouteSpecDestination {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteSpecDestinationAuthentication) DeepCopyInto(out *ArangoRouteSpecDestinationAuthentication) {
*out = *in
if in.Type != nil {
in, out := &in.Type, &out.Type
*out = new(ArangoRouteSpecAuthenticationType)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteSpecDestinationAuthentication.
func (in *ArangoRouteSpecDestinationAuthentication) DeepCopy() *ArangoRouteSpecDestinationAuthentication {
if in == nil {
return nil
}
out := new(ArangoRouteSpecDestinationAuthentication)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteSpecDestinationService) DeepCopyInto(out *ArangoRouteSpecDestinationService) { func (in *ArangoRouteSpecDestinationService) DeepCopyInto(out *ArangoRouteSpecDestinationService) {
*out = *in *out = *in
@ -233,7 +259,7 @@ func (in *ArangoRouteStatus) DeepCopyInto(out *ArangoRouteStatus) {
*out = *in *out = *in
if in.Conditions != nil { if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions in, out := &in.Conditions, &out.Conditions
*out = make(v2alpha1.ConditionList, len(*in)) *out = make(deploymentv1.ConditionList, len(*in))
for i := range *in { for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i]) (*in)[i].DeepCopyInto(&(*out)[i])
} }
@ -274,6 +300,7 @@ func (in *ArangoRouteStatusTarget) DeepCopyInto(out *ArangoRouteStatusTarget) {
*out = new(ArangoRouteStatusTargetTLS) *out = new(ArangoRouteStatusTargetTLS)
(*in).DeepCopyInto(*out) (*in).DeepCopyInto(*out)
} }
out.Authentication = in.Authentication
return return
} }
@ -287,6 +314,22 @@ func (in *ArangoRouteStatusTarget) DeepCopy() *ArangoRouteStatusTarget {
return out return out
} }
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteStatusTargetAuthentication) DeepCopyInto(out *ArangoRouteStatusTargetAuthentication) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ArangoRouteStatusTargetAuthentication.
func (in *ArangoRouteStatusTargetAuthentication) DeepCopy() *ArangoRouteStatusTargetAuthentication {
if in == nil {
return nil
}
out := new(ArangoRouteStatusTargetAuthentication)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ArangoRouteStatusTargetDestination) DeepCopyInto(out *ArangoRouteStatusTargetDestination) { func (in *ArangoRouteStatusTargetDestination) DeepCopyInto(out *ArangoRouteStatusTargetDestination) {
*out = *in *out = *in

View file

@ -9,6 +9,12 @@ v1alpha1:
destination: destination:
description: Destination defines the route destination description: Destination defines the route destination
properties: properties:
authentication:
description: Authentication defines auth methods
properties:
type:
type: string
type: object
path: path:
description: Path defines service path used for overrides description: Path defines service path used for overrides
type: string type: string

View file

@ -30,6 +30,7 @@ import (
kerrors "k8s.io/apimachinery/pkg/api/errors" kerrors "k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1"
pbImplEnvoyAuthV3 "github.com/arangodb/kube-arangodb/integrations/envoy/auth/v3"
networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1" networkingApi "github.com/arangodb/kube-arangodb/pkg/apis/networking/v1alpha1"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared" shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/deployment/resources/gateway" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/gateway"
@ -131,6 +132,7 @@ func (r *Resources) renderGatewayConfig(cachedStatus inspectorInterface.Inspecto
Port: shared.ArangoPort, Port: shared.ArangoPort,
}, },
}, },
AuthExtension: &gateway.ConfigAuthZExtension{},
} }
if spec.TLS.IsSecure() { if spec.TLS.IsSecure() {
@ -193,6 +195,11 @@ func (r *Resources) renderGatewayConfig(cachedStatus inspectorInterface.Inspecto
dest.Type = util.NewType(gateway.ConfigDestinationTypeHTTPS) dest.Type = util.NewType(gateway.ConfigDestinationTypeHTTPS)
} }
dest.Path = util.NewType(target.Path) dest.Path = util.NewType(target.Path)
dest.AuthExtension = &gateway.ConfigAuthZExtension{
AuthZExtension: map[string]string{
pbImplEnvoyAuthV3.AuthConfigAuthRequiredKey: util.BoolSwitch(target.Authentication.Type.Get() == networkingApi.ArangoRouteSpecAuthenticationTypeRequired, pbImplEnvoyAuthV3.AuthConfigKeywordTrue, pbImplEnvoyAuthV3.AuthConfigKeywordFalse),
},
}
cfg.Destinations[at.Spec.GetRoute().GetPath()] = dest cfg.Destinations[at.Spec.GetRoute().GetPath()] = dest
} }

View file

@ -0,0 +1,67 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package gateway
import (
httpFilterAuthzApi "github.com/envoyproxy/go-control-plane/envoy/extensions/filters/http/ext_authz/v3"
"google.golang.org/protobuf/types/known/anypb"
pbImplEnvoyAuthV3 "github.com/arangodb/kube-arangodb/integrations/envoy/auth/v3"
"github.com/arangodb/kube-arangodb/pkg/util"
)
type ConfigAuthZExtension struct {
AuthZExtension map[string]string `json:"authZExtension,omitempty"`
}
func (c *ConfigAuthZExtension) RenderTypedFilterConfig() (util.KV[string, *anypb.Any], error) {
if c == nil {
return util.KV[string, *anypb.Any]{}, nil
}
var data = map[string]string{}
for k, v := range c.AuthZExtension {
data[k] = v
}
data[pbImplEnvoyAuthV3.AuthConfigTypeKey] = pbImplEnvoyAuthV3.AuthConfigTypeValue
q, err := anypb.New(&httpFilterAuthzApi.ExtAuthzPerRoute{
Override: &httpFilterAuthzApi.ExtAuthzPerRoute_CheckSettings{
CheckSettings: &httpFilterAuthzApi.CheckSettings{
ContextExtensions: data,
},
},
})
if err != nil {
return util.KV[string, *anypb.Any]{}, err
}
return util.KV[string, *anypb.Any]{
K: IntegrationSidecarFilterName,
V: q,
}, nil
}
func (c *ConfigAuthZExtension) Validate() error {
return nil
}

View file

@ -26,7 +26,6 @@ import (
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3" clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3"
routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" routeAPI "github.com/envoyproxy/go-control-plane/envoy/config/route/v3"
anypb "github.com/golang/protobuf/ptypes/any"
"google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/durationpb"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared" shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
@ -62,6 +61,8 @@ type ConfigDestination struct {
Type *ConfigDestinationType `json:"type,omitempty"` Type *ConfigDestinationType `json:"type,omitempty"`
Path *string `json:"path,omitempty"` Path *string `json:"path,omitempty"`
AuthExtension *ConfigAuthZExtension `json:"authExtension,omitempty"`
} }
func (c *ConfigDestination) Validate() error { func (c *ConfigDestination) Validate() error {
@ -72,6 +73,7 @@ func (c *ConfigDestination) Validate() error {
shared.PrefixResourceError("targets", c.Targets.Validate()), shared.PrefixResourceError("targets", c.Targets.Validate()),
shared.PrefixResourceError("type", c.Type.Validate()), shared.PrefixResourceError("type", c.Type.Validate()),
shared.PrefixResourceError("path", shared.ValidateAPIPath(c.GetPath())), shared.PrefixResourceError("path", shared.ValidateAPIPath(c.GetPath())),
shared.PrefixResourceError("authExtension", c.AuthExtension.Validate()),
) )
} }
@ -84,6 +86,16 @@ func (c *ConfigDestination) GetPath() string {
} }
func (c *ConfigDestination) RenderRoute(name, prefix string) (*routeAPI.Route, error) { func (c *ConfigDestination) RenderRoute(name, prefix string) (*routeAPI.Route, error) {
var tcg []TypedFilterConfigGen
if c != nil && c.AuthExtension != nil {
tcg = append(tcg, c.AuthExtension)
}
tc, err := NewTypedFilterConfig(tcg...)
if err != nil {
return nil, err
}
return &routeAPI.Route{ return &routeAPI.Route{
Match: &routeAPI.RouteMatch{ Match: &routeAPI.RouteMatch{
PathSpecifier: &routeAPI.RouteMatch_Prefix{ PathSpecifier: &routeAPI.RouteMatch_Prefix{
@ -98,7 +110,7 @@ func (c *ConfigDestination) RenderRoute(name, prefix string) (*routeAPI.Route, e
PrefixRewrite: c.GetPath(), PrefixRewrite: c.GetPath(),
}, },
}, },
TypedPerFilterConfig: map[string]*anypb.Any{}, TypedPerFilterConfig: tc,
}, nil }, nil
} }

View file

@ -0,0 +1,58 @@
//
// DISCLAIMER
//
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
//
// 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.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
package gateway
import (
"google.golang.org/protobuf/types/known/anypb"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
)
type TypedFilterConfigGen interface {
RenderTypedFilterConfig() (util.KV[string, *anypb.Any], error)
}
func NewTypedFilterConfig(gens ...TypedFilterConfigGen) (map[string]*anypb.Any, error) {
generated := map[string]*anypb.Any{}
for _, g := range gens {
if k, err := g.RenderTypedFilterConfig(); err != nil {
return nil, err
} else {
if _, ok := generated[k.K]; ok {
return nil, errors.Errorf("Duplicated key: %s", k.K)
}
if k.V == nil {
continue
}
generated[k.K] = k.V
}
}
if len(generated) == 0 {
return nil, nil
}
return generated, nil
}

View file

@ -238,9 +238,13 @@ func (m *MemberGatewayPod) Labels() map[string]string {
func (m *MemberGatewayPod) Profiles() (schedulerApi.ProfileTemplates, error) { func (m *MemberGatewayPod) Profiles() (schedulerApi.ProfileTemplates, error) {
integration, err := sidecar.NewIntegration(&schedulerContainerResourcesApi.Image{ integration, err := sidecar.NewIntegration(&schedulerContainerResourcesApi.Image{
Image: util.NewType(m.resources.context.GetOperatorImage()), Image: util.NewType(m.resources.context.GetOperatorImage()),
}, m.spec.Gateway.GetSidecar(), []string{shared.ServerContainerName}, sidecar.IntegrationEnvoyV3{ }, m.spec.Gateway.GetSidecar(), []string{shared.ServerContainerName},
Spec: m.spec, sidecar.IntegrationEnvoyV3{
}) Spec: m.spec,
}, sidecar.IntegrationAuthenticationV1{
DeploymentName: m.context.GetName(),
Spec: m.spec,
})
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -121,6 +121,10 @@ func (h *handler) HandleArangoDestination(ctx context.Context, item operation.It
target.Path = dest.GetPath() target.Path = dest.GetPath()
// Render Auth Settings
target.Authentication.Type = dest.GetAuthentication().GetType()
if dest.Schema.Get() == networkingApi.ArangoRouteSpecDestinationSchemaHTTPS { if dest.Schema.Get() == networkingApi.ArangoRouteSpecDestinationSchemaHTTPS {
target.TLS = &networkingApi.ArangoRouteStatusTargetTLS{ target.TLS = &networkingApi.ArangoRouteStatusTargetTLS{
Insecure: util.NewType(extension.Spec.Destination.GetTLS().GetInsecure()), Insecure: util.NewType(extension.Spec.Destination.GetTLS().GetInsecure()),

View file

@ -56,7 +56,7 @@ func (a *authenticationV1) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (a *authenticationV1) Handler(ctx context.Context) (svc.Handler, error) { func (a *authenticationV1) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
return pbImplAuthenticationV1.New(ctx, a.config) return pbImplAuthenticationV1.New(ctx, a.config)
} }
@ -67,3 +67,7 @@ func (a *authenticationV1) Name() string {
func (a *authenticationV1) Description() string { func (a *authenticationV1) Description() string {
return "Enable AuthenticationV1 Integration Service" return "Enable AuthenticationV1 Integration Service"
} }
func (*authenticationV1) Init(ctx context.Context, cmd *cobra.Command) error {
return nil
}

View file

@ -51,6 +51,10 @@ func (a authorizationV0) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (a authorizationV0) Handler(ctx context.Context) (svc.Handler, error) { func (a authorizationV0) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
return pbImplAuthorizationV0.New(), nil return pbImplAuthorizationV0.New(), nil
} }
func (a authorizationV0) Init(ctx context.Context, cmd *cobra.Command) error {
return nil
}

View file

@ -49,7 +49,7 @@ func (a *configV1) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (a *configV1) Handler(ctx context.Context) (svc.Handler, error) { func (a *configV1) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
var cfg pbImplConfigV1.Config var cfg pbImplConfigV1.Config
cfg.Modules = map[string]pbImplConfigV1.ModuleDefinition{} cfg.Modules = map[string]pbImplConfigV1.ModuleDefinition{}
@ -75,3 +75,7 @@ func (a *configV1) Name() string {
func (a *configV1) Description() string { func (a *configV1) Description() string {
return "Enable ConfigV1 Integration Service" return "Enable ConfigV1 Integration Service"
} }
func (*configV1) Init(ctx context.Context, cmd *cobra.Command) error {
return nil
}

View file

@ -25,7 +25,9 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
pbAuthenticationV1 "github.com/arangodb/kube-arangodb/integrations/authentication/v1/definition"
pbImplEnvoyAuthV3 "github.com/arangodb/kube-arangodb/integrations/envoy/auth/v3" pbImplEnvoyAuthV3 "github.com/arangodb/kube-arangodb/integrations/envoy/auth/v3"
"github.com/arangodb/kube-arangodb/pkg/util"
"github.com/arangodb/kube-arangodb/pkg/util/svc" "github.com/arangodb/kube-arangodb/pkg/util/svc"
) )
@ -42,14 +44,26 @@ func (a envoyAuthV3) Name() string {
return pbImplEnvoyAuthV3.Name return pbImplEnvoyAuthV3.Name
} }
func (a envoyAuthV3) Description() string { func (a *envoyAuthV3) Description() string {
return "Enable EnvoyAuthV3 Integration Service" return "Enable EnvoyAuthV3 Integration Service"
} }
func (a envoyAuthV3) Register(cmd *cobra.Command, arg ArgGen) error { func (a *envoyAuthV3) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (a envoyAuthV3) Handler(ctx context.Context) (svc.Handler, error) { func (a *envoyAuthV3) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
return pbImplEnvoyAuthV3.New(), nil f := cmd.Flags()
v, err := f.GetString("services.address")
if err != nil {
return nil, err
}
c, _, err := util.NewGRPCClient(ctx, pbAuthenticationV1.NewAuthenticationV1Client, v)
if err != nil {
return nil, err
}
return pbImplEnvoyAuthV3.New(c), nil
} }

View file

@ -38,7 +38,7 @@ type Integration interface {
Register(cmd *cobra.Command, arg ArgGen) error Register(cmd *cobra.Command, arg ArgGen) error
Handler(ctx context.Context) (svc.Handler, error) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error)
} }
type IntegrationEnablement interface { type IntegrationEnablement interface {

View file

@ -36,6 +36,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/util/errors" "github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/shutdown" "github.com/arangodb/kube-arangodb/pkg/util/shutdown"
"github.com/arangodb/kube-arangodb/pkg/util/svc" "github.com/arangodb/kube-arangodb/pkg/util/svc"
"github.com/arangodb/kube-arangodb/pkg/version"
) )
var registerer = util.NewRegisterer[string, Factory]() var registerer = util.NewRegisterer[string, Factory]()
@ -171,6 +172,8 @@ func (c *configuration) run(cmd *cobra.Command, args []string) error {
} }
func (c *configuration) runWithContext(ctx context.Context, cancel context.CancelFunc, cmd *cobra.Command) error { func (c *configuration) runWithContext(ctx context.Context, cancel context.CancelFunc, cmd *cobra.Command) error {
println(version.GetVersionV1().String())
healthConfig, err := c.health.Config() healthConfig, err := c.health.Config()
if err != nil { if err != nil {
return errors.Wrapf(err, "Unable to parse health config") return errors.Wrapf(err, "Unable to parse health config")
@ -214,7 +217,7 @@ func (c *configuration) runWithContext(ctx context.Context, cancel context.Cance
Info("Service discovered") Info("Service discovered")
if ok && (internalEnabled || externalEnabled) { if ok && (internalEnabled || externalEnabled) {
if svc, err := handler.Handler(ctx); err != nil { if svc, err := handler.Handler(ctx, cmd); err != nil {
return err return err
} else { } else {
if internalEnabled { if internalEnabled {

View file

@ -59,7 +59,7 @@ func (b *schedulerV1) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (b *schedulerV1) Handler(ctx context.Context) (svc.Handler, error) { func (b *schedulerV1) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
client, ok := kclient.GetDefaultFactory().Client() client, ok := kclient.GetDefaultFactory().Client()
if !ok { if !ok {
return nil, errors.Errorf("Unable to create Kubernetes Client") return nil, errors.Errorf("Unable to create Kubernetes Client")
@ -67,3 +67,7 @@ func (b *schedulerV1) Handler(ctx context.Context) (svc.Handler, error) {
return pbImplSchedulerV1.New(ctx, client, b.Configuration) return pbImplSchedulerV1.New(ctx, client, b.Configuration)
} }
func (*schedulerV1) Init(ctx context.Context, cmd *cobra.Command) error {
return nil
}

View file

@ -40,7 +40,7 @@ func init() {
type shutdownV1 struct { type shutdownV1 struct {
} }
func (s *shutdownV1) Handler(ctx context.Context) (svc.Handler, error) { func (s *shutdownV1) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
return pbImplShutdownV1.New(shutdown.Stop), nil return pbImplShutdownV1.New(shutdown.Stop), nil
} }
@ -55,3 +55,7 @@ func (s *shutdownV1) Description() string {
func (s *shutdownV1) Register(cmd *cobra.Command, arg ArgGen) error { func (s *shutdownV1) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (*shutdownV1) Init(ctx context.Context, cmd *cobra.Command) error {
return nil
}

View file

@ -26,15 +26,16 @@ import (
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared" shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/deployment/pod" "github.com/arangodb/kube-arangodb/pkg/deployment/pod"
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
) )
var _ IntegrationVolumes = IntegrationAuthenticationV1{} var _ IntegrationVolumes = IntegrationAuthenticationV1{}
type IntegrationAuthenticationV1 struct { type IntegrationAuthenticationV1 struct {
Core *Core Core *Core
Deployment *api.ArangoDeployment
DeploymentName string
Spec api.DeploymentSpec
} }
func (i IntegrationAuthenticationV1) Name() []string { func (i IntegrationAuthenticationV1) Name() []string {
@ -42,10 +43,6 @@ func (i IntegrationAuthenticationV1) Name() []string {
} }
func (i IntegrationAuthenticationV1) Validate() error { func (i IntegrationAuthenticationV1) Validate() error {
if i.Deployment == nil {
return errors.Errorf("Deployment is nil")
}
return nil return nil
} }
@ -53,7 +50,7 @@ func (i IntegrationAuthenticationV1) Args() (k8sutil.OptionPairs, error) {
options := k8sutil.CreateOptionPairs() options := k8sutil.CreateOptionPairs()
options.Add("--integration.authentication.v1", true) options.Add("--integration.authentication.v1", true)
options.Add("--integration.authentication.v1.enabled", i.Deployment.GetAcceptedSpec().IsAuthenticated()) options.Add("--integration.authentication.v1.enabled", i.Spec.IsAuthenticated())
options.Add("--integration.authentication.v1.path", shared.ClusterJWTSecretVolumeMountDir) options.Add("--integration.authentication.v1.path", shared.ClusterJWTSecretVolumeMountDir)
options.Merge(i.Core.Args(i)) options.Merge(i.Core.Args(i))
@ -62,13 +59,13 @@ func (i IntegrationAuthenticationV1) Args() (k8sutil.OptionPairs, error) {
} }
func (i IntegrationAuthenticationV1) Volumes() ([]core.Volume, []core.VolumeMount, error) { func (i IntegrationAuthenticationV1) Volumes() ([]core.Volume, []core.VolumeMount, error) {
if i.Deployment.GetAcceptedSpec().IsAuthenticated() { if i.Spec.IsAuthenticated() {
return []core.Volume{ return []core.Volume{
{ {
Name: shared.ClusterJWTSecretVolumeName, Name: shared.ClusterJWTSecretVolumeName,
VolumeSource: core.VolumeSource{ VolumeSource: core.VolumeSource{
Secret: &core.SecretVolumeSource{ Secret: &core.SecretVolumeSource{
SecretName: pod.JWTSecretFolder(i.Deployment.GetName()), SecretName: pod.JWTSecretFolder(i.DeploymentName),
}, },
}, },
}, },

View file

@ -64,6 +64,10 @@ func (b *storageV1) Register(cmd *cobra.Command, arg ArgGen) error {
return nil return nil
} }
func (b *storageV1) Handler(ctx context.Context) (svc.Handler, error) { func (b *storageV1) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
return storage.NewService(ctx, b.Configuration) return storage.NewService(ctx, b.Configuration)
} }
func (*storageV1) Init(ctx context.Context, cmd *cobra.Command) error {
return nil
}

View file

@ -109,7 +109,7 @@ func Test_TLSCases(t *testing.T) {
"--tls.enabled=false", "--tls.enabled=false",
"client", "client",
"health", "health",
"v1")).Code(t, codes.Unavailable).Errorf(t, "connection error: desc = \"error reading server preface: EOF\"") "v1")).Code(t, codes.Unavailable)
}) })
t.Run("external", func(t *testing.T) { t.Run("external", func(t *testing.T) {
tgrpc.AsGRPCError(t, executeSync(t, shutdown.Context(), tgrpc.AsGRPCError(t, executeSync(t, shutdown.Context(),
@ -117,7 +117,7 @@ func Test_TLSCases(t *testing.T) {
"--tls.enabled=false", "--tls.enabled=false",
"client", "client",
"health", "health",
"v1")).Code(t, codes.Unavailable).Errorf(t, "connection error: desc = \"error reading server preface: EOF\"") "v1")).Code(t, codes.Unavailable)
}) })
}) })

View file

@ -115,3 +115,12 @@ func IterateSorted[V any](m map[string]V, cb func(string, V)) {
cb(k, m[k]) cb(k, m[k])
} }
} }
func Optional[K comparable, V any](m map[K]V, key K, def V) V {
v, ok := m[key]
if ok {
return v
}
return def
}

View file

@ -1,7 +1,7 @@
// //
// DISCLAIMER // DISCLAIMER
// //
// Copyright 2016-2022 ArangoDB GmbH, Cologne, Germany // Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -30,6 +30,20 @@ func recoverPanic(skipFrames int, in func() error) (err error) {
return in() return in()
} }
func recoverPanicO1[O1 any](skipFrames int, in func() (O1, error)) (o1 O1, err error) {
defer func() {
if r := recover(); r != nil {
err = newPanicError(r, GetStack(skipFrames))
}
}()
return in()
}
func Recover(in func() error) (err error) { func Recover(in func() error) (err error) {
return recoverPanic(4, in) return recoverPanic(4, in)
} }
func RecoverO1[O1 any](in func() (O1, error)) (O1, error) {
return recoverPanicO1(4, in)
}

View file

@ -1,7 +1,7 @@
// //
// DISCLAIMER // DISCLAIMER
// //
// Copyright 2016-2023 ArangoDB GmbH, Cologne, Germany // Copyright 2016-2024 ArangoDB GmbH, Cologne, Germany
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@
package version package version
import ( import (
"fmt"
"runtime" "runtime"
"github.com/arangodb/go-driver" "github.com/arangodb/go-driver"
@ -58,6 +59,10 @@ func (i InfoV1) IsEnterprise() bool {
return i.Edition == EnterpriseEdition return i.Edition == EnterpriseEdition
} }
func (i InfoV1) String() string {
return fmt.Sprintf("Version: %s %s, Build: %s, Go: %s, Build Date: %s", i.Edition.Title(), i.Version, i.Build, i.GoVersion, i.BuildDate)
}
func GetVersionV1() InfoV1 { func GetVersionV1() InfoV1 {
return InfoV1{ return InfoV1{
Version: driver.Version(version), Version: driver.Version(version),