diff --git a/docs/resources/compliance_security_profile_setting.md b/docs/resources/compliance_security_profile_setting.md new file mode 100644 index 0000000000..7de715dec1 --- /dev/null +++ b/docs/resources/compliance_security_profile_setting.md @@ -0,0 +1,37 @@ +--- +subcategory: "Settings" +--- + +# databricks_compliance_security_profile_workspace_setting Resource + +-> **Note** This resource could be only used with workspace-level provider! + +The `databricks_compliance_security_profile_workspace_setting` resource allows you to control whether to enable the +compliance security profile for the current workspace. Enabling it on a workspace is permanent. By default, it is +turned off. This setting can NOT be disabled once it is enabled. + +## Example Usage + +```hcl +resource "databricks_compliance_security_profile_workspace_setting" "this" { + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA", "FEDRAMP_MODERATE"] + } +} +``` + +## Argument Reference + +The resource supports the following arguments: + +* `is_enabled` - (Required) Enable the Compliance Security Profile on the workspace +* `compliance_standards` - (Required) Enable one or more compliance standards on the workspace, e.g. `HIPAA`, `PCI_DSS`, `FEDRAMP_MODERATE` + +## Import + +This resource can be imported by predefined name `global`: + +```bash +terraform import databricks_compliance_security_profile_workspace_setting.this global +``` \ No newline at end of file diff --git a/settings/all_settings.go b/settings/all_settings.go index 50ef2a0b0d..b9abe5a641 100644 --- a/settings/all_settings.go +++ b/settings/all_settings.go @@ -17,6 +17,7 @@ func AllSettingsResources() map[string]common.Resource { return map[string]common.Resource{ "default_namespace": makeSettingResource[settings.DefaultNamespaceSetting, *databricks.WorkspaceClient](defaultNamespaceSetting), "restrict_workspace_admins": makeSettingResource[settings.RestrictWorkspaceAdminsSetting, *databricks.WorkspaceClient](restrictWsAdminsSetting), + "compliance_security_profile_workspace": makeSettingResource[settings.ComplianceSecurityProfileSetting, *databricks.WorkspaceClient](complianceSecurityProfileSetting), "enhanced_security_monitoring_workspace": makeSettingResource[settings.EnhancedSecurityMonitoringSetting, *databricks.WorkspaceClient](enhancedSecurityMonitoringSetting), } } diff --git a/settings/resource_compliance_security_profile_setting.go b/settings/resource_compliance_security_profile_setting.go new file mode 100644 index 0000000000..5ab07ddb86 --- /dev/null +++ b/settings/resource_compliance_security_profile_setting.go @@ -0,0 +1,35 @@ +package settings + +import ( + "context" + "strings" + + "github.com/databricks/databricks-sdk-go" + "github.com/databricks/databricks-sdk-go/service/settings" +) + +// Enhanced Security Monitoring setting +var complianceSecurityProfileFieldMask = strings.Join([]string{ + "compliance_security_profile_workspace.is_enabled", + "compliance_security_profile_workspace.compliance_standards", +}, ",") +var complianceSecurityProfileSetting = workspaceSetting[settings.ComplianceSecurityProfileSetting]{ + settingStruct: settings.ComplianceSecurityProfileSetting{}, + readFunc: func(ctx context.Context, w *databricks.WorkspaceClient, etag string) (*settings.ComplianceSecurityProfileSetting, error) { + return w.Settings.ComplianceSecurityProfile().Get(ctx, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: etag, + }) + }, + updateFunc: func(ctx context.Context, w *databricks.WorkspaceClient, t settings.ComplianceSecurityProfileSetting) (string, error) { + t.SettingName = "default" + res, err := w.Settings.ComplianceSecurityProfile().Update(ctx, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + Setting: t, + FieldMask: complianceSecurityProfileFieldMask, + }) + if err != nil { + return "", err + } + return res.Etag, err + }, +} diff --git a/settings/resource_compliance_security_profile_setting_test.go b/settings/resource_compliance_security_profile_setting_test.go new file mode 100644 index 0000000000..ec7da734e9 --- /dev/null +++ b/settings/resource_compliance_security_profile_setting_test.go @@ -0,0 +1,258 @@ +package settings + +import ( + "testing" + + "github.com/databricks/databricks-sdk-go/apierr" + "github.com/databricks/databricks-sdk-go/experimental/mocks" + "github.com/databricks/databricks-sdk-go/service/settings" + "github.com/databricks/terraform-provider-databricks/qa" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +var testComplianceSecurityProfileSetting = AllSettingsResources()["compliance_security_profile_workspace"] + +func TestQueryCreateComplianceSecurityProfileSettingWithNoneStandard(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + e := w.GetMockComplianceSecurityProfileAPI().EXPECT() + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, + }).Return(nil, &apierr.APIError{ + ErrorCode: "NOT_FOUND", + StatusCode: 404, + Message: "SomeMessage", + Details: []apierr.ErrorDetail{{ + Type: "type.googleapis.com/google.rpc.ErrorInfo", + Metadata: map[string]string{ + etagAttrName: "etag1", + }, + }}, + }) + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag1", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, nil) + e.Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag2", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"NONE"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Create: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["NONE"] + } + `, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "NONE", res["compliance_standards"].([]interface{})[0]) + +} + +func TestQueryReadComplianceSecurityProfileSetting(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + w.GetMockComplianceSecurityProfileAPI().EXPECT().Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag1", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Read: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA"] + } + etag = "etag1" + `, + ID: defaultSettingId, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "HIPAA", res["compliance_standards"].([]interface{})[0]) +} + +func TestQueryUpdateComplianceSecurityProfileSetting(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + e := w.GetMockComplianceSecurityProfileAPI().EXPECT() + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag1", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA", "PCI_DSS"}, + }, + SettingName: "default", + }, + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA", "PCI_DSS"}, + }, + SettingName: "default", + }, nil) + e.Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag2", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA", "PCI_DSS"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Update: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA", "PCI_DSS"] + } + etag = "etag1" + `, + ID: defaultSettingId, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag2", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "HIPAA", res["compliance_standards"].([]interface{})[0]) + assert.Equal(t, "PCI_DSS", res["compliance_standards"].([]interface{})[1]) +} + +func TestQueryUpdateComplianceSecurityProfileSettingWithConflict(t *testing.T) { + d, err := qa.ResourceFixture{ + MockWorkspaceClientFunc: func(w *mocks.MockWorkspaceClient) { + e := w.GetMockComplianceSecurityProfileAPI().EXPECT() + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag1", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, + }).Return(nil, &apierr.APIError{ + ErrorCode: "RESOURCE_CONFLICT", + StatusCode: 409, + Message: "SomeMessage", + Details: []apierr.ErrorDetail{{ + Type: "type.googleapis.com/google.rpc.ErrorInfo", + Metadata: map[string]string{ + etagAttrName: "etag2", + }, + }}, + }) + e.Update(mock.Anything, settings.UpdateComplianceSecurityProfileSettingRequest{ + AllowMissing: true, + FieldMask: complianceSecurityProfileFieldMask, + Setting: settings.ComplianceSecurityProfileSetting{ + Etag: "etag2", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag3", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, nil) + e.Get(mock.Anything, settings.GetComplianceSecurityProfileSettingRequest{ + Etag: "etag3", + }).Return(&settings.ComplianceSecurityProfileSetting{ + Etag: "etag3", + ComplianceSecurityProfileWorkspace: settings.ComplianceSecurityProfile{ + IsEnabled: true, + ComplianceStandards: []settings.ComplianceStandard{"HIPAA"}, + }, + SettingName: "default", + }, nil) + }, + Resource: testComplianceSecurityProfileSetting, + Update: true, + HCL: ` + compliance_security_profile_workspace { + is_enabled = true + compliance_standards = ["HIPAA"] + } + etag = "etag1" + `, + ID: defaultSettingId, + }.Apply(t) + + assert.NoError(t, err) + + assert.Equal(t, defaultSettingId, d.Id()) + assert.Equal(t, "etag3", d.Get(etagAttrName).(string)) + res := d.Get("compliance_security_profile_workspace").([]interface{})[0].(map[string]interface{}) + assert.Equal(t, true, res["is_enabled"]) + assert.Equal(t, "HIPAA", res["compliance_standards"].([]interface{})[0]) +}