From 73ef0dc7d0c715d026bfbd3bf89c8a615bcbde73 Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Wed, 15 Nov 2023 00:12:57 +0300 Subject: [PATCH 1/3] Add JFrog (OAuth) integration module (#97) --- .images/jfrog-oauth.png | Bin 0 -> 75610 bytes jfrog-oauth/README.md | 61 ++++++++++++++++++++++ jfrog-oauth/main.test.ts | 17 ++++++ jfrog-oauth/main.tf | 77 ++++++++++++++++++++++++++++ {jfrog => jfrog-oauth}/run.sh | 27 ++++++---- {jfrog => jfrog-token}/README.md | 32 ++++++++---- {jfrog => jfrog-token}/main.test.ts | 4 +- {jfrog => jfrog-token}/main.tf | 41 +++++++++++---- jfrog-token/run.sh | 58 +++++++++++++++++++++ 9 files changed, 286 insertions(+), 31 deletions(-) create mode 100644 .images/jfrog-oauth.png create mode 100644 jfrog-oauth/README.md create mode 100644 jfrog-oauth/main.test.ts create mode 100644 jfrog-oauth/main.tf rename {jfrog => jfrog-oauth}/run.sh (64%) rename {jfrog => jfrog-token}/README.md (63%) rename {jfrog => jfrog-token}/main.test.ts (94%) rename {jfrog => jfrog-token}/main.tf (69%) create mode 100644 jfrog-token/run.sh diff --git a/.images/jfrog-oauth.png b/.images/jfrog-oauth.png new file mode 100644 index 0000000000000000000000000000000000000000..cd897fc7cf1af4f684a1726c34ef0820f8b9b787 GIT binary patch literal 75610 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/external-auth/jfrog/callback`. + +## Examples + +Configure the Python pip package manager to fetch packages from Artifactory while mapping the Coder email to the Artifactory username. + +```hcl +module "jfrog" { + source = "https://registry.coder.com/modules/jfrog-oauth" + agent_id = coder_agent.example.id + jfrog_url = "https://jfrog.example.com" + auth_method = "oauth" + username_field = "email" + package_managers = { + "pypi": "pypi" + } +} +``` + +You should now be able to install packages from Artifactory using both the `jf pip` and `pip` command. + +```shell +jf pip install requests +``` + +```shell +pip install requests +``` diff --git a/jfrog-oauth/main.test.ts b/jfrog-oauth/main.test.ts new file mode 100644 index 0000000..f31aa5d --- /dev/null +++ b/jfrog-oauth/main.test.ts @@ -0,0 +1,17 @@ +import { serve } from "bun"; +import { describe } from "bun:test"; +import { + createJSONResponse, + runTerraformInit, + testRequiredVariables, +} from "../test"; + +describe("jfrog-oauth", async () => { + await runTerraformInit(import.meta.dir); + + testRequiredVariables(import.meta.dir, { + agent_id: "some-agent-id", + jfrog_url: "http://localhost:8081", + package_managers: "{}", + }); +}); diff --git a/jfrog-oauth/main.tf b/jfrog-oauth/main.tf new file mode 100644 index 0000000..b6f1583 --- /dev/null +++ b/jfrog-oauth/main.tf @@ -0,0 +1,77 @@ +terraform { + required_version = ">= 1.0" + + required_providers { + coder = { + source = "coder/coder" + version = ">= 0.12" + } + } +} + +variable "jfrog_url" { + type = string + description = "JFrog instance URL. e.g. https://jfrog.example.com" +} + +variable "username_field" { + type = string + description = "The field to use for the artifactory username. i.e. Coder username or email." + default = "username" + validation { + condition = can(regex("^(email|username)$", var.username_field)) + error_message = "username_field must be either 'email' or 'username'" + } +} + +variable "external_auth_id" { + type = string + description = "JFrog external auth ID. Default: 'jfrog'" + default = "jfrog" +} + +variable "agent_id" { + type = string + description = "The ID of a Coder agent." +} + +variable "package_managers" { + type = map(string) + description = </dev/null 2>&1; then + echo "✅ JFrog CLI is already installed, skipping installation." +else + echo "📦 Installing JFrog CLI..." + # Install the JFrog CLI. + curl -fL https://install-cli.jfrog.io | sudo sh + sudo chmod 755 /usr/local/bin/jf +fi # The jf CLI checks $CI when determining whether to use interactive # flows. @@ -14,14 +19,16 @@ export CI=true jf c rm 0 || true echo "${ARTIFACTORY_ACCESS_TOKEN}" | jf c add --access-token-stdin --url "${JFROG_URL}" 0 -# Configure the `npm` CLI to use the Artifactory "npm" repository. if [ -z "${REPOSITORY_NPM}" ]; then echo "🤔 REPOSITORY_NPM is not set, skipping npm configuration." else - echo "📦 Configuring npm..." - jf npmc --global --repo-resolve "${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM}" + # check if npm is installed and configure it to use the Artifactory "npm" repository. + if command -v npm >/dev/null 2>&1; then + echo "📦 Configuring npm..." + jf npmc --global --repo-resolve "${REPOSITORY_NPM}" + fi cat <~/.npmrc -email = ${ARTIFACTORY_USERNAME} +email = ${ARTIFACTORY_EMAIL} registry = ${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM} EOF jf rt curl /api/npm/auth >>~/.npmrc @@ -32,6 +39,7 @@ if [ -z "${REPOSITORY_PYPI}" ]; then echo "🤔 REPOSITORY_PYPI is not set, skipping pip configuration." else echo "🐍 Configuring pip..." + jf pipc --global --repo-resolve "${REPOSITORY_PYPI}" mkdir -p ~/.pip cat <~/.pip/pip.conf [global] @@ -44,6 +52,7 @@ if [ -z "${REPOSITORY_GO}" ]; then echo "🤔 REPOSITORY_GO is not set, skipping go configuration." else echo "🐹 Configuring go..." + jf go-config --global --repo-resolve "${REPOSITORY_GO}" export GOPROXY="https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/go/${REPOSITORY_GO}" fi echo "🥳 Configuration complete!" diff --git a/jfrog/README.md b/jfrog-token/README.md similarity index 63% rename from jfrog/README.md rename to jfrog-token/README.md index 9ae7cce..291111f 100644 --- a/jfrog/README.md +++ b/jfrog-token/README.md @@ -1,27 +1,27 @@ --- -display_name: JFrog -description: Install the JF CLI and authenticate with Artifactory +display_name: JFrog (Token) +description: Install the JF CLI and authenticate with Artifactory using Artifactory terraform provider. icon: ../.icons/jfrog.svg maintainer_github: coder partner_github: jfrog verified: true -tags: [integration] +tags: [integration, jfrog] --- # JFrog -Install the JF CLI and authenticate package managers with Artifactory. +Install the JF CLI and authenticate package managers with Artifactory using Artifactory terraform provider. ```hcl module "jfrog" { - source = "https://registry.coder.com/modules/jfrog" + source = "https://registry.coder.com/modules/jfrog-token" agent_id = coder_agent.example.id jfrog_url = "https://YYYY.jfrog.io" artifactory_access_token = var.artifactory_access_token # An admin access token package_managers = { - "npm": "npm-remote", - "go": "go-remote", - "pypi": "pypi-remote" + "npm": "npm", + "go": "go", + "pypi": "pypi" } } ``` @@ -43,7 +43,7 @@ variable "artifactory_access_token" { ```hcl module "jfrog" { - source = "https://registry.coder.com/modules/jfrog" + source = "https://registry.coder.com/modules/jfrog-token" agent_id = coder_agent.example.id jfrog_url = "https://YYYY.jfrog.io" artifactory_access_token = var.artifactory_access_token # An admin access token @@ -54,3 +54,17 @@ module "jfrog" { } } ``` + +You should now be able to install packages from Artifactory using both the `jf npm`, `jf go`, `jf pip` and `npm`, `go`, `pip` commands. + +```shell +jf npm install prettier +jf go get github.com/golang/example/hello +jf pip install requests +``` + +```shell +npm install prettier +go get github.com/golang/example/hello +pip install requests +``` diff --git a/jfrog/main.test.ts b/jfrog-token/main.test.ts similarity index 94% rename from jfrog/main.test.ts rename to jfrog-token/main.test.ts index 82ad38b..b3b8df9 100644 --- a/jfrog/main.test.ts +++ b/jfrog-token/main.test.ts @@ -6,7 +6,7 @@ import { testRequiredVariables, } from "../test"; -describe("jfrog", async () => { +describe("jfrog-token", async () => { await runTerraformInit(import.meta.dir); // Run a fake JFrog server so the provider can initialize @@ -25,7 +25,7 @@ describe("jfrog", async () => { return createJSONResponse({ token_id: "xxx", access_token: "xxx", - scope: "any", + scopes: "any", }); return createJSONResponse({}); }, diff --git a/jfrog/main.tf b/jfrog-token/main.tf similarity index 69% rename from jfrog/main.tf rename to jfrog-token/main.tf index 807bdf8..a586148 100644 --- a/jfrog/main.tf +++ b/jfrog-token/main.tf @@ -8,7 +8,7 @@ terraform { } artifactory = { source = "registry.terraform.io/jfrog/artifactory" - version = "~> 8.4.0" + version = "~> 9.8.0" } } } @@ -23,15 +23,14 @@ variable "artifactory_access_token" { description = "The admin-level access token to use for JFrog." } -# Configure the Artifactory provider -provider "artifactory" { - url = join("/", [var.jfrog_url, "artifactory"]) - access_token = var.artifactory_access_token -} -resource "artifactory_scoped_token" "me" { - # This is hacky, but on terraform plan the data source gives empty strings, - # which fails validation. - username = length(data.coder_workspace.me.owner_email) > 0 ? data.coder_workspace.me.owner_email : "plan" +variable "username_field" { + type = string + description = "The field to use for the artifactory username. i.e. Coder username or email." + default = "email" + validation { + condition = can(regex("^(email|username)$", var.username_field)) + error_message = "username_field must be either 'email' or 'username'" + } } variable "agent_id" { @@ -52,6 +51,25 @@ For example: EOF } +locals { + # The username field to use for artifactory + username = var.username_field == "email" ? data.coder_workspace.me.owner_email : data.coder_workspace.me.owner +} + +# Configure the Artifactory provider +provider "artifactory" { + url = join("/", [var.jfrog_url, "artifactory"]) + access_token = var.artifactory_access_token +} + +resource "artifactory_scoped_token" "me" { + # This is hacky, but on terraform plan the data source gives empty strings, + # which fails validation. + username = length(local.username) > 0 ? local.username : "dummy" + scopes = ["applied-permissions/user"] + refreshable = true +} + data "coder_workspace" "me" {} resource "coder_script" "jfrog" { @@ -61,7 +79,8 @@ resource "coder_script" "jfrog" { script = templatefile("${path.module}/run.sh", { JFROG_URL : var.jfrog_url, JFROG_HOST : replace(var.jfrog_url, "https://", ""), - ARTIFACTORY_USERNAME : data.coder_workspace.me.owner_email, + ARTIFACTORY_USERNAME : local.username, + ARTIFACTORY_EMAIL : data.coder_workspace.me.owner_email, ARTIFACTORY_ACCESS_TOKEN : artifactory_scoped_token.me.access_token, REPOSITORY_NPM : lookup(var.package_managers, "npm", ""), REPOSITORY_GO : lookup(var.package_managers, "go", ""), diff --git a/jfrog-token/run.sh b/jfrog-token/run.sh new file mode 100644 index 0000000..efba187 --- /dev/null +++ b/jfrog-token/run.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +BOLD='\033[0;1m' + +# check if JFrog CLI is already installed +if command -v jf >/dev/null 2>&1; then + echo "✅ JFrog CLI is already installed, skipping installation." +else + echo "📦 Installing JFrog CLI..." + # Install the JFrog CLI. + curl -fL https://install-cli.jfrog.io | sudo sh + sudo chmod 755 /usr/local/bin/jf +fi + +# The jf CLI checks $CI when determining whether to use interactive +# flows. +export CI=true +# Authenticate with the JFrog CLI. +jf c rm 0 || true +echo "${ARTIFACTORY_ACCESS_TOKEN}" | jf c add --access-token-stdin --url "${JFROG_URL}" 0 + +if [ -z "${REPOSITORY_NPM}" ]; then + echo "🤔 REPOSITORY_NPM is not set, skipping npm configuration." +else + # check if npm is installed and configure it to use the Artifactory "npm" repository. + if command -v npm >/dev/null 2>&1; then + echo "📦 Configuring npm..." + jf npmc --global --repo-resolve "${REPOSITORY_NPM}" + fi + cat <~/.npmrc +email = ${ARTIFACTORY_EMAIL} +registry = ${JFROG_URL}/artifactory/api/npm/${REPOSITORY_NPM} +EOF + jf rt curl /api/npm/auth >>~/.npmrc +fi + +# Configure the `pip` to use the Artifactory "python" repository. +if [ -z "${REPOSITORY_PYPI}" ]; then + echo "🤔 REPOSITORY_PYPI is not set, skipping pip configuration." +else + echo "🐍 Configuring pip..." + jf pipc --global --repo-resolve "${REPOSITORY_PYPI}" + mkdir -p ~/.pip + cat <~/.pip/pip.conf +[global] +index-url = https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/pypi/${REPOSITORY_PYPI}/simple +EOF +fi + +# Set GOPROXY to use the Artifactory "go" repository. +if [ -z "${REPOSITORY_GO}" ]; then + echo "🤔 REPOSITORY_GO is not set, skipping go configuration." +else + echo "🐹 Configuring go..." + jf go-config --global --repo-resolve "${REPOSITORY_GO}" + export GOPROXY="https://${ARTIFACTORY_USERNAME}:${ARTIFACTORY_ACCESS_TOKEN}@${JFROG_HOST}/artifactory/api/go/${REPOSITORY_GO}" +fi +echo "🥳 Configuration complete!" From 8e3f48ce5ca43342567ad50f8499c792bb9d874b Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Wed, 15 Nov 2023 16:03:43 +0300 Subject: [PATCH 2/3] fix(jfrog-token)!: add attributes to fine control the token behaviour (#100) --- jfrog-token/README.md | 6 +++--- jfrog-token/main.tf | 30 +++++++++++++++++++++++++----- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/jfrog-token/README.md b/jfrog-token/README.md index 291111f..42525fc 100644 --- a/jfrog-token/README.md +++ b/jfrog-token/README.md @@ -16,8 +16,8 @@ Install the JF CLI and authenticate package managers with Artifactory using Arti module "jfrog" { source = "https://registry.coder.com/modules/jfrog-token" agent_id = coder_agent.example.id - jfrog_url = "https://YYYY.jfrog.io" - artifactory_access_token = var.artifactory_access_token # An admin access token + jfrog_url = "https://XXXX.jfrog.io" + artifactory_access_token = var.artifactory_access_token package_managers = { "npm": "npm", "go": "go", @@ -26,7 +26,7 @@ module "jfrog" { } ``` -Get a JFrog access token from your Artifactory instance. The token must have admin permissions. It is recommended to store the token in a secret terraform variable. +Get a JFrog access token from your Artifactory instance. The token must be an [admin token](https://registry.terraform.io/providers/jfrog/artifactory/latest/docs#access-token). It is recommended to store the token in a secret terraform variable. ```hcl variable "artifactory_access_token" { diff --git a/jfrog-token/main.tf b/jfrog-token/main.tf index a586148..efee07f 100644 --- a/jfrog-token/main.tf +++ b/jfrog-token/main.tf @@ -23,10 +23,28 @@ variable "artifactory_access_token" { description = "The admin-level access token to use for JFrog." } +variable "check_license" { + type = bool + description = "Toggle for pre-flight checking of Artifactory license. Default to `true`." + default = true +} + +variable "refreshable" { + type = bool + description = "Is this token refreshable? Default is `false`." + default = false +} + +variable "expires_in" { + type = number + description = "The amount of time, in seconds, it would take for the token to expire." + default = null +} + variable "username_field" { type = string - description = "The field to use for the artifactory username. i.e. Coder username or email." - default = "email" + description = "The field to use for the artifactory username. Default `username`." + default = "username" validation { condition = can(regex("^(email|username)$", var.username_field)) error_message = "username_field must be either 'email' or 'username'" @@ -58,8 +76,9 @@ locals { # Configure the Artifactory provider provider "artifactory" { - url = join("/", [var.jfrog_url, "artifactory"]) - access_token = var.artifactory_access_token + url = join("/", [var.jfrog_url, "artifactory"]) + access_token = var.artifactory_access_token + check_license = var.check_license } resource "artifactory_scoped_token" "me" { @@ -67,7 +86,8 @@ resource "artifactory_scoped_token" "me" { # which fails validation. username = length(local.username) > 0 ? local.username : "dummy" scopes = ["applied-permissions/user"] - refreshable = true + refreshable = var.refreshable + expires_in = var.expires_in } data "coder_workspace" "me" {} From 98bb94c5f036777e0c52ed14174bdf90efc29b9c Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Wed, 15 Nov 2023 18:15:00 +0300 Subject: [PATCH 3/3] feat: add JFrog access token output to module output (#101) --- jfrog-oauth/README.md | 16 ++++++++++++++++ jfrog-oauth/main.test.ts | 2 ++ jfrog-oauth/main.tf | 11 +++++++++++ jfrog-token/README.md | 16 ++++++++++++++++ jfrog-token/main.tf | 11 +++++++++++ 5 files changed, 56 insertions(+) diff --git a/jfrog-oauth/README.md b/jfrog-oauth/README.md index f7ea867..00eee3d 100644 --- a/jfrog-oauth/README.md +++ b/jfrog-oauth/README.md @@ -59,3 +59,19 @@ jf pip install requests ```shell pip install requests ``` + +### Using the access token in other terraform resources + +JFrog Access token is also available as a terraform output. You can use it in other terraform resources. For example, you can use it to configure an [Artifactory docker registry](https://jfrog.com/help/r/jfrog-artifactory-documentation/docker-registry) with the [docker terraform provider](https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs). + +```hcl + +provider "docker" { + ... + registry_auth { + address = "https://YYYY.jfrog.io/artifactory/api/docker/REPO-KEY" + username = module.jfrog.username + password = module.jfrog.access_token + } +} +``` diff --git a/jfrog-oauth/main.test.ts b/jfrog-oauth/main.test.ts index f31aa5d..3397eeb 100644 --- a/jfrog-oauth/main.test.ts +++ b/jfrog-oauth/main.test.ts @@ -15,3 +15,5 @@ describe("jfrog-oauth", async () => { package_managers: "{}", }); }); + +//TODO add more tests diff --git a/jfrog-oauth/main.tf b/jfrog-oauth/main.tf index b6f1583..8a81594 100644 --- a/jfrog-oauth/main.tf +++ b/jfrog-oauth/main.tf @@ -75,3 +75,14 @@ resource "coder_script" "jfrog" { }) run_on_start = true } + +output "access_token" { + description = "value of the JFrog access token" + value = data.coder_external_auth.jfrog.access_token + sensitive = true +} + +output "username" { + description = "value of the JFrog username" + value = local.username +} diff --git a/jfrog-token/README.md b/jfrog-token/README.md index 42525fc..512c863 100644 --- a/jfrog-token/README.md +++ b/jfrog-token/README.md @@ -68,3 +68,19 @@ npm install prettier go get github.com/golang/example/hello pip install requests ``` + +### Using the access token in other terraform resources + +JFrog Access token is also available as a terraform output. You can use it in other terraform resources. For example, you can use it to configure an [Artifactory docker registry](https://jfrog.com/help/r/jfrog-artifactory-documentation/docker-registry) with the [docker terraform provider](https://registry.terraform.io/providers/kreuzwerker/docker/latest/docs). + +```hcl + +provider "docker" { + ... + registry_auth { + address = "https://YYYY.jfrog.io/artifactory/api/docker/REPO-KEY" + username = module.jfrog.username + password = module.jfrog.access_token + } +} +``` diff --git a/jfrog-token/main.tf b/jfrog-token/main.tf index efee07f..d9aa55f 100644 --- a/jfrog-token/main.tf +++ b/jfrog-token/main.tf @@ -108,3 +108,14 @@ resource "coder_script" "jfrog" { }) run_on_start = true } + +output "access_token" { + description = "value of the JFrog access token" + value = artifactory_scoped_token.me.access_token + sensitive = true +} + +output "username" { + description = "value of the JFrog username" + value = local.username +}