diff --git a/sysdig/internal/client/v2/model.go b/sysdig/internal/client/v2/model.go index 0305b98f..b483285e 100644 --- a/sysdig/internal/client/v2/model.go +++ b/sysdig/internal/client/v2/model.go @@ -1285,3 +1285,32 @@ type SSOSamlConfig struct { IsDestinationVerificationEnabled *bool `json:"isDestinationVerificationEnabled,omitempty"` IsEncryptionSupportEnabled *bool `json:"isEncryptionSupportEnabled,omitempty"` } + +// SSO Group Mapping (Platform API) +type SSOGroupMapping struct { + ID int `json:"id,omitempty"` + GroupName string `json:"groupName"` + StandardTeamRole string `json:"standardTeamRole,omitempty"` + CustomTeamRoleID int `json:"customTeamRoleId,omitempty"` + IsAdmin bool `json:"isAdmin"` + TeamMap *SSOGroupMappingTeamMap `json:"teamMap"` + Weight int `json:"weight,omitempty"` +} + +type SSOGroupMappingTeamMap struct { + IsForAllTeams bool `json:"isForAllTeams"` + TeamIDs []int `json:"teamIds,omitempty"` +} + +// SSO Group Mapping Settings (Platform API) +type SSOGroupMappingSettings struct { + NoMappingStrategy string `json:"noMappingStrategy"` + DifferentRolesSameTeamStrategy string `json:"differentRolesSameTeamStrategy"` + NoMappingsErrorRedirectURL string `json:"noMappingsErrorRedirectUrl,omitempty"` +} + +// SSO Global Settings (Platform API) +type SSOGlobalSettings struct { + Product string `json:"product,omitempty"` + IsPasswordLoginEnabled bool `json:"isPasswordLoginEnabled"` +} diff --git a/sysdig/internal/client/v2/sso_global_settings.go b/sysdig/internal/client/v2/sso_global_settings.go new file mode 100644 index 00000000..88559ede --- /dev/null +++ b/sysdig/internal/client/v2/sso_global_settings.go @@ -0,0 +1,68 @@ +package v2 + +import ( + "context" + "errors" + "fmt" + "net/http" +) + +var ErrSSOGlobalSettingsNotFound = errors.New("SSO global settings not found") + +const ( + ssoGlobalSettingsPath = "%s/platform/v1/global-sso-settings/%s" +) + +type SSOGlobalSettingsInterface interface { + Base + GetSSOGlobalSettings(ctx context.Context, product string) (*SSOGlobalSettings, error) + UpdateSSOGlobalSettings(ctx context.Context, product string, settings *SSOGlobalSettings) (*SSOGlobalSettings, error) +} + +func (c *Client) GetSSOGlobalSettings(ctx context.Context, product string) (result *SSOGlobalSettings, err error) { + response, err := c.requester.Request(ctx, http.MethodGet, c.ssoGlobalSettingsURL(product), nil) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode == http.StatusNotFound { + return nil, ErrSSOGlobalSettingsNotFound + } + if response.StatusCode != http.StatusOK { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGlobalSettings](response.Body) +} + +func (c *Client) UpdateSSOGlobalSettings(ctx context.Context, product string, settings *SSOGlobalSettings) (result *SSOGlobalSettings, err error) { + payload, err := Marshal(settings) + if err != nil { + return nil, err + } + + response, err := c.requester.Request(ctx, http.MethodPut, c.ssoGlobalSettingsURL(product), payload) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode != http.StatusOK { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGlobalSettings](response.Body) +} + +func (c *Client) ssoGlobalSettingsURL(product string) string { + return fmt.Sprintf(ssoGlobalSettingsPath, c.config.url, product) +} diff --git a/sysdig/internal/client/v2/sso_group_mapping.go b/sysdig/internal/client/v2/sso_group_mapping.go new file mode 100644 index 00000000..958f927d --- /dev/null +++ b/sysdig/internal/client/v2/sso_group_mapping.go @@ -0,0 +1,126 @@ +package v2 + +import ( + "context" + "errors" + "fmt" + "net/http" +) + +var ErrSSOGroupMappingNotFound = errors.New("SSO group mapping not found") + +const ( + createSSOGroupMappingPath = "%s/platform/v1/group-mappings" + getSSOGroupMappingPath = "%s/platform/v1/group-mappings/%d" + updateSSOGroupMappingPath = "%s/platform/v1/group-mappings/%d" + deleteSSOGroupMappingPath = "%s/platform/v1/group-mappings/%d" +) + +type SSOGroupMappingInterface interface { + Base + CreateSSOGroupMapping(ctx context.Context, gm *SSOGroupMapping) (*SSOGroupMapping, error) + GetSSOGroupMapping(ctx context.Context, id int) (*SSOGroupMapping, error) + UpdateSSOGroupMapping(ctx context.Context, id int, gm *SSOGroupMapping) (*SSOGroupMapping, error) + DeleteSSOGroupMapping(ctx context.Context, id int) error +} + +func (c *Client) CreateSSOGroupMapping(ctx context.Context, gm *SSOGroupMapping) (result *SSOGroupMapping, err error) { + payload, err := Marshal(gm) + if err != nil { + return nil, err + } + + response, err := c.requester.Request(ctx, http.MethodPost, c.createSSOGroupMappingURL(), payload) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGroupMapping](response.Body) +} + +func (c *Client) GetSSOGroupMapping(ctx context.Context, id int) (result *SSOGroupMapping, err error) { + response, err := c.requester.Request(ctx, http.MethodGet, c.getSSOGroupMappingURL(id), nil) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode == http.StatusNotFound { + return nil, ErrSSOGroupMappingNotFound + } + if response.StatusCode != http.StatusOK { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGroupMapping](response.Body) +} + +func (c *Client) UpdateSSOGroupMapping(ctx context.Context, id int, gm *SSOGroupMapping) (result *SSOGroupMapping, err error) { + payload, err := Marshal(gm) + if err != nil { + return nil, err + } + + response, err := c.requester.Request(ctx, http.MethodPut, c.updateSSOGroupMappingURL(id), payload) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode != http.StatusOK { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGroupMapping](response.Body) +} + +func (c *Client) DeleteSSOGroupMapping(ctx context.Context, id int) (err error) { + response, err := c.requester.Request(ctx, http.MethodDelete, c.deleteSSOGroupMappingURL(id), nil) + if err != nil { + return err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode != http.StatusNoContent && response.StatusCode != http.StatusOK && response.StatusCode != http.StatusNotFound { + return c.ErrorFromResponse(response) + } + + return nil +} + +func (c *Client) createSSOGroupMappingURL() string { + return fmt.Sprintf(createSSOGroupMappingPath, c.config.url) +} + +func (c *Client) getSSOGroupMappingURL(id int) string { + return fmt.Sprintf(getSSOGroupMappingPath, c.config.url, id) +} + +func (c *Client) updateSSOGroupMappingURL(id int) string { + return fmt.Sprintf(updateSSOGroupMappingPath, c.config.url, id) +} + +func (c *Client) deleteSSOGroupMappingURL(id int) string { + return fmt.Sprintf(deleteSSOGroupMappingPath, c.config.url, id) +} diff --git a/sysdig/internal/client/v2/sso_group_mapping_settings.go b/sysdig/internal/client/v2/sso_group_mapping_settings.go new file mode 100644 index 00000000..f76600d9 --- /dev/null +++ b/sysdig/internal/client/v2/sso_group_mapping_settings.go @@ -0,0 +1,72 @@ +package v2 + +import ( + "context" + "errors" + "fmt" + "net/http" +) + +var ErrSSOGroupMappingSettingsNotFound = errors.New("SSO group mapping settings not found") + +const ( + ssoGroupMappingSettingsPath = "%s/platform/v1/group-mappings-settings" +) + +type SSOGroupMappingSettingsInterface interface { + Base + GetSSOGroupMappingSettings(ctx context.Context) (*SSOGroupMappingSettings, error) + UpdateSSOGroupMappingSettings(ctx context.Context, settings *SSOGroupMappingSettings) (*SSOGroupMappingSettings, error) +} + +func (c *Client) GetSSOGroupMappingSettings(ctx context.Context) (result *SSOGroupMappingSettings, err error) { + response, err := c.requester.Request(ctx, http.MethodGet, c.getSSOGroupMappingSettingsURL(), nil) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode == http.StatusNotFound { + return nil, ErrSSOGroupMappingSettingsNotFound + } + if response.StatusCode != http.StatusOK { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGroupMappingSettings](response.Body) +} + +func (c *Client) UpdateSSOGroupMappingSettings(ctx context.Context, settings *SSOGroupMappingSettings) (result *SSOGroupMappingSettings, err error) { + payload, err := Marshal(settings) + if err != nil { + return nil, err + } + + response, err := c.requester.Request(ctx, http.MethodPut, c.updateSSOGroupMappingSettingsURL(), payload) + if err != nil { + return nil, err + } + defer func() { + if dErr := response.Body.Close(); dErr != nil { + err = fmt.Errorf("unable to close response body: %w", dErr) + } + }() + + if response.StatusCode != http.StatusOK { + return nil, c.ErrorFromResponse(response) + } + + return Unmarshal[*SSOGroupMappingSettings](response.Body) +} + +func (c *Client) getSSOGroupMappingSettingsURL() string { + return fmt.Sprintf(ssoGroupMappingSettingsPath, c.config.url) +} + +func (c *Client) updateSSOGroupMappingSettingsURL() string { + return fmt.Sprintf(ssoGroupMappingSettingsPath, c.config.url) +} diff --git a/sysdig/internal/client/v2/sysdig.go b/sysdig/internal/client/v2/sysdig.go index 09e19d6a..24428f28 100644 --- a/sysdig/internal/client/v2/sysdig.go +++ b/sysdig/internal/client/v2/sysdig.go @@ -25,6 +25,9 @@ type SysdigCommon interface { GroupMappingInterface IPFilteringSettingsInterface IPFiltersInterface + SSOGlobalSettingsInterface + SSOGroupMappingInterface + SSOGroupMappingSettingsInterface SSOOpenIDInterface SSOSamlInterface TeamServiceAccountInterface diff --git a/sysdig/provider.go b/sysdig/provider.go index c567eb73..93464333 100644 --- a/sysdig/provider.go +++ b/sysdig/provider.go @@ -115,16 +115,19 @@ func (p *SysdigProvider) Provider() *schema.Provider { }, }, ResourcesMap: map[string]*schema.Resource{ - "sysdig_agent_access_key": resourceSysdigAgentAccessKey(), - "sysdig_custom_role": resourceSysdigCustomRole(), - "sysdig_group_mapping": resourceSysdigGroupMapping(), - "sysdig_group_mapping_config": resourceSysdigGroupMappingConfig(), - "sysdig_ip_filter": resourceSysdigIPFilter(), - "sysdig_ip_filtering_settings": resourceSysdigIPFilteringSettings(), - "sysdig_sso_openid": resourceSysdigSSOOpenID(), - "sysdig_sso_saml": resourceSysdigSSOSaml(), - "sysdig_team_service_account": resourceSysdigTeamServiceAccount(), - "sysdig_user": resourceSysdigUser(), + "sysdig_agent_access_key": resourceSysdigAgentAccessKey(), + "sysdig_custom_role": resourceSysdigCustomRole(), + "sysdig_group_mapping": resourceSysdigGroupMapping(), + "sysdig_group_mapping_config": resourceSysdigGroupMappingConfig(), + "sysdig_ip_filter": resourceSysdigIPFilter(), + "sysdig_ip_filtering_settings": resourceSysdigIPFilteringSettings(), + "sysdig_sso_global_settings": resourceSysdigSSOGlobalSettings(), + "sysdig_sso_group_mapping": resourceSysdigSSOGroupMapping(), + "sysdig_sso_group_mapping_settings": resourceSysdigSSOGroupMappingSettings(), + "sysdig_sso_openid": resourceSysdigSSOOpenID(), + "sysdig_sso_saml": resourceSysdigSSOSaml(), + "sysdig_team_service_account": resourceSysdigTeamServiceAccount(), + "sysdig_user": resourceSysdigUser(), "sysdig_monitor_alert_v2_change": resourceSysdigMonitorAlertV2Change(), "sysdig_monitor_alert_v2_downtime": resourceSysdigMonitorAlertV2Downtime(), diff --git a/sysdig/resource_sysdig_group_mapping.go b/sysdig/resource_sysdig_group_mapping.go index 9168466f..b2a40d37 100644 --- a/sysdig/resource_sysdig_group_mapping.go +++ b/sysdig/resource_sysdig_group_mapping.go @@ -14,10 +14,11 @@ func resourceSysdigGroupMapping() *schema.Resource { timeout := 5 * time.Minute return &schema.Resource{ - ReadContext: resourceSysdigGroupMappingRead, - CreateContext: resourceSysdigGroupMappingCreate, - UpdateContext: resourceSysdigGroupMappingUpdate, - DeleteContext: resourceSysdigGroupMappingDelete, + ReadContext: resourceSysdigGroupMappingRead, + CreateContext: resourceSysdigGroupMappingCreate, + UpdateContext: resourceSysdigGroupMappingUpdate, + DeleteContext: resourceSysdigGroupMappingDelete, + DeprecationMessage: "Use sysdig_sso_group_mapping instead. This resource will be removed in a future version.", Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/sysdig/resource_sysdig_group_mapping_config.go b/sysdig/resource_sysdig_group_mapping_config.go index 7538c1c9..404b4d82 100644 --- a/sysdig/resource_sysdig_group_mapping_config.go +++ b/sysdig/resource_sysdig_group_mapping_config.go @@ -12,10 +12,11 @@ import ( func resourceSysdigGroupMappingConfig() *schema.Resource { timeout := 5 * time.Minute return &schema.Resource{ - ReadContext: resourceSysdigGroupMappingConfigRead, - CreateContext: resourceSysdigGroupMappingConfigCreate, - UpdateContext: resourceSysdigGroupMappingConfigUpdate, - DeleteContext: resourceSysdigGroupMappingConfigDelete, + ReadContext: resourceSysdigGroupMappingConfigRead, + CreateContext: resourceSysdigGroupMappingConfigCreate, + UpdateContext: resourceSysdigGroupMappingConfigUpdate, + DeleteContext: resourceSysdigGroupMappingConfigDelete, + DeprecationMessage: "Use sysdig_sso_group_mapping_settings instead. This resource will be removed in a future version.", Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, diff --git a/sysdig/resource_sysdig_sso_global_settings.go b/sysdig/resource_sysdig_sso_global_settings.go new file mode 100644 index 00000000..266a89aa --- /dev/null +++ b/sysdig/resource_sysdig_sso_global_settings.go @@ -0,0 +1,130 @@ +package sysdig + +import ( + "context" + "time" + + v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceSysdigSSOGlobalSettings() *schema.Resource { + timeout := 5 * time.Minute + + return &schema.Resource{ + CreateContext: resourceSysdigSSOGlobalSettingsCreate, + ReadContext: resourceSysdigSSOGlobalSettingsRead, + UpdateContext: resourceSysdigSSOGlobalSettingsUpdate, + DeleteContext: resourceSysdigSSOGlobalSettingsDelete, + 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: map[string]*schema.Schema{ + "product": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"monitor", "secure"}, false), + }, + "is_password_login_enabled": { + Type: schema.TypeBool, + Required: true, + }, + }, + } +} + +func resourceSysdigSSOGlobalSettingsCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + product := d.Get("product").(string) + settings := ssoGlobalSettingsFromResourceData(d) + + _, err = client.UpdateSSOGlobalSettings(ctx, product, settings) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(product) + + return resourceSysdigSSOGlobalSettingsRead(ctx, d, m) +} + +func resourceSysdigSSOGlobalSettingsRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + product := d.Id() + + settings, err := client.GetSSOGlobalSettings(ctx, product) + if err != nil { + if err == v2.ErrSSOGlobalSettingsNotFound { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + err = ssoGlobalSettingsToResourceData(settings, d) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceSysdigSSOGlobalSettingsUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + product := d.Id() + settings := ssoGlobalSettingsFromResourceData(d) + + _, err = client.UpdateSSOGlobalSettings(ctx, product, settings) + if err != nil { + return diag.FromErr(err) + } + + return resourceSysdigSSOGlobalSettingsRead(ctx, d, m) +} + +func resourceSysdigSSOGlobalSettingsDelete(_ context.Context, _ *schema.ResourceData, _ any) diag.Diagnostics { + return nil +} + +func ssoGlobalSettingsFromResourceData(d *schema.ResourceData) *v2.SSOGlobalSettings { + return &v2.SSOGlobalSettings{ + IsPasswordLoginEnabled: d.Get("is_password_login_enabled").(bool), + } +} + +func ssoGlobalSettingsToResourceData(settings *v2.SSOGlobalSettings, d *schema.ResourceData) error { + // Product may not be returned in API response; use ID (which is the product name) + product := settings.Product + if product == "" { + product = d.Id() + } + if err := d.Set("product", product); err != nil { + return err + } + if err := d.Set("is_password_login_enabled", settings.IsPasswordLoginEnabled); err != nil { + return err + } + + return nil +} diff --git a/sysdig/resource_sysdig_sso_global_settings_test.go b/sysdig/resource_sysdig_sso_global_settings_test.go new file mode 100644 index 00000000..67472885 --- /dev/null +++ b/sysdig/resource_sysdig_sso_global_settings_test.go @@ -0,0 +1,64 @@ +//go:build tf_acc_sysdig_monitor || tf_acc_sysdig_secure || tf_acc_onprem_monitor || tf_acc_onprem_secure + +package sysdig_test + +import ( + "fmt" + "testing" + + "github.com/draios/terraform-provider-sysdig/sysdig" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func TestAccSSOGlobalSettings(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: preCheckAnyEnv(t, SysdigMonitorApiTokenEnv, SysdigSecureApiTokenEnv), + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: ssoGlobalSettingsConfig("monitor", true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_global_settings.test", + "product", + "monitor", + ), + resource.TestCheckResourceAttr( + "sysdig_sso_global_settings.test", + "is_password_login_enabled", + "true", + ), + ), + }, + { + Config: ssoGlobalSettingsConfig("monitor", false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_global_settings.test", + "is_password_login_enabled", + "false", + ), + ), + }, + { + ResourceName: "sysdig_sso_global_settings.test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func ssoGlobalSettingsConfig(product string, isPasswordLoginEnabled bool) string { + return fmt.Sprintf(` +resource "sysdig_sso_global_settings" "test" { + product = "%s" + is_password_login_enabled = %t +} +`, product, isPasswordLoginEnabled) +} diff --git a/sysdig/resource_sysdig_sso_group_mapping.go b/sysdig/resource_sysdig_sso_group_mapping.go new file mode 100644 index 00000000..ac25d605 --- /dev/null +++ b/sysdig/resource_sysdig_sso_group_mapping.go @@ -0,0 +1,244 @@ +package sysdig + +import ( + "context" + "fmt" + "strconv" + "time" + + v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceSysdigSSOGroupMapping() *schema.Resource { + timeout := 5 * time.Minute + + return &schema.Resource{ + CreateContext: resourceSysdigSSOGroupMappingCreate, + ReadContext: resourceSysdigSSOGroupMappingRead, + UpdateContext: resourceSysdigSSOGroupMappingUpdate, + DeleteContext: resourceSysdigSSOGroupMappingDelete, + 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), + }, + CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, meta any) error { + teamMaps := diff.Get("team_map").([]any) + if len(teamMaps) > 0 { + teamMap := teamMaps[0].(map[string]any) + isForAllTeams := teamMap["is_for_all_teams"].(bool) + teamIDs := teamMap["team_ids"].([]any) + if !isForAllTeams && len(teamIDs) == 0 { + return fmt.Errorf("team_ids must be set when is_for_all_teams is false") + } + } + + return nil + }, + Schema: map[string]*schema.Schema{ + "group_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "standard_team_role": { + Type: schema.TypeString, + Optional: true, + ConflictsWith: []string{"custom_team_role_id"}, + AtLeastOneOf: []string{"standard_team_role", "custom_team_role_id"}, + }, + "custom_team_role_id": { + Type: schema.TypeInt, + Optional: true, + ConflictsWith: []string{"standard_team_role"}, + AtLeastOneOf: []string{"standard_team_role", "custom_team_role_id"}, + }, + "is_admin": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "team_map": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "is_for_all_teams": { + Type: schema.TypeBool, + Required: true, + }, + "team_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeInt, + }, + }, + }, + }, + }, + "weight": { + Type: schema.TypeInt, + Optional: true, + Default: 32767, + ValidateFunc: validation.IntBetween(1, 32767), + }, + }, + } +} + +func resourceSysdigSSOGroupMappingCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + gm := ssoGroupMappingFromResourceData(d) + + created, err := client.CreateSSOGroupMapping(ctx, gm) + if err != nil { + return diag.FromErr(err) + } + + d.SetId(strconv.Itoa(created.ID)) + + return resourceSysdigSSOGroupMappingRead(ctx, d, m) +} + +func resourceSysdigSSOGroupMappingRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + id, err := strconv.Atoi(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + gm, err := client.GetSSOGroupMapping(ctx, id) + if err != nil { + if err == v2.ErrSSOGroupMappingNotFound { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + err = ssoGroupMappingToResourceData(gm, d) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceSysdigSSOGroupMappingUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + id, err := strconv.Atoi(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + gm := ssoGroupMappingFromResourceData(d) + + _, err = client.UpdateSSOGroupMapping(ctx, id, gm) + if err != nil { + return diag.FromErr(err) + } + + return resourceSysdigSSOGroupMappingRead(ctx, d, m) +} + +func resourceSysdigSSOGroupMappingDelete(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + id, err := strconv.Atoi(d.Id()) + if err != nil { + return diag.FromErr(err) + } + + err = client.DeleteSSOGroupMapping(ctx, id) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func ssoGroupMappingFromResourceData(d *schema.ResourceData) *v2.SSOGroupMapping { + gm := &v2.SSOGroupMapping{ + GroupName: d.Get("group_name").(string), + IsAdmin: d.Get("is_admin").(bool), + Weight: d.Get("weight").(int), + } + + if v, ok := d.GetOk("standard_team_role"); ok { + gm.StandardTeamRole = v.(string) + } + + if v, ok := d.GetOk("custom_team_role_id"); ok { + gm.CustomTeamRoleID = v.(int) + } + + teamMaps := d.Get("team_map").([]any) + if len(teamMaps) > 0 { + teamMap := teamMaps[0].(map[string]any) + teamIDsInterface := teamMap["team_ids"].([]any) + teamIDs := make([]int, len(teamIDsInterface)) + for i, id := range teamIDsInterface { + teamIDs[i] = id.(int) + } + gm.TeamMap = &v2.SSOGroupMappingTeamMap{ + IsForAllTeams: teamMap["is_for_all_teams"].(bool), + TeamIDs: teamIDs, + } + } + + return gm +} + +func ssoGroupMappingToResourceData(gm *v2.SSOGroupMapping, d *schema.ResourceData) error { + if err := d.Set("group_name", gm.GroupName); err != nil { + return err + } + if err := d.Set("standard_team_role", gm.StandardTeamRole); err != nil { + return err + } + if err := d.Set("custom_team_role_id", gm.CustomTeamRoleID); err != nil { + return err + } + if err := d.Set("is_admin", gm.IsAdmin); err != nil { + return err + } + if err := d.Set("weight", gm.Weight); err != nil { + return err + } + + if gm.TeamMap != nil { + teamMap := map[string]any{ + "is_for_all_teams": gm.TeamMap.IsForAllTeams, + "team_ids": gm.TeamMap.TeamIDs, + } + if err := d.Set("team_map", []map[string]any{teamMap}); err != nil { + return err + } + } + + return nil +} diff --git a/sysdig/resource_sysdig_sso_group_mapping_settings.go b/sysdig/resource_sysdig_sso_group_mapping_settings.go new file mode 100644 index 00000000..e5eed7ab --- /dev/null +++ b/sysdig/resource_sysdig_sso_group_mapping_settings.go @@ -0,0 +1,159 @@ +package sysdig + +import ( + "context" + "fmt" + "time" + + v2 "github.com/draios/terraform-provider-sysdig/sysdig/internal/client/v2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +) + +func resourceSysdigSSOGroupMappingSettings() *schema.Resource { + timeout := 5 * time.Minute + + return &schema.Resource{ + CreateContext: resourceSysdigSSOGroupMappingSettingsCreate, + ReadContext: resourceSysdigSSOGroupMappingSettingsRead, + UpdateContext: resourceSysdigSSOGroupMappingSettingsUpdate, + DeleteContext: resourceSysdigSSOGroupMappingSettingsDelete, + 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), + }, + CustomizeDiff: func(ctx context.Context, diff *schema.ResourceDiff, meta any) error { + strategy := diff.Get("no_mapping_strategy").(string) + redirectURL, hasRedirectURL := diff.GetOk("no_mappings_error_redirect_url") + + if strategy == "NO_MAPPINGS_ERROR_REDIRECT" && (!hasRedirectURL || redirectURL.(string) == "") { + return fmt.Errorf("no_mappings_error_redirect_url must be set when no_mapping_strategy is NO_MAPPINGS_ERROR_REDIRECT") + } + + if strategy != "NO_MAPPINGS_ERROR_REDIRECT" && hasRedirectURL && redirectURL.(string) != "" { + return fmt.Errorf("no_mappings_error_redirect_url can only be set when no_mapping_strategy is NO_MAPPINGS_ERROR_REDIRECT") + } + + return nil + }, + Schema: map[string]*schema.Schema{ + "no_mapping_strategy": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "UNAUTHORIZED", + "DEFAULT_TEAM_DEFAULT_ROLE", + "NO_MAPPINGS_ERROR_REDIRECT", + }, false), + }, + "different_roles_same_team_strategy": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "UNAUTHORIZED", + "HIGHEST_ROLE", + "LOWEST_ROLE", + }, false), + }, + "no_mappings_error_redirect_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 2048), + }, + }, + } +} + +func resourceSysdigSSOGroupMappingSettingsCreate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + settings := ssoGroupMappingSettingsFromResourceData(d) + + _, err = client.UpdateSSOGroupMappingSettings(ctx, settings) + if err != nil { + return diag.FromErr(err) + } + + d.SetId("sso_group_mapping_settings") + + return resourceSysdigSSOGroupMappingSettingsRead(ctx, d, m) +} + +func resourceSysdigSSOGroupMappingSettingsRead(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + settings, err := client.GetSSOGroupMappingSettings(ctx) + if err != nil { + if err == v2.ErrSSOGroupMappingSettingsNotFound { + d.SetId("") + return nil + } + return diag.FromErr(err) + } + + err = ssoGroupMappingSettingsToResourceData(settings, d) + if err != nil { + return diag.FromErr(err) + } + + return nil +} + +func resourceSysdigSSOGroupMappingSettingsUpdate(ctx context.Context, d *schema.ResourceData, m any) diag.Diagnostics { + client, err := m.(SysdigClients).sysdigCommonClientV2() + if err != nil { + return diag.FromErr(err) + } + + settings := ssoGroupMappingSettingsFromResourceData(d) + + _, err = client.UpdateSSOGroupMappingSettings(ctx, settings) + if err != nil { + return diag.FromErr(err) + } + + return resourceSysdigSSOGroupMappingSettingsRead(ctx, d, m) +} + +func resourceSysdigSSOGroupMappingSettingsDelete(_ context.Context, _ *schema.ResourceData, _ any) diag.Diagnostics { + return nil +} + +func ssoGroupMappingSettingsFromResourceData(d *schema.ResourceData) *v2.SSOGroupMappingSettings { + settings := &v2.SSOGroupMappingSettings{ + NoMappingStrategy: d.Get("no_mapping_strategy").(string), + DifferentRolesSameTeamStrategy: d.Get("different_roles_same_team_strategy").(string), + } + + if v, ok := d.GetOk("no_mappings_error_redirect_url"); ok { + settings.NoMappingsErrorRedirectURL = v.(string) + } + + return settings +} + +func ssoGroupMappingSettingsToResourceData(settings *v2.SSOGroupMappingSettings, d *schema.ResourceData) error { + if err := d.Set("no_mapping_strategy", settings.NoMappingStrategy); err != nil { + return err + } + if err := d.Set("different_roles_same_team_strategy", settings.DifferentRolesSameTeamStrategy); err != nil { + return err + } + if err := d.Set("no_mappings_error_redirect_url", settings.NoMappingsErrorRedirectURL); err != nil { + return err + } + + return nil +} diff --git a/sysdig/resource_sysdig_sso_group_mapping_settings_test.go b/sysdig/resource_sysdig_sso_group_mapping_settings_test.go new file mode 100644 index 00000000..30cbbda2 --- /dev/null +++ b/sysdig/resource_sysdig_sso_group_mapping_settings_test.go @@ -0,0 +1,97 @@ +//go:build tf_acc_sysdig_monitor || tf_acc_sysdig_secure || tf_acc_onprem_monitor || tf_acc_onprem_secure + +package sysdig_test + +import ( + "testing" + + "github.com/draios/terraform-provider-sysdig/sysdig" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func TestAccSSOGroupMappingSettings(t *testing.T) { + resource.Test(t, resource.TestCase{ + PreCheck: preCheckAnyEnv(t, SysdigMonitorApiTokenEnv, SysdigSecureApiTokenEnv), + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: ssoGroupMappingSettingsConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping_settings.test", + "no_mapping_strategy", + "UNAUTHORIZED", + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping_settings.test", + "different_roles_same_team_strategy", + "UNAUTHORIZED", + ), + ), + }, + { + Config: ssoGroupMappingSettingsUpdatedConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping_settings.test", + "no_mapping_strategy", + "DEFAULT_TEAM_DEFAULT_ROLE", + ), + ), + }, + { + ResourceName: "sysdig_sso_group_mapping_settings.test", + ImportState: true, + ImportStateVerify: true, + }, + { + Config: ssoGroupMappingSettingsRedirectConfig(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping_settings.test", + "no_mapping_strategy", + "NO_MAPPINGS_ERROR_REDIRECT", + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping_settings.test", + "no_mappings_error_redirect_url", + "https://example.com/error", + ), + ), + }, + }, + }) +} + +func ssoGroupMappingSettingsConfig() string { + return ` +resource "sysdig_sso_group_mapping_settings" "test" { + no_mapping_strategy = "UNAUTHORIZED" + different_roles_same_team_strategy = "UNAUTHORIZED" +} +` +} + +func ssoGroupMappingSettingsUpdatedConfig() string { + return ` +resource "sysdig_sso_group_mapping_settings" "test" { + no_mapping_strategy = "DEFAULT_TEAM_DEFAULT_ROLE" + different_roles_same_team_strategy = "UNAUTHORIZED" +} +` +} + +func ssoGroupMappingSettingsRedirectConfig() string { + return ` +resource "sysdig_sso_group_mapping_settings" "test" { + no_mapping_strategy = "NO_MAPPINGS_ERROR_REDIRECT" + different_roles_same_team_strategy = "UNAUTHORIZED" + no_mappings_error_redirect_url = "https://example.com/error" +} +` +} diff --git a/sysdig/resource_sysdig_sso_group_mapping_test.go b/sysdig/resource_sysdig_sso_group_mapping_test.go new file mode 100644 index 00000000..b3b8dadd --- /dev/null +++ b/sysdig/resource_sysdig_sso_group_mapping_test.go @@ -0,0 +1,185 @@ +//go:build tf_acc_sysdig_monitor || tf_acc_sysdig_secure || tf_acc_onprem_monitor || tf_acc_onprem_secure + +package sysdig_test + +import ( + "fmt" + "testing" + + "github.com/draios/terraform-provider-sysdig/sysdig" + "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" +) + +func TestAccSSOGroupMappingAllTeams(t *testing.T) { + groupName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: preCheckAnyEnv(t, SysdigMonitorApiTokenEnv, SysdigSecureApiTokenEnv), + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: ssoGroupMappingAllTeamsConfig(groupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "group_name", + groupName, + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "is_admin", + "false", + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "team_map.0.is_for_all_teams", + "true", + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "weight", + "10", + ), + ), + }, + { + ResourceName: "sysdig_sso_group_mapping.test", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSSOGroupMappingUpdate(t *testing.T) { + groupName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: preCheckAnyEnv(t, SysdigMonitorApiTokenEnv, SysdigSecureApiTokenEnv), + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: ssoGroupMappingAllTeamsConfig(groupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "group_name", + groupName, + ), + ), + }, + { + Config: ssoGroupMappingAllTeamsUpdatedConfig(groupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "group_name", + fmt.Sprintf("%s-updated", groupName), + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test", + "is_admin", + "true", + ), + ), + }, + }, + }) +} + +func TestAccSSOGroupMappingCustomRole(t *testing.T) { + groupName := acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: preCheckAnyEnv(t, SysdigMonitorApiTokenEnv, SysdigSecureApiTokenEnv), + ProviderFactories: map[string]func() (*schema.Provider, error){ + "sysdig": func() (*schema.Provider, error) { + return sysdig.Provider(), nil + }, + }, + Steps: []resource.TestStep{ + { + Config: ssoGroupMappingCustomRoleConfig(groupName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test_custom", + "group_name", + groupName, + ), + resource.TestCheckResourceAttrSet( + "sysdig_sso_group_mapping.test_custom", + "custom_team_role_id", + ), + resource.TestCheckResourceAttr( + "sysdig_sso_group_mapping.test_custom", + "team_map.0.is_for_all_teams", + "true", + ), + ), + }, + }, + }) +} + +func ssoGroupMappingAllTeamsConfig(groupName string) string { + return fmt.Sprintf(` +resource "sysdig_sso_group_mapping" "test" { + group_name = "%s" + standard_team_role = "ROLE_TEAM_STANDARD" + is_admin = false + + team_map { + is_for_all_teams = true + } + + weight = 10 +} +`, groupName) +} + +func ssoGroupMappingAllTeamsUpdatedConfig(groupName string) string { + return fmt.Sprintf(` +resource "sysdig_sso_group_mapping" "test" { + group_name = "%s-updated" + standard_team_role = "ROLE_TEAM_MANAGER" + is_admin = true + + team_map { + is_for_all_teams = true + } + + weight = 10 +} +`, groupName) +} + +func ssoGroupMappingCustomRoleConfig(groupName string) string { + return fmt.Sprintf(` +resource "sysdig_custom_role" "test_role" { + name = "%[1]s-custom-role" + description = "Test custom role for SSO group mapping" + permissions { + monitor_permissions = ["token.view", "api-token.read"] + } +} + +resource "sysdig_sso_group_mapping" "test_custom" { + group_name = "%[1]s" + custom_team_role_id = sysdig_custom_role.test_role.id + + team_map { + is_for_all_teams = true + } +} +`, groupName) +} diff --git a/website/docs/r/sso_global_settings.md b/website/docs/r/sso_global_settings.md new file mode 100644 index 00000000..8759ac66 --- /dev/null +++ b/website/docs/r/sso_global_settings.md @@ -0,0 +1,48 @@ +--- +subcategory: "Sysdig Platform" +layout: "sysdig" +page_title: "Sysdig: sysdig_sso_global_settings" +description: |- + Manages global SSO settings per product in Sysdig using the Platform API. +--- + +# Resource: sysdig_sso_global_settings + +Manages global SSO settings for a specific Sysdig product (Monitor or Secure) using the Platform API. + +This is a singleton resource per product — only one instance should exist for each product. The resource cannot be deleted; removing it from Terraform configuration will only remove it from state. + +-> **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_sso_global_settings" "monitor" { + product = "monitor" + is_password_login_enabled = true +} + +resource "sysdig_sso_global_settings" "secure" { + product = "secure" + is_password_login_enabled = false +} +``` + +## Argument Reference + +* `product` - (Required, ForceNew) The Sysdig product. Valid values: `monitor`, `secure`. Changing this forces creation of a new resource. + +* `is_password_login_enabled` - (Required) Whether password-based login is enabled alongside SSO for this product. + +## Attributes Reference + +No additional attributes are exported. + +## Import + +SSO global settings can be imported using the product name: + +``` +$ terraform import sysdig_sso_global_settings.monitor monitor +$ terraform import sysdig_sso_global_settings.secure secure +``` diff --git a/website/docs/r/sso_group_mapping.md b/website/docs/r/sso_group_mapping.md new file mode 100644 index 00000000..ee04f686 --- /dev/null +++ b/website/docs/r/sso_group_mapping.md @@ -0,0 +1,95 @@ +--- +subcategory: "Sysdig Platform" +layout: "sysdig" +page_title: "Sysdig: sysdig_sso_group_mapping" +description: |- + Creates an SSO group mapping in Sysdig using the Platform API. +--- + +# Resource: sysdig_sso_group_mapping + +Creates an SSO group mapping in Sysdig using the Platform API. This resource replaces the deprecated `sysdig_group_mapping` resource. + +-> **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 + +### Standard role for all teams + +```terraform +resource "sysdig_sso_group_mapping" "all_teams" { + group_name = "engineering" + standard_team_role = "ROLE_TEAM_STANDARD" + is_admin = false + + team_map { + is_for_all_teams = true + } + + weight = 10 +} +``` + +### Custom role for specific teams + +```terraform +resource "sysdig_sso_group_mapping" "specific_teams" { + group_name = "devops" + custom_team_role_id = sysdig_custom_role.devops_role.id + + team_map { + is_for_all_teams = false + team_ids = [sysdig_secure_team.my_team.id, sysdig_monitor_team.my_team.id] + } + + weight = 20 +} +``` + +### Admin group mapping + +```terraform +resource "sysdig_sso_group_mapping" "admins" { + group_name = "platform-admins" + standard_team_role = "ROLE_TEAM_MANAGER" + is_admin = true + + team_map { + is_for_all_teams = true + } +} +``` + +## Argument Reference + +* `group_name` - (Required) The SSO group name to map. Maximum 256 characters. + +* `standard_team_role` - (Optional) The standard team role assigned to users. Conflicts with `custom_team_role_id`. One of `standard_team_role` or `custom_team_role_id` must be set. + +* `custom_team_role_id` - (Optional) The ID of a custom role to assign to users. Conflicts with `standard_team_role`. One of `standard_team_role` or `custom_team_role_id` must be set. + +* `is_admin` - (Optional) Whether group members should be Sysdig administrators. Default: `false`. + +* `team_map` - (Required) Block defining team mapping. Maximum 1 block. + +* `weight` - (Optional) Priority weight for conflict resolution. Lower numbers have higher priority. Must be between 1 and 32767. Default: `32767`. + +### team_map + +* `is_for_all_teams` - (Required) Whether the mapping applies to all teams. + +* `team_ids` - (Optional) List of team IDs. Required when `is_for_all_teams` is `false`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the SSO group mapping. + +## Import + +SSO group mapping can be imported using the ID: + +``` +$ terraform import sysdig_sso_group_mapping.example 12345 +``` diff --git a/website/docs/r/sso_group_mapping_settings.md b/website/docs/r/sso_group_mapping_settings.md new file mode 100644 index 00000000..4fa2ff55 --- /dev/null +++ b/website/docs/r/sso_group_mapping_settings.md @@ -0,0 +1,62 @@ +--- +subcategory: "Sysdig Platform" +layout: "sysdig" +page_title: "Sysdig: sysdig_sso_group_mapping_settings" +description: |- + Manages SSO group mapping settings in Sysdig using the Platform API. +--- + +# Resource: sysdig_sso_group_mapping_settings + +Manages SSO group mapping conflict resolution settings in Sysdig using the Platform API. This resource replaces the deprecated `sysdig_group_mapping_config` resource. + +This is a singleton resource — only one instance should exist per Sysdig account. The resource cannot be deleted; removing it from Terraform configuration will only remove it from state. + +-> **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 + +### Basic configuration + +```terraform +resource "sysdig_sso_group_mapping_settings" "default" { + no_mapping_strategy = "UNAUTHORIZED" + different_roles_same_team_strategy = "UNAUTHORIZED" +} +``` + +### With error redirect + +```terraform +resource "sysdig_sso_group_mapping_settings" "with_redirect" { + no_mapping_strategy = "NO_MAPPINGS_ERROR_REDIRECT" + different_roles_same_team_strategy = "HIGHEST_ROLE" + no_mappings_error_redirect_url = "https://example.com/sso-error" +} +``` + +## Argument Reference + +* `no_mapping_strategy` - (Required) Strategy when no group mapping matches a user. Valid values: + * `UNAUTHORIZED` - Deny access. + * `DEFAULT_TEAM_DEFAULT_ROLE` - Assign default team and role. + * `NO_MAPPINGS_ERROR_REDIRECT` - Redirect to an error URL (requires `no_mappings_error_redirect_url`). + +* `different_roles_same_team_strategy` - (Required) Strategy when a user matches multiple mappings with different roles for the same team. Valid values: + * `UNAUTHORIZED` - Deny access. + * `HIGHEST_ROLE` - Use the highest-privilege role. + * `LOWEST_ROLE` - Use the lowest-privilege role. + +* `no_mappings_error_redirect_url` - (Optional) URL to redirect users when `no_mapping_strategy` is `NO_MAPPINGS_ERROR_REDIRECT`. Maximum 2048 characters. + +## Attributes Reference + +No additional attributes are exported. + +## Import + +SSO group mapping settings can be imported using the static ID `sso_group_mapping_settings`: + +``` +$ terraform import sysdig_sso_group_mapping_settings.default sso_group_mapping_settings +```