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

GT-525 License Manager for ML Deployment (#1501)

This commit is contained in:
jwierzbo 2023-11-29 10:19:06 +01:00 committed by GitHub
parent 91e7312fcd
commit cbf5e65e8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 150 additions and 28 deletions

3
.gitignore vendored
View file

@ -7,10 +7,13 @@ vendor/
.idea/
deps/
.vscode/
**/*.enterprise.go
**/*.enterprise_test.go
**/enterprise/**
enterprise.mk
license-header.enterprise.txt
local/
kustomize_test/
tools/codegen/boilerplate.go.txt

View file

@ -22,6 +22,7 @@
- (Feature) (ML) Introduce basic Conditions
- (Improvement) Raise memory requests for init containers to 50mi
- (Feature) (ML) Metadata Service Implementation
- (Feature) License Manager for ML Deployment
## [1.2.35](https://github.com/arangodb/kube-arangodb/tree/1.2.35) (2023-11-06)
- (Maintenance) Update go-driver to v1.6.0, update IsNotFound() checks

View file

@ -23,7 +23,7 @@ package v1alpha1
import api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
const (
ExtensionDeploymentFoundCondition api.ConditionType = "DeploymentFound"
ExtensionDeploymentFoundCondition api.ConditionType = "DeploymentFound"
ExtensionMetadataServiceValidCondition api.ConditionType = "MetadataServiceValid"
LicenseValidCondition api.ConditionType = "LicenseValid"
)

View file

@ -16,7 +16,8 @@
// limitations under the License.
//
// Copyright holder is ArangoDB GmbH, Cologne, Germany
//
//go:build !enterprise
package license

View file

@ -55,7 +55,7 @@ const (
// NotLicensed
StatusFeatureExpired
// StatusValid define state when Operator should continue execution
// StatusValid define state when Operator should continue execution
// Licensed
StatusValid
)
@ -70,6 +70,29 @@ func (s Status) Validate(feature Feature, subFeatures ...Feature) Status {
type Feature string
const (
// FeatureAll define feature name for all features
FeatureAll Feature = "*"
// FeatureArangoDB define feature name for ArangoDB
FeatureArangoDB Feature = "ArangoDB"
// FeatureArangoSearch define feature name for ArangoSearch
FeatureArangoSearch Feature = "ArangoSearch"
// FeatureArangoML define feature name for ArangoML
FeatureArangoML Feature = "ArangoML"
)
func (f Feature) In(features []Feature) bool {
for _, v := range features {
if v == f {
return true
}
}
return false
}
type License interface {
// Validate validates the license scope. In case of:
// - if feature is '*' - checks if:
@ -84,5 +107,6 @@ type License interface {
// --- checks if subFeature or '*' is in the list of License Feature enabled SubFeatures
Validate(feature Feature, subFeatures ...Feature) Status
// Refresh refreshes the license from the source (Secret) and verifies the signature
Refresh(ctx context.Context) error
}

View file

@ -23,6 +23,7 @@ package license
import "context"
type Loader interface {
// Refresh reloads license in specified manner, returns license, found, error
// Refresh reloads license in a specified manner.
// It returns license (base64 encoded), found, error
Refresh(ctx context.Context) (string, bool, error)
}

View file

@ -26,48 +26,34 @@ import (
"k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1"
"github.com/arangodb/kube-arangodb/pkg/util/constants"
"github.com/arangodb/kube-arangodb/pkg/util/k8sutil"
"github.com/arangodb/kube-arangodb/pkg/util/kclient"
)
func NewArengoDeploymentLicenseLoader(factory kclient.Factory, namespace, name string) Loader {
func NewArangoDeploymentLicenseLoader(client kubernetes.Interface, deployment *api.ArangoDeployment) Loader {
return arangoDeploymentLicenseLoader{
factory: factory,
namespace: namespace,
name: name,
client: client,
deployment: deployment,
}
}
type arangoDeploymentLicenseLoader struct {
factory kclient.Factory
client kubernetes.Interface
namespace, name string
deployment *api.ArangoDeployment
}
func (a arangoDeploymentLicenseLoader) Refresh(ctx context.Context) (string, bool, error) {
client, ok := a.factory.Client()
if !ok {
return "", false, nil
}
deployment, err := client.Arango().DatabaseV1().ArangoDeployments(a.namespace).Get(ctx, a.name, meta.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return "", false, nil
}
return "", false, err
}
spec := deployment.GetAcceptedSpec()
spec := a.deployment.GetAcceptedSpec()
if !spec.License.HasSecretName() {
return "", false, nil
}
secret, err := client.Kubernetes().CoreV1().Secrets(deployment.GetNamespace()).Get(ctx, spec.License.GetSecretName(), meta.GetOptions{})
secret, err := a.client.CoreV1().Secrets(a.deployment.GetNamespace()).Get(ctx, spec.License.GetSecretName(), meta.GetOptions{})
if err != nil {
if errors.IsNotFound(err) {
return "", false, nil

View file

@ -0,0 +1,35 @@
//
// DISCLAIMER
//
// Copyright 2023 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 license
import (
"context"
"github.com/stretchr/testify/mock"
)
type MockLoader struct {
mock.Mock
}
func (m *MockLoader) Refresh(ctx context.Context) (string, bool, error) {
args := m.Called(ctx)
return args.String(0), args.Bool(1), args.Error(2)
}

71
pkg/util/cert/signer.go Normal file
View file

@ -0,0 +1,71 @@
//
// DISCLAIMER
//
// Copyright 2023 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 cert
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/pem"
)
type Signer struct {
privateKey *rsa.PrivateKey
}
// NewSigner creates a new Signer with a generated private key.
func NewSigner() (*Signer, error) {
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil {
return nil, err
}
return &Signer{privateKey: privateKey}, nil
}
// Sign signs the content with the private key and returns:
// base64 encoded signature, base64 encoded content and error.
func (s *Signer) Sign(content string) (string, string, error) {
hash := sha256.New()
hash.Write([]byte(content))
signature, err := rsa.SignPKCS1v15(rand.Reader, s.privateKey, crypto.SHA256, hash.Sum(nil))
if err != nil {
return "", "", err
}
return base64.StdEncoding.EncodeToString(signature), base64.StdEncoding.EncodeToString([]byte(content)), nil
}
// PublicKey returns the public key in PKIX format.
func (s *Signer) PublicKey() (string, error) {
publicKey := &s.privateKey.PublicKey
publicKeyDer, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
return "", err
}
publicKeyBlock := pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: publicKeyDer,
}
return string(pem.EncodeToMemory(&publicKeyBlock)), nil
}