Skip to content

Commit

Permalink
Merge pull request #37255 from tmatilai/aws_iam_openid_connect_provid…
Browse files Browse the repository at this point in the history
…er_optional_thumbprint_list

r/aws_iam_openid_connect_provider: Make `thumbprint_list` attribute optional
  • Loading branch information
YakDriver authored Dec 10, 2024
2 parents 659126c + 636c1b2 commit b4eb0a1
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 18 deletions.
3 changes: 3 additions & 0 deletions .changelog/37255.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
``release-note:enhancement
resource/aws_iam_openid_connect_provider: Make `thumbprint_list` optional
```
37 changes: 24 additions & 13 deletions internal/service/iam/openid_connect_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ func resourceOpenIDConnectProvider() *schema.Resource {
names.AttrTagsAll: tftags.TagsSchemaComputed(),
"thumbprint_list": {
Type: schema.TypeList,
Required: true,
Optional: true,
Computed: true,
Elem: &schema.Schema{
Type: schema.TypeString,
ValidateFunc: validation.StringLenBetween(40, 40),
Expand All @@ -79,10 +80,13 @@ func resourceOpenIDConnectProviderCreate(ctx context.Context, d *schema.Resource
conn := meta.(*conns.AWSClient).IAMClient(ctx)

input := &iam.CreateOpenIDConnectProviderInput{
ClientIDList: flex.ExpandStringValueSet(d.Get("client_id_list").(*schema.Set)),
Tags: getTagsIn(ctx),
ThumbprintList: flex.ExpandStringValueList(d.Get("thumbprint_list").([]interface{})),
Url: aws.String(d.Get(names.AttrURL).(string)),
ClientIDList: flex.ExpandStringValueSet(d.Get("client_id_list").(*schema.Set)),
Tags: getTagsIn(ctx),
Url: aws.String(d.Get(names.AttrURL).(string)),
}

if v, ok := d.GetOk("thumbprint_list"); ok {
input.ThumbprintList = flex.ExpandStringValueList(v.([]interface{}))
}

output, err := conn.CreateOpenIDConnectProvider(ctx, input)
Expand Down Expand Up @@ -149,15 +153,22 @@ func resourceOpenIDConnectProviderUpdate(ctx context.Context, d *schema.Resource
conn := meta.(*conns.AWSClient).IAMClient(ctx)

if d.HasChange("thumbprint_list") {
input := &iam.UpdateOpenIDConnectProviderThumbprintInput{
OpenIDConnectProviderArn: aws.String(d.Id()),
ThumbprintList: flex.ExpandStringValueList(d.Get("thumbprint_list").([]interface{})),
}

_, err := conn.UpdateOpenIDConnectProviderThumbprint(ctx, input)
if v := d.Get("thumbprint_list").([]interface{}); len(v) > 0 {
// Issues with an update to clear the thumbprint_list:
// - A cleared thumbprint_list will have a length of 0, and not enter this block.
// - Setting it to empty triggers an API error (the API requires either no thumbprints at
// **creation** or at least one thumbprint on update).
// - Removing the thumbprint_list attribute entirely doesn’t work because it won’t register as
// a change (no diff is detected).
// See https://github.com/hashicorp/terraform-provider-aws/issues/40509
input := &iam.UpdateOpenIDConnectProviderThumbprintInput{
OpenIDConnectProviderArn: aws.String(d.Id()),
ThumbprintList: flex.ExpandStringValueList(v),
}

if err != nil {
return sdkdiag.AppendErrorf(diags, "updating IAM OIDC Provider (%s) thumbprint: %s", d.Id(), err)
if _, err := conn.UpdateOpenIDConnectProviderThumbprint(ctx, input); err != nil {
return sdkdiag.AppendErrorf(diags, "updating IAM OIDC Provider (%s) thumbprint: %s", d.Id(), err)
}
}
}

Expand Down
142 changes: 142 additions & 0 deletions internal/service/iam/openid_connect_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,122 @@ func TestAccIAMOpenIDConnectProvider_basic(t *testing.T) {
})
}

func TestAccIAMOpenIDConnectProvider_Thumbprints_none(t *testing.T) {
ctx := acctest.Context(t)
url := "accounts.google.com"
resourceName := "aws_iam_openid_connect_provider.test"

resource.Test(t, resource.TestCase{ // can't run in parallel b/c of google URL, needed for no thumbprints
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckOpenIDConnectProviderDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccOpenIDConnectProviderConfig_withoutThumbprints(),
Check: resource.ComposeTestCheckFunc(
testAccCheckOpenIDConnectProviderExists(ctx, resourceName),
acctest.CheckResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "iam", fmt.Sprintf("oidc-provider/%s", url)),
resource.TestCheckResourceAttr(resourceName, names.AttrURL, url),
resource.TestCheckResourceAttr(resourceName, "client_id_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "client_id_list.0",
"266362248691-342342xasdasdasda-apps.googleusercontent.com"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"),
),
},
},
})
}

func TestAccIAMOpenIDConnectProvider_Thumbprints_withToWithout(t *testing.T) {
ctx := acctest.Context(t)
url := "accounts.google.com"
resourceName := "aws_iam_openid_connect_provider.test"

resource.Test(t, resource.TestCase{ // can't run in parallel b/c of google URL, needed for no thumbprints
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckOpenIDConnectProviderDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccOpenIDConnectProviderConfig_thumbprint(),
Check: resource.ComposeTestCheckFunc(
testAccCheckOpenIDConnectProviderExists(ctx, resourceName),
acctest.CheckResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "iam", fmt.Sprintf("oidc-provider/%s", url)),
resource.TestCheckResourceAttr(resourceName, names.AttrURL, url),
resource.TestCheckResourceAttr(resourceName, "client_id_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "client_id_list.0",
"266362248691-342342xasdasdasda-apps.googleusercontent.com"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.0", "cf23df2207d99a74fbe169e3eba035e633b65d94"),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"),
),
},
{
Config: testAccOpenIDConnectProviderConfig_withoutThumbprints(),
Check: resource.ComposeTestCheckFunc(
testAccCheckOpenIDConnectProviderExists(ctx, resourceName),
acctest.CheckResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "iam", fmt.Sprintf("oidc-provider/%s", url)),
resource.TestCheckResourceAttr(resourceName, names.AttrURL, url),
resource.TestCheckResourceAttr(resourceName, "client_id_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "client_id_list.0",
"266362248691-342342xasdasdasda-apps.googleusercontent.com"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.#", "1"),
// This is a bug: the thumbprint should be the AWS provided for the top intermediate CA of the OIDC IdP
// See https://github.com/hashicorp/terraform-provider-aws/issues/40509
//resource.TestCheckResourceAttr(resourceName, "thumbprint_list.0", "08745487e891c19e3078c1f2a07e452950ef36f6"),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"),
),
},
},
})
}

func TestAccIAMOpenIDConnectProvider_Thumbprints_withoutToWith(t *testing.T) {
ctx := acctest.Context(t)
url := "accounts.google.com"
resourceName := "aws_iam_openid_connect_provider.test"

resource.Test(t, resource.TestCase{ // can't run in parallel b/c of google URL, needed for no thumbprints
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.IAMServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckOpenIDConnectProviderDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccOpenIDConnectProviderConfig_withoutThumbprints(),
Check: resource.ComposeTestCheckFunc(
testAccCheckOpenIDConnectProviderExists(ctx, resourceName),
acctest.CheckResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "iam", fmt.Sprintf("oidc-provider/%s", url)),
resource.TestCheckResourceAttr(resourceName, names.AttrURL, url),
resource.TestCheckResourceAttr(resourceName, "client_id_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "client_id_list.0",
"266362248691-342342xasdasdasda-apps.googleusercontent.com"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.0", "08745487e891c19e3078c1f2a07e452950ef36f6"),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"),
),
},
{
Config: testAccOpenIDConnectProviderConfig_thumbprint(),
Check: resource.ComposeTestCheckFunc(
testAccCheckOpenIDConnectProviderExists(ctx, resourceName),
acctest.CheckResourceAttrGlobalARN(ctx, resourceName, names.AttrARN, "iam", fmt.Sprintf("oidc-provider/%s", url)),
resource.TestCheckResourceAttr(resourceName, names.AttrURL, url),
resource.TestCheckResourceAttr(resourceName, "client_id_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "client_id_list.0",
"266362248691-342342xasdasdasda-apps.googleusercontent.com"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.#", "1"),
resource.TestCheckResourceAttr(resourceName, "thumbprint_list.0", "cf23df2207d99a74fbe169e3eba035e633b65d94"),
resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, "0"),
),
},
},
})
}

func TestAccIAMOpenIDConnectProvider_disappears(t *testing.T) {
ctx := acctest.Context(t)
rString := sdkacctest.RandString(5)
Expand Down Expand Up @@ -240,6 +356,32 @@ resource "aws_iam_openid_connect_provider" "test" {
`, rName)
}

