Skip to content

Commit

Permalink
Merge pull request #139 from jfrog/add-multiple-tfc-workload-identity…
Browse files Browse the repository at this point in the history
…-tokens-support

Add multiple tfc workload identity tokens support
  • Loading branch information
alexhung authored Oct 16, 2024
2 parents 81c8caa + 480ef5b commit d47d191
Show file tree
Hide file tree
Showing 8 changed files with 53 additions and 25 deletions.
3 changes: 0 additions & 3 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@ before:
- go mod tidy
builds:
- env:
# goreleaser does not work with CGO, it could also complicate
# usage by users in CI/CD systems like Terraform Cloud where
# they are unable to install libraries.
- CGO_ENABLED=0
mod_timestamp: '{{ .CommitTimestamp }}'
flags:
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 1.15.0 (October 16, 2024). Tested on Artifactory 7.90.14 with Terraform 1.9.7 and OpenTofu 1.8.3

IMPROVEMENTS:

* 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: [#139](https://github.com/jfrog/terraform-provider-platform/pull/139)

## 1.14.0 (October 11, 2024). Tested on Artifactory 7.90.14 with Terraform 1.9.7 and OpenTofu 1.8.3

IMPROVEMENTS:
Expand Down
9 changes: 8 additions & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ PRODUCT=platform
GO_ARCH=$(shell go env GOARCH)
TARGET_ARCH=$(shell go env GOOS)_${GO_ARCH}
GORELEASER_ARCH=${TARGET_ARCH}
LINUX_GORELEASER_ARCH=linux_${GO_ARCH}

ifeq ($(GO_ARCH), amd64)
GORELEASER_ARCH=${TARGET_ARCH}_$(shell go env GOAMD64)
LINUX_GORELEASER_ARCH:=${LINUX_GORELEASER_ARCH}_$(shell go env GOAMD64)
endif

PKG_NAME=pkg/${PRODUCT}
Expand All @@ -25,6 +27,7 @@ TF_ACC_PROVIDER_HOST="registry.opentofu.org"
endif

BUILD_PATH=terraform.d/plugins/${REGISTRY_HOST}/jfrog/${PRODUCT}/${NEXT_VERSION}/${TARGET_ARCH}
LINUX_BUILD_PATH=terraform.d/plugins/${REGISTRY_HOST}/jfrog/${PRODUCT}/${NEXT_VERSION}/linux_amd64

SONAR_SCANNER_VERSION?=4.7.0.2747
SONAR_SCANNER_HOME?=${HOME}/.sonar/sonar-scanner-${SONAR_SCANNER_VERSION}-macosx
Expand All @@ -34,11 +37,15 @@ default: build
install: clean build
rm -fR .terraform.d && \
mkdir -p ${BUILD_PATH} && \
mkdir -p ${LINUX_BUILD_PATH} && \
mv -v dist/terraform-provider-${PRODUCT}_${GORELEASER_ARCH}/terraform-provider-${PRODUCT}_v${NEXT_VERSION}* ${BUILD_PATH} && \
rm -f .terraform.lock.hcl && \
sed -i.bak '0,/version = ".*"/s//version = "${NEXT_VERSION}"/' sample.tf && rm sample.tf.bak && \
${TERRAFORM_CLI} init

# move this line up when testing on TFC
# mv -v dist/terraform-provider-${PRODUCT}_${LINUX_GORELEASER_ARCH}/terraform-provider-${PRODUCT}_v${NEXT_PROVIDER_VERSION}* ${LINUX_BUILD_PATH} && \
clean:
rm -fR dist terraform.d/ .terraform terraform.tfstate* .terraform.lock.hcl

Expand All @@ -52,7 +59,7 @@ update_pkg_cache:
GOPROXY=https://proxy.golang.org GO111MODULE=on go get github.com/jfrog/terraform-provider-${PRODUCT}@v${VERSION}

build: fmt
GORELEASER_CURRENT_TAG=${NEXT_VERSION} goreleaser build --single-target --clean --snapshot
GORELEASER_CURRENT_TAG=${NEXT_VERSION} goreleaser build --clean --snapshot # --single-target

test:
@echo "==> Starting unit tests"
Expand Down
4 changes: 4 additions & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,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 @@ -158,6 +160,7 @@ terraform {
provider "platform" {
url = "https://myinstance.jfrog.io"
oidc_provider_name = "terraform-cloud"
tfc_credential_tag_name = "JFROG"
}
```

Expand All @@ -172,4 +175,5 @@ provider "platform" {
- `check_license` (Boolean, Deprecated) Toggle for pre-flight checking of Artifactory Pro and Enterprise license. Default to `true`.
- `myjfrog_api_token` (String, Sensitive, Deprecated) MyJFrog API token that allows you to make changes to your JFrog account. See [Generate a Token in MyJFrog](https://jfrog.com/help/r/jfrog-hosting-models-documentation/generate-a-token-in-myjfrog) for more details. This can also be sourced from the `JFROG_MYJFROG_API_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.
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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.22.5
go 1.22.7

require (
github.com/go-resty/resty/v2 v2.15.3
Expand All @@ -12,7 +12,7 @@ require (
github.com/hashicorp/terraform-plugin-framework-validators v0.13.0
github.com/hashicorp/terraform-plugin-go v0.24.0
github.com/hashicorp/terraform-plugin-testing v1.10.0
github.com/jfrog/terraform-provider-shared v1.25.5
github.com/jfrog/terraform-provider-shared v1.26.0
github.com/samber/lo v1.47.0
)

Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
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
45 changes: 28 additions & 17 deletions pkg/platform/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ type PlatformProvider struct {
}

type platformProviderModel struct {
Url types.String `tfsdk:"url"`
AccessToken types.String `tfsdk:"access_token"`
MyJFrogAPIToken types.String `tfsdk:"myjfrog_api_token"`
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
CheckLicense types.Bool `tfsdk:"check_license"`
Url types.String `tfsdk:"url"`
AccessToken types.String `tfsdk:"access_token"`
MyJFrogAPIToken types.String `tfsdk:"myjfrog_api_token"`
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
TFCCredentialTagName types.String `tfsdk:"tfc_credential_tag_name"`
CheckLicense types.Bool `tfsdk:"check_license"`
}

func NewProvider() func() provider.Provider {
Expand Down Expand Up @@ -81,19 +82,22 @@ func (p *PlatformProvider) Configure(ctx context.Context, req provider.Configure
return
}

oidcAccessToken, err := util.OIDCTokenExchange(ctx, platformClient, config.OIDCProviderName.ValueString())
if err != nil {
resp.Diagnostics.AddError(
"Failed OIDC ID token exchange",
err.Error(),
)
return
}
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 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 @@ -254,6 +258,13 @@ func (p *PlatformProvider) Schema(ctx context.Context, req provider.SchemaReques
},
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.",
},
"check_license": schema.BoolAttribute{
Optional: true,
MarkdownDescription: "Toggle for pre-flight checking of Artifactory Pro and Enterprise license. Default to `true`.",
Expand Down
3 changes: 3 additions & 0 deletions templates/index.md.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,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 @@ -93,6 +95,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 d47d191

Please sign in to comment.