Skip to content

Commit

Permalink
Add 'tfc_credential_tag_name' config attribute
Browse files Browse the repository at this point in the history
To support multiple TFC Workload Identity Tokens
  • Loading branch information
alexhung committed Oct 17, 2024
1 parent 1625f35 commit 02b23b1
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 41 deletions.
6 changes: 5 additions & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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:
Expand All @@ -132,6 +134,7 @@ terraform {
provider "platform" {
url = "https://myinstance.jfrog.io"
oidc_provider_name = "terraform-cloud"
tfc_credential_tag_name = "JFROG"
}
```

Expand All @@ -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.
35 changes: 16 additions & 19 deletions go.mod
Original file line number Diff line number Diff line change
@@ -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 (
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
)
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
43 changes: 27 additions & 16 deletions pkg/distribution/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.",
},
},
}
}
5 changes: 4 additions & 1 deletion templates/index.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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:
Expand All @@ -80,6 +82,7 @@ terraform {
provider "platform" {
url = "https://myinstance.jfrog.io"
oidc_provider_name = "terraform-cloud"
tfc_credential_tag_name = "JFROG"
}
```

Expand Down

0 comments on commit 02b23b1

Please sign in to comment.