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
3 changes: 3 additions & 0 deletions .changelog/45841.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-ephemeral
aws_ecrpublic_authorization_token
```
102 changes: 102 additions & 0 deletions internal/service/ecrpublic/authorization_token_ephemeral.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: MPL-2.0

package ecrpublic

import (
"context"
"fmt"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/ecrpublic"
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
"github.com/hashicorp/terraform-provider-aws/internal/smerr"
inttypes "github.com/hashicorp/terraform-provider-aws/internal/types"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @EphemeralResource(aws_ecrpublic_authorization_token, name="AuthorizationToken")
func newAuthorizationTokenEphemeralResource(_ context.Context) (ephemeral.EphemeralResourceWithConfigure, error) {
return &authorizationTokenEphemeralResource{}, nil
}

type authorizationTokenEphemeralResource struct {
framework.EphemeralResourceWithModel[authorizationTokenEphemeralResourceModel]
}

func (e *authorizationTokenEphemeralResource) Schema(_ context.Context, _ ephemeral.SchemaRequest, response *ephemeral.SchemaResponse) {
response.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"authorization_token": schema.StringAttribute{
Computed: true,
Sensitive: true,
},
"expires_at": schema.StringAttribute{
CustomType: timetypes.RFC3339Type{},
Computed: true,
},
names.AttrPassword: schema.StringAttribute{
Computed: true,
Sensitive: true,
},
names.AttrUserName: schema.StringAttribute{
Computed: true,
},
},
}
}

func (e *authorizationTokenEphemeralResource) Open(ctx context.Context, request ephemeral.OpenRequest, response *ephemeral.OpenResponse) {
conn := e.Meta().ECRPublicClient(ctx)
var data authorizationTokenEphemeralResourceModel

smerr.AddEnrich(ctx, &response.Diagnostics, request.Config.Get(ctx, &data))
if response.Diagnostics.HasError() {
return
}

var input ecrpublic.GetAuthorizationTokenInput
output, err := conn.GetAuthorizationToken(ctx, &input)
if err != nil {
smerr.AddError(ctx, &response.Diagnostics, err)
return
}

authorizationData := output.AuthorizationData
authorizationToken := aws.ToString(authorizationData.AuthorizationToken)
authBytes, err := inttypes.Base64Decode(authorizationToken)
if err != nil {
smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("decoding ECR Public authorization token: %w", err))
return
}

basicAuthorization := strings.Split(string(authBytes), ":")
if len(basicAuthorization) != 2 {
smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("unknown ECR Public authorization token format"))
return
}

userName := basicAuthorization[0]
password := basicAuthorization[1]

data.AuthorizationToken = fwflex.StringValueToFramework(ctx, authorizationToken)
data.ExpiresAt = timetypes.NewRFC3339TimePointerValue(authorizationData.ExpiresAt)
data.UserName = fwflex.StringValueToFramework(ctx, userName)
data.Password = fwflex.StringValueToFramework(ctx, password)

smerr.AddEnrich(ctx, &response.Diagnostics, response.Result.Set(ctx, &data))
}

type authorizationTokenEphemeralResourceModel struct {
framework.WithRegionModel
AuthorizationToken types.String `tfsdk:"authorization_token"`
ExpiresAt timetypes.RFC3339 `tfsdk:"expires_at"`
Password types.String `tfsdk:"password"`
UserName types.String `tfsdk:"user_name"`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright IBM Corp. 2014, 2026
// SPDX-License-Identifier: MPL-2.0

package ecrpublic_test

import (
"testing"

"github.com/YakDriver/regexache"
"github.com/hashicorp/aws-sdk-go-base/v2/endpoints"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
"github.com/hashicorp/terraform-plugin-testing/statecheck"
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
"github.com/hashicorp/terraform-plugin-testing/tfversion"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
"github.com/hashicorp/terraform-provider-aws/names"
)

func TestAccECRPublicAuthorizationTokenEphemeral_basic(t *testing.T) {
ctx := acctest.Context(t)
echoResourceName := "echo.test"
dataPath := tfjsonpath.New("data")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckRegion(t, endpoints.UsEast1RegionID) },
ErrorCheck: acctest.ErrorCheck(t, names.ECRServiceID),
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
tfversion.SkipBelow(tfversion.Version1_10_0),
},
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories(ctx, acctest.ProviderNameEcho),
CheckDestroy: acctest.CheckDestroyNoop,
Steps: []resource.TestStep{
{
Config: testAccAuthorizationTokenEphemeralResourceConfig_basic(),
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("authorization_token"), knownvalue.NotNull()),
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("expires_at"), knownvalue.NotNull()),
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey(names.AttrUserName), knownvalue.StringRegexp(regexache.MustCompile(`AWS`))),
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey(names.AttrPassword), knownvalue.NotNull()),
},
},
},
})
}

func testAccAuthorizationTokenEphemeralResourceConfig_basic() string {
return acctest.ConfigCompose(
acctest.ConfigWithEchoProvider("ephemeral.aws_ecrpublic_authorization_token.test"),
`
ephemeral "aws_ecrpublic_authorization_token" "test" {}
`)
}
11 changes: 11 additions & 0 deletions internal/service/ecrpublic/service_package_gen.go

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
subcategory: "ECR Public"
layout: "aws"
page_title: "AWS: aws_ecrpublic_authorization_token"
description: |-
Retrieve an authentication token to communicate with a public ECR repository.
---

# Ephemeral: aws_ecrpublic_authorization_token

Retrieve an authentication token to communicate with a public ECR repository.

~> **NOTE:** Ephemeral resources are a new feature and may evolve as we continue to explore their most effective uses. [Learn more](https://developer.hashicorp.com/terraform/language/resources/ephemeral).

~> **NOTE:** This resource can only be used in the `us-east-1` region.

## Example Usage

```terraform
ephemeral "aws_ecrpublic_authorization_token" "token" {}

provider "helm" {
registries = [
{
url = "oci://public.ecr.aws"
username = ephemeral.aws_ecrpublic_authorization_token.token.user_name
password = ephemeral.aws_ecrpublic_authorization_token.token.password
}
]
}
```

## Argument Reference

This resource supports the following arguments:

* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).

## Attribute Reference

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

* `authorization_token` - Temporary IAM authentication credentials to access the ECR repository encoded in base64 in the form of `user_name:password`.
* `expires_at` - Time in UTC RFC3339 format when the authorization token expires.
* `password` - Password decoded from the authorization token.
* `user_name` - User name decoded from the authorization token.
Loading