Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: External Oauth integration v1 readiness #2907

Merged
merged 18 commits into from
Jul 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,45 @@ Added a new datasource enabling querying and filtering all types of security int
The additional parameters call **DESC SECURITY INTEGRATION** (with `with_describe` turned on) **per security integration** returned by **SHOW SECURITY INTEGRATIONS**.
It's important to limit the records and calls to Snowflake to the minimum. That's why we recommend assessing which information you need from the data source and then providing strong filters and turning off additional fields for better plan performance.

### snowflake_external_oauth_integration resource changes

#### *(behavior change)* Renamed fields
Renamed fields:
- `type` to `external_oauth_type`
- `issuer` to `external_oauth_issuer`
- `token_user_mapping_claims` to `external_oauth_token_user_mapping_claim`
- `snowflake_user_mapping_attribute` to `external_oauth_snowflake_user_mapping_attribute`
- `scope_mapping_attribute` to `external_oauth_scope_mapping_attribute`
- `jws_keys_urls` to `external_oauth_jws_keys_url`
- `rsa_public_key` to `external_oauth_rsa_public_key`
- `rsa_public_key_2` to `external_oauth_rsa_public_key_2`
- `blocked_roles` to `external_oauth_blocked_roles_list`
- `allowed_roles` to `external_oauth_allowed_roles_list`
- `audience_urls` to `external_oauth_audience_list`
- `any_role_mode` to `external_oauth_any_role_mode`
- `scope_delimiter` to `external_oauth_scope_delimiter`
to align with Snowflake docs. Please rename this field in your configuration files. State will be migrated automatically.

#### *(behavior change)* Force new for multiple attributes after removing from config
Conditional force new was added for the following attributes when they are removed from config. There are no alter statements supporting UNSET on these fields.
- `external_oauth_rsa_public_key`
- `external_oauth_rsa_public_key_2`
- `external_oauth_scope_mapping_attribute`
- `external_oauth_jws_keys_url`
- `external_oauth_token_user_mapping_claim`

#### *(behavior change)* Conflicting fields
Fields listed below can not be set at the same time in Snowflake. They are marked as conflicting fields.
- `external_oauth_jws_keys_url` <-> `external_oauth_rsa_public_key`
- `external_oauth_jws_keys_url` <-> `external_oauth_rsa_public_key_2`
- `external_oauth_allowed_roles_list` <-> `external_oauth_blocked_roles_list`

#### *(behavior change)* Changed diff suppress for some fields
The fields listed below had diff suppress which removed '-' from strings. Now, this behavior is removed, so if you had '-' in these strings, please remove them. Note that '-' in these values is not allowed by Snowflake.
- `external_oauth_snowflake_user_mapping_attribute`
- `external_oauth_type`
- `external_oauth_any_role_mode`

### snowflake_scim_integration resource changes
#### *(behavior change)* Changed behavior of `sync_password`

