diff --git a/sysdig/common.go b/sysdig/common.go index 83fa4709..0478cc96 100644 --- a/sysdig/common.go +++ b/sysdig/common.go @@ -64,4 +64,5 @@ const ( SchemaCloudProviderTenantId = "provider_tenant_id" SchemaCloudProviderAlias = "provider_alias" SchemaAccountId = "account_id" + SchemaFeatureFlags = "flags" ) diff --git a/sysdig/internal/client/v2/cloudauth_account_component.go b/sysdig/internal/client/v2/cloudauth_account_component.go index 9bd5de94..e34cddc1 100644 --- a/sysdig/internal/client/v2/cloudauth_account_component.go +++ b/sysdig/internal/client/v2/cloudauth_account_component.go @@ -9,7 +9,6 @@ import ( const ( cloudauthAccountComponentsPath = "%s/api/cloudauth/v1/accounts/%s/components" // POST cloudauthAccountComponentPath = "%s/api/cloudauth/v1/accounts/%s/components/%s/%s" // GET, PUT, DEL - // getCloudauthAccountPath = "%s/api/cloudauth/v1/accounts/%s?decrypt=%s" // does GET require decryption? ) type CloudauthAccountComponentSecureInterface interface { diff --git a/sysdig/internal/client/v2/cloudauth_account_feature.go b/sysdig/internal/client/v2/cloudauth_account_feature.go new file mode 100644 index 00000000..b6d00cc9 --- /dev/null +++ b/sysdig/internal/client/v2/cloudauth_account_feature.go @@ -0,0 +1,82 @@ +package v2 + +import ( + "context" + "fmt" + "net/http" +) + +const ( + cloudauthAccountFeaturePath = "%s/api/cloudauth/v1/accounts/%s/feature/%s" // GET, PUT, DEL +) + +type CloudauthAccountFeatureSecureInterface interface { + Base + CreateOrUpdateCloudauthAccountFeatureSecure(ctx context.Context, accountID, featureType string, cloudAccountFeature *CloudauthAccountFeatureSecure) (*CloudauthAccountFeatureSecure, string, error) + GetCloudauthAccountFeatureSecure(ctx context.Context, accountID, featureType string) (*CloudauthAccountFeatureSecure, string, error) + DeleteCloudauthAccountFeatureSecure(ctx context.Context, accountID, featureType string) (string, error) +} + +// both create and update makes a PUT call to backend +func (client *Client) CreateOrUpdateCloudauthAccountFeatureSecure(ctx context.Context, accountID, featureType string, cloudAccountFeature *CloudauthAccountFeatureSecure) ( + *CloudauthAccountFeatureSecure, string, error) { + payload, err := client.marshalCloudauthProto(cloudAccountFeature) + if err != nil { + return nil, "", err + } + + response, err := client.requester.Request(ctx, http.MethodPut, client.cloudauthAccountFeatureURL(accountID, featureType), payload) + if err != nil { + return nil, "", err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated { + errStatus, err := client.ErrorAndStatusFromResponse(response) + return nil, errStatus, err + } + + cloudauthAccountFeature := &CloudauthAccountFeatureSecure{} + err = client.unmarshalCloudauthProto(response.Body, cloudauthAccountFeature) + if err != nil { + return nil, "", err + } + return cloudauthAccountFeature, "", nil +} + +func (client *Client) GetCloudauthAccountFeatureSecure(ctx context.Context, accountID, featureType string) (*CloudauthAccountFeatureSecure, string, error) { + response, err := client.requester.Request(ctx, http.MethodGet, client.cloudauthAccountFeatureURL(accountID, featureType), nil) + if err != nil { + return nil, "", err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusOK { + errStatus, err := client.ErrorAndStatusFromResponse(response) + return nil, errStatus, err + } + + cloudauthAccountFeature := &CloudauthAccountFeatureSecure{} + err = client.unmarshalCloudauthProto(response.Body, cloudauthAccountFeature) + if err != nil { + return nil, "", err + } + return cloudauthAccountFeature, "", nil +} + +func (client *Client) DeleteCloudauthAccountFeatureSecure(ctx context.Context, accountID, featureType string) (string, error) { + response, err := client.requester.Request(ctx, http.MethodDelete, client.cloudauthAccountFeatureURL(accountID, featureType), nil) + if err != nil { + return "", err + } + defer response.Body.Close() + + if response.StatusCode != http.StatusNoContent && response.StatusCode != http.StatusOK { + return client.ErrorAndStatusFromResponse(response) + } + return "", nil +} + +func (client *Client) cloudauthAccountFeatureURL(accountID string, featureType string) string { + return fmt.Sprintf(cloudauthAccountFeaturePath, client.config.url, accountID, featureType) +} diff --git a/sysdig/internal/client/v2/model.go b/sysdig/internal/client/v2/model.go index bdc33bb7..7380ca4b 100644 --- a/sysdig/internal/client/v2/model.go +++ b/sysdig/internal/client/v2/model.go @@ -609,6 +609,10 @@ type CloudauthAccountComponentSecure struct { cloudauth.AccountComponent } +type CloudauthAccountFeatureSecure struct { + cloudauth.AccountFeature +} + type ScanningPolicy struct { ID string `json:"id,omitempty"` Version string `json:"version,omitempty"` diff --git a/sysdig/internal/client/v2/sysdig.go b/sysdig/internal/client/v2/sysdig.go index b80bba46..b639a705 100644 --- a/sysdig/internal/client/v2/sysdig.go +++ b/sysdig/internal/client/v2/sysdig.go @@ -47,6 +47,7 @@ type SysdigSecure interface { CloudauthAccountSecureInterface OrganizationSecureInterface CloudauthAccountComponentSecureInterface + CloudauthAccountFeatureSecureInterface } func (sr *SysdigRequest) Request(ctx context.Context, method string, url string, payload io.Reader) (*http.Response, error) { diff --git a/sysdig/provider.go b/sysdig/provider.go index 58d91888..87c50177 100644 --- a/sysdig/provider.go +++ b/sysdig/provider.go @@ -156,6 +156,7 @@ func (p *SysdigProvider) Provider() *schema.Provider { "sysdig_secure_scanning_policy_assignment": resourceSysdigSecureScanningPolicyAssignment(), "sysdig_secure_cloud_auth_account": resourceSysdigSecureCloudauthAccount(), "sysdig_secure_cloud_auth_account_component": resourceSysdigSecureCloudauthAccountComponent(), + "sysdig_secure_cloud_auth_account_feature": resourceSysdigSecureCloudauthAccountFeature(), "sysdig_monitor_silence_rule": resourceSysdigMonitorSilenceRule(), "sysdig_monitor_alert_downtime": resourceSysdigMonitorAlertDowntime(), diff --git a/sysdig/resource_sysdig_secure_cloud_auth_account.go b/sysdig/resource_sysdig_secure_cloud_auth_account.go index b9bdf19b..8f82e541 100644 --- a/sysdig/resource_sysdig_secure_cloud_auth_account.go +++ b/sysdig/resource_sysdig_secure_cloud_auth_account.go @@ -23,7 +23,7 @@ import ( declare common schemas used across resources here */ var ( - accountComponents = &schema.Resource{ + accountComponent = &schema.Resource{ Schema: map[string]*schema.Schema{ SchemaType: { Type: schema.TypeString, @@ -166,7 +166,7 @@ func resourceSysdigSecureCloudauthAccount() *schema.Resource { SchemaComponent: { Type: schema.TypeSet, Optional: true, - Elem: accountComponents, + Elem: accountComponent, }, SchemaOrganizationIDKey: { Type: schema.TypeString, diff --git a/sysdig/resource_sysdig_secure_cloud_auth_account_component.go b/sysdig/resource_sysdig_secure_cloud_auth_account_component.go index 46349c07..9e019d12 100644 --- a/sysdig/resource_sysdig_secure_cloud_auth_account_component.go +++ b/sysdig/resource_sysdig_secure_cloud_auth_account_component.go @@ -48,7 +48,7 @@ func getAccountComponentSchema() map[string]*schema.Schema { }, } - for field, schema := range accountComponents.Schema { + for field, schema := range accountComponent.Schema { componentSchema[field] = schema } return componentSchema diff --git a/sysdig/resource_sysdig_secure_cloud_auth_account_feature.go b/sysdig/resource_sysdig_secure_cloud_auth_account_feature.go new file mode 100644 index 00000000..d6f2d8b7 --- /dev/null +++ b/sysdig/resource_sysdig_secure_cloud_auth_account_feature.go @@ -0,0 +1,248 @@ +package sysdig + +import ( + "context" + "errors" + "fmt" + "strings" + "time" + + v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2" + cloudauth "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2/cloudauth/go" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func resourceSysdigSecureCloudauthAccountFeature() *schema.Resource { + timeout := 5 * time.Minute + + return &schema.Resource{ + CreateContext: resourceSysdigSecureCloudauthAccountFeatureCreate, + UpdateContext: resourceSysdigSecureCloudauthAccountFeatureUpdate, + ReadContext: resourceSysdigSecureCloudauthAccountFeatureRead, + DeleteContext: resourceSysdigSecureCloudauthAccountFeatureDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(timeout), + Update: schema.DefaultTimeout(timeout), + Read: schema.DefaultTimeout(timeout), + Delete: schema.DefaultTimeout(timeout), + }, + Schema: getAccountFeatureSchema(), + } +} + +func getAccountFeatureSchema() map[string]*schema.Schema { + // though the schema fields are already defined in cloud_auth_account resource, for AccountFeature + // calls they are required fields. Also, account_id & flags are needed additionally. + featureSchema := map[string]*schema.Schema{ + SchemaAccountId: { + Type: schema.TypeString, + Required: true, + }, + SchemaType: { + Type: schema.TypeString, + Required: true, + }, + SchemaEnabled: { + Type: schema.TypeBool, + Required: true, + }, + SchemaComponents: { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + SchemaFeatureFlags: { + Type: schema.TypeMap, + Optional: true, + }, + } + + return featureSchema +} + +func getSecureCloudauthAccountFeatureClient(client SysdigClients) (v2.CloudauthAccountFeatureSecureInterface, error) { + return client.sysdigSecureClientV2() +} + +func resourceSysdigSecureCloudauthAccountFeatureCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := getSecureCloudauthAccountFeatureClient((meta.(SysdigClients))) + if err != nil { + return diag.FromErr(err) + } + + accountId := data.Get(SchemaAccountId).(string) + cloudauthAccountFeature, errStatus, err := client.CreateOrUpdateCloudauthAccountFeatureSecure( + ctx, accountId, data.Get(SchemaType).(string), cloudauthAccountFeatureFromResourceData(data)) + if err != nil { + return diag.Errorf("Error creating resource: %s %s", errStatus, err) + } + + // using tuple 'accountId/featureType' as TF resource identifier + data.SetId(accountId + "/" + cloudauthAccountFeature.GetType().String()) + err = data.Set(SchemaAccountId, accountId) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceSysdigSecureCloudauthAccountFeatureRead(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := getSecureCloudauthAccountFeatureClient((meta.(SysdigClients))) + if err != nil { + return diag.FromErr(err) + } + + cloudauthAccountFeature, errStatus, err := client.GetCloudauthAccountFeatureSecure( + ctx, data.Get(SchemaAccountId).(string), data.Get(SchemaType).(string)) + + if err != nil { + if strings.Contains(errStatus, "404") { + return nil + } + return diag.Errorf("Error reading resource: %s %s", errStatus, err) + } + + err = cloudauthAccountFeatureToResourceData(data, cloudauthAccountFeature) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceSysdigSecureCloudauthAccountFeatureUpdate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := getSecureCloudauthAccountFeatureClient(meta.(SysdigClients)) + if err != nil { + return diag.FromErr(err) + } + + accountId := data.Get(SchemaAccountId).(string) + existingCloudAccountFeature, errStatus, err := client.GetCloudauthAccountFeatureSecure( + ctx, accountId, data.Get(SchemaType).(string)) + if err != nil { + if strings.Contains(errStatus, "404") { + return nil + } + return diag.Errorf("Error reading resource: %s %s", errStatus, err) + } + + newCloudAccountFeature := cloudauthAccountFeatureFromResourceData(data) + + // validate and reject non-updatable resource schema fields upfront + err = validateCloudauthAccountFeatureUpdate(existingCloudAccountFeature, newCloudAccountFeature) + if err != nil { + return diag.Errorf("Error updating resource: %s", err) + } + + _, errStatus, err = client.CreateOrUpdateCloudauthAccountFeatureSecure( + ctx, accountId, data.Get(SchemaType).(string), newCloudAccountFeature) + if err != nil { + if strings.Contains(errStatus, "404") { + return nil + } + return diag.Errorf("Error updating resource: %s %s", errStatus, err) + } + + return nil +} + +func resourceSysdigSecureCloudauthAccountFeatureDelete(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { + client, err := getSecureCloudauthAccountFeatureClient(meta.(SysdigClients)) + if err != nil { + return diag.FromErr(err) + } + + errStatus, err := client.DeleteCloudauthAccountFeatureSecure( + ctx, data.Get(SchemaAccountId).(string), data.Get(SchemaType).(string)) + if err != nil { + if strings.Contains(errStatus, "404") { + return nil + } + return diag.Errorf("Error deleting resource: %s %s", errStatus, err) + } + + return nil +} + +/* +This function validates and restricts any fields not allowed to be updated during resource updates. +*/ +func validateCloudauthAccountFeatureUpdate(existingFeature *v2.CloudauthAccountFeatureSecure, newFeature *v2.CloudauthAccountFeatureSecure) error { + if existingFeature.Type != newFeature.Type { + errorInvalidResourceUpdate := fmt.Sprintf("Bad Request. Updating restricted fields not allowed: %s", []string{"type"}) + return errors.New(errorInvalidResourceUpdate) + } + + return nil +} + +func getFeatureComponentsList(data *schema.ResourceData) []string { + componentsList := []string{} + componentsResourceList := data.Get(SchemaComponents).([]interface{}) + for _, componentID := range componentsResourceList { + componentsList = append(componentsList, componentID.(string)) + } + return componentsList +} + +func getFeatureFlags(data *schema.ResourceData) map[string]string { + featureFlags := map[string]string{} + flagsResource := data.Get(SchemaFeatureFlags).(map[string]interface{}) + for name, value := range flagsResource { + featureFlags[name] = value.(string) + } + return featureFlags +} + +func cloudauthAccountFeatureFromResourceData(data *schema.ResourceData) *v2.CloudauthAccountFeatureSecure { + cloudAccountFeature := &v2.CloudauthAccountFeatureSecure{ + AccountFeature: cloudauth.AccountFeature{ + Type: cloudauth.Feature(cloudauth.Feature_value[data.Get(SchemaType).(string)]), + Enabled: data.Get(SchemaEnabled).(bool), + Components: getFeatureComponentsList(data), + Flags: getFeatureFlags(data), + }, + } + + return cloudAccountFeature +} + +func cloudauthAccountFeatureToResourceData(data *schema.ResourceData, cloudAccountFeature *v2.CloudauthAccountFeatureSecure) error { + + accountId := data.Get(SchemaAccountId).(string) + data.SetId(accountId + "/" + cloudAccountFeature.GetType().String()) + + err := data.Set(SchemaAccountId, accountId) + if err != nil { + return err + } + + err = data.Set(SchemaType, cloudAccountFeature.GetType().String()) + if err != nil { + return err + } + + err = data.Set(SchemaEnabled, cloudAccountFeature.GetEnabled()) + if err != nil { + return err + } + + err = data.Set(SchemaComponents, cloudAccountFeature.GetComponents()) + if err != nil { + return err + } + + err = data.Set(SchemaFeatureFlags, cloudAccountFeature.GetFlags()) + if err != nil { + return err + } + + return nil +} diff --git a/sysdig/resource_sysdig_secure_cloud_auth_account_feature_test.go b/sysdig/resource_sysdig_secure_cloud_auth_account_feature_test.go new file mode 100644 index 00000000..bb18421e --- /dev/null +++ b/sysdig/resource_sysdig_secure_cloud_auth_account_feature_test.go @@ -0,0 +1,181 @@ +//go:build tf_acc_sysdig_secure || tf_acc_sysdig_common + +package sysdig_test + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + + "github.com/draios/terraform-provider-sysdig/sysdig" +) + +// TF acceptance tests for secure account feature need an actual azure account +// onboarded to use its account_id (uuid based) as input to the account feature CRUD calls. +// They also need related valid component(s) to be onboarded for account feature to work. + +/************ +* Azure tests +************/ +func TestAccSecureCloudAuthAccountFeature(t *testing.T) { + rText := func() string { return acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) } + accID := rText() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" { + t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests") + } + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: secureAzureWithServicePrincipalFeature(accID), + }, + { + ResourceName: "sysdig_secure_cloud_auth_account.azure_sample", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func secureAzureWithServicePrincipalFeature(accountID string) string { + // to replicate user behavior, snippet creates an actual azure account and + // an actual Service Principal component. It then passes cloudauth returned account_id + // as input to the account feature calls. + rID := func() string { return acctest.RandStringFromCharSet(36, acctest.CharSetAlphaNum) } + randomTenantId := rID() + + return fmt.Sprintf(` +resource "sysdig_secure_cloud_auth_account" "azure_sample" { + provider_id = "azure-cspm-test-%s" + provider_type = "PROVIDER_AZURE" + enabled = true + provider_tenant_id = "%s" + provider_alias = "some-alias" + lifecycle { + ignore_changes = [ + component, + feature + ] + } +} + +resource "sysdig_secure_cloud_auth_account_component" "azure_service_principal" { + account_id = sysdig_secure_cloud_auth_account.azure_sample.id + type = "COMPONENT_SERVICE_PRINCIPAL" + instance = "secure-posture" + service_principal_metadata = jsonencode({ + azure = { + active_directory_service_principal = { + id = "some-id" + account_enabled = true + display_name = "some-display-name" + app_display_name = "some-app-display-name" + app_id = "some-app-id" + app_owner_organization_id = "some-app-owner-organization-id" + } + } + }) +} + +resource "sysdig_secure_cloud_auth_account_feature" "azure_config_posture" { + account_id = sysdig_secure_cloud_auth_account.azure_sample.id + type = "FEATURE_SECURE_CONFIG_POSTURE" + enabled = true + components = ["COMPONENT_SERVICE_PRINCIPAL/secure-posture"] + + depends_on = [ sysdig_secure_cloud_auth_account_component.azure_service_principal ] +} +`, accountID, randomTenantId) +} + +func TestAccSecureCloudAuthAccountFeatureWithFlags(t *testing.T) { + rText := func() string { return acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) } + accID := rText() + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + if v := os.Getenv("SYSDIG_SECURE_API_TOKEN"); v == "" { + t.Fatal("SYSDIG_SECURE_API_TOKEN must be set for acceptance tests") + } + }, + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: secureAzureWithScanningFeatureWithFlags(accID), + }, + { + ResourceName: "sysdig_secure_cloud_auth_account.azure_sample", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func secureAzureWithScanningFeatureWithFlags(accountID string) string { + // to replicate user behavior, snippet creates an actual azure account and + // an actual Service Principal component. It then passes cloudauth returned account_id + // as input to the account feature calls. + rID := func() string { return acctest.RandStringFromCharSet(36, acctest.CharSetAlphaNum) } + randomTenantId := rID() + + return fmt.Sprintf(` +resource "sysdig_secure_cloud_auth_account" "azure_sample" { + provider_id = "azure-vmscan-test-%s" + provider_type = "PROVIDER_AZURE" + enabled = true + provider_tenant_id = "%s" + provider_alias = "some-alias" + lifecycle { + ignore_changes = [ + component, + feature + ] + } +} + +resource "sysdig_secure_cloud_auth_account_component" "azure_service_principal" { + account_id = sysdig_secure_cloud_auth_account.azure_sample.id + type = "COMPONENT_SERVICE_PRINCIPAL" + instance = "secure-scanning" + service_principal_metadata = jsonencode({ + azure = { + active_directory_service_principal = { + id = "some-id" + account_enabled = true + display_name = "some-display-name" + app_display_name = "some-app-display-name" + app_id = "some-app-id" + app_owner_organization_id = "some-app-owner-organization-id" + } + } + }) +} + +resource "sysdig_secure_cloud_auth_account_feature" "azure_agentless_scanning" { + account_id = sysdig_secure_cloud_auth_account.azure_sample.id + type = "FEATURE_SECURE_AGENTLESS_SCANNING" + enabled = true + components = ["COMPONENT_SERVICE_PRINCIPAL/secure-scanning"] + flags = { + "SCANNING_HOST_CONTAINER_ENABLED": "true" + } + + depends_on = [ sysdig_secure_cloud_auth_account_component.azure_service_principal ] +} +`, accountID, randomTenantId) +} diff --git a/website/docs/r/secure_cloud_auth_account_feature.md b/website/docs/r/secure_cloud_auth_account_feature.md new file mode 100644 index 00000000..fcf61b9e --- /dev/null +++ b/website/docs/r/secure_cloud_auth_account_feature.md @@ -0,0 +1,73 @@ +--- +subcategory: "Sysdig Secure" +layout: "sysdig" +page_title: "Sysdig: sysdig_secure_cloud_auth_account_feature" +description: |- + Creates a Sysdig Secure Cloud Account Feature using Cloudauth APIs. +--- + +# Resource: sysdig_secure_cloud_auth_account_feature + +Creates a Sysdig Secure Cloud Account Feature using Cloudauth APIs. + +-> **Note:** Sysdig Terraform Provider is under rapid development at this point. If you experience any issue or discrepancy while using it, please make sure you have the latest version. If the issue persists, or you have a Feature Request to support an additional set of resources, please open a [new issue](https://github.com/sysdiglabs/terraform-provider-sysdig/issues/new) in the GitHub repository. + +## Example Usage + +```terraform +resource "sysdig_secure_cloud_auth_account" "sample" { + provider_id = "mygcpproject" + provider_type = "PROVIDER_GCP" + enabled = true + lifecycle { + ignore_changes = [ + component, + feature + ] + } +} +resource "sysdig_secure_cloud_auth_account_component" "sample" { + account_id = sysdig_secure_cloud_auth_account.sample.id + type = "COMPONENT_SERVICE_PRINCIPAL" + instance = "secure-scanning" + service_principal_metadata = jsonencode({ + gcp = { + workload_identity_federation = { + pool_provider_id = "some-pool-provider-id" + } + email = "some-service-account-email" + } + }) +} + +resource "sysdig_secure_cloud_auth_account_feature" "sample" { + account_id = sysdig_secure_cloud_auth_account.sample.id + type = "FEATURE_SECURE_AGENTLESS_SCANNING" + enabled = true + components = ["COMPONENT_SERVICE_PRINCIPAL/secure-scanning"] + flags = { + "SCANNING_HOST_CONTAINER_ENABLED": "true" + } + depends_on = [ sysdig_secure_cloud_auth_account_component.sample ] +} +``` + +## Argument Reference + +* `account_id` - (Required) Cloud Account created using resource sysdig_secure_cloud_auth_account. + +* `type` - (Required) The type of feature to be created/added. e.g. `FEATURE_SECURE_CONFIG_POSTURE`. + +* `enabled` - (Required) Whether or not to enable this feature on the given cloud account. + +* `components` - (Required) Based on the feature type to be created, this is the list of components to be enabled on the cloud account. + +* `flags` - (Optional) Based on the feature type to be created, these are the flags to be added to the feature on the cloud account. + +-> **Note:** Please refer to Sysdig Secure API Documentation for the Cloud Accounts API for `feature` types and their related `components`. + +-> **Note:** Since creation of component resource updates the account resource in the backend, in these configurations we indicate to Terraform to ignore `component` & `feature` attributes when planning updates to the remote account resource object. + +## Attributes Reference + +No additional attributes are exported. \ No newline at end of file