Last active
May 9, 2024 00:49
-
-
Save ffalor/3f13621b0d1a4def8b14d513cc0675e9 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
package prevention_policy | |
import ( | |
"context" | |
"fmt" | |
"time" | |
"github.com/crowdstrike/gofalcon/falcon/client" | |
"github.com/crowdstrike/gofalcon/falcon/client/prevention_policies" | |
"github.com/crowdstrike/gofalcon/falcon/models" | |
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" | |
"github.com/hashicorp/terraform-plugin-framework/path" | |
"github.com/hashicorp/terraform-plugin-framework/resource" | |
"github.com/hashicorp/terraform-plugin-framework/resource/schema" | |
"github.com/hashicorp/terraform-plugin-framework/resource/schema/booldefault" | |
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" | |
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" | |
"github.com/hashicorp/terraform-plugin-framework/schema/validator" | |
"github.com/hashicorp/terraform-plugin-framework/types" | |
) | |
// Ensure the implementation satisfies the expected interfaces. | |
var ( | |
_ resource.Resource = &preventionPolicyResource{} | |
_ resource.ResourceWithConfigure = &preventionPolicyResource{} | |
_ resource.ResourceWithImportState = &preventionPolicyResource{} | |
// _ resource.ResourceWithValidateConfig = &preventionPolicyResource{} | |
) | |
// NewPreventionPolicyResource is a helper function to simplify the provider implementation. | |
func NewPreventionPolicyResource() resource.Resource { | |
return &preventionPolicyResource{} | |
} | |
// preventionPolicyResource is the resource implementation. | |
type preventionPolicyResource struct { | |
client *client.CrowdStrikeAPISpecification | |
} | |
var toggleAttribute = schema.BoolAttribute{ | |
Optional: true, | |
Computed: true, | |
Description: "Whether to enable the setting.", | |
Default: booldefault.StaticBool(false), | |
} | |
var mlSliderLevels = []string{"DISABLED", "CAUTIOUS", "MODERATE", "AGGRESSIVE", "EXTRA_AGGRESSIVE"} | |
var mlSliderDetectionAttribute = schema.StringAttribute{ | |
Required: true, | |
Description: "Machine learning level for detection.", | |
Validators: []validator.String{ | |
stringvalidator.OneOf(mlSliderLevels...), | |
}, | |
} | |
var mlSliderPreventionAttribute = schema.StringAttribute{ | |
Required: true, | |
Description: "Machine learning level for prevention.", | |
Validators: []validator.String{ | |
stringvalidator.OneOf(mlSliderLevels...), | |
}, | |
} | |
var mlSliderAttribute = schema.SingleNestedAttribute{ | |
Optional: true, | |
Computed: true, | |
Description: "ml slider setting.", | |
Attributes: map[string]schema.Attribute{ | |
"detection": mlSliderDetectionAttribute, | |
"prevention": mlSliderPreventionAttribute, | |
}, | |
} | |
type preventionPolicyResourceModel struct { | |
ID types.String `tfsdk:"id"` | |
Enabled types.Bool `tfsdk:"enabled"` | |
Name types.String `tfsdk:"name"` | |
Description types.String `tfsdk:"description"` | |
PlatformName types.String `tfsdk:"platform_name"` | |
LastUpdated types.String `tfsdk:"last_updated"` | |
Windows windowsPolicy `tfsdk:"windows"` | |
} | |
type toggle struct { | |
Enabled types.Bool `tfsdk:"enabled" json:"enabled"` | |
} | |
type mlSlider struct { | |
Detection types.String `tfsdk:"detection"` | |
Prevention types.String `tfsdk:"prevention"` | |
} | |
type windowsPolicy struct { | |
AdditionalUserModeData toggle `tfsdk:"additional_user_mode_data"` | |
CloudAntiMalwareForMicrosoftOfficeFiles mlSlider `tfsdk:"cloud_anti_malware_microsoft_office_files"` | |
} | |
// Configure adds the provider configured client to the resource. | |
func (r *preventionPolicyResource) Configure( | |
ctx context.Context, | |
req resource.ConfigureRequest, | |
resp *resource.ConfigureResponse, | |
) { | |
if req.ProviderData == nil { | |
return | |
} | |
client, ok := req.ProviderData.(*client.CrowdStrikeAPISpecification) | |
if !ok { | |
resp.Diagnostics.AddError( | |
"Unexpected Resource Configure Type", | |
fmt.Sprintf( | |
"Expected *client.CrowdStrikeAPISpecification, got: %T. Please report this issue to the provider developers.", | |
req.ProviderData, | |
), | |
) | |
return | |
} | |
r.client = client | |
} | |
// Metadata returns the resource type name. | |
func (r *preventionPolicyResource) Metadata( | |
_ context.Context, | |
req resource.MetadataRequest, | |
resp *resource.MetadataResponse, | |
) { | |
resp.TypeName = req.ProviderTypeName + "_prevention_policy" | |
} | |
// Schema defines the schema for the resource. | |
func (r *preventionPolicyResource) Schema( | |
_ context.Context, | |
_ resource.SchemaRequest, | |
resp *resource.SchemaResponse, | |
) { | |
resp.Schema = schema.Schema{ | |
Attributes: map[string]schema.Attribute{ | |
"id": schema.StringAttribute{ | |
Computed: true, | |
Description: "Identifier for the prevention policy.", | |
PlanModifiers: []planmodifier.String{ | |
stringplanmodifier.UseStateForUnknown(), | |
}, | |
}, | |
"last_updated": schema.StringAttribute{ | |
Computed: true, | |
Description: "Timestamp of the last Terraform update of the resource.", | |
}, | |
"name": schema.StringAttribute{ | |
Required: true, | |
Description: "Name of the prevention policy.", | |
}, | |
"enabled": schema.BoolAttribute{ | |
Optional: true, | |
Computed: true, | |
Description: "Enable the prevention policy.", | |
Default: booldefault.StaticBool(true), | |
}, | |
"description": schema.StringAttribute{ | |
Optional: true, | |
Description: "Description of the prevention policy.", | |
}, | |
// todo: make this case insensitive | |
"platform_name": schema.StringAttribute{ | |
Required: true, | |
Description: "Platform for the sensor update policy to manage. (Windows, Mac, Linux)", | |
Validators: []validator.String{ | |
stringvalidator.OneOf("Windows", "Linux", "Mac"), | |
}, | |
}, | |
"windows": schema.SingleNestedAttribute{ | |
Optional: true, | |
Description: "Block to configure a windows prevention policy.", | |
Attributes: map[string]schema.Attribute{ | |
"additional_user_mode_data": toggleAttribute, | |
"cloud_anti_malware_microsoft_office_files": mlSliderAttribute, | |
}, | |
}, | |
}, | |
} | |
} | |
type apiToggle struct { | |
Enabled bool `json:"enabled"` | |
} | |
type apiMlSlider struct { | |
Detection string `json:"detection"` | |
Prevention string `json:"prevention"` | |
} | |
// Create creates the resource and sets the initial Terraform state. | |
func (r *preventionPolicyResource) Create( | |
ctx context.Context, | |
req resource.CreateRequest, | |
resp *resource.CreateResponse, | |
) { | |
var plan preventionPolicyResourceModel | |
diags := req.Plan.Get(ctx, &plan) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
windowsPreventionSettings := generateWindowsPreventionSettings(ctx, plan) | |
createParams := prevention_policies.CreatePreventionPoliciesParams{ | |
Context: ctx, | |
Body: &models.PreventionCreatePoliciesReqV1{ | |
Resources: []*models.PreventionCreatePolicyReqV1{ | |
{ | |
Name: plan.Name.ValueStringPointer(), | |
Description: plan.Description.ValueString(), | |
PlatformName: plan.PlatformName.ValueStringPointer(), | |
Settings: windowsPreventionSettings, | |
}, | |
}, | |
}, | |
} | |
res, err := r.client.PreventionPolicies.CreatePreventionPolicies(&createParams) | |
// todo: if we should handle scope and timeout errors instead of giving a vague error | |
if err != nil { | |
resp.Diagnostics.AddError( | |
"Error creating prevention policy", | |
"Could not create prevention policy, unexpected error: "+err.Error(), | |
) | |
return | |
} | |
preventionPolicy := res.Payload.Resources[0] | |
plan.ID = types.StringValue(*preventionPolicy.ID) | |
plan.Description = types.StringValue(*preventionPolicy.Description) | |
plan.PlatformName = types.StringValue(*preventionPolicy.PlatformName) | |
plan.Name = types.StringValue(*preventionPolicy.Name) | |
plan.Enabled = types.BoolValue(*preventionPolicy.Enabled) | |
plan.LastUpdated = types.StringValue(time.Now().Format(time.RFC850)) | |
diags = resp.State.Set(ctx, plan) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
} | |
// Read refreshes the Terraform state with the latest data. | |
func (r *preventionPolicyResource) Read( | |
ctx context.Context, | |
req resource.ReadRequest, | |
resp *resource.ReadResponse, | |
) { | |
var state preventionPolicyResourceModel | |
diags := req.State.Get(ctx, &state) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
// Set refreshed state | |
diags = resp.State.Set(ctx, &state) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
} | |
// Update updates the resource and sets the updated Terraform state on success. | |
func (r *preventionPolicyResource) Update( | |
ctx context.Context, | |
req resource.UpdateRequest, | |
resp *resource.UpdateResponse, | |
) { | |
// Retrieve values from plan | |
var plan preventionPolicyResourceModel | |
diags := req.Plan.Get(ctx, &plan) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
diags = resp.State.Set(ctx, plan) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
} | |
// Delete deletes the resource and removes the Terraform state on success. | |
func (r *preventionPolicyResource) Delete( | |
ctx context.Context, | |
req resource.DeleteRequest, | |
resp *resource.DeleteResponse, | |
) { | |
var state preventionPolicyResourceModel | |
diags := req.State.Get(ctx, &state) | |
resp.Diagnostics.Append(diags...) | |
if resp.Diagnostics.HasError() { | |
return | |
} | |
} | |
// ImportState implements the logic to support resource imports. | |
func (r *preventionPolicyResource) ImportState( | |
ctx context.Context, | |
req resource.ImportStateRequest, | |
resp *resource.ImportStateResponse, | |
) { | |
// Retrieve import ID and save to id attribute | |
resource.ImportStatePassthroughID(ctx, path.Root("id"), req, resp) | |
} | |
// generateWindowsPreventionSettings maps plan prevention settings to api params for create and update. | |
func generateWindowsPreventionSettings( | |
ctx context.Context, | |
config preventionPolicyResourceModel, | |
) []*models.PreventionSettingReqV1 { | |
preventionSettings := []*models.PreventionSettingReqV1{} | |
s1 := "CloudAntiMalwareForMicrosoftOfficeFiles" | |
s2 := "AdditionalUserModeData" | |
preventionSettings = append( | |
preventionSettings, | |
&models.PreventionSettingReqV1{ | |
ID: &s1, | |
Value: apiToggle{Enabled: config.Windows.AdditionalUserModeData.Enabled.ValueBool()}, | |
}, | |
) | |
preventionSettings = append( | |
preventionSettings, | |
&models.PreventionSettingReqV1{ | |
ID: &s2, | |
Value: apiMlSlider{ | |
Prevention: config.Windows.CloudAntiMalwareForMicrosoftOfficeFiles.Prevention.ValueString(), | |
Detection: config.Windows.CloudAntiMalwareForMicrosoftOfficeFiles.Detection.ValueString(), | |
}, | |
}, | |
) | |
return preventionSettings | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment