From 7e889ac9946ba4d991deefa0d6492e74b2e1dd9e Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Tue, 14 Jul 2020 13:32:03 +0000 Subject: [PATCH 1/6] S --- main.go | 2 + pkg/deployment/features/features.go | 49 ++++++++++++++++++++ pkg/deployment/features/jwt.go | 18 ++++++++ pkg/deployment/features/local.go | 69 +++++++++++++++++++++++++++++ 4 files changed, 138 insertions(+) create mode 100644 pkg/deployment/features/features.go create mode 100644 pkg/deployment/features/jwt.go create mode 100644 pkg/deployment/features/local.go diff --git a/main.go b/main.go index b06bcdb5e..6038c7f37 100644 --- a/main.go +++ b/main.go @@ -25,6 +25,7 @@ package main import ( goflag "flag" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "net" "os" "strconv" @@ -134,6 +135,7 @@ func init() { f.StringVar(&operatorOptions.arangoImage, "operator.arango-image", ArangoImageEnv.GetOrDefault(defaultArangoImage), "Docker image used for arango by default") f.BoolVar(&chaosOptions.allowed, "chaos.allowed", false, "Set to allow chaos in deployments. Only activated when allowed and enabled in deployment") + features.Init(&cmdMain) } func main() { diff --git a/pkg/deployment/features/features.go b/pkg/deployment/features/features.go new file mode 100644 index 000000000..205b91171 --- /dev/null +++ b/pkg/deployment/features/features.go @@ -0,0 +1,49 @@ +package features + +import "github.com/arangodb/go-driver" + +var _ Feature = &feature{} + +type Feature interface { + Name() string + Description() string + LongDescription() string + Version() driver.Version + EnterpriseRequired() bool + EnabledByDefault() bool + EnabledPointer() *bool +} + +type feature struct { + name, description, longDescription string + version driver.Version + enterpriseRequired, enabledByDefault, enabled bool +} + +func (f feature) LongDescription() string { + return f.longDescription +} + +func (f *feature) EnabledPointer() *bool { + return &f.enabled +} + +func (f feature) Version() driver.Version { + return f.version +} + +func (f feature) EnterpriseRequired() bool { + return f.enterpriseRequired +} + +func (f feature) EnabledByDefault() bool { + return f.enabledByDefault +} + +func (f feature) Name() string { + return f.name +} + +func (f feature) Description() string { + return f.description +} \ No newline at end of file diff --git a/pkg/deployment/features/jwt.go b/pkg/deployment/features/jwt.go new file mode 100644 index 000000000..283981400 --- /dev/null +++ b/pkg/deployment/features/jwt.go @@ -0,0 +1,18 @@ +package features + +func init() { + registerFeature(jwtRotation) +} + +var jwtRotation Feature = &feature{ + name: "jwt-rotation", + description: "JWT Token rotation in runtime", + longDescription: "Enables Runtime Rotation of JWT tokens on ArangoD Pods", + version: "3.7.0", + enterpriseRequired: true, + enabledByDefault: false, +} + +func JWT() Feature { + return jwtRotation +} diff --git a/pkg/deployment/features/local.go b/pkg/deployment/features/local.go new file mode 100644 index 000000000..c2bc9a794 --- /dev/null +++ b/pkg/deployment/features/local.go @@ -0,0 +1,69 @@ +package features + +import ( + "fmt" + "github.com/spf13/cobra" + "sync" +) + +var features map[string] Feature = map[string]Feature{} +var featuresLock sync.Mutex + +func registerFeature(f Feature) { + featuresLock.Lock() + defer featuresLock.Unlock() + + if f == nil { + panic("Feature cannot be nil") + } + + if _, ok := features[f.Name()]; ok { + panic("Feature already registered") + } + + features[f.Name()] = f +} + +var internalCMD = &cobra.Command{ + Use: "features", + Short: "Describe all operator features", + Run: cmdRun, +} + +func Init(cmd *cobra.Command) { + featuresLock.Lock() + defer featuresLock.Unlock() + + cmd.AddCommand(internalCMD) + + f := cmd.Flags() + + for _, feature := range features { + z := "" + + if v := feature.Version(); v != "" || feature.EnterpriseRequired() { + if v != "" && feature.EnterpriseRequired() { + z = fmt.Sprintf("%s - Required version %s and Enterprise Edition", feature.Description(), v) + } else if v != "" { + z = fmt.Sprintf("%s. Required version %s", feature.Description(), v) + } else if feature.EnterpriseRequired() { + z = fmt.Sprintf("%s - Required Enterprise Edition", feature.Description()) + } else { + z = feature.Description() + } + } + + f.BoolVar(feature.EnabledPointer(), fmt.Sprintf("deployment.feature.%s", feature.Name()), feature.EnabledByDefault(), z) + } +} + +func cmdRun(cmd *cobra.Command, args []string) { + featuresLock.Lock() + defer featuresLock.Unlock() + + for _, feature := range features { + println(fmt.Sprintf("Feature: %s", feature.Name())) + + println() + } +} \ No newline at end of file From a2e005521343776f5a5d5e4252d106ef111dc945 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Wed, 15 Jul 2020 04:48:22 +0000 Subject: [PATCH 2/6] S --- Makefile | 5 ++ chart/kube-arangodb/templates/deployment.yaml | 5 ++ chart/kube-arangodb/values.yaml | 2 + pkg/deployment/context_impl.go | 3 +- pkg/deployment/deployment_encryption_test.go | 66 ++++++++++++++++++- pkg/deployment/deployment_pod_tls_sni_test.go | 15 +++++ pkg/deployment/deployment_run_test.go | 10 +++ pkg/deployment/deployment_suite_test.go | 5 ++ pkg/deployment/features/encryption.go | 37 +++++++++++ pkg/deployment/features/features.go | 33 ++++++++-- pkg/deployment/features/jwt.go | 25 ++++++- pkg/deployment/features/local.go | 45 ++++++++++++- pkg/deployment/features/tls.go | 50 ++++++++++++++ pkg/deployment/pod/encryption.go | 3 +- pkg/deployment/pod/jwt.go | 7 +- pkg/deployment/pod/sni.go | 3 +- pkg/deployment/pod/tls.go | 4 +- .../reconcile/action_encryption_add.go | 8 +-- .../reconcile/action_jwt_status_update.go | 10 ++- .../reconcile/plan_builder_encryption.go | 5 +- pkg/deployment/reconcile/plan_builder_jwt.go | 21 +++--- .../reconcile/plan_builder_restore.go | 7 +- pkg/deployment/reconcile/plan_builder_tls.go | 5 +- .../reconcile/plan_builder_tls_sni.go | 3 +- pkg/deployment/resources/secret_hashes.go | 5 +- pkg/deployment/resources/secrets.go | 11 ++-- 26 files changed, 340 insertions(+), 53 deletions(-) create mode 100644 pkg/deployment/features/encryption.go create mode 100644 pkg/deployment/features/tls.go diff --git a/Makefile b/Makefile index ca873c065..09d43e3b0 100644 --- a/Makefile +++ b/Makefile @@ -187,6 +187,11 @@ fmt: @echo ">> Ensuring style of files" @go run golang.org/x/tools/cmd/goimports -w $(SOURCES) +.PHONY: license +license: + @echo ">> Ensuring license of files" + @go run github.com/google/addlicense -f "./tools/codegen/boilerplate.go.txt" $(SOURCES) + .PHONY: fmt-verify fmt-verify: license-verify @echo ">> Verify files style" diff --git a/chart/kube-arangodb/templates/deployment.yaml b/chart/kube-arangodb/templates/deployment.yaml index e6f79faba..5bc61ab01 100644 --- a/chart/kube-arangodb/templates/deployment.yaml +++ b/chart/kube-arangodb/templates/deployment.yaml @@ -85,6 +85,11 @@ spec: - --operator.backup {{- end }} - --chaos.allowed={{ .Values.operator.allowChaos }} +{{- if .Values.operator.args }} +{{- range .Values.operator.args }} + - {{ . | quote }} +{{- end }} +{{- end }} env: - name: MY_POD_NAMESPACE valueFrom: diff --git a/chart/kube-arangodb/values.yaml b/chart/kube-arangodb/values.yaml index 765494f77..2e809bff4 100644 --- a/chart/kube-arangodb/values.yaml +++ b/chart/kube-arangodb/values.yaml @@ -5,6 +5,8 @@ operator: imagePullPolicy: IfNotPresent imagePullSecrets: [] + args: [] + service: type: ClusterIP diff --git a/pkg/deployment/context_impl.go b/pkg/deployment/context_impl.go index 46b30c6e1..5b842ea02 100644 --- a/pkg/deployment/context_impl.go +++ b/pkg/deployment/context_impl.go @@ -26,6 +26,7 @@ import ( "context" "crypto/tls" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "net" nhttp "net/http" "strconv" @@ -245,7 +246,7 @@ func (d *Deployment) getAuth() (driver.Authentication, error) { secrets := d.GetKubeCli().CoreV1().Secrets(d.apiObject.GetNamespace()) var secret string - if i := d.apiObject.Status.CurrentImage; i == nil || i.ArangoDBVersion.CompareTo("3.7.0") < 0 || !i.Enterprise { + if i := d.apiObject.Status.CurrentImage; i == nil || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { s, err := secrets.Get(d.apiObject.Spec.Authentication.GetJWTSecretName(), meta.GetOptions{}) if err != nil { return nil, goErrors.Errorf("JWT Secret is missing") diff --git a/pkg/deployment/deployment_encryption_test.go b/pkg/deployment/deployment_encryption_test.go index 74fda1fe4..49472cb1b 100644 --- a/pkg/deployment/deployment_encryption_test.go +++ b/pkg/deployment/deployment_encryption_test.go @@ -199,7 +199,7 @@ func TestEnsurePod_ArangoDB_Encryption(t *testing.T) { }, }, { - Name: "Agent EE 3.7.0 Pod with encrypted rocksdb", + Name: "Agent EE 3.7.0 Pod with encrypted rocksdb, disabled feature", ArangoDeployment: &api.ArangoDeployment{ Spec: api.DeploymentSpec{ Image: util.NewString(testImage), @@ -225,6 +225,70 @@ func TestEnsurePod_ArangoDB_Encryption(t *testing.T) { k8sutil.CreateEncryptionKeySecret(secrets, testRocksDBEncryptionKey, key) }, ExpectedEvent: "member agent is created", + ExpectedPod: core.Pod{ + Spec: core.PodSpec{ + Volumes: []core.Volume{ + k8sutil.CreateVolumeEmptyDir(k8sutil.ArangodVolumeName), + k8sutil.CreateVolumeWithSecret(k8sutil.RocksdbEncryptionVolumeName, testRocksDBEncryptionKey), + }, + Containers: []core.Container{ + { + Name: k8sutil.ServerContainerName, + Image: testImage, + Command: BuildTestAgentArgs(t, firstAgentStatus.ID, + AgentArgsWithTLS(firstAgentStatus.ID, false), + ArgsWithAuth(false), + ArgsWithEncryptionKey()), + Ports: createTestPorts(), + VolumeMounts: []core.VolumeMount{ + k8sutil.ArangodVolumeMount(), + k8sutil.RocksdbEncryptionVolumeMount(), + }, + Resources: emptyResources, + LivenessProbe: createTestLivenessProbe(cmd, false, "", k8sutil.ArangoPort), + ImagePullPolicy: core.PullIfNotPresent, + SecurityContext: securityContext.NewSecurityContext(), + }, + }, + RestartPolicy: core.RestartPolicyNever, + TerminationGracePeriodSeconds: &defaultAgentTerminationTimeout, + Hostname: testDeploymentName + "-" + api.ServerGroupAgentsString + "-" + firstAgentStatus.ID, + Subdomain: testDeploymentName + "-int", + Affinity: k8sutil.CreateAffinity(testDeploymentName, api.ServerGroupAgentsString, + false, ""), + }, + }, + }, + { + Name: "Agent EE 3.7.0 Pod with encrypted rocksdb, enabled feature", + ArangoDeployment: &api.ArangoDeployment{ + Spec: api.DeploymentSpec{ + Image: util.NewString(testImage), + Authentication: noAuthentication, + TLS: noTLS, + RocksDB: rocksDBSpec, + }, + }, + Features: testCaseFeatures{ + EncryptionRotation:true, + }, + Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { + deployment.status.last = api.DeploymentStatus{ + Members: api.DeploymentStatusMembers{ + Agents: api.MemberStatusList{ + firstAgentStatus, + }, + }, + Images: createTestImagesWithVersion(true, "3.7.0"), + } + + testCase.createTestPodData(deployment, api.ServerGroupAgents, firstAgentStatus) + + secrets := deployment.GetKubeCli().CoreV1().Secrets(testNamespace) + key := make([]byte, 32) + k8sutil.CreateEncryptionKeySecret(secrets, testRocksDBEncryptionKey, key) + }, + ExpectedEvent: "member agent is created", ExpectedPod: core.Pod{ Spec: core.PodSpec{ Volumes: []core.Volume{ diff --git a/pkg/deployment/deployment_pod_tls_sni_test.go b/pkg/deployment/deployment_pod_tls_sni_test.go index 8d789689f..dfe1d1f19 100644 --- a/pkg/deployment/deployment_pod_tls_sni_test.go +++ b/pkg/deployment/deployment_pod_tls_sni_test.go @@ -83,6 +83,9 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, + Features:testCaseFeatures{ + TLSSNI:true, + }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") createTLSSNISecret(t, deployment.GetKubeCli(), "sni2", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -155,6 +158,9 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, + Features:testCaseFeatures{ + TLSSNI:true, + }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") createTLSSNISecret(t, deployment.GetKubeCli(), "sni2", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -227,6 +233,9 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, + Features:testCaseFeatures{ + TLSSNI:true, + }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") createTLSSNISecret(t, deployment.GetKubeCli(), "sni2", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -299,6 +308,9 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, + Features:testCaseFeatures{ + TLSSNI:true, + }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") createTLSSNISecret(t, deployment.GetKubeCli(), "sni2", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -404,6 +416,9 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, + Features:testCaseFeatures{ + TLSSNI:true, + }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") createTLSSNISecret(t, deployment.GetKubeCli(), "sni2", deployment.Namespace(), constants.SecretTLSKeyfile, "") diff --git a/pkg/deployment/deployment_run_test.go b/pkg/deployment/deployment_run_test.go index 040850c75..64f2210a9 100644 --- a/pkg/deployment/deployment_run_test.go +++ b/pkg/deployment/deployment_run_test.go @@ -25,6 +25,7 @@ package deployment import ( "encoding/json" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "testing" "github.com/rs/zerolog/log" @@ -92,6 +93,15 @@ func runTestCase(t *testing.T, testCase testCaseStruct) { testCase.Resources(t, d) } + // Set features + { + *features.EncryptionRotation().EnabledPointer() = testCase.Features.EncryptionRotation + require.Equal(t, testCase.Features.EncryptionRotation, *features.EncryptionRotation().EnabledPointer()) + *features.JWTRotation().EnabledPointer() = testCase.Features.JWTRotation + *features.TLSSNI().EnabledPointer() = testCase.Features.TLSSNI + *features.TLSRotation().EnabledPointer() = testCase.Features.TLSRotation + } + // Act cache, err := inspector.NewInspector(d.GetKubeCli(), d.GetNamespace()) require.NoError(t, err) diff --git a/pkg/deployment/deployment_suite_test.go b/pkg/deployment/deployment_suite_test.go index 3be9a3973..822ef0081 100644 --- a/pkg/deployment/deployment_suite_test.go +++ b/pkg/deployment/deployment_suite_test.go @@ -68,6 +68,10 @@ const ( testYes = "yes" ) +type testCaseFeatures struct { + TLSSNI, TLSRotation,JWTRotation,EncryptionRotation bool +} + type testCaseStruct struct { Name string ArangoDeployment *api.ArangoDeployment @@ -78,6 +82,7 @@ type testCaseStruct struct { ExpectedError error ExpectedEvent string ExpectedPod core.Pod + Features testCaseFeatures } func createTestTLSVolume(serverGroupString, ID string) core.Volume { diff --git a/pkg/deployment/features/encryption.go b/pkg/deployment/features/encryption.go new file mode 100644 index 000000000..97a9882f2 --- /dev/null +++ b/pkg/deployment/features/encryption.go @@ -0,0 +1,37 @@ +// +// DISCLAIMER +// +// Copyright 2020 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 features + +func init() { + registerFeature(encryptionRotation) +} + +var encryptionRotation = &feature{ + name: "encryption-rotation", + description: "Encryption Key rotation in runtime", + version: "3.7.0", + enterpriseRequired: true, + enabledByDefault: false, +} + +func EncryptionRotation() Feature { + return encryptionRotation +} diff --git a/pkg/deployment/features/features.go b/pkg/deployment/features/features.go index 205b91171..d89e936c5 100644 --- a/pkg/deployment/features/features.go +++ b/pkg/deployment/features/features.go @@ -1,3 +1,23 @@ +// +// DISCLAIMER +// +// Copyright 2020 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 features import "github.com/arangodb/go-driver" @@ -7,21 +27,26 @@ var _ Feature = &feature{} type Feature interface { Name() string Description() string - LongDescription() string Version() driver.Version EnterpriseRequired() bool EnabledByDefault() bool + Enabled() bool EnabledPointer() *bool + Supported(v driver.Version, enterprise bool) bool } type feature struct { - name, description, longDescription string + name, description string version driver.Version enterpriseRequired, enabledByDefault, enabled bool } -func (f feature) LongDescription() string { - return f.longDescription +func (f feature) Supported(v driver.Version, enterprise bool) bool { + return Supported(&f, v, enterprise) +} + +func (f feature) Enabled() bool { + return f.enabled } func (f *feature) EnabledPointer() *bool { diff --git a/pkg/deployment/features/jwt.go b/pkg/deployment/features/jwt.go index 283981400..df6d32431 100644 --- a/pkg/deployment/features/jwt.go +++ b/pkg/deployment/features/jwt.go @@ -1,18 +1,37 @@ +// +// DISCLAIMER +// +// Copyright 2020 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 features func init() { registerFeature(jwtRotation) } -var jwtRotation Feature = &feature{ +var jwtRotation = &feature{ name: "jwt-rotation", description: "JWT Token rotation in runtime", - longDescription: "Enables Runtime Rotation of JWT tokens on ArangoD Pods", version: "3.7.0", enterpriseRequired: true, enabledByDefault: false, } -func JWT() Feature { +func JWTRotation() Feature { return jwtRotation } diff --git a/pkg/deployment/features/local.go b/pkg/deployment/features/local.go index c2bc9a794..b5798ac34 100644 --- a/pkg/deployment/features/local.go +++ b/pkg/deployment/features/local.go @@ -1,13 +1,35 @@ +// +// DISCLAIMER +// +// Copyright 2020 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 features import ( "fmt" + "github.com/arangodb/go-driver" "github.com/spf13/cobra" "sync" ) -var features map[string] Feature = map[string]Feature{} +var features = map[string]Feature{} var featuresLock sync.Mutex +var enableAll = false func registerFeature(f Feature) { featuresLock.Lock() @@ -38,6 +60,8 @@ func Init(cmd *cobra.Command) { f := cmd.Flags() + f.BoolVar(&enableAll, "deployment.feature.all", false, "Enable ALL Features") + for _, feature := range features { z := "" @@ -63,7 +87,26 @@ func cmdRun(cmd *cobra.Command, args []string) { for _, feature := range features { println(fmt.Sprintf("Feature: %s", feature.Name())) + println(fmt.Sprintf("Description: %s", feature.Description())) + if feature.EnabledByDefault() { + println("Enabled: true") + } else { + println("Enabled: false") + } + if v := feature.Version(); v != "" { + println(fmt.Sprintf("ArangoDB Version Required: >= %s", v)) + } + + if feature.EnterpriseRequired() { + println(fmt.Sprintf("ArangoDB Edition Required: Enterprise")) + }else{ + println(fmt.Sprintf("ArangoDB Edition Required: Community, Enterprise")) + } println() } +} + +func Supported(f Feature, v driver.Version, enterprise bool) bool { + return f.Enabled() && ((f.EnterpriseRequired() && enterprise) || !f.EnterpriseRequired()) && v.CompareTo(f.Version()) >= 0 } \ No newline at end of file diff --git a/pkg/deployment/features/tls.go b/pkg/deployment/features/tls.go new file mode 100644 index 000000000..3a17a5d7a --- /dev/null +++ b/pkg/deployment/features/tls.go @@ -0,0 +1,50 @@ +// +// DISCLAIMER +// +// Copyright 2020 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 features + +func init() { + registerFeature(tlsRotation) + registerFeature(tlsSNI) +} + +var tlsRotation Feature = &feature{ + name: "tls-rotation", + description: "TLS Keyfile rotation in runtime", + version: "3.7.0", + enterpriseRequired: true, + enabledByDefault: false, +} + +func TLSRotation() Feature { + return tlsRotation +} + +var tlsSNI Feature = &feature{ + name: "tls-sni", + description: "TLS SNI Support", + version: "3.7.0", + enterpriseRequired: true, + enabledByDefault: true, +} + +func TLSSNI() Feature { + return tlsSNI +} diff --git a/pkg/deployment/pod/encryption.go b/pkg/deployment/pod/encryption.go index 67e2abb5b..ab64abdb8 100644 --- a/pkg/deployment/pod/encryption.go +++ b/pkg/deployment/pod/encryption.go @@ -25,6 +25,7 @@ package pod import ( "crypto/sha256" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "path/filepath" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" @@ -106,7 +107,7 @@ func IsEncryptionEnabled(i Input) bool { } func MultiFileMode(i Input) bool { - return i.Enterprise && i.Version.CompareTo("3.7.0") >= 0 + return features.EncryptionRotation().Supported(i.Version, i.Enterprise) } func Encryption() Builder { diff --git a/pkg/deployment/pod/jwt.go b/pkg/deployment/pod/jwt.go index bcc31e81f..6b450a8ee 100644 --- a/pkg/deployment/pod/jwt.go +++ b/pkg/deployment/pod/jwt.go @@ -24,6 +24,7 @@ package pod import ( "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "path/filepath" "github.com/arangodb/go-driver" @@ -56,7 +57,7 @@ func JWTSecretFolder(name string) string { } func VersionHasJWTSecretKeyfolder(v driver.Version, enterprise bool) bool { - return enterprise && v.CompareTo("3.7.0") > 0 + return features.JWTRotation().Supported(v, enterprise) } func JWT() Builder { @@ -122,11 +123,11 @@ func (e jwt) Verify(i Input, cachedStatus inspector.Inspector) error { if !VersionHasJWTSecretKeyfolder(i.Version, i.Enterprise) { secret, exists := cachedStatus.Secret(i.Deployment.Authentication.GetJWTSecretName()) if !exists { - return errors.Errorf("Secret for JWT token is missing %s", i.Deployment.Authentication.GetJWTSecretName()) + return errors.Errorf("Secret for JWTRotation token is missing %s", i.Deployment.Authentication.GetJWTSecretName()) } if err := k8sutil.ValidateTokenFromSecret(secret); err != nil { - return errors.Wrapf(err, "Cluster JWT secret validation failed") + return errors.Wrapf(err, "Cluster JWTRotation secret validation failed") } } diff --git a/pkg/deployment/pod/sni.go b/pkg/deployment/pod/sni.go index a0b67840c..fb22af719 100644 --- a/pkg/deployment/pod/sni.go +++ b/pkg/deployment/pod/sni.go @@ -25,6 +25,7 @@ package pod import ( "crypto/sha256" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" @@ -66,7 +67,7 @@ func (s sni) isSupported(i Input) bool { return false } - if i.Version.CompareTo("3.7.0") < 0 || !i.Enterprise { + if !features.TLSSNI().Supported(i.Version, i.Enterprise) { // We need 3.7.0+ and Enterprise to support this return false } diff --git a/pkg/deployment/pod/tls.go b/pkg/deployment/pod/tls.go index 978e420e7..60b27d063 100644 --- a/pkg/deployment/pod/tls.go +++ b/pkg/deployment/pod/tls.go @@ -23,6 +23,7 @@ package pod import ( + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "path/filepath" api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" @@ -35,8 +36,7 @@ import ( ) func IsRuntimeTLSKeyfileUpdateSupported(i Input) bool { - return IsTLSEnabled(i) && i.Enterprise && - i.Version.CompareTo("3.7.0") >= 0 && + return IsTLSEnabled(i) && features.TLSRotation().Supported(i.Version, i.Enterprise) && i.Deployment.TLS.Mode.Get() == api.TLSRotateModeInPlace } diff --git a/pkg/deployment/reconcile/action_encryption_add.go b/pkg/deployment/reconcile/action_encryption_add.go index 027daf908..28fa54972 100644 --- a/pkg/deployment/reconcile/action_encryption_add.go +++ b/pkg/deployment/reconcile/action_encryption_add.go @@ -25,6 +25,7 @@ package reconcile import ( "context" "encoding/base64" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/patch" "github.com/arangodb/kube-arangodb/pkg/deployment/pod" @@ -43,11 +44,8 @@ func ensureEncryptionSupport(actionCtx ActionContext) error { if image, ok := actionCtx.GetCurrentImageInfo(); !ok { return errors.Errorf("Missing image info") } else { - if !image.Enterprise { - return errors.Errorf("Supported only in enterprise") - } - if image.ArangoDBVersion.CompareTo("3.7.0") < 0 { - return errors.Errorf("Supported only in 3.7.0+") + if !features.EncryptionRotation().Supported(image.ArangoDBVersion, image.Enterprise) { + return errors.Errorf("Supported only in Enterprise Edition 3.7.0+") } } return nil diff --git a/pkg/deployment/reconcile/action_jwt_status_update.go b/pkg/deployment/reconcile/action_jwt_status_update.go index 11d02918e..76897aff1 100644 --- a/pkg/deployment/reconcile/action_jwt_status_update.go +++ b/pkg/deployment/reconcile/action_jwt_status_update.go @@ -25,6 +25,7 @@ package reconcile import ( "context" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "sort" "github.com/arangodb/kube-arangodb/pkg/util/constants" @@ -56,10 +57,7 @@ func ensureJWTFolderSupport(spec api.DeploymentSpec, status api.DeploymentStatus if image := status.CurrentImage; image == nil { return false, errors.Errorf("Missing image info") } else { - if !image.Enterprise { - return false, nil - } - if image.ArangoDBVersion.CompareTo("3.7.0") < 0 { + if !features.JWTRotation().Supported(image.ArangoDBVersion, image.Enterprise) { return false, nil } } @@ -94,7 +92,7 @@ func (a *jwtStatusUpdateAction) Start(ctx context.Context) (bool, error) { if !folder { f, ok := a.actionCtx.GetCachedStatus().Secret(a.actionCtx.GetSpec().Authentication.GetJWTSecretName()) if !ok { - a.log.Error().Msgf("Unable to get JWT secret info") + a.log.Error().Msgf("Unable to get JWTRotation secret info") return true, nil } @@ -127,7 +125,7 @@ func (a *jwtStatusUpdateAction) Start(ctx context.Context) (bool, error) { f, ok := a.actionCtx.GetCachedStatus().Secret(pod.JWTSecretFolder(a.actionCtx.GetName())) if !ok { - a.log.Error().Msgf("Unable to get JWT folder info") + a.log.Error().Msgf("Unable to get JWTRotation folder info") return true, nil } diff --git a/pkg/deployment/reconcile/plan_builder_encryption.go b/pkg/deployment/reconcile/plan_builder_encryption.go index e6d468dc3..7eed0f442 100644 --- a/pkg/deployment/reconcile/plan_builder_encryption.go +++ b/pkg/deployment/reconcile/plan_builder_encryption.go @@ -24,6 +24,7 @@ package reconcile import ( "context" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" core "k8s.io/api/core/v1" @@ -45,7 +46,7 @@ func skipEncryptionPlan(spec api.DeploymentSpec, status api.DeploymentStatus) bo return true } - if i := status.CurrentImage; i == nil || !i.Enterprise || i.ArangoDBVersion.CompareTo("3.7.0") < 0 { + if i := status.CurrentImage; i == nil || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { return true } @@ -275,7 +276,7 @@ func isEncryptionKeyUpToDate(ctx context.Context, return false, true } - if m.ArangoVersion.CompareTo("3.7.0") < 0 { + if i, ok := status.Images.GetByImageID(m.ImageID); !ok || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { return false, false } diff --git a/pkg/deployment/reconcile/plan_builder_jwt.go b/pkg/deployment/reconcile/plan_builder_jwt.go index 24258f74e..be1384420 100644 --- a/pkg/deployment/reconcile/plan_builder_jwt.go +++ b/pkg/deployment/reconcile/plan_builder_jwt.go @@ -25,6 +25,7 @@ package reconcile import ( "context" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "sort" "github.com/arangodb/kube-arangodb/pkg/deployment/client" @@ -51,7 +52,7 @@ func createJWTKeyUpdate(ctx context.Context, folder, ok := cachedStatus.Secret(pod.JWTSecretFolder(apiObject.GetName())) if !ok { - log.Error().Msgf("Unable to get JWT folder info") + log.Error().Msgf("Unable to get JWTRotation folder info") return nil } @@ -70,7 +71,7 @@ func createJWTKeyUpdate(ctx context.Context, jwtSha := util.SHA256(jwt) if _, ok := folder.Data[jwtSha]; !ok { - return addJWTPropagatedPlanAction(status, api.NewAction(api.ActionTypeJWTAdd, api.ServerGroupUnknown, "", "Add JWT key").AddParam(checksum, jwtSha)) + return addJWTPropagatedPlanAction(status, api.NewAction(api.ActionTypeJWTAdd, api.ServerGroupUnknown, "", "Add JWTRotation key").AddParam(checksum, jwtSha)) } activeKey, ok := folder.Data[pod.ActiveJWTKey] @@ -144,7 +145,7 @@ func createJWTStatusUpdateRequired(ctx context.Context, f, ok := cachedStatus.Secret(spec.Authentication.GetJWTSecretName()) if !ok { - log.Error().Msgf("Unable to get JWT secret info") + log.Error().Msgf("Unable to get JWTRotation secret info") return false } @@ -166,7 +167,7 @@ func createJWTStatusUpdateRequired(ctx context.Context, f, ok := cachedStatus.Secret(pod.JWTSecretFolder(apiObject.GetName())) if !ok { - log.Error().Msgf("Unable to get JWT folder info") + log.Error().Msgf("Unable to get JWTRotation folder info") return false } @@ -246,7 +247,7 @@ func isJWTTokenUpToDate(ctx context.Context, return false, true } - if m.ArangoVersion.CompareTo("3.7.0") < 0 { + if i, ok := status.Images.GetByImageID(m.ImageID); !ok || !features.JWTRotation().Supported(i.ArangoDBVersion, i.Enterprise) { return false, false } @@ -259,7 +260,7 @@ func isJWTTokenUpToDate(ctx context.Context, } if updateRequired, err := isMemberJWTTokenInvalid(ctx, client.NewClient(c.Connection()), folder.Data, false); err != nil { - mlog.Warn().Err(err).Msg("JET UpToDate Check failed") + mlog.Warn().Err(err).Msg("JWT UpToDate Check failed") return false, true } else if updateRequired { return true, false @@ -291,15 +292,15 @@ func isMemberJWTTokenInvalid(ctx context.Context, c client.Client, data map[stri e, err := cmd(ctx) if err != nil { - return false, errors.Wrapf(err, "Unable to fetch JWT tokens") + return false, errors.Wrapf(err, "Unable to fetch JWTRotation tokens") } if e.Result.Active == nil { - return false, errors.Wrapf(err, "There is no active JWT Token") + return false, errors.Wrapf(err, "There is no active JWTRotation Token") } if jwtActive, ok := data[pod.ActiveJWTKey]; !ok { - return false, errors.Errorf("Missing Active JWT Token in folder") + return false, errors.Errorf("Missing Active JWTRotation Token in folder") } else if util.SHA256(jwtActive) != e.Result.Active.GetSHA().Checksum() { log.Info().Str("active", e.Result.Active.GetSHA().Checksum()).Str("expected", util.SHA256(jwtActive)).Msgf("Active key is invalid") return true, nil @@ -319,7 +320,7 @@ func compareJWTKeys(e client.Entries, keys map[string][]byte) bool { } if !e.Contains(k) { - log.Info().Msgf("Missing JWT Key") + log.Info().Msgf("Missing JWTRotation Key") return false } } diff --git a/pkg/deployment/reconcile/plan_builder_restore.go b/pkg/deployment/reconcile/plan_builder_restore.go index 101bd967e..d01ba5c60 100644 --- a/pkg/deployment/reconcile/plan_builder_restore.go +++ b/pkg/deployment/reconcile/plan_builder_restore.go @@ -24,6 +24,7 @@ package reconcile import ( "context" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" @@ -85,9 +86,9 @@ func createRestorePlanEncryption(ctx context.Context, log zerolog.Logger, spec a return true, nil } - if i := status.CurrentImage; i == nil || !i.Enterprise || i.ArangoDBVersion.CompareTo("3.7.0") < 0 { - return true, nil - } + if i := status.CurrentImage; i == nil || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { + return nil + } if !status.Hashes.Encryption.Propagated { return false, nil diff --git a/pkg/deployment/reconcile/plan_builder_tls.go b/pkg/deployment/reconcile/plan_builder_tls.go index 54748fc7c..ce2b348ad 100644 --- a/pkg/deployment/reconcile/plan_builder_tls.go +++ b/pkg/deployment/reconcile/plan_builder_tls.go @@ -27,6 +27,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "net/http" "net/url" "reflect" @@ -382,10 +383,10 @@ func createKeyfileRenewalPlanMode( return nil } - if i := status.CurrentImage; i == nil { + if i, ok := status.Images.GetByImageID(member.ImageID); !ok { mode = api.TLSRotateModeRecreate } else { - if !i.Enterprise || i.ArangoDBVersion.CompareTo("3.7.0") < 0 || i.ImageID != member.ImageID { + if !features.TLSRotation().Supported(i.ArangoDBVersion, i.Enterprise) { mode = api.TLSRotateModeRecreate } } diff --git a/pkg/deployment/reconcile/plan_builder_tls_sni.go b/pkg/deployment/reconcile/plan_builder_tls_sni.go index 72e5e078e..66b7518c5 100644 --- a/pkg/deployment/reconcile/plan_builder_tls_sni.go +++ b/pkg/deployment/reconcile/plan_builder_tls_sni.go @@ -24,6 +24,7 @@ package reconcile import ( "context" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" @@ -75,7 +76,7 @@ func createRotateTLSServerSNIPlan(ctx context.Context, continue } - if m.ArangoVersion.CompareTo("3.7.0") < 0 { + if i, ok := status.Images.GetByImageID(m.ImageID); !ok || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { continue } diff --git a/pkg/deployment/resources/secret_hashes.go b/pkg/deployment/resources/secret_hashes.go index 9c97283b7..afa8cea94 100644 --- a/pkg/deployment/resources/secret_hashes.go +++ b/pkg/deployment/resources/secret_hashes.go @@ -27,6 +27,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "sort" "strings" @@ -138,7 +139,7 @@ func (r *Resources) ValidateSecretHashes(cachedStatus inspector.Inspector) error } if spec.IsAuthenticated() { - if image == nil || image.ArangoDBVersion.CompareTo("3.7.0") < 0 { + if image == nil || !features.JWTRotation().Supported(image.ArangoDBVersion, image.Enterprise) { secretName := spec.Authentication.GetJWTSecretName() getExpectedHash := func() string { return getHashes().AuthJWT } setExpectedHash := func(h string) error { @@ -165,7 +166,7 @@ func (r *Resources) ValidateSecretHashes(cachedStatus inspector.Inspector) error } } if spec.RocksDB.IsEncrypted() { - if image == nil || image.ArangoDBVersion.CompareTo("3.7.0") < 0 { + if image == nil || !features.EncryptionRotation().Supported(image.ArangoDBVersion, image.Enterprise) { secretName := spec.RocksDB.Encryption.GetKeySecretName() getExpectedHash := func() string { return getHashes().RocksDBEncryptionKey } setExpectedHash := func(h string) error { diff --git a/pkg/deployment/resources/secrets.go b/pkg/deployment/resources/secrets.go index edf38267a..94424d0ef 100644 --- a/pkg/deployment/resources/secrets.go +++ b/pkg/deployment/resources/secrets.go @@ -27,6 +27,7 @@ import ( "crypto/sha256" "encoding/hex" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "time" "github.com/arangodb/kube-arangodb/pkg/deployment/patch" @@ -152,7 +153,7 @@ func (r *Resources) EnsureSecrets(log zerolog.Logger, cachedStatus inspector.Ins } } if spec.RocksDB.IsEncrypted() { - if i := status.CurrentImage; i != nil && i.Enterprise && i.ArangoDBVersion.CompareTo("3.7.0") >= 0 { + if i := status.CurrentImage; i != nil && features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { if err := r.refreshCache(cachedStatus, r.ensureEncryptionKeyfolderSecret(cachedStatus, secrets, spec.RocksDB.Encryption.GetKeySecretName(), pod.GetEncryptionFolderSecretName(deploymentName))); err != nil { return maskAny(err) } @@ -583,7 +584,7 @@ func (r *Resources) ensureClientAuthCACertificateSecret(cachedStatus inspector.I return nil } -// getJWTSecret loads the JWT secret from a Secret configured in apiObject.Spec.Authentication.JWTSecretName. +// getJWTSecret loads the JWTRotation secret from a Secret configured in apiObject.Spec.Authentication.JWTSecretName. func (r *Resources) getJWTSecret(spec api.DeploymentSpec) (string, error) { if !spec.IsAuthenticated() { return "", nil @@ -594,13 +595,13 @@ func (r *Resources) getJWTSecret(spec api.DeploymentSpec) (string, error) { secretName := spec.Authentication.GetJWTSecretName() s, err := k8sutil.GetTokenSecret(secrets, secretName) if err != nil { - r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get JWT secret") + r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get JWTRotation secret") return "", maskAny(err) } return s, nil } -// getSyncJWTSecret loads the JWT secret used for syncmasters from a Secret configured in apiObject.Spec.Sync.Authentication.JWTSecretName. +// getSyncJWTSecret loads the JWTRotation secret used for syncmasters from a Secret configured in apiObject.Spec.Sync.Authentication.JWTSecretName. func (r *Resources) getSyncJWTSecret(spec api.DeploymentSpec) (string, error) { kubecli := r.context.GetKubeCli() ns := r.context.GetNamespace() @@ -608,7 +609,7 @@ func (r *Resources) getSyncJWTSecret(spec api.DeploymentSpec) (string, error) { secretName := spec.Sync.Authentication.GetJWTSecretName() s, err := k8sutil.GetTokenSecret(secrets, secretName) if err != nil { - r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get sync JWT secret") + r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get sync JWTRotation secret") return "", maskAny(err) } return s, nil From 3caa0e774859da043be1f01e6a7ac9979ab85881 Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Wed, 15 Jul 2020 04:48:39 +0000 Subject: [PATCH 3/6] S --- main.go | 3 ++- pkg/deployment/context_impl.go | 3 ++- pkg/deployment/deployment_encryption_test.go | 2 +- pkg/deployment/deployment_pod_tls_sni_test.go | 20 +++++++++---------- pkg/deployment/deployment_run_test.go | 3 ++- pkg/deployment/deployment_suite_test.go | 4 ++-- pkg/deployment/features/features.go | 8 ++++---- pkg/deployment/features/local.go | 11 +++++----- pkg/deployment/pod/encryption.go | 3 ++- pkg/deployment/pod/jwt.go | 3 ++- pkg/deployment/pod/sni.go | 1 + pkg/deployment/pod/tls.go | 3 ++- .../reconcile/action_encryption_add.go | 1 + .../reconcile/action_jwt_status_update.go | 3 ++- .../reconcile/plan_builder_encryption.go | 1 + pkg/deployment/reconcile/plan_builder_jwt.go | 3 ++- .../reconcile/plan_builder_restore.go | 1 + pkg/deployment/reconcile/plan_builder_tls.go | 5 +++-- .../reconcile/plan_builder_tls_sni.go | 1 + pkg/deployment/resources/secret_hashes.go | 3 ++- pkg/deployment/resources/secrets.go | 2 +- 21 files changed, 50 insertions(+), 34 deletions(-) diff --git a/main.go b/main.go index 6038c7f37..d7fc96103 100644 --- a/main.go +++ b/main.go @@ -25,13 +25,14 @@ package main import ( goflag "flag" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "net" "os" "strconv" "strings" "time" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/rs/zerolog/log" deploymentApi "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" diff --git a/pkg/deployment/context_impl.go b/pkg/deployment/context_impl.go index 5b842ea02..909638170 100644 --- a/pkg/deployment/context_impl.go +++ b/pkg/deployment/context_impl.go @@ -26,12 +26,13 @@ import ( "context" "crypto/tls" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "net" nhttp "net/http" "strconv" "time" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/go-driver/http" "github.com/arangodb/go-driver/jwt" "github.com/arangodb/kube-arangodb/pkg/deployment/pod" diff --git a/pkg/deployment/deployment_encryption_test.go b/pkg/deployment/deployment_encryption_test.go index 49472cb1b..d9fbf099c 100644 --- a/pkg/deployment/deployment_encryption_test.go +++ b/pkg/deployment/deployment_encryption_test.go @@ -270,7 +270,7 @@ func TestEnsurePod_ArangoDB_Encryption(t *testing.T) { }, }, Features: testCaseFeatures{ - EncryptionRotation:true, + EncryptionRotation: true, }, Helper: func(t *testing.T, deployment *Deployment, testCase *testCaseStruct) { deployment.status.last = api.DeploymentStatus{ diff --git a/pkg/deployment/deployment_pod_tls_sni_test.go b/pkg/deployment/deployment_pod_tls_sni_test.go index dfe1d1f19..ce9338a9a 100644 --- a/pkg/deployment/deployment_pod_tls_sni_test.go +++ b/pkg/deployment/deployment_pod_tls_sni_test.go @@ -83,8 +83,8 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, - Features:testCaseFeatures{ - TLSSNI:true, + Features: testCaseFeatures{ + TLSSNI: true, }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -158,8 +158,8 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, - Features:testCaseFeatures{ - TLSSNI:true, + Features: testCaseFeatures{ + TLSSNI: true, }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -233,8 +233,8 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, - Features:testCaseFeatures{ - TLSSNI:true, + Features: testCaseFeatures{ + TLSSNI: true, }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -308,8 +308,8 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, - Features:testCaseFeatures{ - TLSSNI:true, + Features: testCaseFeatures{ + TLSSNI: true, }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") @@ -416,8 +416,8 @@ func TestEnsurePod_ArangoDB_TLS_SNI(t *testing.T) { }(), }, }, - Features:testCaseFeatures{ - TLSSNI:true, + Features: testCaseFeatures{ + TLSSNI: true, }, Resources: func(t *testing.T, deployment *Deployment) { createTLSSNISecret(t, deployment.GetKubeCli(), "sni1", deployment.Namespace(), constants.SecretTLSKeyfile, "") diff --git a/pkg/deployment/deployment_run_test.go b/pkg/deployment/deployment_run_test.go index 64f2210a9..f357b46d7 100644 --- a/pkg/deployment/deployment_run_test.go +++ b/pkg/deployment/deployment_run_test.go @@ -25,9 +25,10 @@ package deployment import ( "encoding/json" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "testing" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/rs/zerolog/log" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" diff --git a/pkg/deployment/deployment_suite_test.go b/pkg/deployment/deployment_suite_test.go index 822ef0081..d60af5cb5 100644 --- a/pkg/deployment/deployment_suite_test.go +++ b/pkg/deployment/deployment_suite_test.go @@ -69,7 +69,7 @@ const ( ) type testCaseFeatures struct { - TLSSNI, TLSRotation,JWTRotation,EncryptionRotation bool + TLSSNI, TLSRotation, JWTRotation, EncryptionRotation bool } type testCaseStruct struct { @@ -82,7 +82,7 @@ type testCaseStruct struct { ExpectedError error ExpectedEvent string ExpectedPod core.Pod - Features testCaseFeatures + Features testCaseFeatures } func createTestTLSVolume(serverGroupString, ID string) core.Volume { diff --git a/pkg/deployment/features/features.go b/pkg/deployment/features/features.go index d89e936c5..726dff2ec 100644 --- a/pkg/deployment/features/features.go +++ b/pkg/deployment/features/features.go @@ -36,9 +36,9 @@ type Feature interface { } type feature struct { - name, description string - version driver.Version - enterpriseRequired, enabledByDefault, enabled bool + name, description string + version driver.Version + enterpriseRequired, enabledByDefault, enabled bool } func (f feature) Supported(v driver.Version, enterprise bool) bool { @@ -71,4 +71,4 @@ func (f feature) Name() string { func (f feature) Description() string { return f.description -} \ No newline at end of file +} diff --git a/pkg/deployment/features/local.go b/pkg/deployment/features/local.go index b5798ac34..d20abd183 100644 --- a/pkg/deployment/features/local.go +++ b/pkg/deployment/features/local.go @@ -22,9 +22,10 @@ package features import ( "fmt" + "sync" + "github.com/arangodb/go-driver" "github.com/spf13/cobra" - "sync" ) var features = map[string]Feature{} @@ -47,9 +48,9 @@ func registerFeature(f Feature) { } var internalCMD = &cobra.Command{ - Use: "features", + Use: "features", Short: "Describe all operator features", - Run: cmdRun, + Run: cmdRun, } func Init(cmd *cobra.Command) { @@ -99,7 +100,7 @@ func cmdRun(cmd *cobra.Command, args []string) { if feature.EnterpriseRequired() { println(fmt.Sprintf("ArangoDB Edition Required: Enterprise")) - }else{ + } else { println(fmt.Sprintf("ArangoDB Edition Required: Community, Enterprise")) } @@ -109,4 +110,4 @@ func cmdRun(cmd *cobra.Command, args []string) { func Supported(f Feature, v driver.Version, enterprise bool) bool { return f.Enabled() && ((f.EnterpriseRequired() && enterprise) || !f.EnterpriseRequired()) && v.CompareTo(f.Version()) >= 0 -} \ No newline at end of file +} diff --git a/pkg/deployment/pod/encryption.go b/pkg/deployment/pod/encryption.go index ab64abdb8..2f1ab092b 100644 --- a/pkg/deployment/pod/encryption.go +++ b/pkg/deployment/pod/encryption.go @@ -25,9 +25,10 @@ package pod import ( "crypto/sha256" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "path/filepath" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" diff --git a/pkg/deployment/pod/jwt.go b/pkg/deployment/pod/jwt.go index 6b450a8ee..ca7ae65c9 100644 --- a/pkg/deployment/pod/jwt.go +++ b/pkg/deployment/pod/jwt.go @@ -24,9 +24,10 @@ package pod import ( "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "path/filepath" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/go-driver" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" "github.com/arangodb/kube-arangodb/pkg/util/constants" diff --git a/pkg/deployment/pod/sni.go b/pkg/deployment/pod/sni.go index fb22af719..3d59fd242 100644 --- a/pkg/deployment/pod/sni.go +++ b/pkg/deployment/pod/sni.go @@ -25,6 +25,7 @@ package pod import ( "crypto/sha256" "fmt" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" diff --git a/pkg/deployment/pod/tls.go b/pkg/deployment/pod/tls.go index 60b27d063..738daebc9 100644 --- a/pkg/deployment/pod/tls.go +++ b/pkg/deployment/pod/tls.go @@ -23,9 +23,10 @@ package pod import ( - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "path/filepath" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + api "github.com/arangodb/kube-arangodb/pkg/apis/deployment/v1" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" diff --git a/pkg/deployment/reconcile/action_encryption_add.go b/pkg/deployment/reconcile/action_encryption_add.go index 28fa54972..486609efa 100644 --- a/pkg/deployment/reconcile/action_encryption_add.go +++ b/pkg/deployment/reconcile/action_encryption_add.go @@ -25,6 +25,7 @@ package reconcile import ( "context" "encoding/base64" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/patch" diff --git a/pkg/deployment/reconcile/action_jwt_status_update.go b/pkg/deployment/reconcile/action_jwt_status_update.go index 76897aff1..63c2f8fe0 100644 --- a/pkg/deployment/reconcile/action_jwt_status_update.go +++ b/pkg/deployment/reconcile/action_jwt_status_update.go @@ -25,9 +25,10 @@ package reconcile import ( "context" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "sort" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/kube-arangodb/pkg/util/constants" "github.com/pkg/errors" diff --git a/pkg/deployment/reconcile/plan_builder_encryption.go b/pkg/deployment/reconcile/plan_builder_encryption.go index 7eed0f442..57be02cf1 100644 --- a/pkg/deployment/reconcile/plan_builder_encryption.go +++ b/pkg/deployment/reconcile/plan_builder_encryption.go @@ -24,6 +24,7 @@ package reconcile import ( "context" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" core "k8s.io/api/core/v1" diff --git a/pkg/deployment/reconcile/plan_builder_jwt.go b/pkg/deployment/reconcile/plan_builder_jwt.go index be1384420..9a0794c88 100644 --- a/pkg/deployment/reconcile/plan_builder_jwt.go +++ b/pkg/deployment/reconcile/plan_builder_jwt.go @@ -25,9 +25,10 @@ package reconcile import ( "context" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "sort" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/kube-arangodb/pkg/deployment/client" "github.com/pkg/errors" "github.com/rs/zerolog/log" diff --git a/pkg/deployment/reconcile/plan_builder_restore.go b/pkg/deployment/reconcile/plan_builder_restore.go index d01ba5c60..2febc87b9 100644 --- a/pkg/deployment/reconcile/plan_builder_restore.go +++ b/pkg/deployment/reconcile/plan_builder_restore.go @@ -24,6 +24,7 @@ package reconcile import ( "context" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" diff --git a/pkg/deployment/reconcile/plan_builder_tls.go b/pkg/deployment/reconcile/plan_builder_tls.go index ce2b348ad..4da64788d 100644 --- a/pkg/deployment/reconcile/plan_builder_tls.go +++ b/pkg/deployment/reconcile/plan_builder_tls.go @@ -27,12 +27,13 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "net/http" "net/url" "reflect" "time" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/kube-arangodb/pkg/deployment/client" "github.com/arangodb/kube-arangodb/pkg/util/constants" @@ -383,7 +384,7 @@ func createKeyfileRenewalPlanMode( return nil } - if i, ok := status.Images.GetByImageID(member.ImageID); !ok { + if i, ok := status.Images.GetByImageID(member.ImageID); !ok { mode = api.TLSRotateModeRecreate } else { if !features.TLSRotation().Supported(i.ArangoDBVersion, i.Enterprise) { diff --git a/pkg/deployment/reconcile/plan_builder_tls_sni.go b/pkg/deployment/reconcile/plan_builder_tls_sni.go index 66b7518c5..3ce48f8dd 100644 --- a/pkg/deployment/reconcile/plan_builder_tls_sni.go +++ b/pkg/deployment/reconcile/plan_builder_tls_sni.go @@ -24,6 +24,7 @@ package reconcile import ( "context" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/util/k8sutil" diff --git a/pkg/deployment/resources/secret_hashes.go b/pkg/deployment/resources/secret_hashes.go index afa8cea94..df3cec8aa 100644 --- a/pkg/deployment/resources/secret_hashes.go +++ b/pkg/deployment/resources/secret_hashes.go @@ -27,10 +27,11 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "sort" "strings" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" + "github.com/arangodb/kube-arangodb/pkg/deployment/pod" "github.com/arangodb/kube-arangodb/pkg/deployment/resources/inspector" diff --git a/pkg/deployment/resources/secrets.go b/pkg/deployment/resources/secrets.go index 94424d0ef..06e90dc78 100644 --- a/pkg/deployment/resources/secrets.go +++ b/pkg/deployment/resources/secrets.go @@ -27,12 +27,12 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "time" "github.com/arangodb/kube-arangodb/pkg/deployment/patch" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/json" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/util" From e2f0cea746dc5554695c67f873fe99170c2baa1f Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Wed, 15 Jul 2020 08:42:01 +0000 Subject: [PATCH 4/6] S --- main.go | 4 ++++ pkg/operator/operator.go | 25 +++++++++++++++++++++---- pkg/operator/operator_leader.go | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/main.go b/main.go index d7fc96103..95b6cfafb 100644 --- a/main.go +++ b/main.go @@ -107,6 +107,8 @@ var ( enableBackup bool // Run backup operator alpineImage, metricsExporterImage, arangoImage string + + singleMode bool } chaosOptions struct { allowed bool @@ -135,6 +137,7 @@ func init() { f.StringVar(&operatorOptions.metricsExporterImage, "operator.metrics-exporter-image", MetricsExporterImageEnv.GetOrDefault(defaultMetricsExporterImage), "Docker image used for metrics containers by default") f.StringVar(&operatorOptions.arangoImage, "operator.arango-image", ArangoImageEnv.GetOrDefault(defaultArangoImage), "Docker image used for arango by default") f.BoolVar(&chaosOptions.allowed, "chaos.allowed", false, "Set to allow chaos in deployments. Only activated when allowed and enabled in deployment") + f.BoolVar(&operatorOptions.singleMode, "mode.single", false, "Enable single mode in Operator. WARNING: There should be only one replica of Operator, otherwise Operator can take unexpected actions") features.Init(&cmdMain) } @@ -303,6 +306,7 @@ func newOperatorConfigAndDeps(id, namespace, name string) (operator.Config, oper AlpineImage: operatorOptions.alpineImage, MetricsExporterImage: operatorOptions.metricsExporterImage, ArangoImage: operatorOptions.arangoImage, + SingleMode: operatorOptions.singleMode, } deps := operator.Dependencies{ LogService: logService, diff --git a/pkg/operator/operator.go b/pkg/operator/operator.go index 01990a119..33f7c4679 100644 --- a/pkg/operator/operator.go +++ b/pkg/operator/operator.go @@ -92,6 +92,7 @@ type Config struct { EnableStorage bool EnableBackup bool AllowChaos bool + SingleMode bool } type Dependencies struct { @@ -123,16 +124,32 @@ func NewOperator(config Config, deps Dependencies) (*Operator, error) { // Run the operator func (o *Operator) Run() { if o.Config.EnableDeployment { - go o.runLeaderElection("arango-deployment-operator", constants.LabelRole, o.onStartDeployment, o.Dependencies.DeploymentProbe) + if !o.Config.SingleMode { + go o.runLeaderElection("arango-deployment-operator", constants.LabelRole, o.onStartDeployment, o.Dependencies.DeploymentProbe) + } else { + go o.runWithoutLeaderElection("arango-deployment-operator", constants.LabelRole, o.onStartDeployment, o.Dependencies.DeploymentProbe) + } } if o.Config.EnableDeploymentReplication { - go o.runLeaderElection("arango-deployment-replication-operator", constants.LabelRole, o.onStartDeploymentReplication, o.Dependencies.DeploymentReplicationProbe) + if !o.Config.SingleMode { + go o.runLeaderElection("arango-deployment-replication-operator", constants.LabelRole, o.onStartDeploymentReplication, o.Dependencies.DeploymentReplicationProbe) + } else { + go o.runWithoutLeaderElection("arango-deployment-replication-operator", constants.LabelRole, o.onStartDeploymentReplication, o.Dependencies.DeploymentReplicationProbe) + } } if o.Config.EnableStorage { - go o.runLeaderElection("arango-storage-operator", constants.LabelRole, o.onStartStorage, o.Dependencies.StorageProbe) + if !o.Config.SingleMode { + go o.runLeaderElection("arango-storage-operator", constants.LabelRole, o.onStartStorage, o.Dependencies.StorageProbe) + } else { + go o.runWithoutLeaderElection("arango-storage-operator", constants.LabelRole, o.onStartStorage, o.Dependencies.StorageProbe) + } } if o.Config.EnableBackup { - go o.runLeaderElection("arango-backup-operator", constants.BackupLabelRole, o.onStartBackup, o.Dependencies.BackupProbe) + if !o.Config.SingleMode { + go o.runLeaderElection("arango-backup-operator", constants.BackupLabelRole, o.onStartBackup, o.Dependencies.BackupProbe) + } else { + go o.runWithoutLeaderElection("arango-backup-operator", constants.BackupLabelRole, o.onStartBackup, o.Dependencies.BackupProbe) + } } // Wait until process terminates <-context.TODO().Done() diff --git a/pkg/operator/operator_leader.go b/pkg/operator/operator_leader.go index fe7db19c7..ed0cda8d2 100644 --- a/pkg/operator/operator_leader.go +++ b/pkg/operator/operator_leader.go @@ -99,6 +99,25 @@ func (o *Operator) runLeaderElection(lockName, label string, onStart func(stop < }) } +func (o *Operator) runWithoutLeaderElection(lockName, label string, onStart func(stop <-chan struct{}), readyProbe *probe.ReadyProbe) { + log := o.log.With().Str("lock-name", lockName).Logger() + eventTarget := o.getLeaderElectionEventTarget(log) + recordEvent := func(reason, message string) { + if eventTarget != nil { + o.Dependencies.EventRecorder.Event(eventTarget, v1.EventTypeNormal, reason, message) + } + } + ctx := context.Background() + + recordEvent("Leader Election Skipped", fmt.Sprintf("Pod %s is running as leader", o.Config.PodName)) + readyProbe.SetReady() + if err := o.setRoleLabel(log, label, constants.LabelRoleLeader); err != nil { + log.Error().Msg("Cannot set leader role on Pod. Terminating process") + os.Exit(2) + } + onStart(ctx.Done()) +} + // getLeaderElectionEventTarget returns the object that leader election related // events will be added to. func (o *Operator) getLeaderElectionEventTarget(log zerolog.Logger) runtime.Object { From 136c193df6686d459e1cf42381b0db50eda0b77a Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Wed, 15 Jul 2020 12:57:38 +0000 Subject: [PATCH 5/6] Manifests --- pkg/deployment/pod/jwt.go | 4 ++-- .../reconcile/action_jwt_status_update.go | 4 ++-- pkg/deployment/reconcile/plan_builder_jwt.go | 14 +++++++------- pkg/deployment/reconcile/plan_builder_restore.go | 4 ++-- pkg/deployment/reconcile/plan_builder_tls.go | 7 +++++-- pkg/deployment/resources/secrets.go | 10 +++++----- 6 files changed, 23 insertions(+), 20 deletions(-) diff --git a/pkg/deployment/pod/jwt.go b/pkg/deployment/pod/jwt.go index ca7ae65c9..26739f62d 100644 --- a/pkg/deployment/pod/jwt.go +++ b/pkg/deployment/pod/jwt.go @@ -124,11 +124,11 @@ func (e jwt) Verify(i Input, cachedStatus inspector.Inspector) error { if !VersionHasJWTSecretKeyfolder(i.Version, i.Enterprise) { secret, exists := cachedStatus.Secret(i.Deployment.Authentication.GetJWTSecretName()) if !exists { - return errors.Errorf("Secret for JWTRotation token is missing %s", i.Deployment.Authentication.GetJWTSecretName()) + return errors.Errorf("Secret for JWT token is missing %s", i.Deployment.Authentication.GetJWTSecretName()) } if err := k8sutil.ValidateTokenFromSecret(secret); err != nil { - return errors.Wrapf(err, "Cluster JWTRotation secret validation failed") + return errors.Wrapf(err, "Cluster JWT secret validation failed") } } diff --git a/pkg/deployment/reconcile/action_jwt_status_update.go b/pkg/deployment/reconcile/action_jwt_status_update.go index 63c2f8fe0..b229168c3 100644 --- a/pkg/deployment/reconcile/action_jwt_status_update.go +++ b/pkg/deployment/reconcile/action_jwt_status_update.go @@ -93,7 +93,7 @@ func (a *jwtStatusUpdateAction) Start(ctx context.Context) (bool, error) { if !folder { f, ok := a.actionCtx.GetCachedStatus().Secret(a.actionCtx.GetSpec().Authentication.GetJWTSecretName()) if !ok { - a.log.Error().Msgf("Unable to get JWTRotation secret info") + a.log.Error().Msgf("Unable to get JWT secret info") return true, nil } @@ -126,7 +126,7 @@ func (a *jwtStatusUpdateAction) Start(ctx context.Context) (bool, error) { f, ok := a.actionCtx.GetCachedStatus().Secret(pod.JWTSecretFolder(a.actionCtx.GetName())) if !ok { - a.log.Error().Msgf("Unable to get JWTRotation folder info") + a.log.Error().Msgf("Unable to get JWT folder info") return true, nil } diff --git a/pkg/deployment/reconcile/plan_builder_jwt.go b/pkg/deployment/reconcile/plan_builder_jwt.go index 9a0794c88..834f8b40d 100644 --- a/pkg/deployment/reconcile/plan_builder_jwt.go +++ b/pkg/deployment/reconcile/plan_builder_jwt.go @@ -53,7 +53,7 @@ func createJWTKeyUpdate(ctx context.Context, folder, ok := cachedStatus.Secret(pod.JWTSecretFolder(apiObject.GetName())) if !ok { - log.Error().Msgf("Unable to get JWTRotation folder info") + log.Error().Msgf("Unable to get JWT folder info") return nil } @@ -146,7 +146,7 @@ func createJWTStatusUpdateRequired(ctx context.Context, f, ok := cachedStatus.Secret(spec.Authentication.GetJWTSecretName()) if !ok { - log.Error().Msgf("Unable to get JWTRotation secret info") + log.Error().Msgf("Unable to get JWT secret info") return false } @@ -168,7 +168,7 @@ func createJWTStatusUpdateRequired(ctx context.Context, f, ok := cachedStatus.Secret(pod.JWTSecretFolder(apiObject.GetName())) if !ok { - log.Error().Msgf("Unable to get JWTRotation folder info") + log.Error().Msgf("Unable to get JWT folder info") return false } @@ -293,15 +293,15 @@ func isMemberJWTTokenInvalid(ctx context.Context, c client.Client, data map[stri e, err := cmd(ctx) if err != nil { - return false, errors.Wrapf(err, "Unable to fetch JWTRotation tokens") + return false, errors.Wrapf(err, "Unable to fetch JWT tokens") } if e.Result.Active == nil { - return false, errors.Wrapf(err, "There is no active JWTRotation Token") + return false, errors.Wrapf(err, "There is no active JWT Token") } if jwtActive, ok := data[pod.ActiveJWTKey]; !ok { - return false, errors.Errorf("Missing Active JWTRotation Token in folder") + return false, errors.Errorf("Missing Active JWT Token in folder") } else if util.SHA256(jwtActive) != e.Result.Active.GetSHA().Checksum() { log.Info().Str("active", e.Result.Active.GetSHA().Checksum()).Str("expected", util.SHA256(jwtActive)).Msgf("Active key is invalid") return true, nil @@ -321,7 +321,7 @@ func compareJWTKeys(e client.Entries, keys map[string][]byte) bool { } if !e.Contains(k) { - log.Info().Msgf("Missing JWTRotation Key") + log.Info().Msgf("Missing JWT Key") return false } } diff --git a/pkg/deployment/reconcile/plan_builder_restore.go b/pkg/deployment/reconcile/plan_builder_restore.go index 2febc87b9..e9380629d 100644 --- a/pkg/deployment/reconcile/plan_builder_restore.go +++ b/pkg/deployment/reconcile/plan_builder_restore.go @@ -88,8 +88,8 @@ func createRestorePlanEncryption(ctx context.Context, log zerolog.Logger, spec a } if i := status.CurrentImage; i == nil || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { - return nil - } + return false, nil + } if !status.Hashes.Encryption.Propagated { return false, nil diff --git a/pkg/deployment/reconcile/plan_builder_tls.go b/pkg/deployment/reconcile/plan_builder_tls.go index 4da64788d..ef1dad34f 100644 --- a/pkg/deployment/reconcile/plan_builder_tls.go +++ b/pkg/deployment/reconcile/plan_builder_tls.go @@ -27,6 +27,7 @@ import ( "crypto/tls" "crypto/x509" "fmt" + "github.com/rs/zerolog/log" "net/http" "net/url" "reflect" @@ -305,7 +306,7 @@ func createKeyfileRenewalPlanDefault(ctx context.Context, return nil } if renew, recreate := keyfileRenewalRequired(ctx, log, apiObject, spec, status, cachedStatus, context, group, member, api.TLSRotateModeRecreate); renew { - log.Info().Msg("Renewal of keyfile required") + log.Info().Msg("Renewal of keyfile required - Recreate") if recreate { plan = append(plan, api.NewAction(api.ActionTypeCleanTLSKeyfileCertificate, group, member.ID, "Remove server keyfile and enforce renewal")) } @@ -336,7 +337,7 @@ func createKeyfileRenewalPlanInPlace(ctx context.Context, for _, member := range members { if renew, recreate := keyfileRenewalRequired(ctx, log, apiObject, spec, status, cachedStatus, context, group, member, api.TLSRotateModeInPlace); renew { - log.Info().Msg("Renewal of keyfile required") + log.Info().Msg("Renewal of keyfile required - InPlace") if recreate { plan = append(plan, api.NewAction(api.ActionTypeCleanTLSKeyfileCertificate, group, member.ID, "Remove server keyfile and enforce renewal")) } @@ -385,9 +386,11 @@ func createKeyfileRenewalPlanMode( } if i, ok := status.Images.GetByImageID(member.ImageID); !ok { + log.Info().Msgf("IMAGE NOT FOUND!!!") mode = api.TLSRotateModeRecreate } else { if !features.TLSRotation().Supported(i.ArangoDBVersion, i.Enterprise) { + log.Info().Msgf("IT IS NOT SUPPORTED!!!") mode = api.TLSRotateModeRecreate } } diff --git a/pkg/deployment/resources/secrets.go b/pkg/deployment/resources/secrets.go index 06e90dc78..653011526 100644 --- a/pkg/deployment/resources/secrets.go +++ b/pkg/deployment/resources/secrets.go @@ -29,10 +29,10 @@ import ( "fmt" "time" + "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/deployment/patch" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/json" - "github.com/arangodb/kube-arangodb/pkg/deployment/features" "github.com/arangodb/kube-arangodb/pkg/util" @@ -584,7 +584,7 @@ func (r *Resources) ensureClientAuthCACertificateSecret(cachedStatus inspector.I return nil } -// getJWTSecret loads the JWTRotation secret from a Secret configured in apiObject.Spec.Authentication.JWTSecretName. +// getJWTSecret loads the JWT secret from a Secret configured in apiObject.Spec.Authentication.JWTSecretName. func (r *Resources) getJWTSecret(spec api.DeploymentSpec) (string, error) { if !spec.IsAuthenticated() { return "", nil @@ -595,13 +595,13 @@ func (r *Resources) getJWTSecret(spec api.DeploymentSpec) (string, error) { secretName := spec.Authentication.GetJWTSecretName() s, err := k8sutil.GetTokenSecret(secrets, secretName) if err != nil { - r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get JWTRotation secret") + r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get JWT secret") return "", maskAny(err) } return s, nil } -// getSyncJWTSecret loads the JWTRotation secret used for syncmasters from a Secret configured in apiObject.Spec.Sync.Authentication.JWTSecretName. +// getSyncJWTSecret loads the JWT secret used for syncmasters from a Secret configured in apiObject.Spec.Sync.Authentication.JWTSecretName. func (r *Resources) getSyncJWTSecret(spec api.DeploymentSpec) (string, error) { kubecli := r.context.GetKubeCli() ns := r.context.GetNamespace() @@ -609,7 +609,7 @@ func (r *Resources) getSyncJWTSecret(spec api.DeploymentSpec) (string, error) { secretName := spec.Sync.Authentication.GetJWTSecretName() s, err := k8sutil.GetTokenSecret(secrets, secretName) if err != nil { - r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get sync JWTRotation secret") + r.log.Debug().Err(err).Str("secret-name", secretName).Msg("Failed to get sync JWT secret") return "", maskAny(err) } return s, nil From eed0c113e604f78c29af0ac8b86e9a98d9cf0c2d Mon Sep 17 00:00:00 2001 From: ajanikow <12255597+ajanikow@users.noreply.github.com> Date: Tue, 21 Jul 2020 06:52:35 +0000 Subject: [PATCH 6/6] Fix restore --- pkg/deployment/context_impl.go | 2 +- pkg/deployment/reconcile/plan_builder_restore.go | 8 +++++--- pkg/deployment/reconcile/plan_builder_tls.go | 3 --- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/pkg/deployment/context_impl.go b/pkg/deployment/context_impl.go index 909638170..83adff7c8 100644 --- a/pkg/deployment/context_impl.go +++ b/pkg/deployment/context_impl.go @@ -247,7 +247,7 @@ func (d *Deployment) getAuth() (driver.Authentication, error) { secrets := d.GetKubeCli().CoreV1().Secrets(d.apiObject.GetNamespace()) var secret string - if i := d.apiObject.Status.CurrentImage; i == nil || !features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { + if i := d.apiObject.Status.CurrentImage; i == nil || !features.JWTRotation().Supported(i.ArangoDBVersion, i.Enterprise) { s, err := secrets.Get(d.apiObject.Spec.Authentication.GetJWTSecretName(), meta.GetOptions{}) if err != nil { return nil, goErrors.Errorf("JWT Secret is missing") diff --git a/pkg/deployment/reconcile/plan_builder_restore.go b/pkg/deployment/reconcile/plan_builder_restore.go index e9380629d..28e5e4cac 100644 --- a/pkg/deployment/reconcile/plan_builder_restore.go +++ b/pkg/deployment/reconcile/plan_builder_restore.go @@ -67,9 +67,11 @@ func createRestorePlan(ctx context.Context, return p } - if !status.Hashes.Encryption.Propagated { - log.Warn().Msg("Backup not able to be restored in non propagated state") - return nil + if i := status.CurrentImage; i != nil && features.EncryptionRotation().Supported(i.ArangoDBVersion, i.Enterprise) { + if !status.Hashes.Encryption.Propagated { + log.Warn().Msg("Backup not able to be restored in non propagated state") + return nil + } } } diff --git a/pkg/deployment/reconcile/plan_builder_tls.go b/pkg/deployment/reconcile/plan_builder_tls.go index ef1dad34f..107c2f11d 100644 --- a/pkg/deployment/reconcile/plan_builder_tls.go +++ b/pkg/deployment/reconcile/plan_builder_tls.go @@ -27,7 +27,6 @@ import ( "crypto/tls" "crypto/x509" "fmt" - "github.com/rs/zerolog/log" "net/http" "net/url" "reflect" @@ -386,11 +385,9 @@ func createKeyfileRenewalPlanMode( } if i, ok := status.Images.GetByImageID(member.ImageID); !ok { - log.Info().Msgf("IMAGE NOT FOUND!!!") mode = api.TLSRotateModeRecreate } else { if !features.TLSRotation().Supported(i.ArangoDBVersion, i.Enterprise) { - log.Info().Msgf("IT IS NOT SUPPORTED!!!") mode = api.TLSRotateModeRecreate } }