diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b1a550f0..3c076e232 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,6 +23,7 @@
- (Feature) Integration Service TLS
- (Feature) (Gateway) SNI and Authz support
- (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)
- (Maintenance) Go 1.22.4 & Kubernetes 1.29.6 libraries
diff --git a/cmd/version.go b/cmd/version.go
index fb4c9d920..f489ec786 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -1,7 +1,7 @@
//
// 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");
// you may not use this file except in compliance with the License.
@@ -21,8 +21,6 @@
package cmd
import (
- "fmt"
-
"github.com/spf13/cobra"
"github.com/arangodb/kube-arangodb/pkg/version"
@@ -38,6 +36,5 @@ var cmdVersion = &cobra.Command{
}
func versionRun(cmd *cobra.Command, args []string) {
- v := version.GetVersionV1()
- println(fmt.Sprintf("Version: %s %s, Build: %s, Go: %s, Build Date: %s", v.Edition.Title(), v.Version, v.Build, v.GoVersion, v.BuildDate))
+ println(version.GetVersionV1().String())
}
diff --git a/docs/api/ArangoRoute.V1Alpha1.md b/docs/api/ArangoRoute.V1Alpha1.md
index e69bf4c81..b083aa436 100644
--- a/docs/api/ArangoRoute.V1Alpha1.md
+++ b/docs/api/ArangoRoute.V1Alpha1.md
@@ -16,6 +16,12 @@ Deployment specifies the ArangoDeployment object name
***
+### .spec.destination.authentication.type
+
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec_destination_authentication.go#L28)
+
+***
+
### .spec.destination.path
Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_spec_destination.go#L36)
@@ -131,6 +137,12 @@ UID keeps the information about object UID
***
+### .status.target.authentication.type
+
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_authentication.go#L26)
+
+***
+
### .status.target.destinations\[int\].host
Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target_destination.go#L38)
@@ -145,7 +157,7 @@ Type: `integer` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.
### .status.target.path
-Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target.go#L37)
+Type: `string` [\[ref\]](https://github.com/arangodb/kube-arangodb/blob/1.2.42/pkg/apis/networking/v1alpha1/route_status_target.go#L40)
Path specifies request path override
diff --git a/integrations/envoy/auth/v3/check.go b/integrations/envoy/auth/v3/check.go
new file mode 100644
index 000000000..c462276fe
--- /dev/null
+++ b/integrations/envoy/auth/v3/check.go
@@ -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
+}
diff --git a/integrations/envoy/auth/v3/check_adb_jwt.go b/integrations/envoy/auth/v3/check_adb_jwt.go
new file mode 100644
index 000000000..fc96d9ba4
--- /dev/null
+++ b/integrations/envoy/auth/v3/check_adb_jwt.go
@@ -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
+}
diff --git a/integrations/envoy/auth/v3/consts.go b/integrations/envoy/auth/v3/consts.go
index 7cd7c3413..ae414cd3e 100644
--- a/integrations/envoy/auth/v3/consts.go
+++ b/integrations/envoy/auth/v3/consts.go
@@ -22,4 +22,18 @@ package v3
const (
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"
)
diff --git a/integrations/envoy/auth/v3/impl.go b/integrations/envoy/auth/v3/impl.go
index c3930b08b..7c6a96bf7 100644
--- a/integrations/envoy/auth/v3/impl.go
+++ b/integrations/envoy/auth/v3/impl.go
@@ -22,15 +22,23 @@ package v3
import (
"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"
"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"
)
-func New() svc.Handler {
- return &impl{}
+func New(authClient pbAuthenticationV1.AuthenticationV1Client) svc.Handler {
+ return &impl{
+ authClient: authClient,
+ }
}
var _ pbEnvoyAuthV3.AuthorizationServer = &impl{}
@@ -38,6 +46,8 @@ var _ svc.Handler = &impl{}
type impl struct {
pbEnvoyAuthV3.UnimplementedAuthorizationServer
+
+ authClient pbAuthenticationV1.AuthenticationV1Client
}
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) {
- 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{
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
}
diff --git a/integrations/envoy/auth/v3/response.go b/integrations/envoy/auth/v3/response.go
new file mode 100644
index 000000000..15cc2499b
--- /dev/null
+++ b/integrations/envoy/auth/v3/response.go
@@ -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
+}
diff --git a/integrations/envoy/auth/v3/service_test.go b/integrations/envoy/auth/v3/service_test.go
index a1eeb34c3..18e25c454 100644
--- a/integrations/envoy/auth/v3/service_test.go
+++ b/integrations/envoy/auth/v3/service_test.go
@@ -22,6 +22,7 @@ package v3
import (
"context"
+ "net/http"
"testing"
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 {
local := svc.NewService(svc.Configuration{
Address: "127.0.0.1:0",
- }, New())
+ }, New(nil))
start := local.Start(ctx)
@@ -44,7 +45,7 @@ func Client(t *testing.T, ctx context.Context) pbEnvoyAuthV3.AuthorizationClient
return client
}
-func Test_AllowAll(t *testing.T) {
+func Test_DenyHeader(t *testing.T) {
ctx, c := context.WithCancel(context.Background())
defer c()
@@ -53,8 +54,28 @@ func Test_AllowAll(t *testing.T) {
resp, err := client.Check(ctx, &pbEnvoyAuthV3.CheckRequest{})
require.NoError(t, err)
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.NotNil(t, resp.HttpResponse)
require.NotNil(t, tests.CastAs[*pbEnvoyAuthV3.CheckResponse_OkResponse](t, resp.GetHttpResponse()).OkResponse)
- require.Nil(t, resp.DynamicMetadata)
}
diff --git a/pkg/apis/networking/v1alpha1/route_spec_authentication.go b/pkg/apis/networking/v1alpha1/route_spec_authentication.go
new file mode 100644
index 000000000..249302f0e
--- /dev/null
+++ b/pkg/apis/networking/v1alpha1/route_spec_authentication.go
@@ -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))
+}
diff --git a/pkg/apis/networking/v1alpha1/route_spec_destination.go b/pkg/apis/networking/v1alpha1/route_spec_destination.go
index ff1c58018..055fd6cbf 100644
--- a/pkg/apis/networking/v1alpha1/route_spec_destination.go
+++ b/pkg/apis/networking/v1alpha1/route_spec_destination.go
@@ -34,6 +34,9 @@ type ArangoRouteSpecDestination struct {
// Path defines service path used for overrides
Path *string `json:"path,omitempty"`
+
+ // Authentication defines auth methods
+ Authentication *ArangoRouteSpecDestinationAuthentication `json:"authentication,omitempty"`
}
func (a *ArangoRouteSpecDestination) GetService() *ArangoRouteSpecDestinationService {
@@ -68,6 +71,14 @@ func (a *ArangoRouteSpecDestination) GetTLS() *ArangoRouteSpecDestinationTLS {
return a.TLS
}
+func (a *ArangoRouteSpecDestination) GetAuthentication() *ArangoRouteSpecDestinationAuthentication {
+ if a == nil || a.Authentication == nil {
+ return nil
+ }
+
+ return a.Authentication
+}
+
func (a *ArangoRouteSpecDestination) Validate() error {
if a == nil {
a = &ArangoRouteSpecDestination{}
@@ -77,6 +88,7 @@ func (a *ArangoRouteSpecDestination) Validate() error {
shared.ValidateOptionalInterfacePath("service", a.Service),
shared.ValidateOptionalInterfacePath("schema", a.Schema),
shared.ValidateOptionalInterfacePath("tls", a.TLS),
+ shared.ValidateOptionalInterfacePath("authentication", a.Authentication),
shared.PrefixResourceError("path", shared.ValidateAPIPath(a.GetPath())),
); err != nil {
return err
diff --git a/pkg/apis/networking/v1alpha1/route_spec_destination_authentication.go b/pkg/apis/networking/v1alpha1/route_spec_destination_authentication.go
new file mode 100644
index 000000000..47225cab4
--- /dev/null
+++ b/pkg/apis/networking/v1alpha1/route_spec_destination_authentication.go
@@ -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),
+ )
+}
diff --git a/pkg/apis/networking/v1alpha1/route_status_target.go b/pkg/apis/networking/v1alpha1/route_status_target.go
index 89f1b7a0d..26d67b1d3 100644
--- a/pkg/apis/networking/v1alpha1/route_status_target.go
+++ b/pkg/apis/networking/v1alpha1/route_status_target.go
@@ -33,6 +33,9 @@ type ArangoRouteStatusTarget struct {
// TLS Keeps target TLS Settings (if not nil, TLS is enabled)
TLS *ArangoRouteStatusTargetTLS `json:"TLS,omitempty"`
+ // Authentication specifies the authentication details
+ Authentication ArangoRouteStatusTargetAuthentication `json:"authentication,omitempty"`
+
// Path specifies request path override
Path string `json:"path,omitempty"`
}
@@ -61,5 +64,5 @@ func (a *ArangoRouteStatusTarget) Hash() string {
if a == nil {
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())
}
diff --git a/pkg/apis/networking/v1alpha1/route_status_target_authentication.go b/pkg/apis/networking/v1alpha1/route_status_target_authentication.go
new file mode 100644
index 000000000..e24014189
--- /dev/null
+++ b/pkg/apis/networking/v1alpha1/route_status_target_authentication.go
@@ -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())
+}
diff --git a/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go
index ba179a20b..b1cf33eed 100644
--- a/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/networking/v1alpha1/zz_generated.deepcopy.go
@@ -26,7 +26,7 @@
package v1alpha1
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"
runtime "k8s.io/apimachinery/pkg/runtime"
intstr "k8s.io/apimachinery/pkg/util/intstr"
@@ -147,6 +147,11 @@ func (in *ArangoRouteSpecDestination) DeepCopyInto(out *ArangoRouteSpecDestinati
*out = new(string)
**out = **in
}
+ if in.Authentication != nil {
+ in, out := &in.Authentication, &out.Authentication
+ *out = new(ArangoRouteSpecDestinationAuthentication)
+ (*in).DeepCopyInto(*out)
+ }
return
}
@@ -160,6 +165,27 @@ func (in *ArangoRouteSpecDestination) DeepCopy() *ArangoRouteSpecDestination {
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.
func (in *ArangoRouteSpecDestinationService) DeepCopyInto(out *ArangoRouteSpecDestinationService) {
*out = *in
@@ -233,7 +259,7 @@ func (in *ArangoRouteStatus) DeepCopyInto(out *ArangoRouteStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
- *out = make(v2alpha1.ConditionList, len(*in))
+ *out = make(deploymentv1.ConditionList, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
@@ -274,6 +300,7 @@ func (in *ArangoRouteStatusTarget) DeepCopyInto(out *ArangoRouteStatusTarget) {
*out = new(ArangoRouteStatusTargetTLS)
(*in).DeepCopyInto(*out)
}
+ out.Authentication = in.Authentication
return
}
@@ -287,6 +314,22 @@ func (in *ArangoRouteStatusTarget) DeepCopy() *ArangoRouteStatusTarget {
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.
func (in *ArangoRouteStatusTargetDestination) DeepCopyInto(out *ArangoRouteStatusTargetDestination) {
*out = *in
diff --git a/pkg/crd/crds/networking-route.schema.generated.yaml b/pkg/crd/crds/networking-route.schema.generated.yaml
index 49d93b356..5751f46b1 100644
--- a/pkg/crd/crds/networking-route.schema.generated.yaml
+++ b/pkg/crd/crds/networking-route.schema.generated.yaml
@@ -9,6 +9,12 @@ v1alpha1:
destination:
description: Destination defines the route destination
properties:
+ authentication:
+ description: Authentication defines auth methods
+ properties:
+ type:
+ type: string
+ type: object
path:
description: Path defines service path used for overrides
type: string
diff --git a/pkg/deployment/resources/config_map_gateway.go b/pkg/deployment/resources/config_map_gateway.go
index 739474f8e..9285e38f8 100644
--- a/pkg/deployment/resources/config_map_gateway.go
+++ b/pkg/deployment/resources/config_map_gateway.go
@@ -30,6 +30,7 @@ import (
kerrors "k8s.io/apimachinery/pkg/api/errors"
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"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/deployment/resources/gateway"
@@ -131,6 +132,7 @@ func (r *Resources) renderGatewayConfig(cachedStatus inspectorInterface.Inspecto
Port: shared.ArangoPort,
},
},
+ AuthExtension: &gateway.ConfigAuthZExtension{},
}
if spec.TLS.IsSecure() {
@@ -193,6 +195,11 @@ func (r *Resources) renderGatewayConfig(cachedStatus inspectorInterface.Inspecto
dest.Type = util.NewType(gateway.ConfigDestinationTypeHTTPS)
}
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
}
diff --git a/pkg/deployment/resources/gateway/gateway_authz_extension.go b/pkg/deployment/resources/gateway/gateway_authz_extension.go
new file mode 100644
index 000000000..b7e6edf0c
--- /dev/null
+++ b/pkg/deployment/resources/gateway/gateway_authz_extension.go
@@ -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
+}
diff --git a/pkg/deployment/resources/gateway/gateway_config_destination.go b/pkg/deployment/resources/gateway/gateway_config_destination.go
index f8ee81c63..3139b3f31 100644
--- a/pkg/deployment/resources/gateway/gateway_config_destination.go
+++ b/pkg/deployment/resources/gateway/gateway_config_destination.go
@@ -26,7 +26,6 @@ import (
clusterAPI "github.com/envoyproxy/go-control-plane/envoy/config/cluster/v3"
endpointAPI "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/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"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
@@ -62,6 +61,8 @@ type ConfigDestination struct {
Type *ConfigDestinationType `json:"type,omitempty"`
Path *string `json:"path,omitempty"`
+
+ AuthExtension *ConfigAuthZExtension `json:"authExtension,omitempty"`
}
func (c *ConfigDestination) Validate() error {
@@ -72,6 +73,7 @@ func (c *ConfigDestination) Validate() error {
shared.PrefixResourceError("targets", c.Targets.Validate()),
shared.PrefixResourceError("type", c.Type.Validate()),
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) {
+ 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{
Match: &routeAPI.RouteMatch{
PathSpecifier: &routeAPI.RouteMatch_Prefix{
@@ -98,7 +110,7 @@ func (c *ConfigDestination) RenderRoute(name, prefix string) (*routeAPI.Route, e
PrefixRewrite: c.GetPath(),
},
},
- TypedPerFilterConfig: map[string]*anypb.Any{},
+ TypedPerFilterConfig: tc,
}, nil
}
diff --git a/pkg/deployment/resources/gateway/gateway_filter_extension.go b/pkg/deployment/resources/gateway/gateway_filter_extension.go
new file mode 100644
index 000000000..f711e952e
--- /dev/null
+++ b/pkg/deployment/resources/gateway/gateway_filter_extension.go
@@ -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
+}
diff --git a/pkg/deployment/resources/pod_creator_gateway_pod.go b/pkg/deployment/resources/pod_creator_gateway_pod.go
index 5f8fc16bf..16d14c89d 100644
--- a/pkg/deployment/resources/pod_creator_gateway_pod.go
+++ b/pkg/deployment/resources/pod_creator_gateway_pod.go
@@ -238,9 +238,13 @@ func (m *MemberGatewayPod) Labels() map[string]string {
func (m *MemberGatewayPod) Profiles() (schedulerApi.ProfileTemplates, error) {
integration, err := sidecar.NewIntegration(&schedulerContainerResourcesApi.Image{
Image: util.NewType(m.resources.context.GetOperatorImage()),
- }, m.spec.Gateway.GetSidecar(), []string{shared.ServerContainerName}, sidecar.IntegrationEnvoyV3{
- Spec: m.spec,
- })
+ }, m.spec.Gateway.GetSidecar(), []string{shared.ServerContainerName},
+ sidecar.IntegrationEnvoyV3{
+ Spec: m.spec,
+ }, sidecar.IntegrationAuthenticationV1{
+ DeploymentName: m.context.GetName(),
+ Spec: m.spec,
+ })
if err != nil {
return nil, err
diff --git a/pkg/handlers/networking/route/handler_destination.go b/pkg/handlers/networking/route/handler_destination.go
index 80806d135..7a618ffed 100644
--- a/pkg/handlers/networking/route/handler_destination.go
+++ b/pkg/handlers/networking/route/handler_destination.go
@@ -121,6 +121,10 @@ func (h *handler) HandleArangoDestination(ctx context.Context, item operation.It
target.Path = dest.GetPath()
+ // Render Auth Settings
+
+ target.Authentication.Type = dest.GetAuthentication().GetType()
+
if dest.Schema.Get() == networkingApi.ArangoRouteSpecDestinationSchemaHTTPS {
target.TLS = &networkingApi.ArangoRouteStatusTargetTLS{
Insecure: util.NewType(extension.Spec.Destination.GetTLS().GetInsecure()),
diff --git a/pkg/integrations/authentication_v1.go b/pkg/integrations/authentication_v1.go
index 3de449d76..60bc77afa 100644
--- a/pkg/integrations/authentication_v1.go
+++ b/pkg/integrations/authentication_v1.go
@@ -56,7 +56,7 @@ func (a *authenticationV1) Register(cmd *cobra.Command, arg ArgGen) error {
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)
}
@@ -67,3 +67,7 @@ func (a *authenticationV1) Name() string {
func (a *authenticationV1) Description() string {
return "Enable AuthenticationV1 Integration Service"
}
+
+func (*authenticationV1) Init(ctx context.Context, cmd *cobra.Command) error {
+ return nil
+}
diff --git a/pkg/integrations/authorization_v0.go b/pkg/integrations/authorization_v0.go
index d63ab33d5..fd001d687 100644
--- a/pkg/integrations/authorization_v0.go
+++ b/pkg/integrations/authorization_v0.go
@@ -51,6 +51,10 @@ func (a authorizationV0) Register(cmd *cobra.Command, arg ArgGen) error {
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
}
+
+func (a authorizationV0) Init(ctx context.Context, cmd *cobra.Command) error {
+ return nil
+}
diff --git a/pkg/integrations/config_v1.go b/pkg/integrations/config_v1.go
index 582605a03..d0ff5faeb 100644
--- a/pkg/integrations/config_v1.go
+++ b/pkg/integrations/config_v1.go
@@ -49,7 +49,7 @@ func (a *configV1) Register(cmd *cobra.Command, arg ArgGen) error {
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
cfg.Modules = map[string]pbImplConfigV1.ModuleDefinition{}
@@ -75,3 +75,7 @@ func (a *configV1) Name() string {
func (a *configV1) Description() string {
return "Enable ConfigV1 Integration Service"
}
+
+func (*configV1) Init(ctx context.Context, cmd *cobra.Command) error {
+ return nil
+}
diff --git a/pkg/integrations/envoy_auth_v3.go b/pkg/integrations/envoy_auth_v3.go
index aadfabacc..c8cb55808 100644
--- a/pkg/integrations/envoy_auth_v3.go
+++ b/pkg/integrations/envoy_auth_v3.go
@@ -25,7 +25,9 @@ import (
"github.com/spf13/cobra"
+ pbAuthenticationV1 "github.com/arangodb/kube-arangodb/integrations/authentication/v1/definition"
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"
)
@@ -42,14 +44,26 @@ func (a envoyAuthV3) Name() string {
return pbImplEnvoyAuthV3.Name
}
-func (a envoyAuthV3) Description() string {
+func (a *envoyAuthV3) Description() string {
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
}
-func (a envoyAuthV3) Handler(ctx context.Context) (svc.Handler, error) {
- return pbImplEnvoyAuthV3.New(), nil
+func (a *envoyAuthV3) Handler(ctx context.Context, cmd *cobra.Command) (svc.Handler, error) {
+ 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
}
diff --git a/pkg/integrations/integration.go b/pkg/integrations/integration.go
index 0b6543177..d896c7f00 100644
--- a/pkg/integrations/integration.go
+++ b/pkg/integrations/integration.go
@@ -38,7 +38,7 @@ type Integration interface {
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 {
diff --git a/pkg/integrations/register.go b/pkg/integrations/register.go
index 8799452dc..d20a8b0d8 100644
--- a/pkg/integrations/register.go
+++ b/pkg/integrations/register.go
@@ -36,6 +36,7 @@ import (
"github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/shutdown"
"github.com/arangodb/kube-arangodb/pkg/util/svc"
+ "github.com/arangodb/kube-arangodb/pkg/version"
)
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 {
+ println(version.GetVersionV1().String())
+
healthConfig, err := c.health.Config()
if err != nil {
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")
if ok && (internalEnabled || externalEnabled) {
- if svc, err := handler.Handler(ctx); err != nil {
+ if svc, err := handler.Handler(ctx, cmd); err != nil {
return err
} else {
if internalEnabled {
diff --git a/pkg/integrations/scheduler_v1.go b/pkg/integrations/scheduler_v1.go
index e6d906797..ad84aec7f 100644
--- a/pkg/integrations/scheduler_v1.go
+++ b/pkg/integrations/scheduler_v1.go
@@ -59,7 +59,7 @@ func (b *schedulerV1) Register(cmd *cobra.Command, arg ArgGen) error {
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()
if !ok {
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)
}
+
+func (*schedulerV1) Init(ctx context.Context, cmd *cobra.Command) error {
+ return nil
+}
diff --git a/pkg/integrations/shutdown_v1.go b/pkg/integrations/shutdown_v1.go
index 504f1931f..93c4c4a9c 100644
--- a/pkg/integrations/shutdown_v1.go
+++ b/pkg/integrations/shutdown_v1.go
@@ -40,7 +40,7 @@ func init() {
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
}
@@ -55,3 +55,7 @@ func (s *shutdownV1) Description() string {
func (s *shutdownV1) Register(cmd *cobra.Command, arg ArgGen) error {
return nil
}
+
+func (*shutdownV1) Init(ctx context.Context, cmd *cobra.Command) error {
+ return nil
+}
diff --git a/pkg/integrations/sidecar/integration.authentication.v1.go b/pkg/integrations/sidecar/integration.authentication.v1.go
index a51df0c78..9504877df 100644
--- a/pkg/integrations/sidecar/integration.authentication.v1.go
+++ b/pkg/integrations/sidecar/integration.authentication.v1.go
@@ -26,15 +26,16 @@ import (
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
shared "github.com/arangodb/kube-arangodb/pkg/apis/shared"
"github.com/arangodb/kube-arangodb/pkg/deployment/pod"
- "github.com/arangodb/kube-arangodb/pkg/util/errors"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
)
var _ IntegrationVolumes = IntegrationAuthenticationV1{}
type IntegrationAuthenticationV1 struct {
- Core *Core
- Deployment *api.ArangoDeployment
+ Core *Core
+
+ DeploymentName string
+ Spec api.DeploymentSpec
}
func (i IntegrationAuthenticationV1) Name() []string {
@@ -42,10 +43,6 @@ func (i IntegrationAuthenticationV1) Name() []string {
}
func (i IntegrationAuthenticationV1) Validate() error {
- if i.Deployment == nil {
- return errors.Errorf("Deployment is nil")
- }
-
return nil
}
@@ -53,7 +50,7 @@ func (i IntegrationAuthenticationV1) Args() (k8sutil.OptionPairs, error) {
options := k8sutil.CreateOptionPairs()
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.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) {
- if i.Deployment.GetAcceptedSpec().IsAuthenticated() {
+ if i.Spec.IsAuthenticated() {
return []core.Volume{
{
Name: shared.ClusterJWTSecretVolumeName,
VolumeSource: core.VolumeSource{
Secret: &core.SecretVolumeSource{
- SecretName: pod.JWTSecretFolder(i.Deployment.GetName()),
+ SecretName: pod.JWTSecretFolder(i.DeploymentName),
},
},
},
diff --git a/pkg/integrations/storage_v1.go b/pkg/integrations/storage_v1.go
index ffa351f4e..9ca2a1f00 100644
--- a/pkg/integrations/storage_v1.go
+++ b/pkg/integrations/storage_v1.go
@@ -64,6 +64,10 @@ func (b *storageV1) Register(cmd *cobra.Command, arg ArgGen) error {
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)
}
+
+func (*storageV1) Init(ctx context.Context, cmd *cobra.Command) error {
+ return nil
+}
diff --git a/pkg/integrations/tls_test.go b/pkg/integrations/tls_test.go
index 79aa38f6d..0bb1616da 100644
--- a/pkg/integrations/tls_test.go
+++ b/pkg/integrations/tls_test.go
@@ -109,7 +109,7 @@ func Test_TLSCases(t *testing.T) {
"--tls.enabled=false",
"client",
"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) {
tgrpc.AsGRPCError(t, executeSync(t, shutdown.Context(),
@@ -117,7 +117,7 @@ func Test_TLSCases(t *testing.T) {
"--tls.enabled=false",
"client",
"health",
- "v1")).Code(t, codes.Unavailable).Errorf(t, "connection error: desc = \"error reading server preface: EOF\"")
+ "v1")).Code(t, codes.Unavailable)
})
})
diff --git a/pkg/util/dict.go b/pkg/util/dict.go
index edcd37fc4..38af1a980 100644
--- a/pkg/util/dict.go
+++ b/pkg/util/dict.go
@@ -115,3 +115,12 @@ func IterateSorted[V any](m map[string]V, cb func(string, V)) {
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
+}
diff --git a/pkg/util/errors/panics/recovery.go b/pkg/util/errors/panics/recovery.go
index 3a54e4f05..9556da94f 100644
--- a/pkg/util/errors/panics/recovery.go
+++ b/pkg/util/errors/panics/recovery.go
@@ -1,7 +1,7 @@
//
// 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");
// 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()
}
+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) {
return recoverPanic(4, in)
}
+
+func RecoverO1[O1 any](in func() (O1, error)) (O1, error) {
+ return recoverPanicO1(4, in)
+}
diff --git a/pkg/version/version.go b/pkg/version/version.go
index 0115a34ea..94e81316c 100644
--- a/pkg/version/version.go
+++ b/pkg/version/version.go
@@ -1,7 +1,7 @@
//
// 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");
// you may not use this file except in compliance with the License.
@@ -21,6 +21,7 @@
package version
import (
+ "fmt"
"runtime"
"github.com/arangodb/go-driver"
@@ -58,6 +59,10 @@ func (i InfoV1) IsEnterprise() bool {
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 {
return InfoV1{
Version: driver.Version(version),