func testAccOpenIDConnectProviderConfig_thumbprint() string {
return `
resource "aws_iam_openid_connect_provider" "test" {
url = "https://accounts.google.com"
client_id_list = [
"266362248691-342342xasdasdasda-apps.googleusercontent.com",
]
thumbprint_list = ["cf23df2207d99a74fbe169e3eba035e633b65d94"]
}
`
}

func testAccOpenIDConnectProviderConfig_withoutThumbprints() string {
return `
resource "aws_iam_openid_connect_provider" "test" {
url = "https://accounts.google.com"
client_id_list = [
"266362248691-342342xasdasdasda-apps.googleusercontent.com",
]
}
`
}

func testAccOpenIDConnectProviderConfig_clientIDList_first(rName string) string {
return fmt.Sprintf(`
resource "aws_iam_openid_connect_provider" "test" {
Expand Down
24 changes: 19 additions & 5 deletions website/docs/r/iam_openid_connect_provider.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Provides an IAM OpenID Connect provider.

## Example Usage

### Basic Usage

```terraform
resource "aws_iam_openid_connect_provider" "default" {
url = "https://accounts.google.com"
Expand All @@ -24,21 +26,33 @@ resource "aws_iam_openid_connect_provider" "default" {
}
```

### Without A Thumbprint

```terraform
resource "aws_iam_openid_connect_provider" "default" {
url = "https://accounts.google.com"
client_id_list = [
"266362248691-342342xasdasdasda-apps.googleusercontent.com",
]
}
```

## Argument Reference

This resource supports the following arguments:

* `url` - (Required) The URL of the identity provider. Corresponds to the _iss_ claim.
* `client_id_list` - (Required) A list of client IDs (also known as audiences). When a mobile or web app registers with an OpenID Connect provider, they establish a value that identifies the application. (This is the value that's sent as the client_id parameter on OAuth requests.)
* `thumbprint_list` - (Required) A list of server certificate thumbprints for the OpenID Connect (OIDC) identity provider's server certificate(s).
* `url` - (Required) URL of the identity provider, corresponding to the `iss` claim.
* `client_id_list` - (Required) List of client IDs (audiences) that identify the application registered with the OpenID Connect provider. This is the value sent as the `client_id` parameter in OAuth requests.
* `thumbprint_list` - (Optional) List of server certificate thumbprints for the OpenID Connect (OIDC) identity provider's server certificate(s). For certain OIDC identity providers (e.g., Auth0, GitHub, GitLab, Google, or those using an Amazon S3-hosted JWKS endpoint), AWS relies on its own library of trusted root certificate authorities (CAs) for validation instead of using any configured thumbprints. In these cases, any configured `thumbprint_list` is retained in the configuration but not used for verification. For other IdPs, if no `thumbprint_list` is provided, IAM automatically retrieves and uses the top intermediate CA thumbprint from the OIDC IdP server certificate. However, if a `thumbprint_list` is initially configured and later removed, Terraform does not prompt IAM to retrieve a thumbprint the same way. Instead, it continues using the original thumbprint list from the initial configuration. This differs from the behavior when creating an `aws_iam_openid_connect_provider` without a `thumbprint_list`.
* `tags` - (Optional) Map of resource tags for the IAM OIDC provider. 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.

## Attribute Reference

This resource exports the following attributes in addition to the arguments above:

* `arn` - The ARN assigned by AWS for this provider.
* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block).
* `arn` - ARN assigned by AWS for this provider.
* `tags_all` - Map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block).

## Import

Expand Down

0 comments on commit b4eb0a1

Please sign in to comment.