diff --git a/docs/index.md b/docs/index.md index ee41d38..f7438d0 100644 --- a/docs/index.md +++ b/docs/index.md @@ -94,7 +94,7 @@ To setup dynamic credentials, follow these steps: 2. Set environment variable in your Terraform Workspace 3. Setup Terraform Cloud in your configuration -During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` it will use this token with your JFrog instance to exchange for a short-live access token. If that is successful, the provider will the access token for all subsequent API requests with the JFrog instance. +During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` it will use this token with your JFrog instance to exchange for a short-live access token. If that is successful, the provider will use the access token for all subsequent API requests with the JFrog instance. #### Configure Terraform Cloud as generic OIDC provider @@ -108,6 +108,8 @@ In your workspace, add an environment variable `TFC_WORKLOAD_IDENTITY_AUDIENCE` When a run starts on Terraform Cloud, it will create a workload identity token with the specified audience and assigns it to the environment variable `TFC_WORKLOAD_IDENTITY_TOKEN` for the provider to consume. +See [Generating Multiple Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation#generating-multiple-tokens) on HCP Terraform for more details on using different tokens. + #### Setup Terraform Cloud in your configuration Add `cloud` block to `terraform` block, and add `oidc_provider_name` attribute (from JFrog OIDC integration) to provider block: @@ -132,6 +134,7 @@ terraform { provider "platform" { url = "https://myinstance.jfrog.io" oidc_provider_name = "terraform-cloud" + tfc_credential_tag_name = "JFROG" } ``` @@ -144,4 +147,5 @@ provider "platform" { - `access_token` (String, Sensitive) This is a access token that can be given to you by your admin under `Platform Configuration -> User Management -> Access Tokens`. This can also be sourced from the `JFROG_ACCESS_TOKEN` environment variable. - `oidc_provider_name` (String) OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details. +- `tfc_credential_tag_name` (String) Terraform Cloud Workload Identity Token tag name. Use for generating multiple TFC workload identity tokens. When set, the provider will attempt to use env var with this tag name as suffix. **Note:** this is case sensitive, so if set to `JFROG`, then env var `TFC_WORKLOAD_IDENTITY_TOKEN_JFROG` is used instead of `TFC_WORKLOAD_IDENTITY_TOKEN`. See [Generating Multiple Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation#generating-multiple-tokens) on HCP Terraform for more details. - `url` (String) JFrog Platform URL. This can also be sourced from the `JFROG_URL` environment variable. \ No newline at end of file diff --git a/go.mod b/go.mod index 0c89f94..7e7d9be 100644 --- a/go.mod +++ b/go.mod @@ -1,10 +1,16 @@ module github.com/jfrog/terraform-provider-distribution -go 1.22.5 +go 1.22.7 require ( github.com/hashicorp/terraform-plugin-docs v0.19.4 + github.com/hashicorp/terraform-plugin-framework v1.12.0 github.com/hashicorp/terraform-plugin-framework-validators v0.13.0 + github.com/hashicorp/terraform-plugin-go v0.24.0 + github.com/hashicorp/terraform-plugin-log v0.9.0 + github.com/hashicorp/terraform-plugin-testing v1.10.0 + github.com/jfrog/terraform-provider-shared v1.26.0 + github.com/samber/lo v1.47.0 ) require ( @@ -20,7 +26,8 @@ require ( github.com/bgentry/speakeasy v0.1.0 // indirect github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect github.com/cloudflare/circl v1.3.7 // indirect - github.com/go-resty/resty/v2 v2.15.0 // indirect + github.com/fatih/color v1.16.0 // indirect + github.com/go-resty/resty/v2 v2.15.3 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -30,6 +37,7 @@ require ( github.com/hashicorp/go-checkpoint v0.5.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect + github.com/hashicorp/go-hclog v1.6.3 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/hashicorp/go-plugin v1.6.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.7 // indirect @@ -46,8 +54,11 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.15 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect @@ -56,6 +67,8 @@ require ( github.com/shopspring/decimal v1.3.1 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect + github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/yuin/goldmark v1.7.1 // indirect github.com/yuin/goldmark-meta v1.1.0 // indirect github.com/zclconf/go-cty v1.15.0 // indirect @@ -65,6 +78,7 @@ require ( golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/sync v0.8.0 // indirect + golang.org/x/sys v0.23.0 // indirect golang.org/x/text v0.17.0 // indirect golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect google.golang.org/appengine v1.6.8 // indirect @@ -74,20 +88,3 @@ require ( gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) - -require ( - github.com/fatih/color v1.16.0 // indirect - github.com/hashicorp/go-hclog v1.6.3 // indirect - github.com/hashicorp/terraform-plugin-framework v1.12.0 - github.com/hashicorp/terraform-plugin-go v0.24.0 - github.com/hashicorp/terraform-plugin-log v0.9.0 - github.com/hashicorp/terraform-plugin-testing v1.10.0 - github.com/jfrog/terraform-provider-shared v1.25.5 - github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.20 // indirect - github.com/mitchellh/go-testing-interface v1.14.1 // indirect - github.com/samber/lo v1.47.0 - github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect - github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect - golang.org/x/sys v0.23.0 // indirect -) diff --git a/go.sum b/go.sum index e8e19f7..4ea69fd 100644 --- a/go.sum +++ b/go.sum @@ -47,8 +47,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+ github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= -github.com/go-resty/resty/v2 v2.15.0 h1:clPQLZ2x9h4yGY81IzpMPnty+xoGyFaDg0XMkCsHf90= -github.com/go-resty/resty/v2 v2.15.0/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= +github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8= +github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= @@ -130,8 +130,8 @@ github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM= github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= -github.com/jfrog/terraform-provider-shared v1.25.5 h1:+hal/9yDAIt2mZljDR8Ymie28yAHr8CAkfthwQ3O3bM= -github.com/jfrog/terraform-provider-shared v1.25.5/go.mod h1:QthwPRUALElMt2RTGqoeB/3Vztx626YPBzIAoqEp0w0= +github.com/jfrog/terraform-provider-shared v1.26.0 h1:xfJfKcgejlFkIyo6VLJPzNtEVfbTYIiGKD2PWysdgw4= +github.com/jfrog/terraform-provider-shared v1.26.0/go.mod h1:IPwXN48K3uzJNDmT2x6zFGa5IS0KG2AK7jnQR2H4G1A= github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c= github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= diff --git a/pkg/distribution/provider.go b/pkg/distribution/provider.go index c23e5ab..9244449 100644 --- a/pkg/distribution/provider.go +++ b/pkg/distribution/provider.go @@ -28,9 +28,10 @@ type DistributionProvider struct { } type distributionProviderModel struct { - Url types.String `tfsdk:"url"` - AccessToken types.String `tfsdk:"access_token"` - OIDCProviderName types.String `tfsdk:"oidc_provider_name"` + Url types.String `tfsdk:"url"` + AccessToken types.String `tfsdk:"access_token"` + OIDCProviderName types.String `tfsdk:"oidc_provider_name"` + TFCCredentialTagName types.String `tfsdk:"tfc_credential_tag_name"` } func NewProvider() func() provider.Provider { @@ -73,19 +74,22 @@ func (p *DistributionProvider) Configure(ctx context.Context, req provider.Confi return } - oidcAccessToken, err := util.OIDCTokenExchange(ctx, platformClient, config.OIDCProviderName.ValueString()) - if err != nil { - resp.Diagnostics.AddError( - "Failed OIDC ID token exchange", - err.Error(), - ) - return - } - - // use token from OIDC provider, which should take precedence over - // environment variable data, if found. - if oidcAccessToken != "" { - accessToken = oidcAccessToken + oidcProviderName := config.OIDCProviderName.ValueString() + if oidcProviderName != "" { + oidcAccessToken, err := util.OIDCTokenExchange(ctx, platformClient, oidcProviderName, config.TFCCredentialTagName.ValueString()) + if err != nil { + resp.Diagnostics.AddError( + "Failed OIDC ID token exchange", + err.Error(), + ) + return + } + + // use token from OIDC provider, which should take precedence over + // environment variable data, if found. + if oidcAccessToken != "" { + accessToken = oidcAccessToken + } } // use token from configuration, which should take precedence over @@ -178,6 +182,13 @@ func (p *DistributionProvider) Schema(ctx context.Context, req provider.SchemaRe }, MarkdownDescription: "OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details.", }, + "tfc_credential_tag_name": schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthAtLeast(1), + }, + Description: "Terraform Cloud Workload Identity Token tag name. Use for generating multiple TFC workload identity tokens. When set, the provider will attempt to use env var with this tag name as suffix. **Note:** this is case sensitive, so if set to `JFROG`, then env var `TFC_WORKLOAD_IDENTITY_TOKEN_JFROG` is used instead of `TFC_WORKLOAD_IDENTITY_TOKEN`. See [Generating Multiple Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation#generating-multiple-tokens) on HCP Terraform for more details.", + }, }, } } diff --git a/templates/index.md.tmpl b/templates/index.md.tmpl index dc17e2f..649793a 100644 --- a/templates/index.md.tmpl +++ b/templates/index.md.tmpl @@ -42,7 +42,7 @@ To setup dynamic credentials, follow these steps: 2. Set environment variable in your Terraform Workspace 3. Setup Terraform Cloud in your configuration -During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` it will use this token with your JFrog instance to exchange for a short-live access token. If that is successful, the provider will the access token for all subsequent API requests with the JFrog instance. +During the provider start up, if it finds env var `TFC_WORKLOAD_IDENTITY_TOKEN` it will use this token with your JFrog instance to exchange for a short-live access token. If that is successful, the provider will use the access token for all subsequent API requests with the JFrog instance. #### Configure Terraform Cloud as generic OIDC provider @@ -56,6 +56,8 @@ In your workspace, add an environment variable `TFC_WORKLOAD_IDENTITY_AUDIENCE` When a run starts on Terraform Cloud, it will create a workload identity token with the specified audience and assigns it to the environment variable `TFC_WORKLOAD_IDENTITY_TOKEN` for the provider to consume. +See [Generating Multiple Tokens](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation#generating-multiple-tokens) on HCP Terraform for more details on using different tokens. + #### Setup Terraform Cloud in your configuration Add `cloud` block to `terraform` block, and add `oidc_provider_name` attribute (from JFrog OIDC integration) to provider block: @@ -80,6 +82,7 @@ terraform { provider "platform" { url = "https://myinstance.jfrog.io" oidc_provider_name = "terraform-cloud" + tfc_credential_tag_name = "JFROG" } ```