diff --git a/.changelog/33195.txt b/.changelog/33195.txt new file mode 100644 index 00000000000..09fecf08d9c --- /dev/null +++ b/.changelog/33195.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_verifiedaccess_trust_provider +``` \ No newline at end of file diff --git a/.github/labeler-pr-triage.yml b/.github/labeler-pr-triage.yml index dc41f16b9d2..a8ea9662c5b 100644 --- a/.github/labeler-pr-triage.yml +++ b/.github/labeler-pr-triage.yml @@ -1045,7 +1045,7 @@ service/translate: - 'website/**/translate_*' service/verifiedaccess: - 'internal/service/ec2/**/verifiedaccess_*' - - 'website/**/verifiedaccess*' + - 'website/**/verifiedaccess_*' service/verifiedpermissions: - 'internal/service/verifiedpermissions/**/*' - 'website/**/verifiedpermissions_*' diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index 8f9e0b137d7..672311f60be 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -100,6 +100,7 @@ const ( errCodeInvalidTransitGatewayPolicyTableIdNotFound = "InvalidTransitGatewayPolicyTableId.NotFound" errCodeInvalidTransitGatewayIDNotFound = "InvalidTransitGatewayID.NotFound" errCodeInvalidTransitGatewayMulticastDomainIdNotFound = "InvalidTransitGatewayMulticastDomainId.NotFound" + errCodeInvalidVerifiedAccessTrustProviderIdNotFound = "InvalidVerifiedAccessTrustProviderId.NotFound" errCodeInvalidVolumeNotFound = "InvalidVolume.NotFound" errCodeInvalidVPCCIDRBlockAssociationIDNotFound = "InvalidVpcCidrBlockAssociationID.NotFound" errCodeInvalidVPCEndpointIdNotFound = "InvalidVpcEndpointId.NotFound" diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index f23394955dd..4604a86a4dd 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -7020,3 +7020,57 @@ func FindInstanceConnectEndpointByID(ctx context.Context, conn *ec2_sdkv2.Client return output, nil } + +func FindVerifiedAccessTrustProvider(ctx context.Context, conn *ec2_sdkv2.Client, input *ec2_sdkv2.DescribeVerifiedAccessTrustProvidersInput) (*awstypes.VerifiedAccessTrustProvider, error) { + output, err := FindVerifiedAccessTrustProviders(ctx, conn, input) + + if err != nil { + return nil, err + } + + return tfresource.AssertSingleValueResult(output) +} + +func FindVerifiedAccessTrustProviders(ctx context.Context, conn *ec2_sdkv2.Client, input *ec2_sdkv2.DescribeVerifiedAccessTrustProvidersInput) ([]awstypes.VerifiedAccessTrustProvider, error) { + var output []awstypes.VerifiedAccessTrustProvider + paginator := ec2_sdkv2.NewDescribeVerifiedAccessTrustProvidersPaginator(conn, input) + + for paginator.HasMorePages() { + page, err := paginator.NextPage(ctx) + + if tfawserr_sdkv2.ErrCodeEquals(err, errCodeInvalidVerifiedAccessTrustProviderIdNotFound) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + output = append(output, page.VerifiedAccessTrustProviders...) + } + + return output, nil +} + +func FindVerifiedAccessTrustProviderByID(ctx context.Context, conn *ec2_sdkv2.Client, id string) (*awstypes.VerifiedAccessTrustProvider, error) { + input := &ec2_sdkv2.DescribeVerifiedAccessTrustProvidersInput{ + VerifiedAccessTrustProviderIds: []string{id}, + } + output, err := FindVerifiedAccessTrustProvider(ctx, conn, input) + + if err != nil { + return nil, err + } + + // Eventual consistency check. + if aws_sdkv2.ToString(output.VerifiedAccessTrustProviderId) != id { + return nil, &retry.NotFoundError{ + LastRequest: input, + } + } + + return output, nil +} diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index b167e0f629b..60cd9c773eb 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -943,6 +943,14 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka IdentifierAttribute: "id", }, }, + { + Factory: ResourceVerifiedAccessTrustProvider, + TypeName: "aws_verifiedaccess_trust_provider", + Name: "Verified Access Trust Provider", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: "id", + }, + }, { Factory: ResourceVolumeAttachment, TypeName: "aws_volume_attachment", diff --git a/internal/service/ec2/verifiedaccess_trust_provider.go b/internal/service/ec2/verifiedaccess_trust_provider.go new file mode 100644 index 00000000000..79f1efa106d --- /dev/null +++ b/internal/service/ec2/verifiedaccess_trust_provider.go @@ -0,0 +1,372 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + "log" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "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" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_verifiedaccess_trust_provider", name="Verified Access Trust Provider") +// @Tags(identifierAttribute="id") +func ResourceVerifiedAccessTrustProvider() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceVerifiedAccessTrustProviderCreate, + ReadWithoutTimeout: resourceVerifiedAccessTrustProviderRead, + UpdateWithoutTimeout: resourceVerifiedAccessTrustProviderUpdate, + DeleteWithoutTimeout: resourceVerifiedAccessTrustProviderDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(30 * time.Minute), + Update: schema.DefaultTimeout(30 * time.Minute), + Delete: schema.DefaultTimeout(30 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "description": { + Type: schema.TypeString, + Optional: true, + }, + "device_options": { + Type: schema.TypeList, + ForceNew: true, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "tenant_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "device_trust_provider_type": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateDiagFunc: enum.Validate[types.DeviceTrustProviderType](), + }, + "oidc_options": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "authorization_endpoint": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "client_id": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "client_secret": { + Type: schema.TypeString, + Required: true, + Sensitive: true, + }, + "issuer": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "scope": { + Type: schema.TypeString, + Optional: true, + }, + "token_endpoint": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "user_info_endpoint": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + }, + }, + }, + "policy_reference_name": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "trust_provider_type": { + Type: schema.TypeString, + ForceNew: true, + Required: true, + ValidateDiagFunc: enum.Validate[types.TrustProviderType](), + }, + "user_trust_provider_type": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateDiagFunc: enum.Validate[types.UserTrustProviderType](), + }, + }, + + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceVerifiedAccessTrustProviderCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EC2Client(ctx) + + input := &ec2.CreateVerifiedAccessTrustProviderInput{ + PolicyReferenceName: aws.String(d.Get("policy_reference_name").(string)), + TagSpecifications: getTagSpecificationsInV2(ctx, types.ResourceTypeVerifiedAccessTrustProvider), + TrustProviderType: types.TrustProviderType(d.Get("trust_provider_type").(string)), + } + + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + + if v, ok := d.GetOk("device_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.DeviceOptions = expandCreateVerifiedAccessTrustProviderDeviceOptions(v.([]interface{})[0].(map[string]interface{})) + } + + if v, ok := d.GetOk("device_trust_provider_type"); ok { + input.DeviceTrustProviderType = types.DeviceTrustProviderType(v.(string)) + } + + if v, ok := d.GetOk("oidc_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.OidcOptions = expandCreateVerifiedAccessTrustProviderOIDCOptions(v.([]interface{})[0].(map[string]interface{})) + } + + if v, ok := d.GetOk("user_trust_provider_type"); ok { + input.UserTrustProviderType = types.UserTrustProviderType(v.(string)) + } + + output, err := conn.CreateVerifiedAccessTrustProvider(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating Verified Access Trust Provider: %s", err) + } + + d.SetId(aws.ToString(output.VerifiedAccessTrustProvider.VerifiedAccessTrustProviderId)) + + return append(diags, resourceVerifiedAccessTrustProviderRead(ctx, d, meta)...) +} + +func resourceVerifiedAccessTrustProviderRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EC2Client(ctx) + + output, err := FindVerifiedAccessTrustProviderByID(ctx, conn, d.Id()) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EC2 Verified Access Trust Provider (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading Verified Access Trust Provider (%s): %s", d.Id(), err) + } + + d.Set("description", output.Description) + if v := output.DeviceOptions; v != nil { + if err := d.Set("device_options", flattenDeviceOptions(v)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting device_options: %s", err) + } + } else { + d.Set("device_options", nil) + } + d.Set("device_trust_provider_type", output.DeviceTrustProviderType) + if v := output.OidcOptions; v != nil { + if err := d.Set("oidc_options", flattenOIDCOptions(v, d.Get("oidc_options.0.client_secret").(string))); err != nil { + return sdkdiag.AppendErrorf(diags, "setting oidc_options: %s", err) + } + } else { + d.Set("oidc_options", nil) + } + d.Set("policy_reference_name", output.PolicyReferenceName) + d.Set("trust_provider_type", output.TrustProviderType) + d.Set("user_trust_provider_type", output.UserTrustProviderType) + + setTagsOutV2(ctx, output.Tags) + + return diags +} + +func resourceVerifiedAccessTrustProviderUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EC2Client(ctx) + + if d.HasChangesExcept("tags", "tags_all") { + input := &ec2.ModifyVerifiedAccessTrustProviderInput{ + VerifiedAccessTrustProviderId: aws.String(d.Id()), + } + + if d.HasChanges("description") { + input.Description = aws.String(d.Get("description").(string)) + } + + if d.HasChanges("oidc_options") { + if v, ok := d.GetOk("oidc_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.OidcOptions = expandModifyVerifiedAccessTrustProviderOIDCOptions(v.([]interface{})[0].(map[string]interface{})) + } + } + + _, err := conn.ModifyVerifiedAccessTrustProvider(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating Verified Access Trust Provider (%s): %s", d.Id(), err) + } + } + + return append(diags, resourceVerifiedAccessTrustProviderRead(ctx, d, meta)...) +} + +func resourceVerifiedAccessTrustProviderDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EC2Client(ctx) + + log.Printf("[INFO] Deleting Verified Access Trust Provider: %s", d.Id()) + _, err := conn.DeleteVerifiedAccessTrustProvider(ctx, &ec2.DeleteVerifiedAccessTrustProviderInput{ + VerifiedAccessTrustProviderId: aws.String(d.Id()), + }) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting Verified Access Trust Provider (%s): %s", d.Id(), err) + } + + return diags +} + +func flattenDeviceOptions(apiObject *types.DeviceOptions) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.TenantId; v != nil { + tfMap["tenant_id"] = aws.ToString(v) + } + + return []interface{}{tfMap} +} + +func flattenOIDCOptions(apiObject *types.OidcOptions, clientSecret string) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{ + "client_secret": clientSecret, + } + + if v := apiObject.AuthorizationEndpoint; v != nil { + tfMap["authorization_endpoint"] = aws.ToString(v) + } + if v := apiObject.ClientId; v != nil { + tfMap["client_id"] = aws.ToString(v) + } + if v := apiObject.Issuer; v != nil { + tfMap["issuer"] = aws.ToString(v) + } + if v := apiObject.Scope; v != nil { + tfMap["scope"] = aws.ToString(v) + } + if v := apiObject.TokenEndpoint; v != nil { + tfMap["token_endpoint"] = aws.ToString(v) + } + if v := apiObject.UserInfoEndpoint; v != nil { + tfMap["user_info_endpoint"] = aws.ToString(v) + } + + return []interface{}{tfMap} +} + +func expandCreateVerifiedAccessTrustProviderDeviceOptions(tfMap map[string]interface{}) *types.CreateVerifiedAccessTrustProviderDeviceOptions { + if tfMap == nil { + return nil + } + + apiObject := &types.CreateVerifiedAccessTrustProviderDeviceOptions{} + + if v, ok := tfMap["tenant_id"].(string); ok && v != "" { + apiObject.TenantId = aws.String(v) + } + + return apiObject +} + +func expandCreateVerifiedAccessTrustProviderOIDCOptions(tfMap map[string]interface{}) *types.CreateVerifiedAccessTrustProviderOidcOptions { + if tfMap == nil { + return nil + } + + apiObject := &types.CreateVerifiedAccessTrustProviderOidcOptions{} + + if v, ok := tfMap["authorization_endpoint"].(string); ok && v != "" { + apiObject.AuthorizationEndpoint = aws.String(v) + } + if v, ok := tfMap["client_id"].(string); ok && v != "" { + apiObject.ClientId = aws.String(v) + } + if v, ok := tfMap["client_secret"].(string); ok && v != "" { + apiObject.ClientSecret = aws.String(v) + } + if v, ok := tfMap["issuer"].(string); ok && v != "" { + apiObject.Issuer = aws.String(v) + } + if v, ok := tfMap["scope"].(string); ok && v != "" { + apiObject.Scope = aws.String(v) + } + if v, ok := tfMap["token_endpoint"].(string); ok && v != "" { + apiObject.TokenEndpoint = aws.String(v) + } + if v, ok := tfMap["user_info_endpoint"].(string); ok && v != "" { + apiObject.UserInfoEndpoint = aws.String(v) + } + + return apiObject +} + +func expandModifyVerifiedAccessTrustProviderOIDCOptions(tfMap map[string]interface{}) *types.ModifyVerifiedAccessTrustProviderOidcOptions { + if tfMap == nil { + return nil + } + + apiObject := &types.ModifyVerifiedAccessTrustProviderOidcOptions{} + + if v, ok := tfMap["scope"].(string); ok && v != "" { + apiObject.Scope = aws.String(v) + } + + return apiObject +} diff --git a/internal/service/ec2/verifiedaccess_trust_provider_test.go b/internal/service/ec2/verifiedaccess_trust_provider_test.go new file mode 100644 index 00000000000..5c9deab6aac --- /dev/null +++ b/internal/service/ec2/verifiedaccess_trust_provider_test.go @@ -0,0 +1,379 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2_test + +import ( + "context" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccVerifiedAccessTrustProvider_basic(t *testing.T) { + ctx := acctest.Context(t) + + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v types.VerifiedAccessTrustProvider + resourceName := "aws_verifiedaccess_trust_provider.test" + policyReferenceName := "test" + trustProviderType := "user" + userTrustProviderType := "iam-identity-center" + description := sdkacctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.EC2) + testAccPreCheckVerifiedAccess(ctx, t) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/sso.amazonaws.com") + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVerifiedAccessTrustProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVerifiedAccessTrustProviderConfig_basic(policyReferenceName, trustProviderType, userTrustProviderType, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "description", description), + resource.TestCheckResourceAttr(resourceName, "policy_reference_name", policyReferenceName), + resource.TestCheckResourceAttr(resourceName, "trust_provider_type", trustProviderType), + resource.TestCheckResourceAttr(resourceName, "user_trust_provider_type", userTrustProviderType), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{}, + }, + }, + }) +} + +func TestAccVerifiedAccessTrustProvider_deviceOptions(t *testing.T) { + ctx := acctest.Context(t) + var v types.VerifiedAccessTrustProvider + resourceName := "aws_verifiedaccess_trust_provider.test" + policyReferenceName := "test" + trustProviderType := "device" + deviceTrustProviderType := "jamf" + tenantId := sdkacctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheckVerifiedAccess(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVerifiedAccessTrustProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVerifiedAccessTrustProviderConfig_deviceOptions(policyReferenceName, trustProviderType, deviceTrustProviderType, tenantId), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "device_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "device_options.0.tenant_id", tenantId), + resource.TestCheckResourceAttr(resourceName, "device_trust_provider_type", deviceTrustProviderType), + resource.TestCheckResourceAttr(resourceName, "policy_reference_name", policyReferenceName), + resource.TestCheckResourceAttr(resourceName, "trust_provider_type", trustProviderType), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{}, + }, + }, + }) +} + +func TestAccVerifiedAccessTrustProvider_disappears(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var v types.VerifiedAccessTrustProvider + resourceName := "aws_verifiedaccess_trust_provider.test" + policyReferenceName := "test" + trustProviderType := "user" + userTrustProviderType := "iam-identity-center" + description := sdkacctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.EC2) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/sso.amazonaws.com") + testAccPreCheckVerifiedAccess(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVerifiedAccessTrustProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVerifiedAccessTrustProviderConfig_basic(policyReferenceName, trustProviderType, userTrustProviderType, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfec2.ResourceVerifiedAccessTrustProvider(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccVerifiedAccessTrustProvider_oidcOptions(t *testing.T) { + ctx := acctest.Context(t) + var v types.VerifiedAccessTrustProvider + resourceName := "aws_verifiedaccess_trust_provider.test" + policyReferenceName := "test" + trustProviderType := "user" + userTrustProviderType := "oidc" + authorizationEndpoint := "https://authorization.example.com" + clientId := sdkacctest.RandString(10) + clientSecret := sdkacctest.RandString(10) + issuer := "https://issuer.example.com" + scope := sdkacctest.RandString(10) + tokenEndpoint := "https://token.example.com" + userInfoEndpoint := "https://user.example.com" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheckVerifiedAccess(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVerifiedAccessTrustProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVerifiedAccessTrustProviderConfig_oidcOptions(policyReferenceName, trustProviderType, userTrustProviderType, authorizationEndpoint, clientId, clientSecret, issuer, scope, tokenEndpoint, userInfoEndpoint), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "oidc_options.#", "1"), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.authorization_endpoint", authorizationEndpoint), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.client_id", clientId), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.client_secret", clientSecret), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.issuer", issuer), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.scope", scope), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.token_endpoint", tokenEndpoint), + resource.TestCheckResourceAttr(resourceName, "oidc_options.0.user_info_endpoint", userInfoEndpoint), + resource.TestCheckResourceAttr(resourceName, "policy_reference_name", policyReferenceName), + resource.TestCheckResourceAttr(resourceName, "trust_provider_type", trustProviderType), + resource.TestCheckResourceAttr(resourceName, "user_trust_provider_type", userTrustProviderType), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"oidc_options.0.client_secret"}, + }, + }, + }) +} + +func TestAccVerifiedAccessTrustProvider_tags(t *testing.T) { + ctx := acctest.Context(t) + var v types.VerifiedAccessTrustProvider + resourceName := "aws_verifiedaccess_trust_provider.test" + policyReferenceName := "test" + trustProviderType := "user" + userTrustProviderType := "iam-identity-center" + description := sdkacctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + testAccPreCheckVerifiedAccess(ctx, t) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/sso.amazonaws.com") + }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVerifiedAccessTrustProviderDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVerifiedAccessTrustProviderConfig_tags1(policyReferenceName, trustProviderType, userTrustProviderType, description, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), + ), + }, + { + Config: testAccVerifiedAccessTrustProviderConfig_tags2(policyReferenceName, trustProviderType, userTrustProviderType, description, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccVerifiedAccessTrustProviderConfig_tags1(policyReferenceName, trustProviderType, userTrustProviderType, description, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckVerifiedAccessTrustProviderExists(ctx, resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{}, + }, + }, + }) +} + +func testAccCheckVerifiedAccessTrustProviderExists(ctx context.Context, n string, v *types.VerifiedAccessTrustProvider) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + output, err := tfec2.FindVerifiedAccessTrustProviderByID(ctx, conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccCheckVerifiedAccessTrustProviderDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_verifiedaccess_trust_provider" { + continue + } + + _, err := tfec2.FindVerifiedAccessTrustProviderByID(ctx, conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("Verified Access Trust Provider %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccPreCheckVerifiedAccess(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) + + input := &ec2.DescribeVerifiedAccessTrustProvidersInput{} + _, err := conn.DescribeVerifiedAccessTrustProviders(ctx, input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func testAccVerifiedAccessTrustProviderConfig_basic(policyReferenceName, trustProviderType, userTrustProviderType, description string) string { + return fmt.Sprintf(` +resource "aws_verifiedaccess_trust_provider" "test" { + description = %[4]q + policy_reference_name = %[1]q + trust_provider_type = %[2]q + user_trust_provider_type = %[3]q +} +`, policyReferenceName, trustProviderType, userTrustProviderType, description) +} + +func testAccVerifiedAccessTrustProviderConfig_deviceOptions(policyReferenceName, trustProviderType, deviceTrustProviderType, tenantId string) string { + return fmt.Sprintf(` +resource "aws_verifiedaccess_trust_provider" "test" { + device_options { + tenant_id = %[4]q + } + device_trust_provider_type = %[3]q + policy_reference_name = %[1]q + trust_provider_type = %[2]q +} +`, policyReferenceName, trustProviderType, deviceTrustProviderType, tenantId) +} + +func testAccVerifiedAccessTrustProviderConfig_oidcOptions(policyReferenceName, trustProviderType, userTrustProviderType, authorizationEndpoint, clientId, clientSecret, issuer, scope, tokenEndpoint, userInfoEndpoint string) string { + return fmt.Sprintf(` +resource "aws_verifiedaccess_trust_provider" "test" { + oidc_options { + authorization_endpoint = %[4]q + client_id = %[5]q + client_secret = %[6]q + issuer = %[7]q + scope = %[8]q + token_endpoint = %[9]q + user_info_endpoint = %[10]q + } + policy_reference_name = %[1]q + trust_provider_type = %[2]q + user_trust_provider_type = %[3]q +} +`, policyReferenceName, trustProviderType, userTrustProviderType, authorizationEndpoint, clientId, clientSecret, issuer, scope, tokenEndpoint, userInfoEndpoint) +} + +func testAccVerifiedAccessTrustProviderConfig_tags1(policyReferenceName, trustProviderType, userTrustProviderType, description, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_verifiedaccess_trust_provider" "test" { + description = %[4]q + policy_reference_name = %[1]q + trust_provider_type = %[2]q + user_trust_provider_type = %[3]q + tags = { + %[5]q = %[6]q + } +} +`, policyReferenceName, trustProviderType, userTrustProviderType, description, tagKey1, tagValue1) +} + +func testAccVerifiedAccessTrustProviderConfig_tags2(policyReferenceName, trustProviderType, userTrustProviderType, description, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_verifiedaccess_trust_provider" "test" { + description = %[4]q + policy_reference_name = %[1]q + trust_provider_type = %[2]q + user_trust_provider_type = %[3]q + tags = { + %[5]q = %[6]q + %[7]q = %[8]q + } +} +`, policyReferenceName, trustProviderType, userTrustProviderType, description, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/names/names_data.csv b/names/names_data.csv index 735b1638e96..d9036e34bcd 100644 --- a/names/names_data.csv +++ b/names/names_data.csv @@ -357,7 +357,7 @@ transfer,transfer,transfer,transfer,,transfer,,,Transfer,Transfer,,1,,,aws_trans ,,,,,transitgateway,ec2,,TransitGateway,,,,,aws_ec2_transit_gateway,aws_transitgateway_,transitgateway_,ec2_transit_gateway,Transit Gateway,AWS,x,,x,,,Part of EC2 translate,translate,translate,translate,,translate,,,Translate,Translate,,1,,,aws_translate_,,translate_,Translate,Amazon,,x,,,, ,,,,,,,,,,,,,,,,,Trusted Advisor,AWS,x,,,,,Part of Support -,,,,,verifiedaccess,ec2,,VerifiedAccess,,,,,aws_verifiedaccess,aws_verifiedaccess_,verifiedaccess_,verifiedaccess,Verified Access,AWS,x,,x,,,Part of EC2 +,,,,,verifiedaccess,ec2,,VerifiedAccess,,,,,aws_verifiedaccess,aws_verifiedaccess_,verifiedaccess_,verifiedaccess_,Verified Access,AWS,x,,x,,,Part of EC2 ,,,,,vpc,ec2,,VPC,,,,,aws_((default_)?(network_acl|route_table|security_group|subnet|vpc(?!_ipam))|ec2_(managed|network|subnet|traffic)|egress_only_internet|flow_log|internet_gateway|main_route_table_association|nat_gateway|network_interface|prefix_list|route\b),aws_vpc_,vpc_,default_network_;default_route_;default_security_;default_subnet;default_vpc;ec2_managed_;ec2_network_;ec2_subnet_;ec2_traffic_;egress_only_;flow_log;internet_gateway;main_route_;nat_;network_;prefix_list;route_;route\.;security_group;subnet;vpc_dhcp_;vpc_endpoint;vpc_ipv;vpc_network_performance;vpc_peering_;vpc_security_group_;vpc\.;vpcs\.,VPC (Virtual Private Cloud),Amazon,x,,x,,,Part of EC2 vpc-lattice,vpclattice,vpclattice,vpclattice,,vpclattice,,,VPCLattice,VPCLattice,,,2,,aws_vpclattice_,,vpclattice_,VPC Lattice,Amazon,,,,,, ,,,,,ipam,ec2,,IPAM,,,,,aws_vpc_ipam,aws_ipam_,ipam_,vpc_ipam,VPC IPAM (IP Address Manager),Amazon,x,,x,,,Part of EC2 diff --git a/website/docs/r/verifiedaccess_trust_provider.html.markdown b/website/docs/r/verifiedaccess_trust_provider.html.markdown new file mode 100644 index 00000000000..5a28d4a3871 --- /dev/null +++ b/website/docs/r/verifiedaccess_trust_provider.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: "Verified Access" +layout: "aws" +page_title: "AWS: aws_verifiedaccess_trust_provider" +description: |- + Terraform resource for managing a Verified Access Trust Provider. +--- + +# Resource: aws_verifiedaccess_trust_provider + +Terraform resource for managing a Verified Access Trust Provider. + +## Example Usage + +```terraform +resource "aws_verifiedaccess_trust_provider" "example" { + policy_reference_name = "example" + trust_provider_type = "user" + user_trust_provider_type = "iam-identity-center" +} +``` + +## Argument Reference + +The following arguments are required: + +* `policy_reference_name` - (Required) The identifier to be used when working with policy rules. +* `trust_provider_type` - (Required) The type of trust provider can be either user or device-based. + +The following arguments are optional: + +* `description` - (Optional) A description for the AWS Verified Access trust provider. +* `device_options` - (Optional) A block of options for device identity based trust providers. +* `device_trust_provider_type` (Optional) The type of device-based trust provider. +* `oidc_options` - (Optional) The OpenID Connect details for an oidc-type, user-identity based trust provider. +* `tags` - (Optional) Key-value mapping of resource tags. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `user_trust_provider_type` - (Optional) The type of user-based trust provider. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `id` - The ID of the AWS Verified Access trust provider. + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `60m`) +* `update` - (Default `180m`) +* `delete` - (Default `90m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Transfer Workflows using the `id`. For example: + +```terraform +import { + to = aws_verifiedaccess_trust_provider.example + id = "vatp-8012925589" +} +``` + +Using `terraform import`, import Transfer Workflows using the `id`. For example: + +```console +% terraform import aws_verifiedaccess_trust_provider.example vatp-8012925589 +```