Expand Down
283 changes: 257 additions & 26 deletions docs/resources/external_oauth_integration.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1 +1 @@
terraform import snowflake_external_oauth_integration.example name
terraform import snowflake_external_oauth_integration.example "name"
52 changes: 42 additions & 10 deletions examples/resources/snowflake_external_oauth_integration/resource.tf
Original file line number Diff line number Diff line change
@@ -1,10 +1,42 @@
resource "snowflake_external_oauth_integration" "azure" {
name = "AZURE_POWERBI"
type = "AZURE"
enabled = true
issuer = "https://sts.windows.net/00000000-0000-0000-0000-000000000000"
snowflake_user_mapping_attribute = "LOGIN_NAME"
jws_keys_urls = ["https://login.windows.net/common/discovery/keys"]
audience_urls = ["https://analysis.windows.net/powerbi/connector/Snowflake"]
token_user_mapping_claims = ["upn"]
}
# basic resource
resource "snowflake_external_oauth_integration" "test" {
enabled = true
external_oauth_issuer = "issuer"
external_oauth_snowflake_user_mapping_attribute = "LOGIN_NAME"
external_oauth_token_user_mapping_claim = ["upn"]
name = "test"
external_oauth_type = "CUSTOM"
}
# resource with all fields set (jws keys url and allowed roles)
resource "snowflake_external_oauth_integration" "test" {
comment = "comment"
enabled = true
external_oauth_allowed_roles_list = ["user1"]
external_oauth_any_role_mode = "ENABLED"
external_oauth_audience_list = ["https://example.com"]
external_oauth_issuer = "issuer"
external_oauth_jws_keys_url = ["https://example.com"]
external_oauth_scope_delimiter = ","
external_oauth_scope_mapping_attribute = "scope"
external_oauth_snowflake_user_mapping_attribute = "LOGIN_NAME"
external_oauth_token_user_mapping_claim = ["upn"]
name = "test"
external_oauth_type = "CUSTOM"
}
# resource with all fields set (rsa public keys and blocked roles)
resource "snowflake_external_oauth_integration" "test" {
comment = "comment"
enabled = true
external_oauth_any_role_mode = "ENABLED"
external_oauth_audience_list = ["https://example.com"]
external_oauth_blocked_roles_list = ["user1"]
external_oauth_issuer = "issuer"
external_oauth_rsa_public_key = file("key.pem")
external_oauth_rsa_public_key_2 = file("key2.pem")
external_oauth_scope_delimiter = ","
external_oauth_scope_mapping_attribute = "scope"
external_oauth_snowflake_user_mapping_attribute = "LOGIN_NAME"
external_oauth_token_user_mapping_claim = ["upn"]
name = "test"
external_oauth_type = "CUSTOM"
}
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ require (
github.com/avast/retry-go v3.0.0+incompatible
github.com/brianvoe/gofakeit/v6 v6.28.0
github.com/buger/jsonparser v1.1.1
github.com/google/uuid v1.6.0
github.com/gookit/color v1.5.4
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320
github.com/hashicorp/go-uuid v1.0.3
Expand Down
3 changes: 3 additions & 0 deletions pkg/acceptance/check_destroy.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ var showByIdFunctions = map[resources.Resource]showByIdFunc{
resources.ExternalFunction: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error {
return runShowById(ctx, id, client.ExternalFunctions.ShowByID)
},
resources.ExternalOauthSecurityIntegration: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error {
return runShowById(ctx, id, client.SecurityIntegrations.ShowByID)
},
resources.ExternalTable: func(ctx context.Context, client *sdk.Client, id sdk.ObjectIdentifier) error {
return runShowById(ctx, id, client.ExternalTables.ShowByID)
},
Expand Down
8 changes: 8 additions & 0 deletions pkg/acceptance/helpers/security_integration_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ func (c *SecurityIntegrationClient) client() sdk.SecurityIntegrations {
return c.context.client.SecurityIntegrations
}

func (c *SecurityIntegrationClient) UpdateExternalOauth(t *testing.T, request *sdk.AlterExternalOauthSecurityIntegrationRequest) {
t.Helper()
ctx := context.Background()

err := c.client().AlterExternalOauth(ctx, request)
require.NoError(t, err)
}

func (c *SecurityIntegrationClient) CreateSaml2(t *testing.T, id sdk.AccountObjectIdentifier) (*sdk.SecurityIntegration, func()) {
t.Helper()
return c.CreateSaml2WithRequest(t, sdk.NewCreateSaml2SecurityIntegrationRequest(id, c.ids.Alpha(), "https://example.com", "Custom", random.GenerateX509(t)))
Expand Down
1 change: 1 addition & 0 deletions pkg/provider/resources/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
EmailNotificationIntegration resource = "snowflake_email_notification_integration"
ExternalFunction resource = "snowflake_external_function"
ExternalTable resource = "snowflake_external_table"
ExternalOauthSecurityIntegration resource = "snowflake_external_oauth_security_integration"
FailoverGroup resource = "snowflake_failover_group"
FileFormat resource = "snowflake_file_format"
Function resource = "snowflake_function"
Expand Down
1 change: 1 addition & 0 deletions pkg/resources/custom_diffs.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/internal/collections"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/sdk"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
Expand Down
36 changes: 36 additions & 0 deletions pkg/resources/diff_suppressions.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package resources
import (
"fmt"
"log"
"slices"
"strings"

"github.com/Snowflake-Labs/terraform-provider-snowflake/pkg/helpers"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -80,3 +83,36 @@ func SuppressIfAny(diffSuppressFunctions ...schema.SchemaDiffSuppressFunc) schem
return suppress
}
}

func IgnoreValuesFromSetIfParamSet(key, param string, values []string) schema.SchemaDiffSuppressFunc {
return func(k, old, new string, d *schema.ResourceData) bool {
params := d.Get(RelatedParametersAttributeName).([]any)
if len(params) == 0 {
return false
}
result := params[0].(map[string]any)
param := result[strings.ToLower(param)].([]any)
value := param[0].(map[string]any)["value"]
if !helpers.StringToBool(value.(string)) {
return false
}
if k == key+".#" {
old, new := d.GetChange(key)
var numOld, numNew int
oldList := expandStringList(old.(*schema.Set).List())
newList := expandStringList(new.(*schema.Set).List())
for _, v := range oldList {
if !slices.Contains(values, v) {
numOld++
}
}
for _, v := range newList {
if !slices.Contains(values, v) {
numNew++
}
}
return numOld == numNew
}
return slices.Contains(values, old)
}
}
Loading
Loading