-
Notifications
You must be signed in to change notification settings - Fork 171
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Encryption At Host Dynamic Validation
- Frontend will now validate that Encryption At Host is enabled on customer's subscription before installing clusters - In memory of Swetha. Thanks for your amazing contributions to our team, I'm glad we can finally get your work across the line with this one. Co-authored-by: Swetha Chirumamilla <schiruma@redhat.com>
- Loading branch information
1 parent
98fe23c
commit b07dc2a
Showing
27 changed files
with
2,287 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package frontend | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the Apache License 2.0. | ||
|
||
import ( | ||
"context" | ||
"net/http" | ||
|
||
sdk_armfeatures "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armfeatures" | ||
|
||
"github.com/Azure/ARO-RP/pkg/api" | ||
"github.com/Azure/ARO-RP/pkg/env" | ||
"github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/armfeatures" | ||
) | ||
|
||
type EncryptionAtHostValidator interface { | ||
ValidateEncryptionAtHost(ctx context.Context, environment env.Interface, subscriptionID, tenantID string, oc *api.OpenShiftCluster) error | ||
} | ||
|
||
type encryptionAtHostValidator struct{} | ||
|
||
func (e encryptionAtHostValidator) ValidateEncryptionAtHost(ctx context.Context, environment env.Interface, subscriptionID, tenantID string, oc *api.OpenShiftCluster) error { | ||
credential, err := environment.FPNewClientCertificateCredential(tenantID) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
subFeatureRegistrationsClient, err := sdk_armfeatures.NewSubscriptionFeatureRegistrationsClient(subscriptionID, credential, nil) | ||
if err != nil { | ||
return err | ||
} | ||
return validateEncryptionAtHostGivenClient(ctx, subFeatureRegistrationsClient, oc) | ||
} | ||
|
||
func validateEncryptionAtHostGivenClient(ctx context.Context, subFeatureRegistrationsClient armfeatures.SubscriptionFeatureRegistrationsClient, oc *api.OpenShiftCluster) error { | ||
var hasEncryptionAtHostEnabled bool | ||
profilesToCheck := append([]api.WorkerProfile{{EncryptionAtHost: oc.Properties.MasterProfile.EncryptionAtHost}}, oc.Properties.WorkerProfiles...) | ||
for _, profile := range profilesToCheck { | ||
if profile.EncryptionAtHost == api.EncryptionAtHostEnabled { | ||
hasEncryptionAtHostEnabled = true | ||
break | ||
} | ||
} | ||
if hasEncryptionAtHostEnabled { | ||
err := isRegisteredForEncryptionAtHostFeature(ctx, subFeatureRegistrationsClient) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func isRegisteredForEncryptionAtHostFeature(ctx context.Context, subFeatureRegistrationsClient armfeatures.SubscriptionFeatureRegistrationsClient) error { | ||
response, err := subFeatureRegistrationsClient.Get(ctx, "Microsoft.Compute", "EncryptionAtHost", nil) | ||
if err != nil { | ||
return err | ||
} | ||
if *response.Properties.State != sdk_armfeatures.SubscriptionFeatureRegistrationStateRegistered { | ||
return &api.CloudError{ | ||
StatusCode: http.StatusBadRequest, | ||
CloudErrorBody: &api.CloudErrorBody{ | ||
Code: api.CloudErrorCodeInvalidParameter, | ||
Message: "Microsoft.Compute/EncryptionAtHost feature is not enabled for this subscription. Register the feature using 'az feature register --namespace Microsoft.Compute --name EncryptionAtHost'", | ||
Target: "armfeatures.SubscriptionFeatureRegistrationProperties", | ||
}, | ||
} | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package frontend | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the Apache License 2.0. | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armfeatures" | ||
"github.com/golang/mock/gomock" | ||
|
||
"github.com/Azure/ARO-RP/pkg/api" | ||
mock_armfeatures "github.com/Azure/ARO-RP/pkg/util/mocks/azureclient/azuresdk/armfeatures" | ||
utilerror "github.com/Azure/ARO-RP/test/util/error" | ||
) | ||
|
||
func TestValidateEncryptionAtHost(t *testing.T) { | ||
getClusterWithNodeProfiles := func(MasterProfile api.MasterProfile, WorkerProfiles []api.WorkerProfile) *api.OpenShiftCluster { | ||
return &api.OpenShiftCluster{ | ||
Properties: api.OpenShiftClusterProperties{ | ||
MasterProfile: MasterProfile, | ||
WorkerProfiles: WorkerProfiles, | ||
}, | ||
} | ||
} | ||
|
||
getSubscriptionWithFeatureState := func(state armfeatures.SubscriptionFeatureRegistrationState) *armfeatures.SubscriptionFeatureRegistrationsClientGetResponse { | ||
return &armfeatures.SubscriptionFeatureRegistrationsClientGetResponse{ | ||
SubscriptionFeatureRegistration: armfeatures.SubscriptionFeatureRegistration{ | ||
Properties: &armfeatures.SubscriptionFeatureRegistrationProperties{ | ||
State: &state, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
for _, tt := range []struct { | ||
name string | ||
oc *api.OpenShiftCluster | ||
mockResponse *armfeatures.SubscriptionFeatureRegistrationsClientGetResponse | ||
mockErr error | ||
wantErr string | ||
wantNumArmCalls int | ||
}{ | ||
{ | ||
name: "valid: cluster encryption at host disabled and subscription feature isn't registered", | ||
oc: getClusterWithNodeProfiles(api.MasterProfile{EncryptionAtHost: api.EncryptionAtHostDisabled}, []api.WorkerProfile{{EncryptionAtHost: api.EncryptionAtHostDisabled}}), | ||
mockResponse: getSubscriptionWithFeatureState(armfeatures.SubscriptionFeatureRegistrationStateNotRegistered), | ||
wantNumArmCalls: 0, | ||
}, | ||
{ | ||
name: "valid: cluster encryption at host disabled and subscription feature is registered", | ||
oc: getClusterWithNodeProfiles(api.MasterProfile{EncryptionAtHost: api.EncryptionAtHostDisabled}, []api.WorkerProfile{{EncryptionAtHost: api.EncryptionAtHostDisabled}}), | ||
mockResponse: getSubscriptionWithFeatureState(armfeatures.SubscriptionFeatureRegistrationStateRegistered), | ||
wantNumArmCalls: 0, | ||
}, | ||
{ | ||
name: "valid: cluster encryption at host enabled and subscription feature is registered", | ||
oc: getClusterWithNodeProfiles(api.MasterProfile{EncryptionAtHost: api.EncryptionAtHostEnabled}, []api.WorkerProfile{{EncryptionAtHost: api.EncryptionAtHostEnabled}}), | ||
mockResponse: getSubscriptionWithFeatureState(armfeatures.SubscriptionFeatureRegistrationStateRegistered), | ||
wantNumArmCalls: 1, | ||
}, | ||
{ | ||
name: "invalid: cluster master and worker encryption at host enabled and subscription feature isn't registered", | ||
oc: getClusterWithNodeProfiles(api.MasterProfile{EncryptionAtHost: api.EncryptionAtHostEnabled}, []api.WorkerProfile{{EncryptionAtHost: api.EncryptionAtHostEnabled}}), | ||
mockResponse: getSubscriptionWithFeatureState(armfeatures.SubscriptionFeatureRegistrationStateNotRegistered), | ||
wantErr: "400: InvalidParameter: armfeatures.SubscriptionFeatureRegistrationProperties: Microsoft.Compute/EncryptionAtHost feature is not enabled for this subscription. Register the feature using 'az feature register --namespace Microsoft.Compute --name EncryptionAtHost'", | ||
wantNumArmCalls: 1, | ||
}, | ||
{ | ||
name: "invalid: cluster master encryption at host enabled and subscription feature isn't registered", | ||
oc: getClusterWithNodeProfiles(api.MasterProfile{EncryptionAtHost: api.EncryptionAtHostEnabled}, []api.WorkerProfile{{EncryptionAtHost: api.EncryptionAtHostDisabled}}), | ||
mockResponse: getSubscriptionWithFeatureState(armfeatures.SubscriptionFeatureRegistrationStateNotRegistered), | ||
wantErr: "400: InvalidParameter: armfeatures.SubscriptionFeatureRegistrationProperties: Microsoft.Compute/EncryptionAtHost feature is not enabled for this subscription. Register the feature using 'az feature register --namespace Microsoft.Compute --name EncryptionAtHost'", | ||
wantNumArmCalls: 1, | ||
}, | ||
{ | ||
name: "invalid: cluster worker encryption at host enabled and subscription feature isn't registered", | ||
oc: getClusterWithNodeProfiles(api.MasterProfile{EncryptionAtHost: api.EncryptionAtHostDisabled}, []api.WorkerProfile{{EncryptionAtHost: api.EncryptionAtHostEnabled}}), | ||
mockResponse: getSubscriptionWithFeatureState(armfeatures.SubscriptionFeatureRegistrationStateNotRegistered), | ||
wantErr: "400: InvalidParameter: armfeatures.SubscriptionFeatureRegistrationProperties: Microsoft.Compute/EncryptionAtHost feature is not enabled for this subscription. Register the feature using 'az feature register --namespace Microsoft.Compute --name EncryptionAtHost'", | ||
wantNumArmCalls: 1, | ||
}, | ||
} { | ||
t.Run(tt.name, func(t *testing.T) { | ||
controller := gomock.NewController(t) | ||
defer controller.Finish() | ||
|
||
subFeatureRegistrationsClient := mock_armfeatures.NewMockSubscriptionFeatureRegistrationsClient(controller) | ||
subFeatureRegistrationsClient.EXPECT().Get(gomock.Any(), "Microsoft.Compute", "EncryptionAtHost", gomock.Any()).Return(*tt.mockResponse, tt.mockErr).Times(tt.wantNumArmCalls) | ||
|
||
err := validateEncryptionAtHostGivenClient(context.Background(), subFeatureRegistrationsClient, tt.oc) | ||
utilerror.AssertErrorMessage(t, err, tt.wantErr) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package armfeatures | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the Apache License 2.0. | ||
|
||
//go:generate rm -rf ../../../../../pkg/util/mocks/azureclient/azuresdk/$GOPACKAGE | ||
//go:generate mockgen -destination=../../../mocks/azureclient/azuresdk/$GOPACKAGE/$GOPACKAGE.go github.com/Azure/ARO-RP/pkg/util/azureclient/azuresdk/$GOPACKAGE SubscriptionFeatureRegistrationsClient | ||
//go:generate goimports -local=github.com/Azure/ARO-RP -e -w ../../../mocks/azureclient/azuresdk/$GOPACKAGE/$GOPACKAGE.go |
15 changes: 15 additions & 0 deletions
15
pkg/util/azureclient/azuresdk/armfeatures/subscription_feature_registrations.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package armfeatures | ||
|
||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the Apache License 2.0. | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armfeatures" | ||
) | ||
|
||
// SubscriptionFeatureRegistrationsClient is a minimal interface for azure SubscriptionFeatureRegistrationsClient | ||
type SubscriptionFeatureRegistrationsClient interface { | ||
Get(ctx context.Context, providerNamespace string, featureName string, options *armfeatures.SubscriptionFeatureRegistrationsClientGetOptions) (armfeatures.SubscriptionFeatureRegistrationsClientGetResponse, error) | ||
} |
51 changes: 51 additions & 0 deletions
51
pkg/util/mocks/azureclient/azuresdk/armfeatures/armfeatures.go
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
20 changes: 20 additions & 0 deletions
20
...m/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armfeatures/CHANGELOG.md
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
21 changes: 21 additions & 0 deletions
21
...r/github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armfeatures/LICENSE.txt
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.