Skip to content

Add aws_workspaces_directory.certificate_based_auth_properties #42269

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

Merged
7 changes: 7 additions & 0 deletions .changelog/42269.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
data-source/aws_workspaces_directory: Add `certificate_based_auth_properties` attribute
```

```release-note:enhancement
resource/aws_workspaces_directory: Add `certificate_based_auth_properties` configuration block
```
159 changes: 127 additions & 32 deletions internal/service/workspaces/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
itypes "github.com/hashicorp/terraform-provider-aws/internal/types"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
"github.com/hashicorp/terraform-provider-aws/names"
)

Expand All @@ -44,6 +45,27 @@ func resourceDirectory() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"certificate_based_auth_properties": {
Type: schema.TypeList,
Computed: true,
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"certificate_authority_arn": {
Type: schema.TypeString,
Optional: true,
ValidateFunc: verify.ValidARN,
},
names.AttrStatus: {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateDiagFunc: enum.Validate[types.CertificateBasedAuthStatusEnum](),
},
},
},
},
"customer_user_name": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -245,7 +267,7 @@ func resourceDirectoryCreate(ctx context.Context, d *schema.ResourceData, meta a
conn := meta.(*conns.AWSClient).WorkSpacesClient(ctx)

directoryID := d.Get("directory_id").(string)
input := &workspaces.RegisterWorkspaceDirectoryInput{
input := workspaces.RegisterWorkspaceDirectoryInput{
DirectoryId: aws.String(directoryID),
EnableSelfService: aws.Bool(false), // this is handled separately below
EnableWorkDocs: aws.Bool(false),
Expand All @@ -262,7 +284,7 @@ func resourceDirectoryCreate(ctx context.Context, d *schema.ResourceData, meta a
)
_, err := tfresource.RetryWhenIsA[*types.InvalidResourceStateException](ctx, timeout,
func() (any, error) {
return conn.RegisterWorkspaceDirectory(ctx, input)
return conn.RegisterWorkspaceDirectory(ctx, &input)
})

if err != nil {
Expand All @@ -276,64 +298,78 @@ func resourceDirectoryCreate(ctx context.Context, d *schema.ResourceData, meta a
}

if v, ok := d.GetOk("saml_properties"); ok {
input := &workspaces.ModifySamlPropertiesInput{
input := workspaces.ModifySamlPropertiesInput{
ResourceId: aws.String(d.Id()),
SamlProperties: expandSAMLProperties(v.([]any)),
}

_, err := conn.ModifySamlProperties(ctx, input)
_, err := conn.ModifySamlProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting WorkSpaces Directory (%s) SAML properties: %s", d.Id(), err)
}
}

// SAML needs to be enabled for directory before enabling certificate based authentication.
if v, ok := d.GetOk("certificate_based_auth_properties"); ok {
input := workspaces.ModifyCertificateBasedAuthPropertiesInput{
CertificateBasedAuthProperties: expandCertificateBasedAuthProperties(v.([]any)),
ResourceId: aws.String(d.Id()),
}

_, err := conn.ModifyCertificateBasedAuthProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting WorkSpaces Directory (%s) certificate-based authentication properties: %s", d.Id(), err)
}
}

if v, ok := d.GetOk("self_service_permissions"); ok {
input := &workspaces.ModifySelfservicePermissionsInput{
input := workspaces.ModifySelfservicePermissionsInput{
ResourceId: aws.String(d.Id()),
SelfservicePermissions: expandSelfservicePermissions(v.([]any)),
}

_, err := conn.ModifySelfservicePermissions(ctx, input)
_, err := conn.ModifySelfservicePermissions(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting WorkSpaces Directory (%s) self-service permissions: %s", d.Id(), err)
}
}

if v, ok := d.GetOk("workspace_access_properties"); ok {
input := &workspaces.ModifyWorkspaceAccessPropertiesInput{
input := workspaces.ModifyWorkspaceAccessPropertiesInput{
ResourceId: aws.String(d.Id()),
WorkspaceAccessProperties: expandWorkspaceAccessProperties(v.([]any)),
}

_, err := conn.ModifyWorkspaceAccessProperties(ctx, input)
_, err := conn.ModifyWorkspaceAccessProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting WorkSpaces Directory (%s) access properties: %s", d.Id(), err)
}
}

if v, ok := d.GetOk("workspace_creation_properties"); ok {
input := &workspaces.ModifyWorkspaceCreationPropertiesInput{
input := workspaces.ModifyWorkspaceCreationPropertiesInput{
ResourceId: aws.String(d.Id()),
WorkspaceCreationProperties: expandWorkspaceCreationProperties(v.([]any)),
}

_, err := conn.ModifyWorkspaceCreationProperties(ctx, input)
_, err := conn.ModifyWorkspaceCreationProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "setting WorkSpaces Directory (%s) creation properties: %s", d.Id(), err)
}
}

if v, ok := d.GetOk("ip_group_ids"); ok && v.(*schema.Set).Len() > 0 {
input := &workspaces.AssociateIpGroupsInput{
input := workspaces.AssociateIpGroupsInput{
DirectoryId: aws.String(d.Id()),
GroupIds: flex.ExpandStringValueSet(v.(*schema.Set)),
}

_, err := conn.AssociateIpGroups(ctx, input)
_, err := conn.AssociateIpGroups(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "asassociating WorkSpaces Directory (%s) IP Groups: %s", d.Id(), err)
Expand All @@ -360,6 +396,9 @@ func resourceDirectoryRead(ctx context.Context, d *schema.ResourceData, meta any
}

d.Set(names.AttrAlias, directory.Alias)
if err := d.Set("certificate_based_auth_properties", flattenCertificateBasedAuthProperties(directory.CertificateBasedAuthProperties)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting certificate_based_auth_properties: %s", err)
}
d.Set("directory_id", directory.DirectoryId)
d.Set("directory_name", directory.DirectoryName)
d.Set("directory_type", directory.DirectoryType)
Expand Down Expand Up @@ -390,8 +429,8 @@ func resourceDirectoryUpdate(ctx context.Context, d *schema.ResourceData, meta a
conn := meta.(*conns.AWSClient).WorkSpacesClient(ctx)

if d.HasChange("saml_properties") {
tfListSAMLProperties := d.Get("saml_properties").([]any)
tfMap := tfListSAMLProperties[0].(map[string]any)
tfList := d.Get("saml_properties").([]any)
tfMap := tfList[0].(map[string]any)

var dels []types.DeletableSamlProperty
if tfMap["relay_state_parameter_name"].(string) == "" {
Expand All @@ -401,52 +440,75 @@ func resourceDirectoryUpdate(ctx context.Context, d *schema.ResourceData, meta a
dels = append(dels, types.DeletableSamlPropertySamlPropertiesUserAccessUrl)
}

input := &workspaces.ModifySamlPropertiesInput{
input := workspaces.ModifySamlPropertiesInput{
PropertiesToDelete: dels,
ResourceId: aws.String(d.Id()),
SamlProperties: expandSAMLProperties(tfListSAMLProperties),
SamlProperties: expandSAMLProperties(tfList),
}

_, err := conn.ModifySamlProperties(ctx, input)
_, err := conn.ModifySamlProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating WorkSpaces Directory (%s) SAML properties: %s", d.Id(), err)
}
}

// SAML needs to be enabled for directory before enabling certificate based authentication
if d.HasChange("certificate_based_auth_properties") {
tfList := d.Get("certificate_based_auth_properties").([]any)
tfMap := tfList[0].(map[string]any)

var dels []types.DeletableCertificateBasedAuthProperty
if tfMap["certificate_authority_arn"].(string) == "" {
dels = append(dels, types.DeletableCertificateBasedAuthPropertyCertificateBasedAuthPropertiesCertificateAuthorityArn)
}

input := &workspaces.ModifyCertificateBasedAuthPropertiesInput{
CertificateBasedAuthProperties: expandCertificateBasedAuthProperties(tfList),
PropertiesToDelete: dels,
ResourceId: aws.String(d.Id()),
}

_, err := conn.ModifyCertificateBasedAuthProperties(ctx, input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating WorkSpaces Directory (%s) certificate-based authentication properties: %s", d.Id(), err)
}
}

if d.HasChange("self_service_permissions") {
input := &workspaces.ModifySelfservicePermissionsInput{
input := workspaces.ModifySelfservicePermissionsInput{
ResourceId: aws.String(d.Id()),
SelfservicePermissions: expandSelfservicePermissions(d.Get("self_service_permissions").([]any)),
}

_, err := conn.ModifySelfservicePermissions(ctx, input)
_, err := conn.ModifySelfservicePermissions(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating WorkSpaces Directory (%s) self-service permissions: %s", d.Id(), err)
}
}

if d.HasChange("workspace_access_properties") {
input := &workspaces.ModifyWorkspaceAccessPropertiesInput{
input := workspaces.ModifyWorkspaceAccessPropertiesInput{
ResourceId: aws.String(d.Id()),
WorkspaceAccessProperties: expandWorkspaceAccessProperties(d.Get("workspace_access_properties").([]any)),
}

_, err := conn.ModifyWorkspaceAccessProperties(ctx, input)
_, err := conn.ModifyWorkspaceAccessProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating WorkSpaces Directory (%s) access properties: %s", d.Id(), err)
}
}

if d.HasChange("workspace_creation_properties") {
input := &workspaces.ModifyWorkspaceCreationPropertiesInput{
input := workspaces.ModifyWorkspaceCreationPropertiesInput{
ResourceId: aws.String(d.Id()),
WorkspaceCreationProperties: expandWorkspaceCreationProperties(d.Get("workspace_creation_properties").([]any)),
}

_, err := conn.ModifyWorkspaceCreationProperties(ctx, input)
_, err := conn.ModifyWorkspaceCreationProperties(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating WorkSpaces Directory (%s) creation properties: %s", d.Id(), err)
Expand All @@ -459,25 +521,25 @@ func resourceDirectoryUpdate(ctx context.Context, d *schema.ResourceData, meta a
add, del := ns.Difference(os), os.Difference(ns)

if add.Len() > 0 {
input := &workspaces.AssociateIpGroupsInput{
input := workspaces.AssociateIpGroupsInput{
DirectoryId: aws.String(d.Id()),
GroupIds: flex.ExpandStringValueSet(add),
}

_, err := conn.AssociateIpGroups(ctx, input)
_, err := conn.AssociateIpGroups(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "associating WorkSpaces Directory (%s) IP Groups: %s", d.Id(), err)
}
}

if del.Len() > 0 {
input := &workspaces.DisassociateIpGroupsInput{
input := workspaces.DisassociateIpGroupsInput{
DirectoryId: aws.String(d.Id()),
GroupIds: flex.ExpandStringValueSet(del),
}

_, err := conn.DisassociateIpGroups(ctx, input)
_, err := conn.DisassociateIpGroups(ctx, &input)

if err != nil {
return sdkdiag.AppendErrorf(diags, "disassociating WorkSpaces Directory (%s) IP Groups: %s", d.Id(), err)
Expand All @@ -493,14 +555,15 @@ func resourceDirectoryDelete(ctx context.Context, d *schema.ResourceData, meta a
conn := meta.(*conns.AWSClient).WorkSpacesClient(ctx)

log.Printf("[DEBUG] Deleting WorkSpaces Directory: %s", d.Id())
input := workspaces.DeregisterWorkspaceDirectoryInput{
DirectoryId: aws.String(d.Id()),
}
const (
timeout = 2 * time.Minute
)
_, err := tfresource.RetryWhenIsA[*types.InvalidResourceStateException](ctx, timeout,
func() (any, error) {
return conn.DeregisterWorkspaceDirectory(ctx, &workspaces.DeregisterWorkspaceDirectoryInput{
DirectoryId: aws.String(d.Id()),
})
return conn.DeregisterWorkspaceDirectory(ctx, &input)
})

if errs.IsA[*types.ResourceNotFoundException](err) {
Expand All @@ -519,11 +582,11 @@ func resourceDirectoryDelete(ctx context.Context, d *schema.ResourceData, meta a
}

func findDirectoryByID(ctx context.Context, conn *workspaces.Client, id string) (*types.WorkspaceDirectory, error) {
input := &workspaces.DescribeWorkspaceDirectoriesInput{
input := workspaces.DescribeWorkspaceDirectoriesInput{
DirectoryIds: []string{id},
}

output, err := findDirectory(ctx, conn, input)
output, err := findDirectory(ctx, conn, &input)

if err != nil {
return nil, err
Expand Down Expand Up @@ -677,6 +740,25 @@ func expandWorkspaceAccessProperties(tfList []any) *types.WorkspaceAccessPropert
return apiObject
}

func expandCertificateBasedAuthProperties(tfList []any) *types.CertificateBasedAuthProperties {
if len(tfList) == 0 || tfList[0] == nil {
return nil
}

apiObject := &types.CertificateBasedAuthProperties{}
tfMap := tfList[0].(map[string]any)

if tfMap["certificate_authority_arn"].(string) != "" {
apiObject.CertificateAuthorityArn = aws.String(tfMap["certificate_authority_arn"].(string))
}

if tfMap[names.AttrStatus].(string) != "" {
apiObject.Status = types.CertificateBasedAuthStatusEnum(tfMap[names.AttrStatus].(string))
}

return apiObject
}

func expandSAMLProperties(tfList []any) *types.SamlProperties {
if len(tfList) == 0 || tfList[0] == nil {
return nil
Expand Down Expand Up @@ -783,6 +865,19 @@ func flattenWorkspaceAccessProperties(apiObject *types.WorkspaceAccessProperties
}
}

func flattenCertificateBasedAuthProperties(apiObject *types.CertificateBasedAuthProperties) []any {
if apiObject == nil {
return []any{}
}

return []any{
map[string]any{
"certificate_authority_arn": aws.ToString(apiObject.CertificateAuthorityArn),
names.AttrStatus: apiObject.Status,
},
}
}

func flattenSAMLProperties(apiObject *types.SamlProperties) []any {
if apiObject == nil {
return []any{}
Expand Down
19 changes: 19 additions & 0 deletions internal/service/workspaces/directory_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,22 @@ func dataSourceDirectory() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"certificate_based_auth_properties": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"certificate_authority_arn": {
Type: schema.TypeString,
Computed: true,
},
names.AttrStatus: {
Type: schema.TypeString,
Computed: true,
},
},
},
},
"customer_user_name": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -202,6 +218,9 @@ func dataSourceDirectoryRead(ctx context.Context, d *schema.ResourceData, meta a

d.SetId(directoryID)
d.Set(names.AttrAlias, directory.Alias)
if err := d.Set("certificate_based_auth_properties", flattenCertificateBasedAuthProperties(directory.CertificateBasedAuthProperties)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting certificate_based_auth_properties: %s", err)
}
d.Set("directory_id", directory.DirectoryId)
d.Set("directory_name", directory.DirectoryName)
d.Set("directory_type", directory.DirectoryType)
Expand Down
Loading
Loading