Skip to content

Commit 8a6a017

Browse files
authored
Merge pull request #44949 from marianafidalgof/f-aws_ecr_authorization_token
ecr: add ephemeral aws_ecr_authorization_token resource
2 parents b3b1119 + 6def4d2 commit 8a6a017

File tree

5 files changed

+225
-0
lines changed

5 files changed

+225
-0
lines changed

.changelog/44949.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-ephemeral
2+
aws_ecr_authorization_token
3+
```
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package ecr
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"strings"
10+
"time"
11+
12+
"github.com/aws/aws-sdk-go-v2/aws"
13+
"github.com/aws/aws-sdk-go-v2/service/ecr"
14+
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
15+
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
16+
"github.com/hashicorp/terraform-plugin-framework/types"
17+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
18+
"github.com/hashicorp/terraform-provider-aws/internal/smerr"
19+
itypes "github.com/hashicorp/terraform-provider-aws/internal/types"
20+
"github.com/hashicorp/terraform-provider-aws/names"
21+
)
22+
23+
// @EphemeralResource(aws_ecr_authorization_token, name="AuthorizationToken")
24+
func newAuthorizationTokenEphemeralResource(_ context.Context) (ephemeral.EphemeralResourceWithConfigure, error) {
25+
return &authorizationTokenEphemeralResource{}, nil
26+
}
27+
28+
type authorizationTokenEphemeralResource struct {
29+
framework.EphemeralResourceWithModel[authorizationTokenEphemeralResourceModel]
30+
}
31+
32+
func (e *authorizationTokenEphemeralResource) Schema(ctx context.Context, _ ephemeral.SchemaRequest, response *ephemeral.SchemaResponse) {
33+
response.Schema = schema.Schema{
34+
Attributes: map[string]schema.Attribute{
35+
"authorization_token": schema.StringAttribute{
36+
Computed: true,
37+
Sensitive: true,
38+
},
39+
"expires_at": schema.StringAttribute{
40+
Computed: true,
41+
},
42+
names.AttrPassword: schema.StringAttribute{
43+
Computed: true,
44+
Sensitive: true,
45+
},
46+
"proxy_endpoint": schema.StringAttribute{
47+
Computed: true,
48+
},
49+
names.AttrUserName: schema.StringAttribute{
50+
Computed: true,
51+
},
52+
},
53+
}
54+
}
55+
56+
func (e *authorizationTokenEphemeralResource) Open(ctx context.Context, request ephemeral.OpenRequest, response *ephemeral.OpenResponse) {
57+
conn := e.Meta().ECRClient(ctx)
58+
data := authorizationTokenEphemeralResourceModel{}
59+
60+
smerr.AddEnrich(ctx, &response.Diagnostics, request.Config.Get(ctx, &data))
61+
if response.Diagnostics.HasError() {
62+
return
63+
}
64+
65+
input := ecr.GetAuthorizationTokenInput{}
66+
67+
out, err := conn.GetAuthorizationToken(ctx, &input)
68+
if err != nil {
69+
smerr.AddError(ctx, &response.Diagnostics, err)
70+
return
71+
}
72+
73+
if len(out.AuthorizationData) == 0 {
74+
smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("no authorization data returned"))
75+
return
76+
}
77+
78+
authorizationData := out.AuthorizationData[0]
79+
authorizationToken := aws.ToString(authorizationData.AuthorizationToken)
80+
expiresAt := aws.ToTime(authorizationData.ExpiresAt).Format(time.RFC3339)
81+
proxyEndpoint := aws.ToString(authorizationData.ProxyEndpoint)
82+
authBytes, err := itypes.Base64Decode(authorizationToken)
83+
if err != nil {
84+
smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("decoding ECR authorization token: %w", err))
85+
return
86+
}
87+
88+
basicAuthorization := strings.Split(string(authBytes), ":")
89+
if len(basicAuthorization) != 2 {
90+
smerr.AddError(ctx, &response.Diagnostics, fmt.Errorf("unknown ECR authorization token format"))
91+
return
92+
}
93+
94+
userName := basicAuthorization[0]
95+
password := basicAuthorization[1]
96+
97+
data.AuthorizationToken = types.StringValue(authorizationToken)
98+
data.ProxyEndpoint = types.StringValue(proxyEndpoint)
99+
data.ExpiresAt = types.StringValue(expiresAt)
100+
data.UserName = types.StringValue(userName)
101+
data.Password = types.StringValue(password)
102+
103+
smerr.AddEnrich(ctx, &response.Diagnostics, response.Result.Set(ctx, &data))
104+
}
105+
106+
type authorizationTokenEphemeralResourceModel struct {
107+
framework.WithRegionModel
108+
AuthorizationToken types.String `tfsdk:"authorization_token"`
109+
ExpiresAt types.String `tfsdk:"expires_at"`
110+
Password types.String `tfsdk:"password"`
111+
ProxyEndpoint types.String `tfsdk:"proxy_endpoint"`
112+
UserName types.String `tfsdk:"user_name"`
113+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package ecr_test
5+
6+
import (
7+
"testing"
8+
9+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
10+
"github.com/hashicorp/terraform-plugin-testing/knownvalue"
11+
"github.com/hashicorp/terraform-plugin-testing/statecheck"
12+
"github.com/hashicorp/terraform-plugin-testing/tfjsonpath"
13+
"github.com/hashicorp/terraform-plugin-testing/tfversion"
14+
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
15+
"github.com/hashicorp/terraform-provider-aws/names"
16+
)
17+
18+
func TestAccECRAuthorizationTokenEphemeral_basic(t *testing.T) {
19+
ctx := acctest.Context(t)
20+
echoResourceName := "echo.test"
21+
dataPath := tfjsonpath.New("data")
22+
23+
resource.ParallelTest(t, resource.TestCase{
24+
PreCheck: func() { acctest.PreCheck(ctx, t) },
25+
ErrorCheck: acctest.ErrorCheck(t, names.ECRServiceID),
26+
TerraformVersionChecks: []tfversion.TerraformVersionCheck{
27+
tfversion.SkipBelow(tfversion.Version1_10_0),
28+
},
29+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
30+
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories(ctx, acctest.ProviderNameEcho),
31+
CheckDestroy: acctest.CheckDestroyNoop,
32+
Steps: []resource.TestStep{
33+
{
34+
Config: testAccAuthorizationTokenEphemeralResourceConfig_basic(),
35+
ConfigStateChecks: []statecheck.StateCheck{
36+
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("authorization_token"), knownvalue.NotNull()),
37+
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("proxy_endpoint"), knownvalue.NotNull()),
38+
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey("expires_at"), knownvalue.NotNull()),
39+
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey(names.AttrUserName), knownvalue.NotNull()),
40+
statecheck.ExpectKnownValue(echoResourceName, dataPath.AtMapKey(names.AttrPassword), knownvalue.NotNull()),
41+
},
42+
},
43+
},
44+
})
45+
}
46+
47+
func testAccAuthorizationTokenEphemeralResourceConfig_basic() string {
48+
return acctest.ConfigCompose(
49+
acctest.ConfigWithEchoProvider("ephemeral.aws_ecr_authorization_token.test"),
50+
`
51+
ephemeral "aws_ecr_authorization_token" "test" {}
52+
`)
53+
}

internal/service/ecr/service_package_gen.go

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
subcategory: "ECR (Elastic Container Registry)"
3+
layout: "aws"
4+
page_title: "AWS: aws_ecr_authorization_token"
5+
description: |-
6+
Retrieve an authentication token to communicate with an ECR repository.
7+
---
8+
9+
# Ephemeral: aws_ecr_authorization_token
10+
11+
Retrieve an authentication token to communicate with an ECR repository.
12+
13+
~> **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).
14+
15+
~> **NOTE:** The returned authorization token can be used to access any Amazon ECR registry that the IAM principal has access to. The token's permissions scope is determined by the IAM principal's permissions, not by any specific registry.
16+
17+
## Example Usage
18+
19+
```terraform
20+
ephemeral "aws_ecr_authorization_token" "token" {}
21+
22+
provider "docker" {
23+
registry_auth {
24+
address = ephemeral.aws_ecr_authorization_token.token.proxy_endpoint
25+
username = ephemeral.aws_ecr_authorization_token.token.user_name
26+
password = ephemeral.aws_ecr_authorization_token.token.password
27+
}
28+
}
29+
```
30+
31+
## Argument Reference
32+
33+
This resource supports the following arguments:
34+
35+
* `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).
36+
37+
## Attribute Reference
38+
39+
This resource exports the following attributes in addition to the arguments above:
40+
41+
* `authorization_token` - Temporary IAM authentication credentials to access the ECR repository encoded in base64 in the form of `user_name:password`.
42+
* `expires_at` - Time in UTC RFC3339 format when the authorization token expires.
43+
* `password` - Password decoded from the authorization token.
44+
* `proxy_endpoint` - Registry URL to use in the docker login command.
45+
* `user_name` - User name decoded from the authorization token.

0 commit comments

Comments
 (0)