From 5cb64c3a535803bc95cf54cff56e85214dc5747a Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Fri, 1 Nov 2024 10:27:53 +0000 Subject: [PATCH 01/12] add valid fields for gcp and az --- pkg/api/v1/encryption_at_rest.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pkg/api/v1/encryption_at_rest.go b/pkg/api/v1/encryption_at_rest.go index 750b12120b..6a4b3e2be0 100644 --- a/pkg/api/v1/encryption_at_rest.go +++ b/pkg/api/v1/encryption_at_rest.go @@ -51,6 +51,7 @@ type AzureKeyVault struct { keyIdentifier string // The unique identifier of a key in an Azure Key Vault. secret string // The secret associated with the Azure Key Vault specified by azureKeyVault.tenantID. TenantID string `json:"tenantID,omitempty"` // The unique identifier for an Azure AD tenant within an Azure subscription. + Valid *bool `json:"valid,omitempty"` // Specifies whether the encryption key set for the provider is valid and may be used to encrypt and decrypt data. // A reference to as Secret containing the SubscriptionID, KeyVaultName, KeyIdentifier, Secret fields // +optional SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` @@ -84,6 +85,7 @@ type GoogleCloudKms struct { Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. serviceAccountKey string // String-formatted JSON object containing GCP KMS credentials from your GCP account. keyVersionResourceID string // The Key Version Resource ID from your GCP account. + Valid *bool `json:"valid,omitempty"` // Specifies whether the encryption key set for the provider is valid and may be used to encrypt and decrypt data. // A reference to as Secret containing the ServiceAccountKey, KeyVersionResourceID fields // +optional SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` From 3ceb8c3a0757c86b31785bd046832b6322776baf Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Fri, 1 Nov 2024 10:28:02 +0000 Subject: [PATCH 02/12] add translation layer --- .../encryptionatrest/conversion.go | 177 ++++++++++++++++++ .../encryptionatrest/conversion_test.go | 52 +++++ .../encryptionatrest/encryptionatrest.go | 39 ++++ 3 files changed, 268 insertions(+) create mode 100644 internal/translation/encryptionatrest/conversion.go create mode 100644 internal/translation/encryptionatrest/conversion_test.go create mode 100644 internal/translation/encryptionatrest/encryptionatrest.go diff --git a/internal/translation/encryptionatrest/conversion.go b/internal/translation/encryptionatrest/conversion.go new file mode 100644 index 0000000000..d1c0dba53c --- /dev/null +++ b/internal/translation/encryptionatrest/conversion.go @@ -0,0 +1,177 @@ +package encryptionatrest + +import ( + "reflect" + + "go.mongodb.org/atlas-sdk/v20231115008/admin" + + akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" +) + +type EncryptionAtRest struct { + AWS AwsKms + Azure AzureKeyVault + GCP GoogleCloudKms +} + +type AwsKms struct { + akov2.AwsKms + AccessKeyID string + SecretAccessKey string + CustomerMasterKeyID string + RoleID string + CloudProviderIntegrationRole string +} + +func (a *AwsKms) SetSecrets(customerMasterKeyID, roleID string) { + a.CustomerMasterKeyID = customerMasterKeyID + a.RoleID = roleID +} + +func (a *AwsKms) ToAtlas() *admin.AWSKMSConfiguration { + if a == nil { + return nil + } + + result := &admin.AWSKMSConfiguration{ + Enabled: a.AwsKms.Enabled, + Region: &a.AwsKms.Region, + Valid: a.AwsKms.Valid, + + RoleId: &a.RoleID, + CustomerMasterKeyID: &a.CustomerMasterKeyID, + } + + if result.RoleId == nil && a.CloudProviderIntegrationRole != "" { + result.RoleId = &a.CloudProviderIntegrationRole + } + + return result +} + +type AzureKeyVault struct { + akov2.AzureKeyVault + SubscriptionID string + KeyVaultName string + KeyIdentifier string + Secret string +} + +func (az *AzureKeyVault) SetSecrets(subscriptionID, keyVaultName, keyIdentifier, secret string) { + az.SubscriptionID = subscriptionID + az.KeyVaultName = keyVaultName + az.KeyIdentifier = keyIdentifier + az.Secret = secret +} + +func (az *AzureKeyVault) ToAtlas() *admin.AzureKeyVault { + if az == nil { + return nil + } + + return &admin.AzureKeyVault{ + Enabled: az.AzureKeyVault.Enabled, + ClientID: &az.AzureKeyVault.ClientID, + AzureEnvironment: &az.AzureKeyVault.AzureEnvironment, + ResourceGroupName: &az.AzureKeyVault.ResourceGroupName, + TenantID: &az.AzureKeyVault.TenantID, + + SubscriptionID: &az.SubscriptionID, + KeyVaultName: &az.KeyVaultName, + KeyIdentifier: &az.KeyIdentifier, + Secret: &az.Secret, + } +} + +type GoogleCloudKms struct { + akov2.GoogleCloudKms + ServiceAccountKey string + KeyVersionResourceID string +} + +func (g *GoogleCloudKms) SetSecrets(serviceAccountKey, keyVersionResourceID string) { + g.ServiceAccountKey = serviceAccountKey + g.KeyVersionResourceID = keyVersionResourceID +} + +func (g *GoogleCloudKms) ToAtlas() *admin.GoogleCloudKMS { + if g == nil { + return nil + } + + return &admin.GoogleCloudKMS{ + Enabled: g.GoogleCloudKms.Enabled, + + ServiceAccountKey: &g.ServiceAccountKey, + KeyVersionResourceID: &g.KeyVersionResourceID, + } +} + +func NewEncryptionAtRest(project *akov2.AtlasProject) *EncryptionAtRest { + ear := &EncryptionAtRest{} + spec := project.Spec.EncryptionAtRest + if spec == nil { + return nil + } + + if *spec.AwsKms.Enabled { + ear.AWS.AwsKms = spec.AwsKms + for _, role := range project.Status.CloudProviderIntegrations { + if role.ProviderName == "AWS" { + ear.AWS.CloudProviderIntegrationRole = role.RoleID + } + } + } + if *spec.AzureKeyVault.Enabled { + ear.Azure.AzureKeyVault = spec.AzureKeyVault + } + if *spec.GoogleCloudKms.Enabled { + ear.GCP.GoogleCloudKms = spec.GoogleCloudKms + } + return ear +} + +func toAtlas(spec *EncryptionAtRest) *admin.EncryptionAtRest { + if spec == nil { + return nil + } + + return &admin.EncryptionAtRest{ + AwsKms: spec.AWS.ToAtlas(), + AzureKeyVault: spec.Azure.ToAtlas(), + GoogleCloudKms: spec.GCP.ToAtlas(), + } +} + +func fromAtlas(ear *admin.EncryptionAtRest) *EncryptionAtRest { + out := &EncryptionAtRest{} + if ear.HasAwsKms() { + out.AWS.AwsKms = akov2.AwsKms{ + Enabled: ear.AwsKms.Enabled, + Region: ear.AwsKms.GetRegion(), + Valid: ear.AwsKms.Valid, + } + } + if ear.HasAzureKeyVault() { + out.Azure.AzureKeyVault = akov2.AzureKeyVault{ + Enabled: ear.AzureKeyVault.Enabled, + AzureEnvironment: ear.AzureKeyVault.GetAzureEnvironment(), + ClientID: ear.AzureKeyVault.GetClientID(), + ResourceGroupName: ear.AzureKeyVault.GetResourceGroupName(), + TenantID: ear.AzureKeyVault.GetTenantID(), + Valid: ear.AzureKeyVault.Valid, + } + } + if ear.HasGoogleCloudKms() { + out.GCP.GoogleCloudKms = akov2.GoogleCloudKms{ + Enabled: ear.GoogleCloudKms.Enabled, + Valid: ear.GoogleCloudKms.Valid, + } + } + return out +} + +func EqualSpecs(spec, atlas *EncryptionAtRest) bool { + // Retracted secrets mean that this will never be equal + return reflect.DeepEqual(atlas, spec) +} diff --git a/internal/translation/encryptionatrest/conversion_test.go b/internal/translation/encryptionatrest/conversion_test.go new file mode 100644 index 0000000000..a0294dcbae --- /dev/null +++ b/internal/translation/encryptionatrest/conversion_test.go @@ -0,0 +1,52 @@ +package encryptionatrest + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + fuzz "github.com/google/gofuzz" + "github.com/stretchr/testify/require" + + "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" +) + +func TestRoundtrip_EncryptionAtRest(t *testing.T) { + f := fuzz.New() + + for range 100 { + fuzzed := &EncryptionAtRest{} + f.Fuzz(fuzzed) + + //ignore secret fields + fuzzed.AWS.AccessKeyID = "" + fuzzed.AWS.SecretAccessKey = "" + fuzzed.AWS.CustomerMasterKeyID = "" + fuzzed.AWS.RoleID = "" + fuzzed.AWS.CloudProviderIntegrationRole = "" + fuzzed.AWS.SecretRef = common.ResourceRefNamespaced{} + + fuzzed.Azure.SubscriptionID = "" + fuzzed.Azure.KeyVaultName = "" + fuzzed.Azure.KeyIdentifier = "" + fuzzed.Azure.Secret = "" + fuzzed.Azure.SecretRef = common.ResourceRefNamespaced{} + + fuzzed.GCP.ServiceAccountKey = "" + fuzzed.GCP.KeyVersionResourceID = "" + fuzzed.GCP.SecretRef = common.ResourceRefNamespaced{} + + //ignore read-only 'Valid' field + fuzzed.AWS.Valid = nil + fuzzed.Azure.Valid = nil + fuzzed.GCP.Valid = nil + + toAtlasResult := toAtlas(fuzzed) + fromAtlasResult := fromAtlas(toAtlasResult) + + equals := EqualSpecs(fuzzed, fromAtlasResult) + if !equals { + t.Log(cmp.Diff(fuzzed, fromAtlasResult)) + } + require.True(t, equals) + } +} diff --git a/internal/translation/encryptionatrest/encryptionatrest.go b/internal/translation/encryptionatrest/encryptionatrest.go new file mode 100644 index 0000000000..5afe7d8d9c --- /dev/null +++ b/internal/translation/encryptionatrest/encryptionatrest.go @@ -0,0 +1,39 @@ +package encryptionatrest + +import ( + "context" + "fmt" + + "go.mongodb.org/atlas-sdk/v20231115008/admin" +) + +type EncryptionAtRestService interface { + Get(context.Context, string) (*EncryptionAtRest, error) + Update(context.Context, string, EncryptionAtRest) error +} + +type EncryptionAtRestAPI struct { + encryptionAtRestAPI admin.EncryptionAtRestUsingCustomerKeyManagementApi +} + +func NewEncryptionAtRestAPI(api admin.EncryptionAtRestUsingCustomerKeyManagementApi) *EncryptionAtRestAPI { + return &EncryptionAtRestAPI{encryptionAtRestAPI: api} +} + +func (e *EncryptionAtRestAPI) Get(ctx context.Context, projectID string) (*EncryptionAtRest, error) { + result, _, err := e.encryptionAtRestAPI.GetEncryptionAtRest(ctx, projectID).Execute() + if err != nil { + return nil, fmt.Errorf("failed to get encryption at rest from Atlas: %w", err) + } + + return fromAtlas(result), nil +} + +func (e *EncryptionAtRestAPI) Update(ctx context.Context, projectID string, ear EncryptionAtRest) error { + _, _, err := e.encryptionAtRestAPI.UpdateEncryptionAtRest(ctx, projectID, toAtlas(&ear)).Execute() + if err != nil { + return fmt.Errorf("failed to update encryption at rest in Atlas: %w", err) + } + + return nil +} From a7bf48c75a4be8a579751a418a6c24f1544f6536 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 11 Nov 2024 18:44:03 +0000 Subject: [PATCH 03/12] implement translation layer --- helm-charts | 2 +- .../translation/atlas_deployments_service.go | 1 - pkg/api/v1/encryption_at_rest.go | 3 +- .../atlasdeployment/customzonemapping.go | 1 - .../atlasproject/atlasproject_controller.go | 8 +- .../atlasproject/encryption_at_rest.go | 204 +++--------------- .../atlasproject/maintenancewindow_test.go | 3 +- 7 files changed, 35 insertions(+), 187 deletions(-) diff --git a/helm-charts b/helm-charts index 6e9ddabe27..5ab115da85 160000 --- a/helm-charts +++ b/helm-charts @@ -1 +1 @@ -Subproject commit 6e9ddabe2786e8a5f61720d68f384f7ad190a988 +Subproject commit 5ab115da8598419ef179ca02ec446e0daa9c6b6a diff --git a/internal/mocks/translation/atlas_deployments_service.go b/internal/mocks/translation/atlas_deployments_service.go index f9f3e93bc6..f3b3cb5329 100644 --- a/internal/mocks/translation/atlas_deployments_service.go +++ b/internal/mocks/translation/atlas_deployments_service.go @@ -8,7 +8,6 @@ import ( mock "github.com/stretchr/testify/mock" deployment "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/deployment" - v1 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" ) diff --git a/pkg/api/v1/encryption_at_rest.go b/pkg/api/v1/encryption_at_rest.go index 6a4b3e2be0..2eee6f276e 100644 --- a/pkg/api/v1/encryption_at_rest.go +++ b/pkg/api/v1/encryption_at_rest.go @@ -1,10 +1,9 @@ package v1 import ( - "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/compat" - "go.mongodb.org/atlas/mongodbatlas" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/compat" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" ) diff --git a/pkg/controller/atlasdeployment/customzonemapping.go b/pkg/controller/atlasdeployment/customzonemapping.go index 07aef0cf12..13024666a2 100644 --- a/pkg/controller/atlasdeployment/customzonemapping.go +++ b/pkg/controller/atlasdeployment/customzonemapping.go @@ -4,7 +4,6 @@ import ( "fmt" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api" - akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/status" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow" diff --git a/pkg/controller/atlasproject/atlasproject_controller.go b/pkg/controller/atlasproject/atlasproject_controller.go index 6a161b2722..cc25be93d6 100644 --- a/pkg/controller/atlasproject/atlasproject_controller.go +++ b/pkg/controller/atlasproject/atlasproject_controller.go @@ -36,6 +36,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/encryptionatrest" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/maintenancewindow" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/teams" @@ -60,9 +61,10 @@ type AtlasProjectReconciler struct { ObjectDeletionProtection bool SubObjectDeletionProtection bool - projectService project.ProjectService - teamsService teams.TeamsService - maintenanceService maintenancewindow.MaintenanceWindowService + projectService project.ProjectService + teamsService teams.TeamsService + maintenanceService maintenancewindow.MaintenanceWindowService + encryptionAtRestService encryptionatrest.EncryptionAtRestService } // Dev note: duplicate the permissions in both sections below to generate both Role and ClusterRoles diff --git a/pkg/controller/atlasproject/encryption_at_rest.go b/pkg/controller/atlasproject/encryption_at_rest.go index 071aedbed9..26e8b8749f 100644 --- a/pkg/controller/atlasproject/encryption_at_rest.go +++ b/pkg/controller/atlasproject/encryption_at_rest.go @@ -3,19 +3,16 @@ package atlasproject import ( "context" "fmt" - "reflect" "regexp" "strings" - "go.mongodb.org/atlas/mongodbatlas" v1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/encryptionatrest" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/status" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow" ) @@ -24,12 +21,14 @@ const ( ) func (r *AtlasProjectReconciler) ensureEncryptionAtRest(workflowCtx *workflow.Context, project *akov2.AtlasProject) workflow.Result { - if err := readEncryptionAtRestSecrets(r.Client, workflowCtx, project.Spec.EncryptionAtRest, project.Namespace); err != nil { + encRest := encryptionatrest.NewEncryptionAtRest(project) + + if err := readEncryptionAtRestSecrets(r.Client, workflowCtx, encRest, project.Namespace); err != nil { workflowCtx.UnsetCondition(api.EncryptionAtRestReadyType) return workflow.Terminate(workflow.ProjectEncryptionAtRestReady, err.Error()) } - result := createOrDeleteEncryptionAtRests(workflowCtx, project.ID(), project) + result := createOrDeleteEncryptionAtRests(workflowCtx, r.encryptionAtRestService, project.ID(), encRest) if !result.IsOk() { workflowCtx.SetConditionFromResult(api.EncryptionAtRestReadyType, result) return result @@ -44,27 +43,27 @@ func (r *AtlasProjectReconciler) ensureEncryptionAtRest(workflowCtx *workflow.Co return workflow.OK() } -func readEncryptionAtRestSecrets(kubeClient client.Client, service *workflow.Context, encRest *akov2.EncryptionAtRest, parentNs string) error { +func readEncryptionAtRestSecrets(kubeClient client.Client, service *workflow.Context, encRest *encryptionatrest.EncryptionAtRest, parentNs string) error { if encRest == nil { return nil } - if encRest.AwsKms.Enabled != nil && *encRest.AwsKms.Enabled && encRest.AwsKms.SecretRef.Name != "" { - err := readAndFillAWSSecret(service.Context, kubeClient, parentNs, &encRest.AwsKms) + if encRest.AWS.Enabled != nil && *encRest.AWS.Enabled && encRest.AWS.SecretRef.Name != "" { + err := readAndFillAWSSecret(service.Context, kubeClient, parentNs, &encRest.AWS) if err != nil { return err } } - if encRest.GoogleCloudKms.Enabled != nil && *encRest.GoogleCloudKms.Enabled && encRest.GoogleCloudKms.SecretRef.Name != "" { - err := readAndFillGoogleSecret(service.Context, kubeClient, parentNs, &encRest.GoogleCloudKms) + if encRest.GCP.Enabled != nil && *encRest.GCP.Enabled && encRest.GCP.SecretRef.Name != "" { + err := readAndFillGoogleSecret(service.Context, kubeClient, parentNs, &encRest.GCP) if err != nil { return err } } - if encRest.AzureKeyVault.Enabled != nil && *encRest.AzureKeyVault.Enabled && encRest.AzureKeyVault.SecretRef.Name != "" { - err := readAndFillAzureSecret(service.Context, kubeClient, parentNs, &encRest.AzureKeyVault) + if encRest.Azure.Enabled != nil && *encRest.Azure.Enabled && encRest.Azure.SecretRef.Name != "" { + err := readAndFillAzureSecret(service.Context, kubeClient, parentNs, &encRest.Azure) if err != nil { return err } @@ -73,7 +72,7 @@ func readEncryptionAtRestSecrets(kubeClient client.Client, service *workflow.Con return nil } -func readAndFillAWSSecret(ctx context.Context, kubeClient client.Client, parentNs string, awsKms *akov2.AwsKms) error { +func readAndFillAWSSecret(ctx context.Context, kubeClient client.Client, parentNs string, awsKms *encryptionatrest.AwsKms) error { fieldData, err := readSecretData(ctx, kubeClient, awsKms.SecretRef, parentNs, "CustomerMasterKeyID", "RoleID") if err != nil { return err @@ -84,7 +83,7 @@ func readAndFillAWSSecret(ctx context.Context, kubeClient client.Client, parentN return nil } -func readAndFillGoogleSecret(ctx context.Context, kubeClient client.Client, parentNs string, gkms *akov2.GoogleCloudKms) error { +func readAndFillGoogleSecret(ctx context.Context, kubeClient client.Client, parentNs string, gkms *encryptionatrest.GoogleCloudKms) error { fieldData, err := readSecretData(ctx, kubeClient, gkms.SecretRef, parentNs, "ServiceAccountKey", "KeyVersionResourceID") if err != nil { return err @@ -95,7 +94,7 @@ func readAndFillGoogleSecret(ctx context.Context, kubeClient client.Client, pare return nil } -func readAndFillAzureSecret(ctx context.Context, kubeClient client.Client, parentNs string, azureVault *akov2.AzureKeyVault) error { +func readAndFillAzureSecret(ctx context.Context, kubeClient client.Client, parentNs string, azureVault *encryptionatrest.AzureKeyVault) error { fieldData, err := readSecretData(ctx, kubeClient, azureVault.SecretRef, parentNs, "Secret", "SubscriptionID", "KeyVaultName", "KeyIdentifier") if err != nil { return err @@ -140,57 +139,30 @@ func readSecretData(ctx context.Context, kubeClient client.Client, res common.Re return result, nil } -func createOrDeleteEncryptionAtRests(ctx *workflow.Context, projectID string, project *akov2.AtlasProject) workflow.Result { - encryptionAtRestsInAtlas, err := fetchEncryptionAtRests(ctx, projectID) +func createOrDeleteEncryptionAtRests(ctx *workflow.Context, service encryptionatrest.EncryptionAtRestService, projectID string, encRest *encryptionatrest.EncryptionAtRest) workflow.Result { + encryptionAtRestsInAtlas, err := service.Get(ctx.Context, projectID) if err != nil { return workflow.Terminate(workflow.Internal, err.Error()) } - inSync, err := AtlasInSync(encryptionAtRestsInAtlas, project.Spec.EncryptionAtRest) - if err != nil { - return workflow.Terminate(workflow.Internal, err.Error()) - } + inSync := encryptionatrest.EqualSpecs(encRest, encryptionAtRestsInAtlas) if inSync { return workflow.OK() } - if err := syncEncryptionAtRestsInAtlas(ctx, projectID, project); err != nil { + if err := normalizeAwsKms(ctx, projectID, &encRest.AWS); err != nil { return workflow.Terminate(workflow.Internal, err.Error()) } - return workflow.OK() -} - -func fetchEncryptionAtRests(ctx *workflow.Context, projectID string) (*mongodbatlas.EncryptionAtRest, error) { - encryptionAtRestsInAtlas, _, err := ctx.Client.EncryptionsAtRest.Get(ctx.Context, projectID) - if err != nil { - return nil, err - } - ctx.Log.Debugf("Got EncryptionAtRests From Atlas: %v", *encryptionAtRestsInAtlas) - return encryptionAtRestsInAtlas, nil -} - -func syncEncryptionAtRestsInAtlas(ctx *workflow.Context, projectID string, project *akov2.AtlasProject) error { - requestBody := mongodbatlas.EncryptionAtRest{ - GroupID: projectID, - AwsKms: getAwsKMS(project), - AzureKeyVault: getAzureKeyVault(project), - GoogleCloudKms: getGoogleCloudKms(project), - } - - if err := normalizeAwsKms(ctx, projectID, &requestBody.AwsKms); err != nil { - return err - } - - if _, _, err := ctx.Client.EncryptionsAtRest.Create(ctx.Context, &requestBody); err != nil { // Create() sends PATCH request - return err + if err := service.Update(ctx.Context, projectID, *encRest); err != nil { + return workflow.Terminate(workflow.Internal, err.Error()) } - return nil + return workflow.OK() } -func normalizeAwsKms(ctx *workflow.Context, projectID string, awsKms *mongodbatlas.AwsKms) error { +func normalizeAwsKms(ctx *workflow.Context, projectID string, awsKms *encryptionatrest.AwsKms) error { if awsKms == nil || awsKms.Enabled == nil || !*awsKms.Enabled { return nil } @@ -206,14 +178,14 @@ func normalizeAwsKms(ctx *workflow.Context, projectID string, awsKms *mongodbatl } // assume that role ID is set as AWS ARN - resp, _, err := ctx.Client.CloudProviderAccess.ListRoles(ctx.Context, projectID) + resp, _, err := ctx.SdkClient.CloudProviderAccessApi.ListCloudProviderAccessRoles(ctx.Context, projectID).Execute() if err != nil { return err } - for _, role := range resp.AWSIAMRoles { - if role.IAMAssumedRoleARN == awsKms.RoleID { - awsKms.RoleID = role.RoleID + for _, role := range resp.GetAwsIamRoles() { + if role.GetIamAssumedRoleArn() == awsKms.RoleID { + awsKms.RoleID = role.GetRoleId() return nil } } @@ -222,49 +194,6 @@ func normalizeAwsKms(ctx *workflow.Context, projectID string, awsKms *mongodbatl return fmt.Errorf("can not use '%s' aws roleID for encryption at rest. AWS ARN not configured as Cloud Provider Access", awsKms.RoleID) } -func AtlasInSync(atlas *mongodbatlas.EncryptionAtRest, spec *akov2.EncryptionAtRest) (bool, error) { - if IsEncryptionAtlasEmpty(atlas) && IsEncryptionSpecEmpty(spec) { - return true, nil - } - - if IsEncryptionAtlasEmpty(atlas) || IsEncryptionSpecEmpty(spec) { - return false, nil - } - - specAsAtlas, err := spec.ToAtlas(atlas.GroupID) - if err != nil { - return false, err - } - - balanceAsymmetricalFields(atlas, specAsAtlas) - - return reflect.DeepEqual(atlas, specAsAtlas), nil -} - -func balanceAsymmetricalFields(atlas *mongodbatlas.EncryptionAtRest, spec *mongodbatlas.EncryptionAtRest) { - if spec.AwsKms.RoleID == "" && atlas.AwsKms.RoleID != "" { - spec.AwsKms.RoleID = atlas.AwsKms.RoleID - } - if spec.AzureKeyVault.Secret == "" && atlas.AzureKeyVault.Secret != "" { - spec.AzureKeyVault.Secret = atlas.AzureKeyVault.Secret - } - if spec.GoogleCloudKms.ServiceAccountKey == "" && atlas.GoogleCloudKms.ServiceAccountKey != "" { - spec.GoogleCloudKms.ServiceAccountKey = "" - } - - if isNotNilAndFalse(atlas.AwsKms.Enabled) { - spec.AwsKms.Enabled = pointer.MakePtr(false) - } - if isNotNilAndFalse(atlas.AzureKeyVault.Enabled) { - spec.AzureKeyVault.Enabled = pointer.MakePtr(false) - } - if isNotNilAndFalse(atlas.GoogleCloudKms.Enabled) { - spec.GoogleCloudKms.Enabled = pointer.MakePtr(false) - } - - spec.Valid = atlas.Valid -} - func IsEncryptionSpecEmpty(spec *akov2.EncryptionAtRest) bool { if spec == nil { return true @@ -281,85 +210,6 @@ func IsEncryptionSpecEmpty(spec *akov2.EncryptionAtRest) bool { return true } -func IsEncryptionAtlasEmpty(atlas *mongodbatlas.EncryptionAtRest) bool { - if atlas == nil { - return true - } - - awsEnabled := atlas.AwsKms.Enabled - azureEnabled := atlas.AzureKeyVault.Enabled - gcpEnabled := atlas.GoogleCloudKms.Enabled - - if isNotNilAndTrue(awsEnabled) || isNotNilAndTrue(azureEnabled) || isNotNilAndTrue(gcpEnabled) { - return false - } - - return true -} - func isNotNilAndTrue(val *bool) bool { return val != nil && *val } - -func isNotNilAndFalse(val *bool) bool { - return val != nil && !*val -} - -func getAwsKMS(project *akov2.AtlasProject) (result mongodbatlas.AwsKms) { - if project.Spec.EncryptionAtRest == nil { - return - } - - result = project.Spec.EncryptionAtRest.AwsKms.ToAtlas() - - if (result == mongodbatlas.AwsKms{}) { - result.Enabled = pointer.MakePtr(false) - } - - if result.RoleID == "" { - awsRole, foundRole := selectRole(project.Status.CloudProviderIntegrations, "AWS") - if foundRole { - result.RoleID = awsRole.RoleID - } - } - - return -} - -func getAzureKeyVault(project *akov2.AtlasProject) (result mongodbatlas.AzureKeyVault) { - if project.Spec.EncryptionAtRest == nil { - return - } - - result = project.Spec.EncryptionAtRest.AzureKeyVault.ToAtlas() - - if (result == mongodbatlas.AzureKeyVault{}) { - result.Enabled = pointer.MakePtr(false) - } - - return -} - -func getGoogleCloudKms(project *akov2.AtlasProject) (result mongodbatlas.GoogleCloudKms) { - if project.Spec.EncryptionAtRest == nil { - return - } - - result = project.Spec.EncryptionAtRest.GoogleCloudKms.ToAtlas() - - if (result == mongodbatlas.GoogleCloudKms{}) { - result.Enabled = pointer.MakePtr(false) - } - - return -} - -func selectRole(accessRoles []status.CloudProviderIntegration, providerName string) (result status.CloudProviderIntegration, found bool) { - for _, role := range accessRoles { - if role.ProviderName == providerName { - return role, true - } - } - - return -} diff --git a/pkg/controller/atlasproject/maintenancewindow_test.go b/pkg/controller/atlasproject/maintenancewindow_test.go index 6542a2264e..82fc767a3a 100644 --- a/pkg/controller/atlasproject/maintenancewindow_test.go +++ b/pkg/controller/atlasproject/maintenancewindow_test.go @@ -13,10 +13,9 @@ import ( "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/maintenancewindow" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow" - "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/project" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/status" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow" ) func TestValidateMaintenanceWindow(t *testing.T) { From 3a1eda3c273ebc35844b86ddf728bc78520fcbab Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 11 Nov 2024 18:44:35 +0000 Subject: [PATCH 04/12] remove old secret fields --- pkg/api/v1/atlasproject_types.go | 6 -- pkg/api/v1/encryption_at_rest.go | 122 ++----------------------------- 2 files changed, 8 insertions(+), 120 deletions(-) diff --git a/pkg/api/v1/atlasproject_types.go b/pkg/api/v1/atlasproject_types.go index 8411a90532..1cec26bff9 100644 --- a/pkg/api/v1/atlasproject_types.go +++ b/pkg/api/v1/atlasproject_types.go @@ -135,12 +135,6 @@ const hiddenField = "*** redacted ***" //nolint:errcheck func (p AtlasProjectSpec) MarshalLogObject(e zapcore.ObjectEncoder) error { printable := p.DeepCopy() - // cleanup encryption at EncryptionAtRest - if printable.EncryptionAtRest != nil { - printable.EncryptionAtRest.AwsKms.SetSecrets(hiddenField, hiddenField) - printable.EncryptionAtRest.AzureKeyVault.SetSecrets(hiddenField, hiddenField, hiddenField, hiddenField) - printable.EncryptionAtRest.GoogleCloudKms.SetSecrets(hiddenField, hiddenField) - } // cleanup AlertConfigurations for i := range printable.AlertConfigurations { for j := range printable.AlertConfigurations[i].Notifications { diff --git a/pkg/api/v1/encryption_at_rest.go b/pkg/api/v1/encryption_at_rest.go index 2eee6f276e..0877b96bdf 100644 --- a/pkg/api/v1/encryption_at_rest.go +++ b/pkg/api/v1/encryption_at_rest.go @@ -1,9 +1,6 @@ package v1 import ( - "go.mongodb.org/atlas/mongodbatlas" - - "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/compat" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" ) @@ -16,133 +13,30 @@ type EncryptionAtRest struct { // AwsKms specifies AWS KMS configuration details and whether Encryption at Rest is enabled for an Atlas project. type AwsKms struct { - Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project, To disable Encryption at Rest, pass only this parameter with a value of false, When you disable Encryption at Rest, Atlas also removes the configuration details. - customerMasterKeyID string // The AWS customer master key used to encrypt and decrypt the MongoDB master keys. - Region string `json:"region,omitempty"` // The AWS region in which the AWS customer master key exists: CA_CENTRAL_1, US_EAST_1, US_EAST_2, US_WEST_1, US_WEST_2, SA_EAST_1 - roleID string // ID of an AWS IAM role authorized to manage an AWS customer master key. - Valid *bool `json:"valid,omitempty"` // Specifies whether the encryption key set for the provider is valid and may be used to encrypt and decrypt data. + Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project, To disable Encryption at Rest, pass only this parameter with a value of false, When you disable Encryption at Rest, Atlas also removes the configuration details. + Region string `json:"region,omitempty"` // The AWS region in which the AWS customer master key exists: CA_CENTRAL_1, US_EAST_1, US_EAST_2, US_WEST_1, US_WEST_2, SA_EAST_1 + Valid *bool `json:"valid,omitempty"` // Specifies whether the encryption key set for the provider is valid and may be used to encrypt and decrypt data. // A reference to as Secret containing the AccessKeyID, SecretAccessKey, CustomerMasterKeyID and RoleID fields // +optional SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` } -func (a *AwsKms) SetSecrets(customerMasterKeyID, roleID string) { - a.customerMasterKeyID = customerMasterKeyID - a.roleID = roleID -} - -func (a AwsKms) CustomerMasterKeyID() string { - return a.customerMasterKeyID -} - -func (a AwsKms) RoleID() string { - return a.roleID -} - // AzureKeyVault specifies Azure Key Vault configuration details and whether Encryption at Rest is enabled for an Atlas project. type AzureKeyVault struct { - Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. - ClientID string `json:"clientID,omitempty"` // The Client ID, also known as the application ID, for an Azure application associated with the Azure AD tenant. - AzureEnvironment string `json:"azureEnvironment,omitempty"` // The Azure environment where the Azure account credentials reside. Valid values are the following: AZURE, AZURE_CHINA, AZURE_GERMANY - subscriptionID string // The unique identifier associated with an Azure subscription. + Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. + ClientID string `json:"clientID,omitempty"` // The Client ID, also known as the application ID, for an Azure application associated with the Azure AD tenant. + AzureEnvironment string `json:"azureEnvironment,omitempty"` // The Azure environment where the Azure account credentials reside. Valid values are the following: AZURE, AZURE_CHINA, AZURE_GERMANY ResourceGroupName string `json:"resourceGroupName,omitempty"` // The name of the Azure Resource group that contains an Azure Key Vault. - keyVaultName string // The name of an Azure Key Vault containing your key. - keyIdentifier string // The unique identifier of a key in an Azure Key Vault. - secret string // The secret associated with the Azure Key Vault specified by azureKeyVault.tenantID. - TenantID string `json:"tenantID,omitempty"` // The unique identifier for an Azure AD tenant within an Azure subscription. - Valid *bool `json:"valid,omitempty"` // Specifies whether the encryption key set for the provider is valid and may be used to encrypt and decrypt data. + TenantID string `json:"tenantID,omitempty"` // The unique identifier for an Azure AD tenant within an Azure subscription. // A reference to as Secret containing the SubscriptionID, KeyVaultName, KeyIdentifier, Secret fields // +optional SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` } -func (az *AzureKeyVault) SetSecrets(subscriptionID, keyVaultName, keyIdentifier, secret string) { - az.subscriptionID = subscriptionID - az.keyVaultName = keyVaultName - az.keyIdentifier = keyIdentifier - az.secret = secret -} - -func (az AzureKeyVault) KeyIdentifier() string { - return az.keyIdentifier -} - -func (az AzureKeyVault) KeyVaultName() string { - return az.keyVaultName -} - -func (az AzureKeyVault) SubscriptionID() string { - return az.subscriptionID -} - -func (az AzureKeyVault) Secret() string { - return az.secret -} - // GoogleCloudKms specifies GCP KMS configuration details and whether Encryption at Rest is enabled for an Atlas project. type GoogleCloudKms struct { - Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. - serviceAccountKey string // String-formatted JSON object containing GCP KMS credentials from your GCP account. - keyVersionResourceID string // The Key Version Resource ID from your GCP account. - Valid *bool `json:"valid,omitempty"` // Specifies whether the encryption key set for the provider is valid and may be used to encrypt and decrypt data. + Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. // A reference to as Secret containing the ServiceAccountKey, KeyVersionResourceID fields // +optional SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` } - -func (g *GoogleCloudKms) SetSecrets(serviceAccountKey, keyVersionResourceID string) { - g.serviceAccountKey = serviceAccountKey - g.keyVersionResourceID = keyVersionResourceID -} - -func (g GoogleCloudKms) KeyVersionResourceID() string { - return g.keyVersionResourceID -} - -func (g GoogleCloudKms) ServiceAccountKey() string { - return g.serviceAccountKey -} - -func (e EncryptionAtRest) ToAtlas(projectID string) (*mongodbatlas.EncryptionAtRest, error) { - result := &mongodbatlas.EncryptionAtRest{ - GroupID: projectID, - AwsKms: e.AwsKms.ToAtlas(), - GoogleCloudKms: e.GoogleCloudKms.ToAtlas(), - AzureKeyVault: e.AzureKeyVault.ToAtlas(), - } - - err := compat.JSONCopy(result, e) - return result, err -} - -func (a AwsKms) ToAtlas() mongodbatlas.AwsKms { - return mongodbatlas.AwsKms{ - Enabled: a.Enabled, - RoleID: a.roleID, - CustomerMasterKeyID: a.customerMasterKeyID, - Region: a.Region, - Valid: a.Valid, - } -} - -func (g GoogleCloudKms) ToAtlas() mongodbatlas.GoogleCloudKms { - return mongodbatlas.GoogleCloudKms{ - Enabled: g.Enabled, - ServiceAccountKey: g.serviceAccountKey, - KeyVersionResourceID: g.keyVersionResourceID, - } -} - -func (az AzureKeyVault) ToAtlas() mongodbatlas.AzureKeyVault { - return mongodbatlas.AzureKeyVault{ - Enabled: az.Enabled, - ClientID: az.ClientID, - AzureEnvironment: az.AzureEnvironment, - SubscriptionID: az.subscriptionID, - ResourceGroupName: az.ResourceGroupName, - KeyVaultName: az.keyVaultName, - KeyIdentifier: az.keyIdentifier, - TenantID: az.TenantID, - Secret: az.secret, - } -} From 2e192186503cc441ef67b70c7434d459a72dcc92 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 11 Nov 2024 18:44:54 +0000 Subject: [PATCH 05/12] generate mocks --- .mockery.yaml | 1 + .../translation/encryption_at_rest_service.go | 145 ++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 internal/mocks/translation/encryption_at_rest_service.go diff --git a/.mockery.yaml b/.mockery.yaml index bcf1bf2170..af49f0f615 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -15,3 +15,4 @@ packages: github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/teams: github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/privateendpoint: github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/maintenancewindow: + github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/encryptionatrest: diff --git a/internal/mocks/translation/encryption_at_rest_service.go b/internal/mocks/translation/encryption_at_rest_service.go new file mode 100644 index 0000000000..9b49603dff --- /dev/null +++ b/internal/mocks/translation/encryption_at_rest_service.go @@ -0,0 +1,145 @@ +// Code generated by mockery. DO NOT EDIT. + +package translation + +import ( + context "context" + + mock "github.com/stretchr/testify/mock" + + encryptionatrest "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/encryptionatrest" +) + +// EncryptionAtRestServiceMock is an autogenerated mock type for the EncryptionAtRestService type +type EncryptionAtRestServiceMock struct { + mock.Mock +} + +type EncryptionAtRestServiceMock_Expecter struct { + mock *mock.Mock +} + +func (_m *EncryptionAtRestServiceMock) EXPECT() *EncryptionAtRestServiceMock_Expecter { + return &EncryptionAtRestServiceMock_Expecter{mock: &_m.Mock} +} + +// Get provides a mock function with given fields: _a0, _a1 +func (_m *EncryptionAtRestServiceMock) Get(_a0 context.Context, _a1 string) (*encryptionatrest.EncryptionAtRest, error) { + ret := _m.Called(_a0, _a1) + + if len(ret) == 0 { + panic("no return value specified for Get") + } + + var r0 *encryptionatrest.EncryptionAtRest + var r1 error + if rf, ok := ret.Get(0).(func(context.Context, string) (*encryptionatrest.EncryptionAtRest, error)); ok { + return rf(_a0, _a1) + } + if rf, ok := ret.Get(0).(func(context.Context, string) *encryptionatrest.EncryptionAtRest); ok { + r0 = rf(_a0, _a1) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*encryptionatrest.EncryptionAtRest) + } + } + + if rf, ok := ret.Get(1).(func(context.Context, string) error); ok { + r1 = rf(_a0, _a1) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// EncryptionAtRestServiceMock_Get_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Get' +type EncryptionAtRestServiceMock_Get_Call struct { + *mock.Call +} + +// Get is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 string +func (_e *EncryptionAtRestServiceMock_Expecter) Get(_a0 interface{}, _a1 interface{}) *EncryptionAtRestServiceMock_Get_Call { + return &EncryptionAtRestServiceMock_Get_Call{Call: _e.mock.On("Get", _a0, _a1)} +} + +func (_c *EncryptionAtRestServiceMock_Get_Call) Run(run func(_a0 context.Context, _a1 string)) *EncryptionAtRestServiceMock_Get_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string)) + }) + return _c +} + +func (_c *EncryptionAtRestServiceMock_Get_Call) Return(_a0 *encryptionatrest.EncryptionAtRest, _a1 error) *EncryptionAtRestServiceMock_Get_Call { + _c.Call.Return(_a0, _a1) + return _c +} + +func (_c *EncryptionAtRestServiceMock_Get_Call) RunAndReturn(run func(context.Context, string) (*encryptionatrest.EncryptionAtRest, error)) *EncryptionAtRestServiceMock_Get_Call { + _c.Call.Return(run) + return _c +} + +// Update provides a mock function with given fields: _a0, _a1, _a2 +func (_m *EncryptionAtRestServiceMock) Update(_a0 context.Context, _a1 string, _a2 encryptionatrest.EncryptionAtRest) error { + ret := _m.Called(_a0, _a1, _a2) + + if len(ret) == 0 { + panic("no return value specified for Update") + } + + var r0 error + if rf, ok := ret.Get(0).(func(context.Context, string, encryptionatrest.EncryptionAtRest) error); ok { + r0 = rf(_a0, _a1, _a2) + } else { + r0 = ret.Error(0) + } + + return r0 +} + +// EncryptionAtRestServiceMock_Update_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Update' +type EncryptionAtRestServiceMock_Update_Call struct { + *mock.Call +} + +// Update is a helper method to define mock.On call +// - _a0 context.Context +// - _a1 string +// - _a2 encryptionatrest.EncryptionAtRest +func (_e *EncryptionAtRestServiceMock_Expecter) Update(_a0 interface{}, _a1 interface{}, _a2 interface{}) *EncryptionAtRestServiceMock_Update_Call { + return &EncryptionAtRestServiceMock_Update_Call{Call: _e.mock.On("Update", _a0, _a1, _a2)} +} + +func (_c *EncryptionAtRestServiceMock_Update_Call) Run(run func(_a0 context.Context, _a1 string, _a2 encryptionatrest.EncryptionAtRest)) *EncryptionAtRestServiceMock_Update_Call { + _c.Call.Run(func(args mock.Arguments) { + run(args[0].(context.Context), args[1].(string), args[2].(encryptionatrest.EncryptionAtRest)) + }) + return _c +} + +func (_c *EncryptionAtRestServiceMock_Update_Call) Return(_a0 error) *EncryptionAtRestServiceMock_Update_Call { + _c.Call.Return(_a0) + return _c +} + +func (_c *EncryptionAtRestServiceMock_Update_Call) RunAndReturn(run func(context.Context, string, encryptionatrest.EncryptionAtRest) error) *EncryptionAtRestServiceMock_Update_Call { + _c.Call.Return(run) + return _c +} + +// NewEncryptionAtRestServiceMock creates a new instance of EncryptionAtRestServiceMock. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +// The first argument is typically a *testing.T value. +func NewEncryptionAtRestServiceMock(t interface { + mock.TestingT + Cleanup(func()) +}) *EncryptionAtRestServiceMock { + mock := &EncryptionAtRestServiceMock{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} From ead68f8b61a506e6d69f727bca4dfb839fe57c6e Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 11 Nov 2024 18:45:42 +0000 Subject: [PATCH 06/12] add and update tests --- .../encryptionatrest/conversion_test.go | 2 - .../atlasproject/encryption_at_rest_test.go | 198 ++++++------------ pkg/controller/atlasproject/project_test.go | 64 ++++-- 3 files changed, 113 insertions(+), 151 deletions(-) diff --git a/internal/translation/encryptionatrest/conversion_test.go b/internal/translation/encryptionatrest/conversion_test.go index a0294dcbae..9477035941 100644 --- a/internal/translation/encryptionatrest/conversion_test.go +++ b/internal/translation/encryptionatrest/conversion_test.go @@ -37,8 +37,6 @@ func TestRoundtrip_EncryptionAtRest(t *testing.T) { //ignore read-only 'Valid' field fuzzed.AWS.Valid = nil - fuzzed.Azure.Valid = nil - fuzzed.GCP.Valid = nil toAtlasResult := toAtlas(fuzzed) fromAtlasResult := fromAtlas(toAtlasResult) diff --git a/pkg/controller/atlasproject/encryption_at_rest_test.go b/pkg/controller/atlasproject/encryption_at_rest_test.go index 35a1c3d029..b3ea3725a2 100644 --- a/pkg/controller/atlasproject/encryption_at_rest_test.go +++ b/pkg/controller/atlasproject/encryption_at_rest_test.go @@ -4,13 +4,13 @@ import ( "testing" "github.com/stretchr/testify/assert" - "go.mongodb.org/atlas/mongodbatlas" v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client/fake" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/pointer" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/encryptionatrest" akov2 "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api/v1/common" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/controller/workflow" @@ -41,22 +41,24 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - AwsKms: akov2.AwsKms{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "aws-secret", - Namespace: "test", + encRest := &encryptionatrest.EncryptionAtRest{ + AWS: encryptionatrest.AwsKms{ + AwsKms: akov2.AwsKms{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "aws-secret", + Namespace: "test", + }, + Region: "testRegion", }, - Region: "testRegion", }, } err := readEncryptionAtRestSecrets(kk, service, encRest, "test") assert.Nil(t, err) - assert.Equal(t, string(secretData["CustomerMasterKeyID"]), encRest.AwsKms.CustomerMasterKeyID()) - assert.Equal(t, string(secretData["RoleID"]), encRest.AwsKms.RoleID()) + assert.Equal(t, string(secretData["CustomerMasterKeyID"]), encRest.AWS.CustomerMasterKeyID) + assert.Equal(t, string(secretData["RoleID"]), encRest.AWS.RoleID) }) t.Run("AWS with correct secret data (fallback namespace)", func(t *testing.T) { @@ -83,11 +85,13 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - AwsKms: akov2.AwsKms{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "aws-secret", + encRest := &encryptionatrest.EncryptionAtRest{ + AWS: encryptionatrest.AwsKms{ + AwsKms: akov2.AwsKms{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "aws-secret", + }, }, }, } @@ -95,8 +99,8 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { err := readEncryptionAtRestSecrets(kk, service, encRest, "test-fallback-ns") assert.Nil(t, err) - assert.Equal(t, string(secretData["CustomerMasterKeyID"]), encRest.AwsKms.CustomerMasterKeyID()) - assert.Equal(t, string(secretData["RoleID"]), encRest.AwsKms.RoleID()) + assert.Equal(t, string(secretData["CustomerMasterKeyID"]), encRest.AWS.CustomerMasterKeyID) + assert.Equal(t, string(secretData["RoleID"]), encRest.AWS.RoleID) }) t.Run("AWS with missing fields", func(t *testing.T) { @@ -122,12 +126,14 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - AwsKms: akov2.AwsKms{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "aws-secret", - Namespace: "test", + encRest := &encryptionatrest.EncryptionAtRest{ + AWS: encryptionatrest.AwsKms{ + AwsKms: akov2.AwsKms{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "aws-secret", + Namespace: "test", + }, }, }, } @@ -158,11 +164,13 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - GoogleCloudKms: akov2.GoogleCloudKms{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "gcp-secret", + encRest := &encryptionatrest.EncryptionAtRest{ + GCP: encryptionatrest.GoogleCloudKms{ + GoogleCloudKms: akov2.GoogleCloudKms{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "gcp-secret", + }, }, }, } @@ -170,8 +178,8 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { err := readEncryptionAtRestSecrets(kk, service, encRest, "test") assert.Nil(t, err) - assert.Equal(t, string(secretData["ServiceAccountKey"]), encRest.GoogleCloudKms.ServiceAccountKey()) - assert.Equal(t, string(secretData["KeyVersionResourceID"]), encRest.GoogleCloudKms.KeyVersionResourceID()) + assert.Equal(t, string(secretData["ServiceAccountKey"]), encRest.GCP.ServiceAccountKey) + assert.Equal(t, string(secretData["KeyVersionResourceID"]), encRest.GCP.KeyVersionResourceID) }) t.Run("GCP with missing fields", func(t *testing.T) { @@ -195,11 +203,13 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - GoogleCloudKms: akov2.GoogleCloudKms{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "gcp-secret", + encRest := &encryptionatrest.EncryptionAtRest{ + GCP: encryptionatrest.GoogleCloudKms{ + GoogleCloudKms: akov2.GoogleCloudKms{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "gcp-secret", + }, }, }, } @@ -232,11 +242,13 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - AzureKeyVault: akov2.AzureKeyVault{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "azure-secret", + encRest := &encryptionatrest.EncryptionAtRest{ + Azure: encryptionatrest.AzureKeyVault{ + AzureKeyVault: akov2.AzureKeyVault{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "azure-secret", + }, }, }, } @@ -244,10 +256,10 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { err := readEncryptionAtRestSecrets(kk, service, encRest, "test") assert.Nil(t, err) - assert.Equal(t, string(secretData["Secret"]), encRest.AzureKeyVault.Secret()) - assert.Equal(t, string(secretData["SubscriptionID"]), encRest.AzureKeyVault.SubscriptionID()) - assert.Equal(t, string(secretData["KeyVaultName"]), encRest.AzureKeyVault.KeyVaultName()) - assert.Equal(t, string(secretData["KeyIdentifier"]), encRest.AzureKeyVault.KeyIdentifier()) + assert.Equal(t, string(secretData["Secret"]), encRest.Azure.Secret) + assert.Equal(t, string(secretData["SubscriptionID"]), encRest.Azure.SubscriptionID) + assert.Equal(t, string(secretData["KeyVaultName"]), encRest.Azure.KeyVaultName) + assert.Equal(t, string(secretData["KeyIdentifier"]), encRest.Azure.KeyIdentifier) }) t.Run("Azure with missing fields", func(t *testing.T) { @@ -274,11 +286,13 @@ func TestReadEncryptionAtRestSecrets(t *testing.T) { service := &workflow.Context{} - encRest := &akov2.EncryptionAtRest{ - AzureKeyVault: akov2.AzureKeyVault{ - Enabled: pointer.MakePtr(true), - SecretRef: common.ResourceRefNamespaced{ - Name: "gcp-secret", + encRest := &encryptionatrest.EncryptionAtRest{ + Azure: encryptionatrest.AzureKeyVault{ + AzureKeyVault: akov2.AzureKeyVault{ + Enabled: pointer.MakePtr(true), + SecretRef: common.ResourceRefNamespaced{ + Name: "gcp-secret", + }, }, }, } @@ -301,89 +315,3 @@ func TestIsEncryptionAtlasEmpty(t *testing.T) { isEmpty = IsEncryptionSpecEmpty(spec) assert.True(t, isEmpty, "Enabled flag set to false is same as empty") } - -func TestAtlasInSync(t *testing.T) { - areInSync, err := AtlasInSync(nil, nil) - assert.NoError(t, err) - assert.True(t, areInSync, "Both atlas and spec are nil") - - groupID := "0" - atlas := mongodbatlas.EncryptionAtRest{ - GroupID: groupID, - AwsKms: mongodbatlas.AwsKms{ - Enabled: pointer.MakePtr(true), - }, - } - spec := akov2.EncryptionAtRest{ - AwsKms: akov2.AwsKms{ - Enabled: pointer.MakePtr(true), - }, - } - - areInSync, err = AtlasInSync(nil, &spec) - assert.NoError(t, err) - assert.False(t, areInSync, "Nil atlas") - - areInSync, err = AtlasInSync(&atlas, nil) - assert.NoError(t, err) - assert.False(t, areInSync, "Nil spec") - - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.True(t, areInSync, "Both are the same") - - spec.AwsKms.Enabled = pointer.MakePtr(false) - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.False(t, areInSync, "Atlas is disabled") - - atlas.AwsKms.Enabled = pointer.MakePtr(false) - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.True(t, areInSync, "Both are disabled") - - atlas.AwsKms.RoleID = "example" - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.True(t, areInSync, "Both are disabled but atlas RoleID field") - - spec.AwsKms.Enabled = pointer.MakePtr(true) - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.False(t, areInSync, "Spec is re-enabled") - - atlas.AwsKms.Enabled = pointer.MakePtr(true) - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.True(t, areInSync, "Both are re-enabled and only RoleID is different") - - atlas = mongodbatlas.EncryptionAtRest{ - AwsKms: mongodbatlas.AwsKms{ - Enabled: pointer.MakePtr(true), - CustomerMasterKeyID: "testCustomerMasterKeyID", - Region: "US_EAST_1", - RoleID: "testRoleID", - Valid: pointer.MakePtr(true), - }, - AzureKeyVault: mongodbatlas.AzureKeyVault{ - Enabled: pointer.MakePtr(false), - }, - GoogleCloudKms: mongodbatlas.GoogleCloudKms{ - Enabled: pointer.MakePtr(false), - }, - } - spec = akov2.EncryptionAtRest{ - AwsKms: akov2.AwsKms{ - Enabled: pointer.MakePtr(true), - Region: "US_EAST_1", - Valid: pointer.MakePtr(true), - }, - AzureKeyVault: akov2.AzureKeyVault{}, - GoogleCloudKms: akov2.GoogleCloudKms{}, - } - spec.AwsKms.SetSecrets("testCustomerMasterKeyID", "testRoleID") - - areInSync, err = AtlasInSync(&atlas, &spec) - assert.NoError(t, err) - assert.True(t, areInSync, "Realistic example. should be equal") -} diff --git a/pkg/controller/atlasproject/project_test.go b/pkg/controller/atlasproject/project_test.go index 9fcb46564a..e2402c85ea 100644 --- a/pkg/controller/atlasproject/project_test.go +++ b/pkg/controller/atlasproject/project_test.go @@ -27,6 +27,7 @@ import ( atlasmocks "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/mocks/atlas" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/mocks/translation" + "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/encryptionatrest" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/project" "github.com/mongodb/mongodb-atlas-kubernetes/v2/internal/translation/teams" "github.com/mongodb/mongodb-atlas-kubernetes/v2/pkg/api" @@ -42,15 +43,16 @@ func TestHandleProject(t *testing.T) { deletionTime := metav1.Now() tests := map[string]struct { - atlasClientMocker func() *mongodbatlas.Client - atlasSDKMocker func() *admin.APIClient - projectServiceMocker func() project.ProjectService - teamServiceMocker func() teams.TeamsService - interceptors interceptor.Funcs - project *akov2.AtlasProject - result reconcile.Result - conditions []api.Condition - finalizers []string + atlasClientMocker func() *mongodbatlas.Client + atlasSDKMocker func() *admin.APIClient + projectServiceMocker func() project.ProjectService + teamServiceMocker func() teams.TeamsService + encryptionAtRestMocker func() encryptionatrest.EncryptionAtRestService + interceptors interceptor.Funcs + project *akov2.AtlasProject + result reconcile.Result + conditions []api.Condition + finalizers []string }{ "should fail to get project from atlas": { atlasClientMocker: func() *mongodbatlas.Client { @@ -69,6 +71,9 @@ func TestHandleProject(t *testing.T) { teamServiceMocker: func() teams.TeamsService { return nil }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + return nil + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -104,6 +109,9 @@ func TestHandleProject(t *testing.T) { teamServiceMocker: func() teams.TeamsService { return nil }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + return nil + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -168,6 +176,9 @@ func TestHandleProject(t *testing.T) { service.EXPECT().ListProjectTeams(context.Background(), mock.Anything).Return([]teams.AssignedTeam{}, nil) return service }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + return nil + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -198,6 +209,9 @@ func TestHandleProject(t *testing.T) { teamServiceMocker: func() teams.TeamsService { return nil }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + return nil + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -228,6 +242,9 @@ func TestHandleProject(t *testing.T) { teamServiceMocker: func() teams.TeamsService { return nil }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + return nil + }, interceptors: interceptor.Funcs{ Patch: func(ctx context.Context, client client.WithWatch, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { return errors.New("failed to remove finalizer") @@ -269,6 +286,9 @@ func TestHandleProject(t *testing.T) { teamServiceMocker: func() teams.TeamsService { return nil }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + return nil + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -374,6 +394,11 @@ func TestHandleProject(t *testing.T) { service.EXPECT().ListProjectTeams(context.Background(), mock.Anything).Return([]teams.AssignedTeam{}, nil) return service }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + service := translation.NewEncryptionAtRestServiceMock(t) + service.EXPECT().Get(context.Background(), mock.Anything).Return(nil, nil) + return service + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -475,6 +500,11 @@ func TestHandleProject(t *testing.T) { service.EXPECT().ListProjectTeams(context.Background(), mock.Anything).Return([]teams.AssignedTeam{}, nil) return service }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + service := translation.NewEncryptionAtRestServiceMock(t) + service.EXPECT().Get(context.Background(), mock.Anything).Return(nil, nil) + return service + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -578,6 +608,11 @@ func TestHandleProject(t *testing.T) { service.EXPECT().ListProjectTeams(context.Background(), mock.Anything).Return([]teams.AssignedTeam{}, nil) return service }, + encryptionAtRestMocker: func() encryptionatrest.EncryptionAtRestService { + service := translation.NewEncryptionAtRestServiceMock(t) + service.EXPECT().Get(context.Background(), mock.Anything).Return(nil, nil) + return service + }, project: &akov2.AtlasProject{ ObjectMeta: metav1.ObjectMeta{ Name: "my-project", @@ -625,11 +660,12 @@ func TestHandleProject(t *testing.T) { Build() logger := zaptest.NewLogger(t).Sugar() reconciler := &AtlasProjectReconciler{ - Client: k8sClient, - Log: logger, - projectService: tt.projectServiceMocker(), - teamsService: tt.teamServiceMocker(), - EventRecorder: record.NewFakeRecorder(30), + Client: k8sClient, + Log: logger, + projectService: tt.projectServiceMocker(), + teamsService: tt.teamServiceMocker(), + encryptionAtRestService: tt.encryptionAtRestMocker(), + EventRecorder: record.NewFakeRecorder(30), } ctx := &workflow.Context{ Context: context.Background(), From dd27b326dd738307ef0fba7efe6ceefe10715309 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Mon, 11 Nov 2024 22:38:07 +0000 Subject: [PATCH 07/12] properly initialise EaR service in project controller --- internal/translation/encryptionatrest/conversion.go | 2 -- pkg/controller/atlasproject/atlasproject_controller.go | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/translation/encryptionatrest/conversion.go b/internal/translation/encryptionatrest/conversion.go index d1c0dba53c..ba5cbc0aed 100644 --- a/internal/translation/encryptionatrest/conversion.go +++ b/internal/translation/encryptionatrest/conversion.go @@ -159,13 +159,11 @@ func fromAtlas(ear *admin.EncryptionAtRest) *EncryptionAtRest { ClientID: ear.AzureKeyVault.GetClientID(), ResourceGroupName: ear.AzureKeyVault.GetResourceGroupName(), TenantID: ear.AzureKeyVault.GetTenantID(), - Valid: ear.AzureKeyVault.Valid, } } if ear.HasGoogleCloudKms() { out.GCP.GoogleCloudKms = akov2.GoogleCloudKms{ Enabled: ear.GoogleCloudKms.Enabled, - Valid: ear.GoogleCloudKms.Valid, } } return out diff --git a/pkg/controller/atlasproject/atlasproject_controller.go b/pkg/controller/atlasproject/atlasproject_controller.go index cc25be93d6..bb2560888b 100644 --- a/pkg/controller/atlasproject/atlasproject_controller.go +++ b/pkg/controller/atlasproject/atlasproject_controller.go @@ -145,6 +145,7 @@ func (r *AtlasProjectReconciler) Reconcile(ctx context.Context, req ctrl.Request r.projectService = project.NewProjectAPIService(atlasSdkClient.ProjectsApi) r.teamsService = teams.NewTeamsAPIService(atlasSdkClient.TeamsApi, atlasSdkClient.MongoDBCloudUsersApi) r.maintenanceService = maintenancewindow.NewMaintenanceWindowAPIService(atlasSdkClient.MaintenanceWindowsApi) + r.encryptionAtRestService = encryptionatrest.NewEncryptionAtRestAPI(atlasSdkClient.EncryptionAtRestUsingCustomerKeyManagementApi) atlasClient, _, err := r.AtlasProvider.Client(workflowCtx.Context, atlasProject.ConnectionSecretObjectKey(), log) if err != nil { From a6a322741825280da4d1de90aa186655f2a7c016 Mon Sep 17 00:00:00 2001 From: Roo Thorp Date: Tue, 12 Nov 2024 11:19:14 +0000 Subject: [PATCH 08/12] fix panic --- pkg/controller/atlasproject/encryption_at_rest.go | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pkg/controller/atlasproject/encryption_at_rest.go b/pkg/controller/atlasproject/encryption_at_rest.go index 26e8b8749f..e4c2146b38 100644 --- a/pkg/controller/atlasproject/encryption_at_rest.go +++ b/pkg/controller/atlasproject/encryption_at_rest.go @@ -151,12 +151,13 @@ func createOrDeleteEncryptionAtRests(ctx *workflow.Context, service encryptionat return workflow.OK() } - if err := normalizeAwsKms(ctx, projectID, &encRest.AWS); err != nil { - return workflow.Terminate(workflow.Internal, err.Error()) - } - - if err := service.Update(ctx.Context, projectID, *encRest); err != nil { - return workflow.Terminate(workflow.Internal, err.Error()) + if encRest != nil { + if err := normalizeAwsKms(ctx, projectID, &encRest.AWS); err != nil { + return workflow.Terminate(workflow.Internal, err.Error()) + } + if err := service.Update(ctx.Context, projectID, *encRest); err != nil { + return workflow.Terminate(workflow.Internal, err.Error()) + } } return workflow.OK() From 661c238449d34f43965ae0122ea2d0828589df63 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Mon, 18 Nov 2024 14:35:35 +0100 Subject: [PATCH 09/12] add IsEnabled --- pkg/api/v1/encryption_at_rest.go | 12 ++++++++++++ pkg/controller/atlasproject/encryption_at_rest.go | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/pkg/api/v1/encryption_at_rest.go b/pkg/api/v1/encryption_at_rest.go index 0877b96bdf..f9cb06fa2e 100644 --- a/pkg/api/v1/encryption_at_rest.go +++ b/pkg/api/v1/encryption_at_rest.go @@ -21,6 +21,10 @@ type AwsKms struct { SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` } +func (a *AwsKms) IsEnabled() bool { + return a != nil && a.Enabled != nil && *a.Enabled +} + // AzureKeyVault specifies Azure Key Vault configuration details and whether Encryption at Rest is enabled for an Atlas project. type AzureKeyVault struct { Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. @@ -33,6 +37,10 @@ type AzureKeyVault struct { SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` } +func (a *AzureKeyVault) IsEnabled() bool { + return a != nil && a.Enabled != nil && *a.Enabled +} + // GoogleCloudKms specifies GCP KMS configuration details and whether Encryption at Rest is enabled for an Atlas project. type GoogleCloudKms struct { Enabled *bool `json:"enabled,omitempty"` // Specifies whether Encryption at Rest is enabled for an Atlas project. To disable Encryption at Rest, pass only this parameter with a value of false. When you disable Encryption at Rest, Atlas also removes the configuration details. @@ -40,3 +48,7 @@ type GoogleCloudKms struct { // +optional SecretRef common.ResourceRefNamespaced `json:"secretRef,omitempty"` } + +func (g *GoogleCloudKms) IsEnabled() bool { + return g != nil && g.Enabled != nil && *g.Enabled +} diff --git a/pkg/controller/atlasproject/encryption_at_rest.go b/pkg/controller/atlasproject/encryption_at_rest.go index e4c2146b38..6206b73898 100644 --- a/pkg/controller/atlasproject/encryption_at_rest.go +++ b/pkg/controller/atlasproject/encryption_at_rest.go @@ -48,21 +48,21 @@ func readEncryptionAtRestSecrets(kubeClient client.Client, service *workflow.Con return nil } - if encRest.AWS.Enabled != nil && *encRest.AWS.Enabled && encRest.AWS.SecretRef.Name != "" { + if encRest.AWS.IsEnabled() && encRest.AWS.SecretRef.Name != "" { err := readAndFillAWSSecret(service.Context, kubeClient, parentNs, &encRest.AWS) if err != nil { return err } } - if encRest.GCP.Enabled != nil && *encRest.GCP.Enabled && encRest.GCP.SecretRef.Name != "" { + if encRest.GCP.IsEnabled() && encRest.GCP.SecretRef.Name != "" { err := readAndFillGoogleSecret(service.Context, kubeClient, parentNs, &encRest.GCP) if err != nil { return err } } - if encRest.Azure.Enabled != nil && *encRest.Azure.Enabled && encRest.Azure.SecretRef.Name != "" { + if encRest.Azure.IsEnabled() && encRest.Azure.SecretRef.Name != "" { err := readAndFillAzureSecret(service.Context, kubeClient, parentNs, &encRest.Azure) if err != nil { return err From 0658268f2b9332d8ec8ec247fc744c4e63b4bf34 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Mon, 18 Nov 2024 14:38:16 +0100 Subject: [PATCH 10/12] Update internal/translation/encryptionatrest/conversion.go Co-authored-by: josvaz --- internal/translation/encryptionatrest/conversion.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/translation/encryptionatrest/conversion.go b/internal/translation/encryptionatrest/conversion.go index ba5cbc0aed..1aee57aae0 100644 --- a/internal/translation/encryptionatrest/conversion.go +++ b/internal/translation/encryptionatrest/conversion.go @@ -108,11 +108,12 @@ func (g *GoogleCloudKms) ToAtlas() *admin.GoogleCloudKMS { } func NewEncryptionAtRest(project *akov2.AtlasProject) *EncryptionAtRest { - ear := &EncryptionAtRest{} spec := project.Spec.EncryptionAtRest if spec == nil { return nil } + + ear := &EncryptionAtRest{} if *spec.AwsKms.Enabled { ear.AWS.AwsKms = spec.AwsKms From 224c9372fadaaf2be54897525349042f3ee1184c Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Mon, 18 Nov 2024 14:52:24 +0100 Subject: [PATCH 11/12] make generate --- internal/translation/encryptionatrest/conversion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/translation/encryptionatrest/conversion.go b/internal/translation/encryptionatrest/conversion.go index 1aee57aae0..aa9f11342d 100644 --- a/internal/translation/encryptionatrest/conversion.go +++ b/internal/translation/encryptionatrest/conversion.go @@ -112,7 +112,7 @@ func NewEncryptionAtRest(project *akov2.AtlasProject) *EncryptionAtRest { if spec == nil { return nil } - + ear := &EncryptionAtRest{} if *spec.AwsKms.Enabled { From c45a719f9ecd8de15443460cbf9cf146094e18a2 Mon Sep 17 00:00:00 2001 From: Sergiusz Urbaniak Date: Mon, 18 Nov 2024 16:00:10 +0100 Subject: [PATCH 12/12] fix panic --- internal/translation/encryptionatrest/conversion.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/internal/translation/encryptionatrest/conversion.go b/internal/translation/encryptionatrest/conversion.go index aa9f11342d..6e1ee58e15 100644 --- a/internal/translation/encryptionatrest/conversion.go +++ b/internal/translation/encryptionatrest/conversion.go @@ -114,8 +114,7 @@ func NewEncryptionAtRest(project *akov2.AtlasProject) *EncryptionAtRest { } ear := &EncryptionAtRest{} - - if *spec.AwsKms.Enabled { + if spec.AwsKms.IsEnabled() { ear.AWS.AwsKms = spec.AwsKms for _, role := range project.Status.CloudProviderIntegrations { if role.ProviderName == "AWS" { @@ -123,10 +122,10 @@ func NewEncryptionAtRest(project *akov2.AtlasProject) *EncryptionAtRest { } } } - if *spec.AzureKeyVault.Enabled { + if spec.AzureKeyVault.IsEnabled() { ear.Azure.AzureKeyVault = spec.AzureKeyVault } - if *spec.GoogleCloudKms.Enabled { + if spec.GoogleCloudKms.IsEnabled() { ear.GCP.GoogleCloudKms = spec.GoogleCloudKms } return ear