Skip to content

Commit

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

Add 'tfc_credential_tag_name' config attribute
  • Loading branch information
alexhung authored Oct 16, 2024
2 parents c5ea5ae + 51fea4d commit 5790af2
Show file tree
Hide file tree
Showing 8 changed files with 56 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 @@
## 12.3.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: [#1097](https://github.com/jfrog/terraform-provider-artifactory/pull/1097)

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

IMPROVEMENTS:
Expand Down
10 changes: 9 additions & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@ PRODUCT=artifactory
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/artifactory
# if this path ever changes, you need to also update the 'ldflags' value in .goreleaser.yml
PROVIDER_VERSION?=$(shell git describe --tags --abbrev=0 | sed -n 's/v\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1.\2.\3/p')
Expand All @@ -26,6 +29,7 @@ TF_ACC_PROVIDER_HOST="registry.opentofu.org"
endif

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

SONAR_SCANNER_VERSION?=4.7.0.2747
SONAR_SCANNER_HOME?=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION-macosx
Expand All @@ -36,10 +40,14 @@ default: build

install: clean build
mkdir -p ${BUILD_PATH} && \
mkdir -p ${LINUX_BUILD_PATH} && \
mv -v dist/terraform-provider-${PRODUCT}_${GORELEASER_ARCH}/terraform-provider-${PRODUCT}_v${NEXT_PROVIDER_VERSION}* ${BUILD_PATH} && \
sed -i.bak 's/version = ".*"/version = "${NEXT_PROVIDER_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.d/ .terraform.lock.hcl

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

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

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

Expand All @@ -144,4 +147,4 @@ The following arguments are supported:
* `access_token` - (Optional) This can also be sourced from `JFROG_ACCESS_TOKEN` or `ARTIFACTORY_ACCESS_TOKEN` environment variables.
* `api_key` - (Optional, deprecated) API key for api auth.
* `oidc_provider_name` - (Optional) OIDC provider name. See [Configure an OIDC Integration](https://jfrog.com/help/r/jfrog-platform-administration-documentation/configure-an-oidc-integration) for more details.
* `check_license` - (Optional) Toggle for pre-flight checking of Artifactory license. Default to `true`.
* `tfc_credential_tag_name` - (Optional) 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.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ require (
github.com/hashicorp/terraform-plugin-mux v0.16.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.34.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
github.com/sethvargo/go-password v0.3.1
github.com/stretchr/testify v1.9.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,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/artifactory/provider/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,11 @@ type ArtifactoryProvider struct{}

// ArtifactoryProviderModel describes the provider data model.
type ArtifactoryProviderModel struct {
Url types.String `tfsdk:"url"`
AccessToken types.String `tfsdk:"access_token"`
ApiKey types.String `tfsdk:"api_key"`
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
Url types.String `tfsdk:"url"`
AccessToken types.String `tfsdk:"access_token"`
ApiKey types.String `tfsdk:"api_key"`
OIDCProviderName types.String `tfsdk:"oidc_provider_name"`
TFCCredentialTagName types.String `tfsdk:"tfc_credential_tag_name"`
}

// Metadata satisfies the provider.Provider interface for ArtifactoryProvider
Expand Down Expand Up @@ -79,6 +80,13 @@ func (p *ArtifactoryProvider) Schema(ctx context.Context, req provider.SchemaReq
},
Description: "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.",
},
},
}
}
Expand Down Expand Up @@ -119,19 +127,22 @@ func (p *ArtifactoryProvider) Configure(ctx context.Context, req provider.Config
return
}

oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, 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, restyClient, 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
}
}

// Check configuration data, which should take precedence over
Expand Down
8 changes: 7 additions & 1 deletion pkg/artifactory/provider/sdkv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ func SdkV2() *schema.Provider {
ValidateDiagFunc: validator.StringIsNotEmpty,
Description: "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": {
Type: schema.TypeString,
Optional: true,
ValidateDiagFunc: validator.StringIsNotEmpty,
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.",
},
},

ResourcesMap: resourcesMap(),
Expand Down Expand Up @@ -85,7 +91,7 @@ func providerConfigure(ctx context.Context, d *schema.ResourceData, terraformVer
}

if v, ok := d.GetOk("oidc_provider_name"); ok {
oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, v.(string))
oidcAccessToken, err := util.OIDCTokenExchange(ctx, restyClient, v.(string), d.Get("tfc_credential_tag_name").(string))
if err != nil {
return nil, diag.FromErr(err)
}
Expand Down

0 comments on commit 5790af2

Please sign in to comment.