Skip to content
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
6 changes: 6 additions & 0 deletions .changelog/46869.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:new-list-resource
aws_iam_user
```
```release-note:enhancement
resource/aws_iam_user: Add resource identity support
```
19 changes: 19 additions & 0 deletions internal/service/iam/service_package_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions internal/service/iam/testdata/User/basic/main_gen.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

resource "aws_iam_user" "test" {
name = var.rName
}

variable "rName" {
description = "Name for resource"
type = string
nullable = false
}
22 changes: 22 additions & 0 deletions internal/service/iam/testdata/User/basic_v6.35.1/main_gen.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

resource "aws_iam_user" "test" {
name = var.rName
}

variable "rName" {
description = "Name for resource"
type = string
nullable = false
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "6.35.1"
}
}
}

provider "aws" {}
20 changes: 20 additions & 0 deletions internal/service/iam/testdata/User/list_basic/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

resource "aws_iam_user" "test" {
count = var.resource_count

name = "${var.rName}-${count.index}"
}

variable "rName" {
description = "Name for resource"
type = string
nullable = false
}

variable "resource_count" {
description = "Number of resources to create"
type = number
nullable = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

list "aws_iam_user" "test" {
provider = aws
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

resource "aws_iam_user" "test" {
count = var.resource_count

name = "${var.rName}-${count.index}"

tags = var.resource_tags
}

variable "rName" {
description = "Name for resource"
type = string
nullable = false
}

variable "resource_count" {
description = "Number of resources to create"
type = number
nullable = false
}

variable "resource_tags" {
description = "Tags to set on resource"
type = map(string)
nullable = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

list "aws_iam_user" "test" {
provider = aws

include_resource = true
}
40 changes: 40 additions & 0 deletions internal/service/iam/testdata/User/list_path_prefix/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

resource "aws_iam_user" "expected" {
count = var.resource_count

name = "${var.rName}-${count.index}"
path = var.expected_path_name
}

resource "aws_iam_user" "not_expected" {
count = var.resource_count

name = "${var.rName}-other-${count.index}"
path = var.other_path_name
}

variable "rName" {
description = "Name for resource"
type = string
nullable = false
}

variable "resource_count" {
description = "Number of resources to create"
type = number
nullable = false
}

variable "expected_path_name" {
description = "Path name for expected resources"
type = string
nullable = false
}

variable "other_path_name" {
description = "Path name for non-expected resources"
type = string
nullable = false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright IBM Corp. 2014, 2026
# SPDX-License-Identifier: MPL-2.0

list "aws_iam_user" "test" {
provider = aws

config {
path_prefix = var.expected_path_name
}
}
34 changes: 19 additions & 15 deletions internal/service/iam/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,20 @@ import (
)

// @SDKResource("aws_iam_user", name="User")
// @IdentityAttribute("name")
// @MutableIdentity
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Identity is mutable because the provider allows name and path can be modified in place.

Perhaps this is something we reconsider in a future major version, but for now I'm not sure we can avoid marking it this way without breaking existing behavior.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AWS API also allows changing the name and path in-place.

Technically, the UserId (exposed as unique_id in the provider) is the stable unique identifier, but it's not exposed to the user, so not useful for import.

Alternatively, we could use unique_id as the Identifier, but the GetUser and ListUsers API calls aren't documented to accept the value, just the name. This would require a "full table scan" for reading IAM Users.

// @Tags(identifierAttribute="id", resourceType="User")
// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/iam/types;types.User", importIgnore="force_destroy")
// @Testing(existsType="github.com/aws/aws-sdk-go-v2/service/iam/types;types.User")
// @Testing(importIgnore="force_destroy")
// @Testing(plannableImportAction="NoOp")
// @Testing(preIdentityVersion="v6.35.1")
func resourceUser() *schema.Resource {
return &schema.Resource{
CreateWithoutTimeout: resourceUserCreate,
ReadWithoutTimeout: resourceUserRead,
UpdateWithoutTimeout: resourceUserUpdate,
DeleteWithoutTimeout: resourceUserDelete,

Importer: &schema.ResourceImporter{
StateContext: schema.ImportStatePassthroughContext,
},

Schema: map[string]*schema.Schema{
names.AttrARN: {
Type: schema.TypeString,
Expand Down Expand Up @@ -156,16 +157,7 @@ func resourceUserRead(ctx context.Context, d *schema.ResourceData, meta any) dia
return sdkdiag.AppendErrorf(diags, "reading IAM User (%s): %s", d.Id(), err)
}

d.Set(names.AttrARN, user.Arn)
d.Set(names.AttrName, user.UserName)
d.Set(names.AttrPath, user.Path)
if user.PermissionsBoundary != nil {
d.Set("permissions_boundary", user.PermissionsBoundary.PermissionsBoundaryArn)
} else {
d.Set("permissions_boundary", nil)
}
d.Set("unique_id", user.UserId)

resourceUserFlatten(user, d)
setTagsOut(ctx, user.Tags)

return diags
Expand Down Expand Up @@ -666,3 +658,15 @@ func retryCreateUser(ctx context.Context, conn *iam.Client, input *iam.CreateUse

return output, err
}

func resourceUserFlatten(user *awstypes.User, d *schema.ResourceData) {
d.Set(names.AttrARN, user.Arn)
d.Set(names.AttrName, user.UserName)
d.Set(names.AttrPath, user.Path)
if user.PermissionsBoundary != nil {
d.Set("permissions_boundary", user.PermissionsBoundary.PermissionsBoundaryArn)
} else {
d.Set("permissions_boundary", nil)
}
d.Set("unique_id", user.UserId)
}
Loading
Loading