From 93291666e6de9946ce7b50dd0d8c89119c88a02a Mon Sep 17 00:00:00 2001 From: Muhammad Atif Ali Date: Sun, 12 Nov 2023 16:32:57 +0300 Subject: [PATCH] add outh method --- jfrog/README.md | 60 ++++++++++++++++++++++++++++++------------------- jfrog/main.tf | 45 +++++++++++++++++++++++++++++++++---- 2 files changed, 78 insertions(+), 27 deletions(-) diff --git a/jfrog/README.md b/jfrog/README.md index 9ae7cce..6b939a9 100644 --- a/jfrog/README.md +++ b/jfrog/README.md @@ -12,45 +12,59 @@ tags: [integration] Install the JF CLI and authenticate package managers with Artifactory. +There are two ways to authenticate with Artifactory: + +1. Using an admin access token +2. Using OAuth configured via Coder [`external-auth`](https://docs.coder.com/docs/admin/external-auth/) feature. This is the recommended approach. + +Examples of both approaches are provided below. + +## Examples + +### Using an admin access token + ```hcl module "jfrog" { - source = "https://registry.coder.com/modules/jfrog" - 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" - } + source = "https://registry.coder.com/modules/jfrog" + 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", + "go": "go", + "pypi": "pypi" + } } ``` -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 have admin permissions, i.e. with scopes = ["applied-permissions/admin"]. It is recommended to store the token in a secret terraform variable. ```hcl variable "artifactory_access_token" { - type = string - sensitive = true + type = string + sensitive = true } ``` ![JFrog](../.images/jfrog.png) -## Examples +### Using OAuth + +You can use OAuth to authenticate with Artifactory. This is the recommended approach. To use OAuth, you must have the Coder [`external-auth`](https://coder.com/docs/v2/latest/admin/external-auth#jfrog) configured with Artifactory. -### Configure npm, go, and pypi to use Artifactory local repositories +![JFrog OAuth](../.images/jfrog-oauth.png) ```hcl module "jfrog" { - source = "https://registry.coder.com/modules/jfrog" - 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-local", - "go": "go-local", - "pypi": "pypi-local" - } + source = "https://registry.coder.com/modules/jfrog" + agent_id = coder_agent.example.id + jfrog_url = "https://YYYY.jfrog.io" + auth_method = "oauth" + username_field = "username" # If you are using GitHub to login to both Coder and Artifactory, use username_field = "username" + package_managers = { + "npm": "npm", + "go": "go", + "pypi": "pypi" + } } ``` diff --git a/jfrog/main.tf b/jfrog/main.tf index 807bdf8..9a999c6 100644 --- a/jfrog/main.tf +++ b/jfrog/main.tf @@ -23,15 +23,52 @@ variable "artifactory_access_token" { description = "The admin-level access token to use for JFrog." } +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 "auth_method" { + type = string + description = "The authentication method to use for JFrog." + default = "access_token" + validation { + condition = can(regex("^(access_token|oauth)$", var.auth_method)) + error_message = "auth_method must be either 'access_token' or 'oauth'" + } +} + +variable "external_auth_id" { + type = string + description = "JFrog external auth ID. Default: 'jfrog'" + default = "jfrog" +} +locals { + # The username field to use for artifactory + username = var.username_field == "email" ? data.coder_workspace.me.owner_email : data.coder_workspace.me.username + access_token = var.auth_method == "access_token" ? artifactory_scoped_token.me.access_token : data.coder_external_auth.jfrog.access_token +} # Configure the Artifactory provider provider "artifactory" { url = join("/", [var.jfrog_url, "artifactory"]) - access_token = var.artifactory_access_token + access_token = var.artifactory_access_token == "" ? null : 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" + count = var.artifactory_access_token == "" ? 0 : 1 + username = length(local.username) > 0 ? local.username : "plan" + scopes = ["applied-permissions/user"] + refreshable = true +} + +data "coder_external_auth" "jfrog" { + id = var.external_auth_id } variable "agent_id" { @@ -61,8 +98,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_ACCESS_TOKEN : artifactory_scoped_token.me.access_token, + ARTIFACTORY_USERNAME : local.username, + ARTIFACTORY_ACCESS_TOKEN : local.access_token, REPOSITORY_NPM : lookup(var.package_managers, "npm", ""), REPOSITORY_GO : lookup(var.package_managers, "go", ""), REPOSITORY_PYPI : lookup(var.package_managers, "pypi", ""),