Skip to content

Commit 44d3881

Browse files
author
Alex Hung
authored
Merge pull request #11 from jfrog/add-multiple-tfc-workload-identity-tokens-support
Add 'tfc_credential_tag_name' config attribute
2 parents 1625f35 + bbde75b commit 44d3881

File tree

6 files changed

+60
-41
lines changed

6 files changed

+60
-41
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 1.2.0 (October 17, 2024). Tested on Artifactory 7.95.0 with Terraform 1.9.8 and OpenTofu 1.8.3
2+
3+
* provider: Add `tfc_credential_tag_name` configuration attribute to support use of different/[multiple Workload Identity Token in Terraform Cloud Platform](https://developer.hashicorp.com/terraform/cloud-docs/workspaces/dynamic-provider-credentials/manual-generation#generating-multiple-tokens). Issue: [#68](https://github.com/jfrog/terraform-provider-shared/issues/68) PR: [#11](https://github.com/jfrog/terraform-provider-distribution/pull/11)
4+
15
## 1.1.0 (September 4, 2024). Tested on Artifactory 7.94.1 with Terraform 1.9.5 and OpenTofu 1.8.1
26

37
FEATURES:

docs/index.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ To setup dynamic credentials, follow these steps:
9494
2. Set environment variable in your Terraform Workspace
9595
3. Setup Terraform Cloud in your configuration
9696

97-
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.
97+
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.
9898

9999
#### Configure Terraform Cloud as generic OIDC provider
100100

@@ -108,6 +108,8 @@ In your workspace, add an environment variable `TFC_WORKLOAD_IDENTITY_AUDIENCE`
108108

109109
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.
110110

111+
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.
112+
111113
#### Setup Terraform Cloud in your configuration
112114

113115
Add `cloud` block to `terraform` block, and add `oidc_provider_name` attribute (from JFrog OIDC integration) to provider block:
@@ -132,6 +134,7 @@ terraform {
132134
provider "platform" {
133135
url = "https://myinstance.jfrog.io"
134136
oidc_provider_name = "terraform-cloud"
137+
tfc_credential_tag_name = "JFROG"
135138
}
136139
```
137140

@@ -144,4 +147,5 @@ provider "platform" {
144147

145148
- `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.
146149
- `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.
150+
- `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.
147151
- `url` (String) JFrog Platform URL. This can also be sourced from the `JFROG_URL` environment variable.

go.mod

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
module github.com/jfrog/terraform-provider-distribution
22

3-
go 1.22.5
3+
go 1.22.7
44

55
require (
66
github.com/hashicorp/terraform-plugin-docs v0.19.4
7+
github.com/hashicorp/terraform-plugin-framework v1.12.0
78
github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
9+
github.com/hashicorp/terraform-plugin-go v0.24.0
10+
github.com/hashicorp/terraform-plugin-log v0.9.0
11+
github.com/hashicorp/terraform-plugin-testing v1.10.0
12+
github.com/jfrog/terraform-provider-shared v1.26.0
13+
github.com/samber/lo v1.47.0
814
)
915

1016
require (
@@ -20,7 +26,8 @@ require (
2026
github.com/bgentry/speakeasy v0.1.0 // indirect
2127
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
2228
github.com/cloudflare/circl v1.3.7 // indirect
23-
github.com/go-resty/resty/v2 v2.15.0 // indirect
29+
github.com/fatih/color v1.16.0 // indirect
30+
github.com/go-resty/resty/v2 v2.15.3 // indirect
2431
github.com/golang/protobuf v1.5.4 // indirect
2532
github.com/google/go-cmp v0.6.0 // indirect
2633
github.com/google/uuid v1.6.0 // indirect
@@ -30,6 +37,7 @@ require (
3037
github.com/hashicorp/go-checkpoint v0.5.0 // indirect
3138
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
3239
github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect
40+
github.com/hashicorp/go-hclog v1.6.3 // indirect
3341
github.com/hashicorp/go-multierror v1.1.1 // indirect
3442
github.com/hashicorp/go-plugin v1.6.1 // indirect
3543
github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
@@ -46,8 +54,11 @@ require (
4654
github.com/hashicorp/yamux v0.1.1 // indirect
4755
github.com/huandu/xstrings v1.3.3 // indirect
4856
github.com/imdario/mergo v0.3.15 // indirect
57+
github.com/mattn/go-colorable v0.1.13 // indirect
58+
github.com/mattn/go-isatty v0.0.20 // indirect
4959
github.com/mattn/go-runewidth v0.0.9 // indirect
5060
github.com/mitchellh/copystructure v1.2.0 // indirect
61+
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
5162
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
5263
github.com/mitchellh/mapstructure v1.5.0 // indirect
5364
github.com/mitchellh/reflectwalk v1.0.2 // indirect
@@ -56,6 +67,8 @@ require (
5667
github.com/shopspring/decimal v1.3.1 // indirect
5768
github.com/spf13/cast v1.5.0 // indirect
5869
github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect
70+
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
71+
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
5972
github.com/yuin/goldmark v1.7.1 // indirect
6073
github.com/yuin/goldmark-meta v1.1.0 // indirect
6174
github.com/zclconf/go-cty v1.15.0 // indirect
@@ -65,6 +78,7 @@ require (
6578
golang.org/x/mod v0.19.0 // indirect
6679
golang.org/x/net v0.27.0 // indirect
6780
golang.org/x/sync v0.8.0 // indirect
81+
golang.org/x/sys v0.23.0 // indirect
6882
golang.org/x/text v0.17.0 // indirect
6983
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
7084
google.golang.org/appengine v1.6.8 // indirect
@@ -74,20 +88,3 @@ require (
7488
gopkg.in/yaml.v2 v2.3.0 // indirect
7589
gopkg.in/yaml.v3 v3.0.1 // indirect
7690
)
77-
78-
require (
79-
github.com/fatih/color v1.16.0 // indirect
80-
github.com/hashicorp/go-hclog v1.6.3 // indirect
81-
github.com/hashicorp/terraform-plugin-framework v1.12.0
82-
github.com/hashicorp/terraform-plugin-go v0.24.0
83-
github.com/hashicorp/terraform-plugin-log v0.9.0
84-
github.com/hashicorp/terraform-plugin-testing v1.10.0
85-
github.com/jfrog/terraform-provider-shared v1.25.5
86-
github.com/mattn/go-colorable v0.1.13 // indirect
87-
github.com/mattn/go-isatty v0.0.20 // indirect
88-
github.com/mitchellh/go-testing-interface v1.14.1 // indirect
89-
github.com/samber/lo v1.47.0
90-
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
91-
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
92-
golang.org/x/sys v0.23.0 // indirect
93-
)

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+
4747
github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
4848
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
4949
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
50-
github.com/go-resty/resty/v2 v2.15.0 h1:clPQLZ2x9h4yGY81IzpMPnty+xoGyFaDg0XMkCsHf90=
51-
github.com/go-resty/resty/v2 v2.15.0/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
50+
github.com/go-resty/resty/v2 v2.15.3 h1:bqff+hcqAflpiF591hhJzNdkRsFhlB96CYfBwSFvql8=
51+
github.com/go-resty/resty/v2 v2.15.3/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
5252
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68=
5353
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
5454
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=
130130
github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
131131
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
132132
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
133-
github.com/jfrog/terraform-provider-shared v1.25.5 h1:+hal/9yDAIt2mZljDR8Ymie28yAHr8CAkfthwQ3O3bM=
134-
github.com/jfrog/terraform-provider-shared v1.25.5/go.mod h1:QthwPRUALElMt2RTGqoeB/3Vztx626YPBzIAoqEp0w0=
133+
github.com/jfrog/terraform-provider-shared v1.26.0 h1:xfJfKcgejlFkIyo6VLJPzNtEVfbTYIiGKD2PWysdgw4=
134+
github.com/jfrog/terraform-provider-shared v1.26.0/go.mod h1:IPwXN48K3uzJNDmT2x6zFGa5IS0KG2AK7jnQR2H4G1A=
135135
github.com/jhump/protoreflect v1.15.1 h1:HUMERORf3I3ZdX05WaQ6MIpd/NJ434hTp5YiKgfCL6c=
136136
github.com/jhump/protoreflect v1.15.1/go.mod h1:jD/2GMKKE6OqX8qTjhADU1e6DShO+gavG9e0Q693nKo=
137137
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=

pkg/distribution/provider.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ type DistributionProvider struct {
2828
}
2929

3030
type distributionProviderModel struct {
31-
Url types.String `tfsdk:"url"`
32-
AccessToken types.String `tfsdk:"access_token"`
33-
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
31+
Url types.String `tfsdk:"url"`
32+
AccessToken types.String `tfsdk:"access_token"`
33+
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
34+
TFCCredentialTagName types.String `tfsdk:"tfc_credential_tag_name"`
3435
}
3536

3637
func NewProvider() func() provider.Provider {
@@ -73,19 +74,22 @@ func (p *DistributionProvider) Configure(ctx context.Context, req provider.Confi
7374
return
7475
}
7576

76-
oidcAccessToken, err := util.OIDCTokenExchange(ctx, platformClient, config.OIDCProviderName.ValueString())
77-
if err != nil {
78-
resp.Diagnostics.AddError(
79-
"Failed OIDC ID token exchange",
80-
err.Error(),
81-
)
82-
return
83-
}
84-
85-
// use token from OIDC provider, which should take precedence over
86-
// environment variable data, if found.
87-
if oidcAccessToken != "" {
88-
accessToken = oidcAccessToken
77+
oidcProviderName := config.OIDCProviderName.ValueString()
78+
if oidcProviderName != "" {
79+
oidcAccessToken, err := util.OIDCTokenExchange(ctx, platformClient, oidcProviderName, config.TFCCredentialTagName.ValueString())
80+
if err != nil {
81+
resp.Diagnostics.AddError(
82+
"Failed OIDC ID token exchange",
83+
err.Error(),
84+
)
85+
return
86+
}
87+
88+
// use token from OIDC provider, which should take precedence over
89+
// environment variable data, if found.
90+
if oidcAccessToken != "" {
91+
accessToken = oidcAccessToken
92+
}
8993
}
9094

9195
// use token from configuration, which should take precedence over
@@ -178,6 +182,13 @@ func (p *DistributionProvider) Schema(ctx context.Context, req provider.SchemaRe
178182
},
179183
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.",
180184
},
185+
"tfc_credential_tag_name": schema.StringAttribute{
186+
Optional: true,
187+
Validators: []validator.String{
188+
stringvalidator.LengthAtLeast(1),
189+
},
190+
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.",
191+
},
181192
},
182193
}
183194
}

templates/index.md.tmpl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ To setup dynamic credentials, follow these steps:
4242
2. Set environment variable in your Terraform Workspace
4343
3. Setup Terraform Cloud in your configuration
4444

45-
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.
45+
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.
4646

4747
#### Configure Terraform Cloud as generic OIDC provider
4848

@@ -56,6 +56,8 @@ In your workspace, add an environment variable `TFC_WORKLOAD_IDENTITY_AUDIENCE`
5656

5757
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.
5858

59+
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.
60+
5961
#### Setup Terraform Cloud in your configuration
6062

6163
Add `cloud` block to `terraform` block, and add `oidc_provider_name` attribute (from JFrog OIDC integration) to provider block:
@@ -80,6 +82,7 @@ terraform {
8082
provider "platform" {
8183
url = "https://myinstance.jfrog.io"
8284
oidc_provider_name = "terraform-cloud"
85+
tfc_credential_tag_name = "JFROG"
8386
}
8487
```
8588

0 commit comments

Comments
 (0)