From b7f0930d4635ac43283004e08bb6eac7200c46cc Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 21 Aug 2024 09:08:28 -0700 Subject: [PATCH 1/9] Add 'platform_aws_iam_role' resource --- docs/resources/aws_iam_role.md | 36 +++ .../resources/platform_aws_iam_role/import.sh | 1 + .../platform_aws_iam_role/resource.tf | 4 + pkg/platform/provider.go | 1 + pkg/platform/resource_aws_iam_role.go | 224 ++++++++++++++++++ pkg/platform/resource_aws_iam_role_test.go | 111 +++++++++ 6 files changed, 377 insertions(+) create mode 100644 docs/resources/aws_iam_role.md create mode 100644 examples/resources/platform_aws_iam_role/import.sh create mode 100644 examples/resources/platform_aws_iam_role/resource.tf create mode 100644 pkg/platform/resource_aws_iam_role.go create mode 100644 pkg/platform/resource_aws_iam_role_test.go diff --git a/docs/resources/aws_iam_role.md b/docs/resources/aws_iam_role.md new file mode 100644 index 0000000..e61f958 --- /dev/null +++ b/docs/resources/aws_iam_role.md @@ -0,0 +1,36 @@ +--- +# generated by https://github.com/hashicorp/terraform-plugin-docs +page_title: "platform_aws_iam_role Resource - terraform-provider-platform" +subcategory: "" +description: |- + Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see Passwordless Access for Amazon EKS https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks. +--- + +# platform_aws_iam_role (Resource) + +Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see [Passwordless Access for Amazon EKS](https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks). + +## Example Usage + +```terraform +resource "platform_aws_iam_role" "myuser-aws-iam-role" { + username = "myuser" + iam_role = "arn:aws:iam::000000000000:role/example" +} +``` + + +## Schema + +### Required + +- `iam_role` (String) The AWS IAM role. Must follow the regex, "^arn:aws:iam::\d{12}:role/[\w+=,.@:-]+$" +- `username` (String) The JFrog Platform user name. + +## Import + +Import is supported using the following syntax: + +```shell +terraform import platform_aws_iam_role.myuser-aws-iam-role myuser +``` diff --git a/examples/resources/platform_aws_iam_role/import.sh b/examples/resources/platform_aws_iam_role/import.sh new file mode 100644 index 0000000..654f032 --- /dev/null +++ b/examples/resources/platform_aws_iam_role/import.sh @@ -0,0 +1 @@ +terraform import platform_aws_iam_role.myuser-aws-iam-role myuser \ No newline at end of file diff --git a/examples/resources/platform_aws_iam_role/resource.tf b/examples/resources/platform_aws_iam_role/resource.tf new file mode 100644 index 0000000..9336b0e --- /dev/null +++ b/examples/resources/platform_aws_iam_role/resource.tf @@ -0,0 +1,4 @@ +resource "platform_aws_iam_role" "myuser-aws-iam-role" { + username = "myuser" + iam_role = "arn:aws:iam::000000000000:role/example" +} \ No newline at end of file diff --git a/pkg/platform/provider.go b/pkg/platform/provider.go index 558b809..b6a1018 100644 --- a/pkg/platform/provider.go +++ b/pkg/platform/provider.go @@ -205,6 +205,7 @@ func (p *PlatformProvider) DataSources(ctx context.Context) []func() datasource. func (p *PlatformProvider) Resources(ctx context.Context) []func() resource.Resource { return []func() resource.Resource{ + NewAWSIAMRoleResource, NewLicenseResource, NewGlobalRoleResource, NewOIDCConfigurationResource, diff --git a/pkg/platform/resource_aws_iam_role.go b/pkg/platform/resource_aws_iam_role.go new file mode 100644 index 0000000..a9f1b0d --- /dev/null +++ b/pkg/platform/resource_aws_iam_role.go @@ -0,0 +1,224 @@ +package platform + +import ( + "context" + "net/http" + "regexp" + + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/jfrog/terraform-provider-shared/util" + utilfw "github.com/jfrog/terraform-provider-shared/util/fw" +) + +const ( + AWSIAMRolesEndpoint = "access/api/v1/aws/iam_role" + AWSIAMRoleEndpoint = "access/api/v1/aws/iam_role/{username}" +) + +func NewAWSIAMRoleResource() resource.Resource { + return &AWSIAMRoleResource{ + TypeName: "platform_aws_iam_role", + } +} + +type AWSIAMRoleResource struct { + ProviderData PlatformProviderMetadata + TypeName string +} + +type AWSIAMRoleResourceModel struct { + Username types.String `tfsdk:"username"` + IAMRole types.String `tfsdk:"iam_role"` +} + +type AWSIAMRoleAPIModel struct { + Username string `json:"username"` + IAMRole string `json:"iam_role"` +} + +func (r *AWSIAMRoleResource) Metadata(ctx context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = r.TypeName +} + +func (r *AWSIAMRoleResource) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "username": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Description: "The JFrog Platform user name.", + }, + "iam_role": schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexp.MustCompile(`^arn:aws:iam::\d{12}:role/[\w+=,.@:-]+$`), "Must follow the regex, \"^arn:aws:iam::\\d{12}:role/[\\w+=,.@:-]+$\""), + }, + MarkdownDescription: "The AWS IAM role. Must follow the regex, \"^arn:aws:iam::\\d{12}:role/[\\w+=,.@:-]+$\"", + }, + }, + MarkdownDescription: "Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see [Passwordless Access for Amazon EKS](https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks).", + } +} + +func (r *AWSIAMRoleResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { + // Prevent panic if the provider has not been configured. + if req.ProviderData == nil { + return + } + r.ProviderData = req.ProviderData.(PlatformProviderMetadata) +} + +func (r *AWSIAMRoleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + go util.SendUsageResourceCreate(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var plan AWSIAMRoleResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + role := AWSIAMRoleAPIModel{ + Username: plan.Username.ValueString(), + IAMRole: plan.IAMRole.ValueString(), + } + + response, err := r.ProviderData.Client.R(). + SetBody(role). + Put(AWSIAMRolesEndpoint) + + if err != nil { + utilfw.UnableToCreateResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToCreateResourceError(resp, response.String()) + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *AWSIAMRoleResource) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + go util.SendUsageResourceRead(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var state AWSIAMRoleResourceModel + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + var role AWSIAMRoleAPIModel + + response, err := r.ProviderData.Client.R(). + SetPathParam("username", state.Username.ValueString()). + SetResult(&role). + Get(AWSIAMRoleEndpoint) + + if err != nil { + utilfw.UnableToRefreshResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToRefreshResourceError(resp, response.String()) + return + } + + // Treat HTTP 404 Not Found status as a signal to recreate resource + // and return early + if response.StatusCode() == http.StatusNotFound { + resp.State.RemoveResource(ctx) + return + } + + // Convert from the API data model to the Terraform data model + // and refresh any attribute values. + state.Username = types.StringValue(role.Username) + state.IAMRole = types.StringValue(role.IAMRole) + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *AWSIAMRoleResource) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + go util.SendUsageResourceUpdate(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var plan AWSIAMRoleResourceModel + + // Read Terraform plan data into the model + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + role := AWSIAMRoleAPIModel{ + Username: plan.Username.ValueString(), + IAMRole: plan.IAMRole.ValueString(), + } + + response, err := r.ProviderData.Client.R(). + SetBody(role). + Put(AWSIAMRolesEndpoint) + + if err != nil { + utilfw.UnableToUpdateResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToUpdateResourceError(resp, response.String()) + return + } + + // Save data into Terraform state + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *AWSIAMRoleResource) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + go util.SendUsageResourceDelete(ctx, r.ProviderData.Client.R(), r.ProviderData.ProductId, r.TypeName) + + var state AWSIAMRoleResourceModel + + diags := req.State.Get(ctx, &state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + response, err := r.ProviderData.Client.R(). + SetPathParam("username", state.Username.ValueString()). + Delete(AWSIAMRoleEndpoint) + + if err != nil { + utilfw.UnableToDeleteResourceError(resp, err.Error()) + return + } + + if response.IsError() { + utilfw.UnableToDeleteResourceError(resp, response.String()) + return + } + + // If the logic reaches here, it implicitly succeeded and will remove + // the resource from state if there are no other errors. +} + +func (r *AWSIAMRoleResource) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root("username"), req, resp) +} diff --git a/pkg/platform/resource_aws_iam_role_test.go b/pkg/platform/resource_aws_iam_role_test.go new file mode 100644 index 0000000..6b64aa8 --- /dev/null +++ b/pkg/platform/resource_aws_iam_role_test.go @@ -0,0 +1,111 @@ +package platform_test + +import ( + "fmt" + "net/http" + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/jfrog/terraform-provider-platform/pkg/platform" + "github.com/jfrog/terraform-provider-shared/testutil" + "github.com/jfrog/terraform-provider-shared/util" +) + +func TestAccAWSIAMRole_full(t *testing.T) { + _, fqrn, name := testutil.MkNames("test-aws-iam-role", "platform_aws_iam_role") + + id, _, _ := testutil.MkNames("test-user-upgrade-", "artifactory_managed_user") + username := fmt.Sprintf("dummy_user%d", id) + email := fmt.Sprintf(username + "@test.com") + + temp := ` + resource "artifactory_managed_user" "{{ .username }}" { + name = "{{ .username }}" + email = "{{ .email }}" + password = "Passsw0rd!12" + } + + resource "platform_aws_iam_role" "{{ .name }}" { + username = artifactory_managed_user.{{ .username }}.name + iam_role = "{{ .iam_role }}" + }` + + testData := map[string]string{ + "name": name, + "email": email, + "username": username, + "iam_role": "arn:aws:iam::000000000000:role/example", + } + + config := util.ExecuteTemplate(name, temp, testData) + + updatedTestData := map[string]string{ + "name": name, + "email": email, + "username": username, + "iam_role": "arn:aws:iam::000000000000:role/example-2", + } + + updatedConfig := util.ExecuteTemplate(name, temp, updatedTestData) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ExternalProviders: map[string]resource.ExternalProvider{ + "artifactory": { + Source: "jfrog/artifactory", + }, + }, + ProtoV6ProviderFactories: testAccProviders(), + CheckDestroy: testAccAWSIAMRoleDestroy(fqrn), + Steps: []resource.TestStep{ + { + Config: config, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(fqrn, "username", testData["username"]), + resource.TestCheckResourceAttr(fqrn, "iam_role", testData["iam_role"]), + ), + }, + { + Config: updatedConfig, + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(fqrn, "username", updatedTestData["username"]), + resource.TestCheckResourceAttr(fqrn, "iam_role", updatedTestData["iam_role"]), + ), + }, + { + ResourceName: fqrn, + ImportState: true, + ImportStateVerify: true, + ImportStateId: updatedTestData["username"], + ImportStateVerifyIdentifierAttribute: "username", + }, + }, + }) +} + +func testAccAWSIAMRoleDestroy(id string) func(*terraform.State) error { + return func(s *terraform.State) error { + c := TestProvider.(*platform.PlatformProvider).Meta.Client + + rs, ok := s.RootModule().Resources[id] + if !ok { + return fmt.Errorf("error: resource id [%s] not found", id) + } + + var role platform.AWSIAMRoleAPIModel + resp, err := c.R(). + SetPathParam("username", rs.Primary.Attributes["username"]). + SetResult(&role). + Get(platform.AWSIAMRoleEndpoint) + if err != nil { + return err + } + + if resp != nil && resp.StatusCode() == http.StatusNotFound { + return nil + } + + return fmt.Errorf("error: AWS IAM role for username %s still exists", rs.Primary.Attributes["username"]) + } +} From b772d676cdfb324721152ddb1022ffaae46eeeca Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 21 Aug 2024 09:08:36 -0700 Subject: [PATCH 2/9] Code tidy up --- pkg/platform/resource_scim_group.go | 4 ++-- pkg/platform/resource_scim_user.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/platform/resource_scim_group.go b/pkg/platform/resource_scim_group.go index 0c5f468..ed345bc 100644 --- a/pkg/platform/resource_scim_group.go +++ b/pkg/platform/resource_scim_group.go @@ -56,7 +56,7 @@ type SCIMGroupMemberAPIModel struct { Display string `json:"display"` } -func (r *SCIMGroupResourceModel) toAPIModel(ctx context.Context, apiModel *SCIMGroupAPIModel) (ds diag.Diagnostics) { +func (r *SCIMGroupResourceModel) toAPIModel(_ context.Context, apiModel *SCIMGroupAPIModel) (ds diag.Diagnostics) { apiModel.Schemas = []string{"urn:ietf:params:scim:schemas:core:2.0:Group"} apiModel.ID = r.ID.ValueString() @@ -83,7 +83,7 @@ var SCIMGroupMemberResourceModelAttributeType map[string]attr.Type = map[string] "display": types.StringType, } -func (r *SCIMGroupResourceModel) fromAPIModel(ctx context.Context, apiModel *SCIMGroupAPIModel) (ds diag.Diagnostics) { +func (r *SCIMGroupResourceModel) fromAPIModel(_ context.Context, apiModel *SCIMGroupAPIModel) (ds diag.Diagnostics) { r.ID = types.StringValue(apiModel.ID) r.DisplayName = types.StringValue(apiModel.DisplayName) diff --git a/pkg/platform/resource_scim_user.go b/pkg/platform/resource_scim_user.go index d38c248..b8740dd 100644 --- a/pkg/platform/resource_scim_user.go +++ b/pkg/platform/resource_scim_user.go @@ -46,7 +46,7 @@ type SCIMUserResourceModel struct { Meta types.Map `tfsdk:"meta"` } -func (r *SCIMUserResourceModel) toAPIModel(ctx context.Context, apiModel *SCIMUserAPIModel) (ds diag.Diagnostics) { +func (r *SCIMUserResourceModel) toAPIModel(_ context.Context, apiModel *SCIMUserAPIModel) (ds diag.Diagnostics) { apiModel.Schemas = []string{"urn:ietf:params:scim:schemas:core:2.0:User"} apiModel.Username = r.Username.ValueString() @@ -77,7 +77,7 @@ var SCIMUserGroupResourceModelAttributeType map[string]attr.Type = map[string]at "value": types.StringType, } -func (r *SCIMUserResourceModel) fromAPIModel(ctx context.Context, apiModel *SCIMUserAPIModel) (ds diag.Diagnostics) { +func (r *SCIMUserResourceModel) fromAPIModel(_ context.Context, apiModel *SCIMUserAPIModel) (ds diag.Diagnostics) { r.Username = types.StringValue(apiModel.Username) r.Active = types.BoolValue(apiModel.Active) From 1d86ee37ee0d309515e731fbaa0f776dfa355e1e Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 21 Aug 2024 09:09:30 -0700 Subject: [PATCH 3/9] Update Go version to 1.22 --- .github/workflows/acceptance-tests.yml | 2 +- .github/workflows/release.yml | 2 +- go.mod | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/acceptance-tests.yml b/.github/workflows/acceptance-tests.yml index 0ab4d31..e3ed8fa 100644 --- a/.github/workflows/acceptance-tests.yml +++ b/.github/workflows/acceptance-tests.yml @@ -31,7 +31,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: 1.21 + go-version: 1.22 - name: Install Helm uses: azure/setup-helm@v4.2.0 - name: Install Terraform CLI diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4e03151..7cc896b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -30,7 +30,7 @@ jobs: name: Set up Go uses: actions/setup-go@v3 with: - go-version: 1.21 + go-version: 1.22 - name: Import GPG key id: import_gpg diff --git a/go.mod b/go.mod index 6088d38..43e22ca 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/jfrog/terraform-provider-platform // if you need to do local dev, literally just uncomment the line below // replace github.com/jfrog/terraform-provider-shared => ../terraform-provider-shared -go 1.21.5 +go 1.22.5 require ( github.com/go-resty/resty/v2 v2.14.0 From 9fe20a46b77efe0b955f86feccd8c0d9dce8d7d6 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 21 Aug 2024 09:13:42 -0700 Subject: [PATCH 4/9] Update TF OIDC doc --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index ed2e2d9..fe3b951 100644 --- a/docs/index.md +++ b/docs/index.md @@ -126,7 +126,7 @@ During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` Follow [confgure an OIDC integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration). Enter a name for the provider, e.g. `terraform-cloud`. Use `https://app.terraform.io` for "Provider URL". Choose your own value for "Audience", e.g. `jfrog-terraform-cloud`. -Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with an empty "Claims JSON" (`{}`), and select the "Token scope", "User", and "Service" as desired. +Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with appropriate "Claims JSON" (e.g. `aud`, `sub`, `terraform_organization_id`, `terraform_workspace_id`, `terraform_run_phase`. See [Terraform Workload Identity Token Specification](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/workload-identity-tokens#token-specification)), and select the "Token scope", "User", and "Service" as desired. #### Set environment variable in your Terraform Workspace From c2cd0f929167f76aa152b834500e14b8259c07be Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 21 Aug 2024 09:28:08 -0700 Subject: [PATCH 5/9] Update doc link --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index fe3b951..e4d424c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -126,7 +126,7 @@ During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` Follow [confgure an OIDC integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration). Enter a name for the provider, e.g. `terraform-cloud`. Use `https://app.terraform.io` for "Provider URL". Choose your own value for "Audience", e.g. `jfrog-terraform-cloud`. -Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with appropriate "Claims JSON" (e.g. `aud`, `sub`, `terraform_organization_id`, `terraform_workspace_id`, `terraform_run_phase`. See [Terraform Workload Identity Token Specification](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/workload-identity-tokens#token-specification)), and select the "Token scope", "User", and "Service" as desired. +Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with appropriate "Claims JSON" (e.g. `aud`, `sub` at minimum. See [Terraform Workload Identity - Configuring Trust with your Cloud Platform](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/workload-identity-tokens#configuring-trust-with-your-cloud-platform)), and select the "Token scope", "User", and "Service" as desired. #### Set environment variable in your Terraform Workspace From 3dbf7da2156f6908dbbda30b7f3818379ecbe33d Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 11 Sep 2024 09:53:43 -0700 Subject: [PATCH 6/9] Add version check Update doc with version limitation --- docs/resources/aws_iam_role.md | 3 +++ pkg/platform/resource_aws_iam_role.go | 21 ++++++++++++++++++++- pkg/platform/resource_aws_iam_role_test.go | 2 +- templates/index.md.tmpl | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/docs/resources/aws_iam_role.md b/docs/resources/aws_iam_role.md index e61f958..b1f644c 100644 --- a/docs/resources/aws_iam_role.md +++ b/docs/resources/aws_iam_role.md @@ -4,12 +4,15 @@ page_title: "platform_aws_iam_role Resource - terraform-provider-platform" subcategory: "" description: |- Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see Passwordless Access for Amazon EKS https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks. + ->Only available for Artifactory 7.90.10 or later. --- # platform_aws_iam_role (Resource) Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see [Passwordless Access for Amazon EKS](https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks). +->Only available for Artifactory 7.90.10 or later. + ## Example Usage ```terraform diff --git a/pkg/platform/resource_aws_iam_role.go b/pkg/platform/resource_aws_iam_role.go index a9f1b0d..348bfa6 100644 --- a/pkg/platform/resource_aws_iam_role.go +++ b/pkg/platform/resource_aws_iam_role.go @@ -2,6 +2,7 @@ package platform import ( "context" + "fmt" "net/http" "regexp" @@ -68,7 +69,8 @@ func (r *AWSIAMRoleResource) Schema(ctx context.Context, req resource.SchemaRequ MarkdownDescription: "The AWS IAM role. Must follow the regex, \"^arn:aws:iam::\\d{12}:role/[\\w+=,.@:-]+$\"", }, }, - MarkdownDescription: "Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see [Passwordless Access for Amazon EKS](https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks).", + MarkdownDescription: "Provides a resource to manage AWS IAM roles for JFrog platform users. You can use the AWS IAM roles for passwordless access to Amazon EKS. For more information, see [Passwordless Access for Amazon EKS](https://jfrog.com/help/r/jfrog-installation-setup-documentation/passwordless-access-for-amazon-eks).\n\n" + + "->Only available for Artifactory 7.90.10 or later.", } } @@ -78,6 +80,23 @@ func (r *AWSIAMRoleResource) Configure(ctx context.Context, req resource.Configu return } r.ProviderData = req.ProviderData.(PlatformProviderMetadata) + + supported, err := util.CheckVersion(r.ProviderData.ArtifactoryVersion, "7.90.10") + if err != nil { + resp.Diagnostics.AddError( + "Failed to check Artifactory version", + err.Error(), + ) + return + } + + if !supported { + resp.Diagnostics.AddError( + "Unsupported Artifactory version", + fmt.Sprintf("This resource is supported by Artifactory version 7.90.10 or later. Current version: %s", r.ProviderData.ArtifactoryVersion), + ) + return + } } func (r *AWSIAMRoleResource) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { diff --git a/pkg/platform/resource_aws_iam_role_test.go b/pkg/platform/resource_aws_iam_role_test.go index 6b64aa8..b407cd6 100644 --- a/pkg/platform/resource_aws_iam_role_test.go +++ b/pkg/platform/resource_aws_iam_role_test.go @@ -102,7 +102,7 @@ func testAccAWSIAMRoleDestroy(id string) func(*terraform.State) error { return err } - if resp != nil && resp.StatusCode() == http.StatusNotFound { + if resp != nil && resp.StatusCode() == http.StatusBadRequest { return nil } diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index 7db41c1..fa4809e 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -61,7 +61,7 @@ During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` Follow [confgure an OIDC integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration). Enter a name for the provider, e.g. `terraform-cloud`. Use `https://app.terraform.io` for "Provider URL". Choose your own value for "Audience", e.g. `jfrog-terraform-cloud`. -Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with an empty "Claims JSON" (`{}`), and select the "Token scope", "User", and "Service" as desired. +Then [configure an identity mapping](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-identity-mappings) with appropriate "Claims JSON" (e.g. `aud`, `sub` at minimum. See [Terraform Workload Identity - Configuring Trust with your Cloud Platform](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/workload-identity-tokens#configuring-trust-with-your-cloud-platform)), and select the "Token scope", "User", and "Service" as desired. #### Set environment variable in your Terraform Workspace From 7767e2795dd4a49f011e6cee69cf97541ae78c27 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Wed, 11 Sep 2024 09:55:51 -0700 Subject: [PATCH 7/9] Update CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9347888..a9bd2e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +## 1.12.0 (September 12, 2024) + +FEATURES: + +**New Resource:** +* `platform_aws_iam_role` - Resource to manage AWS IAM role. PR: [#125](https://github.com/jfrog/terraform-provider-platform/pull/125) + ## 1.11.1 (September 9, 2024). Tested on Artifactory 7.90.9 with Terraform 1.9.5 and OpenTofu 1.8.2 IMPROVEMENTS: From ab99cc5cfa521b0cc7572b7621d93539d39db7e1 Mon Sep 17 00:00:00 2001 From: JFrog CI Date: Wed, 11 Sep 2024 17:01:04 +0000 Subject: [PATCH 8/9] JFrog Pipelines - Add Artifactory version to CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9bd2e1..dad757d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.12.0 (September 12, 2024) +## 1.12.0 (September 12, 2024). Tested on Artifactory 7.90.10 with Terraform 1.9.5 and OpenTofu 1.8.2 FEATURES: From 20e6e2a99b35b847cb106e1ce7713da5e331bcf3 Mon Sep 17 00:00:00 2001 From: Alex Hung Date: Thu, 12 Sep 2024 12:50:27 -0700 Subject: [PATCH 9/9] Update CHANGELOG --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dad757d..b77df27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.12.0 (September 12, 2024). Tested on Artifactory 7.90.10 with Terraform 1.9.5 and OpenTofu 1.8.2 +## 1.12.0 (September 13, 2024). Tested on Artifactory 7.90.10 with Terraform 1.9.5 and OpenTofu 1.8.2 FEATURES: