Git Product home page Git Product logo

vault-plugin-secrets-artifactory's Introduction

Vault Artifactory Secrets Plugin

This plugin is actively maintained by JFrog Inc. Please refer to CONTRIBUTING.md for contributions and create GitHub issues to ask for feature requests and support.

Contact JFrog Support for urgent, time sensitive issues.


This is a HashiCorp Vault secret plugin which talks to JFrog Artifactory server and will dynamically provision access tokens with specified scopes. This backend can be mounted multiple times to provide access to multiple Artifactory servers.

Using this plugin, you can limit the accidental exposure window of Artifactory tokens; useful for continuous integration servers.

Access Token Creation and Revoking

This backend creates access tokens in Artifactory using the admin credentials provided. Note that if you provide non-administrative credentials, then the "username" must match the username of the credential owner.

Visit JFrog Help Center for more information on Access Tokens.

Admin Token Expiration Notice

Important

Prior to Artifactory 7.42.1, admin access token was created with the system token expiration (default to 1 year) even when expires_in API field is set to 0. In 7.42.1, admin token expiration no longer constrained by system configuration and therefore can be set to non-expiring. See section "Generate a Non-expiry Admin Token without Changing the Configuration" in the release note.

Therefore if you created access token(s) with Artifactory prior to 7.42.1, the tokens will have a 1 year expiration time (or whatever value is set in the Artifactory configuration) and will become unusable silently when it expires.

We suggest upgrading your Artifactory to 7.42.1 or later (if possible) and rotate your tokens to get new, non-expiring tokens. Or set reminders to ensure you rotate your tokens before expiration.

It should also be noted that some "scripts" used to create an admin token may default to expiration in 1h, so it is best to rotate the admin token immediately, to ensure it doesn't expire unexpectedly.

If you are using v0.2.9 or later, you can check if your admin token has an expiration using vault read artifactory/config/admin. If the exp/expires fields are not present, your token has no expiration set.

Dynamic Usernames

Previous versions of this plugin required a static username associated to the roles. This is still supported for backwards compatibility, but you can now use a dynamically generated username, based on Vault Username Templates. The generated tokens will be associated to a username generated from the template v-{{.RoleName}}-{{Random 8}}) (v-jenkins-x4mohTA8), by default. You can change this template by specifying a username_template= option to the /artifactory/config/admin endpoint. The "scope" in the role should be applied-permissions/groups:(list-of-groups), since applied-permissions/user would require the username to exist ahead of time. The user will not show in the Users list, but will be dynamically created during the scope of the token. The username still needs to be compliant with artifactory requirements (less than 255 characters). It will be converted to lowercase by the API.

Example:

vault write artifactory/config/admin username_template="v_{{.DisplayName}}_{{.RoleName}}_{{random 10}}_{{unix_time}}"

Expiring Tokens

By default, the Vault generated Artifactory tokens will not show an expiration date, which means that Artifactory will not automatically revoke them. Vault will revoke the token when its lease expires due to logout or timeout (ttl/max_ttl). The reason for this is because of the default Revocable/Persistency Thresholds in Artifactory. If you would like the artifactory token itself to show an expiration, and you are using Artifactory v7.50.3 or higher, you can write use_expiring_tokens=true to the /artifactory/config/admin path. This will set the force_revocable=true parameter and set expires_in to either max lease TTL or role's max_ttl, whichever is lower, when a token is created, overriding the default thresholds mentioned above.

Example:

vault write artifactory/config/admin use_expiring_tokens=true

Example Token Output:

$ ACCESS_TOKEN=$(vault read -field access_token artifactory/token/test)
$ jwt decode $ACCESS_TOKEN

Token header
------------
{
"typ": "JWT",
"alg": "RS256",
"kid": "nxB2_1jNkYS5oYsl6nbUaaeALfKpfBZUyP0SW3txYUM"
}

Token claims
------------
{
"aud": "*@*",
"exp": 1678913614,
"ext": "{\"revocable\":\"true\"}",
"iat": 1678902814,
"iss": "jfac@01gvgpzpv8jytn0fvq41wb1srj",
"jti": "e39cec86-069c-4b75-8897-c2bf05dc8354",
"scp": "applied-permissions/groups:readers",
"sub": "jfac@01gvgpzpv8jytn0fvq41wb1srj/userv-test-p9nprfwr"
}

Artifactory Version Detection

Some of the functionality of this plugin requires certain versions of Artifactory. For example, as of Artifactory 7.50.3, we can optionally set the force_revocable flag and set the expiration of the token to max_ttl.

If you have upgraded Artifactory after installing this plugin, and would like to take advantage of newer features, you can issue an empty write to the artifactory/config/admin endpoint to re-detect the version, or it will re-detect upon reload.

Example:

vault write -f artifactory/config/admin

Installation

Using pre-built releases

You can find pre-built releases of the plugin here and download the latest binary file corresponding to your target OS.

From Sources

If you prefer to build the plugin from sources, clone the GitHub repository locally and run the command make build from the root of the sources directory.

See Local Development Prerequisites section for pre-requisites.

Upon successful compilation, the resulting artifactory-secrets-plugin binary is stored in the dist/vault-plugin-secrets-artifactory_<OS architecture> directory.

Configuration

Copy the plugin binary into a location of your choice; this directory must be specified as the plugin_directory in the Vault configuration file:

plugin_directory = "path/to/plugin/directory"

Start a Vault server with this configuration file:

vault server -config=path/to/vault/config.hcl

Once the server is started, register the plugin in the Vault server's plugin catalog:

vault plugin register \
  -sha256=$(sha256sum path/to/plugin/directory/artifactory | cut -d " " -f 1) \
  -command=artifactory-secrets-plugin \
  secret artifactory

Note

you may need to also add arguments to the registration like -args="-ca-cert ca.pem or something insecure like: -args="-tls-skip-verify" depending on your environment. (see ./path/to/plugins/artifactory -help for all the options)

Caution

This inline checksum calculation above is provided for illustration purpose and does not validate your binary. It should not be used for production environment. Instead you should use the checksum provided as part of the release. See How to verify binary checksums section.

You can now enable the Artifactory secrets plugin:

vault secrets enable artifactory

When upgrading, please refer to the Vault documentation for detailed instructions.

How to verify binary checksums

Checksums for each binary are provided in the artifactory-secrets-plugin_<version>_checksums.txt file. It is signed with the public key vault-plugin-secrets-artifactory-public-key.asc which creates the signature file artifactory-secrets-plugin_<version>_checksums.txt.sig.

If the public key is not in your GPG keychain, import it:

gpg --import artifactory-secrets-plugin-public-key.asc

Then verify the checksums file signature:

gpg --verify artifactory-secrets-plugin_<version>_checksums.txt.sig

You should see something like the following:

gpg: assuming signed data in 'artifactory-secrets-plugin_0.2.17_checksums.txt'
gpg: Signature made Mon May  8 14:22:12 2023 PDT
gpg:                using RSA key ED4FF1CD6C2318B470A33A1659FE1520A4A355CD
gpg: Good signature from "Alex Hung <[email protected]>" [ultimate]

With the checksums file verified, you can now safely use the SHA256 checkum inside as part of the Vault plugin registration (vs calling sha256sum).

Artifactory

  1. Log into the Artifactory UI as an "admin".
  2. Create the Access Token that Vault will use to interact with Artifactory. In Artifactory 7.x this can be done in the UI Administration (gear) -> User Management -> Access Tokens -> Generate Token.
    • Token Type: Scoped Token
    • Description: (optional) vault-plugin-secrets-artifactory (NOTE: This will be lost on admin token rotation, because it is not part of the token)
    • Token Scope: Admin (IMPORTANT)
    • User name: vault-admin (for example)
    • Service: Artifactory (or you can leave it on "All")
    • Expiration time: Never (do not set the expiration time less than 7h, since by default, it will not be revocable once the expiration is less than 6h)
  3. Save the generated token as the environment variable TOKEN

Alternatives:

  • Use the CreateToken REST API, and save the access_token from the JSON response as the environment variable TOKEN.

  • Use getArtifactoryAdminToken.sh.

    export JFROG_URL=https://artifactory.example.org
    export ARTIFACTORY_USERNAME=admin
    export ARTIFACTORY_PASSWORD=password
    TOKEN=$(scripts/getArtifactoryAdminToken.sh)

Vault

vault write artifactory/config/admin \
    url=https://artifactory.example.org \
    access_token=$TOKEN

OPTIONAL, but recommended: Rotate the admin token, so that only Vault knows it.

vault write -f artifactory/config/rotate

Note

some versions of artifactory (notably 7.39.10) fail to rotate correctly. As noted above, we recommend being on 7.42.1 or higher. The token was indeed rotated, but as the error indicates, the old token could not be revoked.

ALSO If you want to change the username for the admin token (tired of it just being "admin"?) or set a "Description" on the token, those parameters are optionally available on the artifactory/config/rotate endpoint.

vault write artifactory/config/rotate username="new-username" description="A token used by vault-secrets-engine on our vault server"`

Bypass TLS connection verification with Artifactory

To bypass TLS connection verification with Artifactory, set bypass_artifactory_tls_verification to true, e.g.

vault write artifactory/config/admin \
    url=https://artifactory.example.org \
    access_token=$TOKEN \
    bypass_artifactory_tls_verification=true

OPTIONAL: Check the results:

vault read artifactory/config/admin

Example output:

Key                                 Value
---                                 -----
access_token_sha256                 74834a86b2082750201e2a1e520f21f7bfc7d4026e5bd2b075ca2d0699b7c4e3
bypass_artifactory_tls_verification false
scope                               applied-permissions/admin
token_id                            db0002b0-af08-486c-bbad-b255a3cc7b31
url                                 http://localhost:8082
use_expiring_tokens                 false
username                            vault-admin
version                             7.55.6

Use expiring tokens

To enable creation of token that expires using TTL (system default, system max TTL, or config overrides), set use_expiring_tokens to true, e.g.

vault write artifactory/config/admin \
    url=https://artifactory.example.org \
    access_token=$TOKEN \
    use_expiring_tokens=true

Enable Scoped down Tokens

Warning

In order to decouple Artifactory Group maintenance from Vault plugin configuration, you can configure a single role to request Access Tokens for specific groups. This option should be used with extreme care to ensure that your Vault policies are restricting which groups it can request tokens on behalf of.

vault write artifactory/config/admin \
    url=https://artifactory.example.org \
    access_token=$TOKEN \
    allow_scope_override=true

Usage

Create a role (scope for artifactory >= 7.21.1)

vault write artifactory/roles/jenkins \
    scope="applied-permissions/groups:automation " \
    default_ttl=3600 max_ttl=10800

Also supports grant_type=[Optional, default: "client_credentials"], and audience=[Optional, default: *@*] see JFrog documentation.

Note

By default, the username will be generated automatically using the template v-(RoleName)-(random 8) (i.e. v-jenkins-x4mohTA8). If you would prefer to have a static username (the same for every token), you can set username=whatever-you-want, but keep in mind that in a dynamic environment, someone or something using an old, expired token might cause a denial of service (too many failed logins) against users with the correct token.

CLICK for: Create a Role (scope for artifactory < 7.21.1)
vault write artifactory/roles/jenkins \
    username="example-service-jenkins" \
    scope="api:* member-of-groups:ci-server" \
    default_ttl=1h max_ttl=3h

Note

There are some changes in the scopes supported in artifactory request >7.21. Please refer to the JFrog documentation for the same according to the artifactory version.

vault list artifactory/roles

Example Output:

Keys
----
jenkins
vault read artifactory/token/jenkins

Example output (token truncated):

Key                Value
---                -----
lease_id           artifactory/token/jenkins/9hHxV1NlyLzPgmNIzjssRCa9
lease_duration     1h
lease_renewable    true
access_token       eyJ2ZXIiOiIyIiw...
role               jenkins
scope              applied-permissions/groups:automation
token_id           06d962b2-63e2-4279-a25d-d2a9cab6507f
username           v-jenkins-x4mohTA8

Scoped Access Tokens

Important

In order to use this functionality, you must enable allow_scope_override when configuring the plugin, see Enable Scoped down Tokens

Create a role (scope for artifactory >= 7.21.1)

vault write artifactory/roles/jenkins \
    username="jenkins-vault"
    scope="applied-permissions/groups:admin" \
    default_ttl=1h max_ttl=3h

Request Access Token for test-group

vault read artifactory/token/jenkins scope=applied-permissions/groups:test-group

Example output (token truncated):

Key                Value
---                -----
lease_id           artifactory/token/jenkins/9hHxV1NlyLzPgmNIzjssRCa9
lease_duration     1h
lease_renewable    true
access_token       eyJ2ZXIiOiIyIiw....
role               jenkins
scope              applied-permissions/groups:test-group
token_id           06d962b2-63e2-4279-a25d-d2a9cab6507f
username           v-jenkins-b0ftbTAG

Example Vault Policy

path "artifactory/token/jenkins" {
  capabilities = ["read"],
  required_parameters = ["scope"],
  allowed_parameters = {
    "scope" = ["applied-permissions/groups:test-group"]
  }
  denied_parameters = {
    "scope" = ["applied-permissions/groups:admin"]
  }
}

User Token Path

User tokens may be obtained from the /artifactory/user_token/<user-name> endpoint. This is useful in conjunction with ACL Policy Path Templating to allow users authenticated to Vault to obtain API tokens in Artfactory for their own account. Be careful to ensure that Vault authentication methods & policies align with user account names in Artifactory.

For example the following policy allows users authenticated to the azure-ad-oidc authentication mount to obtain a token for Artifactory for themselves, assuming the upn metadata is populated in Vault during authentication.

path "artifactory/user_token/{{identity.entity.aliases.azure-ad-oidc.metadata.upn}}" {
  capabilities = [ "read" ]
}

Default values for the token's access_token, description, ttl, max_ttl, audience, refreshable, include_reference_token, and use_expiring_tokens may be configured at the /artifactory/config/user_token or /artifactory/config/user_token/<user-name> path.

access_token field allows the use of user's identity token in place of the admin access token from the /artifactory/config/admin path, enabling creating access token scoped to that user only.

TTL rules follow Vault's general cases and token hierarchy. The desired lease TTL will be determined by the most specific TTL value specified with the request ttl parameter being highest precedence, followed by the plugin configuration, secret mount tuning, or system default ttl. The maximum TTL value allowed is limited to the lowest value of the max_ttl setting set on the system, secret mount tuning, plugin configuration, or the specific request.

Example Token Configuration:

vault write artifactory/config/user_token \
  default_description="Generated by Vault" \
  max_ttl=604800 \
  default_ttl=86400
$ vault read artifactory/config/user_token
Key                        Value
---                        -----
audience                   n/a
default_description        Generated by Vault
default_ttl                24h
include_reference_token    true
max_ttl                    168h
refreshable                true
scope                      applied-permissions/user
token_id                   8df5dd21-31ae-4062-bbe5-580a607f5645
username                   vault-admin

Example Usage:

$ vault read artifactory/user_token/admin description="Dev Desktop"
Key                Value
---                -----
lease_id           artifactory/user_token/admin/4UhTThCwctPGX0TYXeoyoVEt
lease_duration     24h
lease_renewable    true
access_token       eyJ2Z424242424...
description        Dev Desktop
reference_token    cmVmdGtu...
refresh_token      629299be-...
scope              applied-permissions/user
token_id           3c6b2e63-87dc-4d26-9698-ffdfb282a6ee
username           admin

References

Admin Config

Command Path
write artifactory/config/admin
read artifactory/config/admin
delete artifactory/config/admin

Configure the parameters used to connect to the Artifactory server integrated with this backend.

The two main parameters are url which is the absolute URL to the Artifactory server. Note that /artifactory/api is prepended by the individual calls, so do not include it in the URL here.

The second is access_token which must be an access token enough permissions to generate the other access tokens you'll be using. This value is stored seal wrapped when available. Once set, the access token cannot be retrieved, but the backend will send a sha256 hash of the token so you can compare it to your notes. If the token is a JWT Access Token, it will return additional information such as jfrog_token_id, username and scope.

An optional username_template parameter will override the built-in default username_template for dynamically generating usernames if a static one is not provided.

An optional bypass_artifactory_tls_verification parameter will enable bypassing the TLS connection verification with Artifactory.

No renewals or new tokens will be issued if the backend configuration (config/admin) is deleted.

Parameters

  • url (string) - Address of the Artifactory instance, e.g. https://my.jfrog.io
  • access_token (stirng) - Administrator token to access Artifactory
  • username_template (string) - Optional. Vault Username Template for dynamically generating usernames.
  • use_expiring_tokens (boolean) - Optional. If Artifactory version >= 7.50.3, set expires_in to max_ttl (admin token) or ttl (user token) and force_revocable = true. Default to false.
  • force_revocable (boolean) - Optional. When set to true, we will add the force_revocable flag to the token's extension. In addition, a new configuration has been added that sets the default for setting the force_revocable default when creating a new token - the default of this configuration will be false to ensure that the Circle of Trust remains in place.
  • bypass_artifactory_tls_verification (boolean) - Optional. Bypass certification verification for TLS connection with Artifactory. Default to false.
  • revoke_on_delete (boolean) - Optional. Revoke Administrator access token when this configuration is deleted. Default to false. Will be set to true if token is rotated.
  • allow_scope_override (boolean) - Optional. Determine if scoped tokens should be allowed. This is an advanced configuration option. Default to false.

Example

vault write artifactory/config/admin url=$JFROG_URL \
  access_token=$JFROG_ACCESS_TOKEN \
  username_template="v_{{.DisplayName}}_{{.RoleName}}_{{random 10}}_{{unix_time}}" \
  use_expiring_tokens=true \
  bypass_artifactory_tls_verification=true \
  revoke_on_delete=true

User Token Config

Command Path
write artifactory/user_config
read artifactory/user_config
write artifactory/user_config/:username
read artifactory/user_config/:username

Configures default values for the user_token/:user-name path. The optional username field allows the configuration to be set for specific username.

Parameters

  • access_token (stirng) - Optional. User identity token to access Artifactory. If username is not set then this token will be used for all users.
  • refresh_token (string) - Optional. Refresh token for the user access token. If username is not set then this token will be used for all users.
  • audience (string) - Optional. See the JFrog Platform REST documentation on Create Token for a full and up to date description. Service ID must begin with valid JFrog service type. Options: jfrt, jfxr, jfpip, jfds, jfmc, jfac, jfevt, jfmd, jfcon, or *. For instructions to retrieve the Artifactory Service ID see this documentation
  • refreshable (boolean) - Optional. A refreshable access token gets replaced by a new access token, which is not what a consumer of tokens from this backend would be expecting; instead they'd likely just request a new token periodically. Set this to true only if your usage requires this. See the JFrog Platform documentation on Generating Refreshable Tokens for a full and up to date description. Defaults to false.
  • include_reference_token (boolean) - Optional. Generate a Reference Token (alias to Access Token) in addition to the full token (available from Artifactory 7.38.10). A reference token is a shorter, 64-character string, which can be used as a bearer token, a password, or with the X-JFrog-Art-Apiheader. Note: Using the reference token might have performance implications over a full length token. Defaults to false.
  • use_expiring_tokens (boolean) - Optional. If Artifactory version >= 7.50.3, set expires_in to ttl and force_revocable = true. Defaults to false.
  • force_revocable (boolean) - Optional. When set to true, we will add the force_revocable flag to the token's extension. In addition, a new configuration has been added that sets the default for setting the force_revocable default when creating a new token - the default of this configuration will be false to ensure that the Circle of Trust remains in place.
  • default_ttl (int64) - Optional. Default TTL for issued user access tokens. If unset, uses the backend's default_ttl. Cannot exceed max_ttl.
  • default_description (string) - Optional. Default token description to set in Artifactory for issued user access tokens.

Examples

# Set user token configuration for ALL users
vault write artifactory/config/user_token \
  access_token="eyJ2Z...3sT9r6nA" \
  refresh_token="4ab...471" \
  default_ttl=60s

vault read artifactory/config/user_token

# Set user token configuration for 'myuser' user
vault write artifactory/config/user_token/myuser \
  access_token="eyJ2Z...3sT9r6nA" \
  refresh_token="4ab...471" \
  audience="jfrt@* jfxr@*"

vault read artifactory/config/user_token/myuser

vault delete artifactory/config/user_token/myuser

Role

Command Path
write artifactory/role/:rolename
patch artifactory/role/:rolename
read artifactory/role/:rolename
delete artifactory/role/:rolename

Parameters

  • grant_type (stirng) - Optional. Defaults to client_credentials when creating the access token. You likely don't need to change this.
  • username (string) - Optional. Defaults to using the username_template. The static username for which the access token is created. If the user does not exist, Artifactory will create a transient user. Note that non-administrative access tokens can only create tokens for themselves.
  • scope (string) - Space-delimited list. See the JFrog Artifactory REST documentation on "Create Token" for a full and up to date description.
  • refreshable (boolean) - Optional. A refreshable access token gets replaced by a new access token, which is not what a consumer of tokens from this backend would be expecting; instead they'd likely just request a new token periodically. Set this to true only if your usage requires this. See the JFrog Platform documentation on Generating Refreshable Tokens for a full and up to date description. Defaults to false.
  • audience (string) - Optional. See the JFrog Platform REST documentation on Create Token for a full and up to date description. Service ID must begin with valid JFrog service type. Options: jfrt, jfxr, jfpip, jfds, jfmc, jfac, jfevt, jfmd, jfcon, or *. For instructions to retrieve the Artifactory Service ID see this documentation
  • include_reference_token (boolean) - Optional. Generate a Reference Token (alias to Access Token) in addition to the full token (available from Artifactory 7.38.10). A reference token is a shorter, 64-character string, which can be used as a bearer token, a password, or with the X-JFrog-Art-Apiheader. Note: Using the reference token might have performance implications over a full length token. Defaults to false.
  • default_ttl (int64) - Default TTL for issued user access tokens. If unset, uses the backend's default_ttl. Cannot exceed max_ttl.
  • max_ttl (int64) - Maximum TTL that an access token can be renewed for. If unset, uses the backend's max_ttl. Cannot exceed backend's max_ttl.

Examples

vault write artifactory/roles/test \
  scope="applied-permissions/groups:readers applied-permissions/groups:ci" \
  max_ttl=3h \
  default_ttl=2h

vault read artifactory/roles/test

vault delete artifactory/roles/test

Admin Token

Command Path
read artifactory/token/:rolename

Create an Artifactory access token using paramters from the specified role.

Parameters

  • ttl (int64) - Optional. Override the default TTL when issuing this access token. Cannot exceed smallest (system, backend, role, this request) maximum TTL.
  • max_ttl (int64) - Optional. Override the maximum TTL for this access token. Cannot exceed smallest (system, backend) maximum TTL.

Examples

vault read artifactory/token/test \
  ttl=30m \
  max_ttl=1h

Rotate Admin Token

Command Path
write artifactory/config/rotate

This will rotate the access_token used to access artifactory from this plugin. A new access token is created first then revokes the old access token.

Examples

vault write artifactory/config/rotate

User Token

Command Path
read artifactory/user_token/:username

Provides optional parameters to override default values for the user_token/:username path

Parameters

  • description (string) - Optional. Override the token description to set in Artifactory for issued user access tokens.
  • refreshable (boolean) - Optional. Override the refreshable for this access token. Defaults to false.
  • include_reference_token (boolean) - Optional. Override the include_reference_token for this access token. Defaults to false.
  • use_expiring_tokens (boolean) - Optional. Override the use_expiring_tokens for this access token. If Artifactory version >= 7.50.3, set expires_in to ttl and force_revocable = true. Defaults to false.
  • force_revocable (boolean) - Optional. When set to true, we will add the force_revocable flag to the token's extension. In addition, a new configuration has been added that sets the default for setting the force_revocable default when creating a new token - the default of this configuration will be false to ensure that the Circle of Trust remains in place.
  • ttl (int64) - Optional. Override the default TTL when issuing this access token. Cannot exceed smallest (system, backend, role, this request) maximum TTL.
  • max_ttl (int64) - Optional. Override the maximum TTL for this access token. Cannot exceed smallest (system, backend) maximum TTL.

Examples

vault read artifactory/user_token/test_user \
  description="Refreshable token for Test user"
  refreshable=true \
  include_reference_token=true \
  use_expiring_tokens=true

Development

Local Development Prerequisites

Testing Locally

If you're compiling this yourself and want to test locally, you will need a working Docker environment. You will also need Vault cli and Golang installed, then you can follow the steps below.

  • In first terminal, build the plugin and start the local dev server:
make
  • In another terminal, setup a test artifactory instance.
make artifactory
  • In the same terminal, setup artifactory-secrets-engine in vault with values:
export VAULT_ADDR=http://localhost:8200
export VAULT_TOKEN=root
make setup
  • In the same terminal, you can configure and generate an admin access token:
make admin

Generate an user token:

make usertoken

NOTE: Each time you rebuild (make), vault will restart, so you will need to run make setup again, since vault is in dev mode.

  • Once you are done testing, you can destroy the local artifactory instance:
make stop_artifactory

Other Local Development Details

This section is informational, and is not intended as a step-by-step. If you really want the gory details, checkout the Makefile

Install Vault binary

  • You can follow the Installing Vault instructions.
  • Alternatively, if you are on MacOS, and have HomeBrew, you can use that:
brew tap hashicorp/tap
brew install hashicorp/tap/vault

Start Vault dev server

make start

Export Vault url and token

export VAULT_ADDR='http://127.0.0.1:8200'
export VAULT_TOKEN=root

Build plugin binary

make build

Upgrade plugin binary

To build and upgrade the plugin without having to reconfigure it...

make upgrade

Create Test Artifactory

make artifactory

Set ARTIFACTORY_VERSION to a specific self hosted version to override the default.

Example:

make artifactory ARTIFACTORY_VERSION=7.49.10

Note

If you get a message like:

make: Nothing to be done for `artifactory'.

This simply means that "make" thinks artifactory is >already running due to the existence of the ./vault/>artifactory.env file.

If you want to run a different version, first use make >stop_artifactory. If you stopped artifactory using other >means (docker), then rm vault/artifactory.env manually.

Register artifactory-secrets plugin with Vault server

If you didn't run make upgrade (i.e. just make build), then you need to register the newly built plugin with the Vault server.

make register

Enable artifactory-secrets plugin

make enable

Disable plugin (unmount from vault)

make disable

Note

This is a good idea before stopping artifactory, especially if you plan to change versions of artifactory. Alternatively, just exit vault (Ctrl+c), and it will go back to default state.

Get ADMIN Artifactory token and write it to vault

make admin

NOTE: This following might be some useful environment variables:

  • JFROG_URL
  • ARTIFACTORY_USERNAME
  • ARTIFACTORY_PASSWORD

For example:

JFROG_URL=https://artifactory.example.org ARTIFACTORY_USERNAME=tommy ARTIFACTORY_PASSWORD='SuperSecret' make admin

If you already have a `JFROG_ACCESS_TOKEN``, you can skip straight to that too:

export JFROG_URL=https://artifactory.example.com
export JFROG_ACCESS_TOKEN=(PASTE YOUR JFROG ADMIN TOKEN)
make admin
  • Setup a "test" role, bound to the "readers" group
make testrole

Run Acceptance Tests

make acceptance

This requires the following:

  • A running Artifactory instance
  • Env vars JFROG_URL and JFROG_ACCESS_TOKEN for the running Artifactory instance be set

Issues

  • RTFACT-22477 - proposing CIDR restrictions on the created access tokens.
  • () - Artifactory 7.39.10 fails to revoke previous token during rotation. Recommend 7.42.1. or higher.

Contributors

See the contribution guide.

License

Copyright (c) 2024 JFrog.

Apache 2.0 licensed, see LICENSE file.

vault-plugin-secrets-artifactory's People

Contributors

alexhung avatar backjo avatar betarelease avatar danielmkn avatar davidcorrigan714 avatar dependabot[bot] avatar drautureau-sonarsource avatar evertonsa avatar georgemc98 avatar giri-vsr avatar idcmp avatar kkronenb avatar malena-ebert-sonarsource avatar mitalibo avatar sabre1041 avatar tjm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

vault-plugin-secrets-artifactory's Issues

make acceptance uses inconsistent env variables

as per the conversation in #66 ... we found that make acceptance uses different variables than the rest.

The rest of the make targets use:

JFROG_ACCESS_TOKEN / ARTIFACTORY_URL

make acceptance uses:

ARTIFACTORY_ACCESS_TOKEN / JFROG_URL

Should we change the test code to ARTIFACTORY_URL and JFROG_ACCESS_TOKEN to match the test, or change everything to JFROG_blah or ARTIFACTORY_blah. It does seem a bit strange to use ARTIFACTORY_ for one and JFROG_ for the other.

Circle of Trust Instances cannot be Supported with expiring tokens.

Describe the bug
I am attempting to use the plugin with a Circle of Trust enabled Artifactory instance. For Circle of Trust to work properly, the tokens cannot be revocable. The tokens work if the I set use_expiring_tokens to false, but do not if set to true. This is caused by the tokens being revocable. So, I am asking to make force_revocable a parameter, so that I can use expiring tokens that cannot be revoked. It's also important note our Artifactory's instance has the setting revocable-expiry-threshold = -1.

To Reproduce
Steps to reproduce the behavior:

  1. Setup the Vault plugin with the following config:
vault write artifactory/config/admin     url=<ARTIFACTORY_URL> access_token=ARTIFACTORY_TOKEN" use_expiring_tokens=true

vault write  artifactory/config/user_token scope="applied-permissions/user" default_ttl=24h max_ttl=48h default_description="Generated by Vault" 

admin@devvy:~/vault-engine-github-token$ vault read artifactory/user_token/ <ARTIFACTORY_USERNAME>
Key                Value
---                -----
lease_id           artifactory/user_token/ <ARTIFACTORY_USERNAME>/CgdNHp7zxR9EhEOv20Iorg1r
lease_duration     24h
lease_renewable    true
access_token       
description        Generated by Vault
expires_in         86400
reference_token    n/a
refresh_token      n/a
scope              applied-permissions/user
token_id           e556518d-ef9d-4782-87ac-0a67e47d177f
username            <ARTIFACTORY_USERNAME>

admin@devvy:~/vault-engine-github-token$ vault write  artifactory/config/user_token scope="applied-permissions/user" default_ttl=24h max_ttl=48h default_description="Generated by Vault" use_expiring_tokens=false
Success! Data written to: artifactory/config/user_token
admin@devvy:~/vault-engine-github-token$ vault read artifactory/user_token/ <ARTIFACTORY_USERNAME>
Key                Value
---                -----
lease_id           artifactory/user_token/ <ARTIFACTORY_USERNAME>/Zz9E3RpgLErArYjt2SjaO5v5
lease_duration     24h
lease_renewable    true
access_token       
description        Generated by Vault
expires_in         0
reference_token    n/a
refresh_token      n/a
scope              applied-permissions/user
token_id           a9e4a036-4837-4a1e-9548-7d1e26b559ca
username           <ARTIFACTORY_USERNAME>

This inability to have revocable tokens with expiration prevents us from using the plugin with Circle of Trust enabled instances.

Requirements for and issue

  • A description of the bug
  • A fully functioning vault configuration snippet that can be copy&pasted (no outside files or ENV vars unless that's part of the issue). If this is not supplied, this issue will likely be closed without any effort expended.
  • Your version of artifactory - 7.77.5 Enterprise
  • Your version of vault - v1.13.2 Enterprise
  • Your version of vault plugin - v1.5.0

Expected behavior
The plugin should be able to generate tokens that are not revocable, but do expire.

Doc support with Kubernetes

I'm not sure if this is the right place to ask this question. It's not a bug just a query!

I have configured the vault to connect artifactory using this plugin to dynamically generate the access token, everything works fine for me.
I want to know how can I call the vault role for artifactory within Kubernetes manifest file to dynamically generate the access token. I checked the vault documentation but I couldn't find it.

Is there any documentation available on how to use it or if someone can share a sample Kubernetes manifest file on how to do that would be helpful?

Future Makefile ideas

In an effort to get the "fixes" in #79 in, I am going to start putting future "ideas" in this issue... please feel free to contribute ;)

None of this is critical, and I am sure we all have better things to do with our time, but this "pretty" stuff can make for a much better developer experience, thus making our lives easier, in addition encouraging others to contribute.

~tommy

dev version suggestion

It might be good to indicate "dev" in the non-released version somehow?

  • maybe add -dev
  • maybe -dev-DATESTAMP?
  • Maybe git hash?

Some combination? Something else? :)

revoke not working

I noticed in the vault logs that revoke wasn't working... at the end of make setup we have the following:

vault read artifactory/token/test
Key                Value
---                -----
lease_id           artifactory/token/test/Xm8lGA2dwut8mwtOQ3ul2F3m
lease_duration     2h
lease_renewable    true
access_token       eyJ2ZXIiOiIyIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYiLCJraWQiOiJyRHlWeHZiZ1BqS0pLUE1zUnRfdUlzZC1ESmZCY3k2RDRIUlh1eXgtRmU4In0.eyJzdWIiOiJqZmFjQDAxZ3Zla2FyaDgycm1nMG5jbXlqZXMxYzY0XC91c2Vyc1wvdi10ZXN0LWFxdHZ6MjJrIiwic2NwIjoiYXBwbGllZC1wZXJtaXNzaW9uc1wvZ3JvdXBzOnJlYWRlcnMiLCJhdWQiOiIqQCoiLCJpc3MiOiJqZmFjQDAxZ3Zla2FyaDgycm1nMG5jbXlqZXMxYzY0IiwiZXhwIjoxNjc4NzU5NzkzLCJpYXQiOjE2Nzg3NDg5OTMsImp0aSI6ImIwNTdkMmM2LTUwMWMtNGJhOS04NGFiLWFmMDIyYzcwNWU3ZCJ9.nDVTNo2YuNCXf1kgX2wwqLsss6KQcse0J-c0RfOcnN1fregwK5hxR48WAXOBMGK2HqFT-7Yw9XjnzSropnSynVmL8ISjvrEw2HPXO-Nb8KPsQAOd_UMIQ1b7T6lHGtqhCEAhI_554qV-w82rf2zILcHl-Bp97Vtj7YmN05nxC1O7GWBN9sdQuQnpLXFPnt4KmCV9djE8Y20TrsOrI75yLxKIo9cFwLH6EJyE4hspuJccI45-fFCeUSlKSwk_VhRiX1QtlEndDtFTvrtz5BLkhWAYwT0SqW8fTYCdr6XR13F5x9mTxnQy7-w_uuGj-EkU4YP-QnljgQigGdyKOC26hA
role               test
scope              applied-permissions/groups:readers
token_id           b057d2c6-501c-4ba9-84ab-af022c705e7d
username           v-test-Aqtvz22K

... however if we try to revoke that:

[tmcneely@local artifactory-secrets-plugin]$ vault lease revoke artifactory/token/test/Xm8lGA2dwut8mwtOQ3ul2F3m
All revocation operations queued successfully!

That looks good, right? Wrong!

2023-03-13T17:09:47.805-0600 [INFO]  core: successful mount: namespace="" path=artifactory/ type=artifactory version=""
2023-03-13T17:10:18.900-0600 [WARN]  secrets.artifactory.artifactory_31f2f22d.artifactory.artifactory: revokeToken got bad http status code: statusCode=400 timestamp=2023-03-13T17:10:18.899-0600
2023-03-13T17:10:18.901-0600 [ERROR] expiration: failed to revoke lease: lease_id=artifactory/token/test/Xm8lGA2dwut8mwtOQ3ul2F3m error="failed to revoke entry: resp: (*logical.Response)(nil) err: could not revoke tokenID: b057d2c6-501c-4ba9-84ab-af022c705e7d - HTTP response 400" attempts=1 next_attempt=22.284232237s
2023-03-13T17:10:41.203-0600 [WARN]  secrets.artifactory.artifactory_31f2f22d.artifactory.artifactory: revokeToken got bad http status code: statusCode=400 timestamp=2023-03-13T17:10:41.203-0600
2023-03-13T17:10:41.203-0600 [ERROR] expiration: failed to revoke lease: lease_id=artifactory/token/test/Xm8lGA2dwut8mwtOQ3ul2F3m error="failed to revoke entry: resp: (*logical.Response)(nil) err: could not revoke tokenID: b057d2c6-501c-4ba9-84ab-af022c705e7d - HTTP response 400" attempts=2 next_attempt=42.633743859s
2023-03-13T17:11:23.853-0600 [WARN]  secrets.artifactory.artifactory_31f2f22d.artifactory.artifactory: revokeToken got bad http status code: statusCode=400 timestamp=2023-03-13T17:11:23.853-0600
2023-03-13T17:11:23.853-0600 [ERROR] expiration: failed to revoke lease: lease_id=artifactory/token/test/Xm8lGA2dwut8mwtOQ3ul2F3m error="failed to revoke entry: resp: (*logical.Response)(nil) err: could not revoke tokenID: b057d2c6-501c-4ba9-84ab-af022c705e7d - HTTP response 400" attempts=3 next_attempt=1m9.848250511s
  • It probably shouldn't tell the user "success"
  • There is something bad about the revoke... maybe force_revocable isn't working as designed?
    • NOTE: I cannot revoke them from inside the Artifactory UI either

I am going to come up with a hotfix to disable the force_revocable stuff... then a more complete fix once we sort it out.

useExpiringTokens should be TypeBool

          > Learned something... ![Screenshot 2023-04-26 at 8 46 13 AM](https://user-images.githubusercontent.com/1641316/234613903-dbc6318d-d31e-4bd2-ba69-8c5f63a65f59.png)

We don't need this case statement to check for bool, because no matter what we submit, it comes out as a string? although this feels like a bug to me :)

Most likely because the attribute is defined as TypeString (https://github.com/jfrog/artifactory-secrets-plugin/blob/master/path_config.go#L33) 😄

Instead we should use TypeBool.

Originally posted by @alexhung in #88 (comment)

Admin Token Expiration or auto-rotation

The "admin" token we create in artifactory to configure the aritifactory-secrets-engine in Vault appears to expire after 1 year from issue. Is there a way to automatically renew those tokens? We actually have a "security policy" that ours are supposed to last no more than 30 days, so it is more than just once per year. I think we can just call the /artifactory/config/rotate path or function on a periodic basis, but I am not sure how that would be managed.

Test Coverage Improvement

Current:

ok  	github.com/jfrog/artifactory-secrets-plugin	0.508s	coverage: 62.7% of statements

See coverage.html file (inside coverage.html.gz) for details. Generated with: go tool cover -html=coverage.txt -o ~/Downloads/coverage.html.

Most of the uncovered code is inside if err != nil sections, which I think we can cover with mock tests. Some of the bigger sections are like the "renew" and "revoke" which are super easy in acceptance, but could also be mocked.

expires_in=0 ends up with a 1 year token (will this burn is in 1y)

From my (albeit very quick) testing in 7.49.3, setting the expires_in field to 0 in the POST /access/api/v1/tokens request works to create a non-expiring token. There's no expires_in field when GET /access/api/v1/tokens and no expiry date in the web UI. I am able to revoke by DELETE /access/api/v1/tokens/{id}.

When I create a token with expires_in set to a non-zero value (say 900 = 15 min), I was not able to revoke it which is correct behavior.

{
    "code": "BAD_REQUEST",
    "message": "Token not revocable",
    "detail": "Token not revocable. Token expirationTimeMillis: 1673028200098, issuedAtMillis: 1673027300098, revocableExpiryThresholdMillis: 21600000"
}

Originally posted by @alexhung in #22 (comment)

We may have to add something to the readme if we can figure out what version that "non-expiring" token thing was fixed in. In the one that the user is referencing (7.33.12), even when expires_in=0, the token still ends up with a one year expiration, but it does allow the token to be revoked (curl -X DELETE). I am afraid that our current setup will silently fail 1year from setup due to the "default" 1 year token expiration being applied.

[Question] Using bearer token for login

I was able to successfully configure the vault plugin and get an access token for a Gitlab CI pipeline.

How can I use this token in combination with "conan user" command to log in to a conan remote or also for a docker login command?

The token is a scoped access token, similar to:

vault write artifactory/roles/gitlab \
    scope="applied-permissions/groups:vault-ci " \
    default_ttl=3600 max_ttl=10800

It is unclear to me if I can use the token instead of a password, and which username I have to use during conan login.

Is it possible to use the vault plugin for temporary user & password access to conan (and other package managers such as Docker)?

Scoped down tokens from artifactory role

Is your feature request related to a problem? Please describe.
I am working on setting up this integration and would like to configure our CI role be able to create tokens for any scope, i.e. applied-permissions/groups:*. Currently when a token is created for a role, it uses the scope that is configured without the ability to set an explicitly reduced scope.

Describe the solution you'd like
When calling vault read artifactory/token/jenkins, I'd like to be able to specify a scope such as scope=readonly.

Describe alternatives you've considered
The current behavior is a blocker for our implementation.

Additional context
Add any other context or screenshots about the feature request here.

Embed some useful details into "description" of token

The create token API has a description field, which is defined as:

Free text token description. Useful for filtering and managing tokens.
Limited to 1024 characters.

I suggest that we embed some useful details into that field, possibly even JSON encoded. I don't know what will be available, but at a minimum, I can already see that it would be nice to know what vault server created the token (we have two). I was also thinking stuff like clientIP, username? ... stuff like that. I'd have to look into what is available in the context at that point.

Here is an example of what it looks like after you create a token with a description in 7.38.8's API...

{
    "token_id" : "475435e0-30e6-40a7-8488-8815b871f699",
    "subject" : "jfac@01fr1x1h805xmg0t17xhqr1v7a/users/tommy-2",
    "expiry" : 1677632178,
    "issued_at" : 1677545778,
    "issuer" : "jfac@01fr1x1h805xmg0t17xhqr1v7a",
    "description" : "tommy was here",
    "refreshable" : false
  }

... but the GUI doesn't show it, nor offer filtering on it. I do see description in the Access Tokens section of the GUI of 7.49.8, but it is really difficult to see (have to basically hover it to see the value).
Screen Shot 2023-02-27 at 6 07 42 PM

I don't know when "description" was added, and searching for description in the release notes is a lost cause. @alexhung maybe you can check in the "git" history (or ask someone) to see what version it was added so we can add a check to prevent it from breaking older versions, but I am not too concerned that someone will want to run a crusty old version of Artifactory with the latest and greatest secrets plugin. :)

Verification Steps: Signature on GPG Key?

Describe the bug
Would it be possible to get rid of the WARNING about the GPG Key?

gpg: WARNING: This key is not certified with a trusted signature!

I am not even really sure what that would entail.

To Reproduce
Steps to reproduce the behavior:

  • Follow the GPG Verification on a different system (or maybe inside a docker container) ... or just move aside the .gpg dir for the test? :)
$ gpg --import vault-plugin-secrets-artifactory-public-key.asc
$ curl -JLO https://github.com/jfrog/vault-plugin-secrets-artifactory/releases/download/v1.0.0/artifactory-secrets-plugin_1.0.0.checksums.txt
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100  1582  100  1582    0     0   2912      0 --:--:-- --:--:-- --:--:--     0
$ curl -JLO https://github.com/jfrog/vault-plugin-secrets-artifactory/releases/download/v1.0.0/artifactory-secrets-plugin_1.0.0.checksums.txt.sig
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
100   566  100   566    0     0    924      0 --:--:-- --:--:-- --:--:--   924

$ gpg --verify artifactory-secrets-plugin_1.0.0.checksums.txt.sig 
gpg: assuming signed data in 'artifactory-secrets-plugin_1.0.0.checksums.txt'
gpg: Signature made Mon May 15 12:30:40 2023 MDT
gpg:                using RSA key ED4FF1CD6C2318B470A33A1659FE1520A4A355CD
gpg: Good signature from "Alex Hung <[email protected]>" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg:          There is no indication that the signature belongs to the owner.
Primary key fingerprint: ED4F F1CD 6C23 18B4 70A3  3A16 59FE 1520 A4A3 55CD
  • The script succeeds (exit 0) but the "WARNING" was brought up for discussion by our security folks.

Expected behavior

We may need to modify the steps or at least the "expected output" to look more favorable.

Additional context

Based on the output in the README.md, you produced this on the same system that created the key, or at least has had some additional commands run to fully trust the key.

TTL is not being respected in V1.3

Describe the bug
The default TTL for tokens is not being applied to user tokens in V1.3. V1.2 applied the correct default TTL to user tokens, but V1.3 has broken my org's TTL policy.

To Reproduce
When using the V1.3 plugin, I run these commands:

vault secrets enable -path=artifactory artifactory_1.3

vault write artifactory/config/admin url=<artifactory_instanceurl.com> access_token=<token>

vault write artifactory/config/user_token scope="applied-permissions/user" default_ttl=24h max_ttl=48h default_description="Generated by Vault"

vault read artifactory/user_token/<username>

This is the output of the previous command:

vault read artifactory/user_token/<username>
Key                Value
---                -----
lease_id           artifactory/user_token/<username>/IpZOc5pGLad1BoX82Pf98DDp
lease_duration     768h
lease_renewable    true
access_token       <access_token>
description        n/a
expires_in         0
reference_token    n/a
refresh_token      n/a
scope              applied-permissions/user
token_id           dfd799c8-ef13-471e-be98-120bfd978fd8
username           <username>

The lease duration is not connected to the default_ttl. Whereas, when I run the exact same commands with version 1.2 of the plugin, my user token's TTL is correct.

admin@gold-devvy:~/jfrog--vault-plugin-secrets-artifactory$ vault read artifactory/user_token/<username>
Key                Value
---                -----
lease_id           artifactory/user_token/<username>/f32dmCtgdnYE3Cv5O4mE451f
lease_duration     24h
lease_renewable    true
access_token       <access_token>
description        n/a
expires_in         0
reference_token    n/a
refresh_token      n/a
scope              applied-permissions/user
token_id           dfd799c8-ef13-471e-be98-120bfd978fd8
username           <username>```

Here is my vault config:

vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     true
Sealed          false
Total Shares    1
Threshold       1
Version         1.15.5
Build Date      2024-01-26T14:53:40Z
Storage Type    inmem
Cluster Name    vault-cluster-1eb112b5
Cluster ID      bfe3c12a-6052-3e1f-0bb9-eb984bcfcf3a
HA Enabled      false

I am interacting with an Artifactory instance that is running version EnterpriseX 7.77.5

Requirements for and issue

  • A description of the bug
  • A fully functioning vault configuration snippet that can be copy&pasted (no outside files or ENV vars unless that's part of the issue). If this is not supplied, this issue will likely be closed without any effort expended.
  • Your version of artifactory (you can curl it at $host/artifactory/api/system/version
  • Your version of vault
  • Your version of vault plugin

Expected behavior
The default TTL should be honored for user tokens with V1.3

Desktop (please complete the following information):

  • OS: Linux
  • Browser Chrome

DELETE artifactory/config/admin should revoke its own access token

While looking at the tests (specifically the cleanup), and even our own terraform code, it occurs to me that the DELETE request to /config/admin should revoke its own access token before deleting, especially if it has been rotated.

On a positive note, revoking an already revoked token will return 204, so even if someone (like us) has cleanups written into the terraform code, they will not start failing.

include_reference_token and refreshable not working when configured by default

Describe the bug

When configuring the user_token with include_reference_token and refreshable parameters set to true, requesting a user token seems to not return the reference_token and refresh_token by default.

To Reproduce
Steps to reproduce the behavior:

  1. Configure the user_token
vault write artifactory/config/user_token max_ttl=600 default_ttl=600 include_reference_token=true refreshable=true
  1. Check it has been activated
Key                        Value
---                        -----
audience                   n/a
default_description        Generated by Vault
default_ttl                10m
include_reference_token    true
max_ttl                    10m
refreshable                true
  1. Request a token
vault read artifactory/user_token/myUser
  1. In the response, reference token and refresh token are missing
Key                Value
---                -----
...
reference_token    n/a
refresh_token      n/a
...

However, when specifying the include_reference_token and refreshable parameters when requesting the token

vault read artifactory/user_token/myUser include_reference_token=true refreshable=true

It works, the tokens are returned as expected

Requirements for and issue

  • Artifactory 7.68.19
  • Vault 1.15.5
  • Vault Plugin 1.2.0

Expected behavior
I was expecting to not having to specify the parameters when requesting the token, as they were defined to true on the default configuration. Is this current behaviour the expected behaviour, or did I miss something ?

username template / dynamic username for role

Enhancement to allow creating a templated/dynamic username instead of a "static" account. Maybe default to something like a prefix-unixtimestamp or whatever (automation-1677017997)?

Backstory

We have had a problem where "someone" (something) was using an expired token, and because all the different namespaces were using the same role, and thus the same "username" that username was being "blocked" by artifactory. So, even if they had the correct token, they were getting a backoff. If each retrieved token had a dynamically created user account, they couldn't affect eachother.

This may also be relevant to #27

Admin user cannot rotate token

Artifactory version: 7.33.12
Vault Version: 1.12.2
Artifactory Plugin version: 0.2.0

I have set the Artifactory vault plugin following the instructions here https://www.jfrog.com/confluence/display/JFROG/Hashicorp+Vault+Artifactory+Secrets+Plugin

However when I try to rotate the admin token as documented I get an error

❯ vault write -f artifactory/config/rotate
Error writing data to artifactory/config/rotate: Error making API request.

URL: PUT https://vault.<redacted>/v1/artifactory/config/rotate
Code: 400. Errors:

* error revoking existing AccessToken

I cannot see any errors in the Artifactory logs and in-fact the logs looks like there is success in creating the new token

2022-12-19T10:23:23.066Z|418fe7ca2db009c7|UNKNOWN|UNKNOWN|admin|jfac@01e7hr4k76vr470nkn64m81n3n/users/admin|C|TKN|{"added":{"owner":"jfac@01e7hr4k76vr470nkn64m81n3n","created":"1671445403063","expirationTime":"1702981403063","subject":"jfac@01e7hr4k76vr470nkn64m81n3n/users/admin","scope":"applied-permissions/admin","id":"2662c852-b527-40a9-a6c3-8b328d6fde2d","type":"generic","username":"admin"}}

10:23:27.102
2022-12-19T10:23:23.038Z|4f01f51bfd85b52|<redacted>|token:admin|GET|/api/system/version|200|-1|0|13|art-secrets-plugin
 
10:23:27.326
2022-12-19T10:23:23.038Z [4f01f51bfd85b52 ] [ACCEPTED LOGIN]   for client : token:admin / <redacted>

But there doesn't seem to be anything in the logs for even trying to revoke the old token

Set token expiration and force_revokable from Artifactory 7.50.3

https://www.jfrog.com/confluence/display/JFROG/JFrog+Platform+REST+API#JFrogPlatformRESTAPI-CreateToken

From Artifactory 7.50.3, the "force revocable" flag in the tokens has been removed as a default setting and is now a Boolean parameter called force_revocable in the Create Token REST API. When this parameter is set to true, we will add the force_revocable flag to the token's extension.

I think this will allow us to set the expiration date on the tokens themselves too, while still allowing them to be revokable (without messing with the config)... This will help prevent the "orphaned tokens" we are seeing periodically.

Risky documentation (sha256 sum)

It is my opinion that the following step in the README.md is risky:

$ vault write sys/plugins/catalog/secret/artifactory \
    sha_256="$(sha256sum path/to/plugin/directory/artifactory | cut -d " " -f 1)" \
    command="artifactory"

The whole point of a security product like Vault validating the sha256sum of the binary is to ensure that it has not been modified. If you just read the sha256sum from the filesystem as you "register" the plugin, it will of course match, but you haven't validated anything. At a minimum, it would be a good idea to note that the procedure is for proof of concept or lab testing, and should not be used in production or anywhere security matters.

I would suggest that the binary itself should have a published SHA256sum, that is GPG signed, so that we can ensure that the binary is unmodified. I do thank you for at least publishing the list of sums for the zip files, which allows us to validate the zip file, but as they are not signed, they could be modified at the same time the binaries are being compromised.

Thanks,
Tommy

slashes in admin token username shows wrong username

Due to the simplistic parsing of username from the subject of the JWT token, it will display the username incorrectly in vault read /artifactory/config/admin if the username has a forward slash (/) in it. This does not affect anything, but should probably be fixed. I ran into this when I was using ${VAULT_NAMESPACE}-vault-admin for a "learning-center/tommy-mcneely" namespace, and I got "tommy-mcneely" as the username.

NOTE: The Artifactory Tokens UI also shows the same bug.

Vault errors with "HTTP response 400" when trying to provision a new token

Hi,

Following the instructions here and trying this against our Artifactory SaaS setup (it's running now version 7.26.3) - and when I'm trying to provision a token with Vault, I only get:

2021-12-15T16:40:21.099+0100 [WARN]  secrets.artifactory.artifactory_cf9f4e43.artifactory.artifactory: got non-200 status code: statusCode=401 timestamp="2021-12-15T16:40:21.099+0100"

Any idea how to poke this...?

Also, I'm running Vault locally (Vault version 1.9.1) and the Artifactory plugin version is v0.1.0-beta: https://github.com/jfrog/artifactory-secrets-plugin/releases/tag/v0.1.0

This is what I did exactly:

export TOKEN=<our_admin_token>

vault secrets enable artifactory

vault write artifactory/config/admin \
               url=https://artifactory.ourcompany.com/artifactory \
               access_token=$TOKEN

 vault write artifactory/roles/githubactions \
               username="example-githubactions" \
               scope="api:* member-of-groups:readers" \
               default_ttl=1h max_ttl=3h 

vault list artifactory/roles

vault read artifactory/token/githubactions

My question would be, is the plugin (and / or the docs) 100% up to date...? Anyone else bumped to this?

Local Testing discussion

I think the first step to being able to do automated tests would be to define what a local test environment would look like.

I suggest using something like minikube or kind (especially since kind has a built-in gitlab-action)... then install artifactory-jcr helm chart. (since that doesn't require a license)

I think we just need to figure out how to "bootstrap" it so that there isn't a bunch of interactive tasks.

Can we get any help from the artifactory devs on how we might manage that?
We (our mutual customer) also has Artifactory Enterprise, and has completely automated the setup, but that is a lot of custom terraform code (with a lot of shell script resources)... licenses, etc... seems like a lot of unnecessary overhead.

I think the first step will be trying to get the initial admin token -- https://jfrog.com/knowledge-base/artifactory-how-to-create-an-admin-token-without-using-the-ui/

... then feeding that back into the make setup (see #37)

Then, of course, we need to figure out what we are going to test... how many versions, etc etc... but I think getting a working Artifactory stood up is a crucial step.

returning 400 on role not found

I'm calling a get on a role for this secret plugin that does not exist and I'm geting 400 error instead of 404

GET https://vault.vault.svc:8200/v1/artifactory/raffa-artifactory/roles/one-repo-only\nCode: 400. Errors:\n\n* no such role

The role actually does not exist, the code should return 404.

Show token ID (maybe other details) for admin token

I suggest that we use some of the code for rotating admin tokens to show the token ID, and perhaps other details in the vault read artifactory/admin/config output. It wouldn't take much effort to move that parsing capability out and use it. Before I add that capability, I wanted to know if it was something that is desirable or "undesirable" ;)

I am sitting here looking at ~50 access tokens with the username "admin" .... in addition to #34 which would allow me to name the admin access token (and maintain that name through rotation), I think it would be useful if I could see which token ID vault is using, specifically. (since we rotated, the sha256 is useless to us) ;)

GPG Signed *binary* sha256sums in release

It would be a "Good Thing" (tm) if we could get a GPG signed sha256sum of the plugin binary, since that is what Vault is looking for. We are currently publishing the sha256sum of the zip file, which is good, and I don't suggest changing that, but it should also be GPG signed. ;)

I saw a public key in the release and figured it was time we started doing it ;)

Max_ttl can be exceeded when configured at plugin level

Describe the bug
When configuring a max_ttl at the plugin level, the value can be overidden and thus exceeded by a specific request.

To Reproduce
Steps to reproduce the behavior:

  1. Mount the plugin
vault secrets enable artifactory
  1. Configure the plugin
vault write artifactory/config/admin url=<myUrl> access_token=<myAccessToken>
  1. Configure the user_token
vault write artifactory/config/user_token default_description="Generated by Vault" max_ttl=7200 default_ttl=3600 include_reference_token=true refreshable=true

The max_ttl is 2 hours. The default_ttl is 1 hour.

  1. Check the configuration
vault read artifactory/config/user_token

Key                        Value
---                        -----
access_token_sha256        ***
audience                   n/a
default_description        Generated by Vault
default_ttl                1h
force_revocable            <nil>
include_reference_token    true
max_ttl                    2h
refresh_token_sha256       ***
refreshable                true
scope                      applied-permissions/admin
token_id                   ***
use_expiring_tokens        false
username                   vault
  1. Ask for a token by specifying a max_ttl and a default_ttl that exceed the max_ttl configured on the plugin
vault read artifactory/user_token/<myUser> max_ttl=15000 ttl=15000
  1. Check the lease duration of the delivered token
vault read artifactory/user_token/<myUser> max_ttl=15000 ttl=15000

Key                Value
---                -----
lease_id           artifactory/user_token/<myUser>/***
lease_duration     4h10m

➡️ The lease duration is exceeding the max_ttl configured at the plugin level.

  1. Mount the plugin on another path with a max-lease-ttl and a default-lease-ttl
vault secrets enable -path=artifactory2 -max-lease-ttl=7200 -default-lease-ttl=3600 artifactory
  1. Configure the artifactory2 plugin just like the artifactory plugin, and ask for a token that exceeds the max-lease-ttl
vault read artifactory2/user_token/<myUser> max_ttl=15000 ttl=15000
Key                Value
---                -----
lease_id           artifactory2/user_token/<myUser>/***
lease_duration     2h

The lease duration is limited to 2 hours no matter the max_ttl parameter.

Requirements for and issue

  • Artifactory 7.71.18
  • Vault 1.16.2
  • Vault Plugin 1.6.0

Expected behavior

Reading the documentation: https://github.com/jfrog/vault-plugin-secrets-artifactory?tab=readme-ov-file#user-token-path, I was expecting the max_ttl to be limited to the max_ttl configured at plugin level (2 hours in this scenario), no matter if the user is giving a max_ttl parameter.

When setting the max-lease-ttl at the secret mount level, the max_ttl cannot be exceed as expected.

Is this an expected behaviour? If yes, is setting the max-lease-ttl when mounting the secret engine the proper way to definitely limit the max_ttl?

non-admin token

Is your feature request related to a problem? Please describe.

We have a multi-tenant artifactory, each tenant has their own Vault cluster. We setup the vault-artifactory-secrets-engine, but we have to give it an "admin" token. This would allow anyone to create a role with group=admin and obtain an admin token to artifactory. (their pipelines have administrative access to Vault so that they can setup GKE authentication and policies)

Describe the solution you'd like

I would like to be able to use a token for something less than platform admin. Maybe a project admin token? This may require support form JFAC as well.

Describe alternatives you've considered

  • We tried using a "user" level token in MOUNT/config/admin (using a non-admin token)

    • but it is unable to rotate (likely because the rotate is hard-coded to create an admin token)
    • We also could not seem to get it to issue a token (kept getting error 400)... but I think this is resolvable
  • Using a separate (shared) vault, but then we need to grant them the ability to link their GKE clusters in... but maybe we could be more restrictive about what they have access to do since it is not "their" vault cluster

  • Google Artifact Registry :p

Additional context

What we need is a folder or "namespace" in artifactory. We thought that is what "Projects" provided. WIth the GCP Secrets Engine, we can grant "owner" level access to a specific sub-folder of the organization, they can do whatever they want within that sub-folder (within org policy of course). We would like to figure out a way to provide similar functionality.

We also created a JFrog Support ticket for this - 288012

Allow for "username" parameter on /config/rotate to change token username

We have just changed all of our admin tokens from the username "admin" to "${VAULT_NAMESPACE}-vault-admin," and had to do it all "by hand" (as in generate the new admin token and vault write artifactory/config/admin access_token=$NEW_TOKEN. It might be nice if people could specify a username parameter to the /config/rotate endpoint, allowing them to set/change the username for the admin token.

I got error"* 1 error occurred: * internal error"

Dear,
When I executed the command "vault write artifactory/config/vault url=https://artifactory.xxxx.cn/artifactory access_token=$TOKEN"
I got the error as below:
Error writing data to artifactory/config/vault: Error making API request.

URL: PUT https://vault-test.xxx.cn/v1/artifactory/config/vault
Code: 500. Errors:

  • 1 error occurred:
    • internal error

Must I use the "admin" user instead of "vault" user? my vault version is enterprise Vault v1.5.4+prem, Could you do me a favor please?

Bump version to 1.0.0

The JFrog team feels that we have reached a reasonable point to declare this plugin 'released' as 1.0.0.

Pros:

  • Allows finer control of SemVer. i.e. we now have 'patch' version field to use.

Cons:

  • Nothing material or functional

Please leave comment if you feel otherwise.

BATs acceptance tests?

While I was looking for ways to test for the storage errors, I noticed that the Hashicorp plugins tend to use "BATs" for acceptance testing. That way they are able to spin up docker containers as needed (artifactory) and use the vault binary directly instead of interfacing at the "Backend" layer in code, which feels like more like unit testing (unit tests with a real artifactory server).

I am not saying we can't keep the go-based acceptance tests, but it feels kinda strange to have direct code access when doing acceptance tests. Acceptance Tests are supposed to be "black-box" or completely separate from the code. We can write them in golang, but they need to be in a separate directory (package).

Since the "normal" user interface is the vault binary, it feels like a shell based testing system would be easier.

Thoughts?

Should DELETE artifactory/config/admin cleanup all leased tokens?

If you DISABLE the plugin mount, vault will try to cleanup all the leased tokens.

However, if you vault delete artifactory/config/admin, we could potentially leave behind a bunch of leased (generated) tokens in Artifactory, which by default, never expire.

Should the plugin be cleaning all of those up?

I am wondering if we provide this "DELETE" endpoint, if that means that we need to code in the cleanup?

Token lease not being respected

Artifactory version: 7.33.12
Vault Version: 1.12.2
Artifactory Plugin version: 0.2.0

I have set the Artifactory vault plugin following the instructions here https://www.jfrog.com/confluence/display/JFROG/Hashicorp+Vault+Artifactory+Secrets+Plugin

However when I request a token with a 1h lease even though the plugin returns the lease is for 1h it is valid of 1 YEAR in Artifactory.

❯ vault write artifactory/roles/ci \
∙ username="<redacted>" \
∙ scope="applied-permissions/groups:<redacted>" \
∙ default_ttl=1h max_ttl=3h
Success! Data written to: artifactory/roles/ci

Token has a lease_duration of 1h

❯ vault read artifactory/token/ci
Key                Value
---                -----
lease_id           artifactory/token/ci/xpFDZ5qdWmnaHUP49BLZl2ag
lease_duration     1h
lease_renewable    true
access_token       ey<redacted>
role               ci
scope              applied-permissions/groups:<redacted>
token_id           b79872ec-b8fc-4f1e-b7e0-53443e2aa578

But in Artifactory the token lives for a year

{
    "token_id" : "b79872ec-b8fc-4f1e-b7e0-53443e2aa578",
    "subject" : "jfac@01e7hr4k76vr470nkn64m81n3n/users/<redacted>",
    "expiry" : 1702977006,
    "issued_at" : 1671441006,
    "issuer" : "jfac@01e7hr4k76vr470nkn64m81n3n",
    "refreshable" : false
  }

Using identity metadata in token roles

We're looking to get this setup in the next few weeks, though I've played with in the past. I'm trying to figure out how I might allow users to authenticate to Vault and then get an API token through Vault for their specific account in Artifactory. For example some templated policy like:

path "artifactory/users/{{identity.entity.id}}" {
  capabilities = [ "read" ]
}

That would allow users to use their authenticated identity in Vault to get an API token for JFrog for their account. Is this doable somehow? The way the roles path is structured now it looks like I could only map devs to some shared role and not their exact identity in Artifactory.

Add Examples (was: filename in release)

... as per the changelog in v0.2.12:

IMPROVEMENTS:

- Plugin now reports its version to Vault server. You can see it with `vault plugin list` command.
- Remove version number from the binary file name (now `artifactory-secrets-plugin`, vs `artifactory-secrets-plugin_v0.2.6`) now that it registers as 'versioned' plugin with Vault server.
- Update README on how to register plugin to reflect this change of binary name.
- Update Makefile to use GoRelease (same as GitHub Action) to build binary for development process.

The problem is that when upgrading the plugin on a cluster, you will need both binaries on the system at the same time, so you will need to rename it to have the version in the name or do something funky like _new or _old ??

I can handle this in my packer script, but it was easier to just have the name be the version.

Or.. maybe I am doing something wrong? :)

something like:

#!/bin/bash -e
## LOTS OF OTHER STUFF
  ## Artifactory Secrets Plugin - keep the name artifactory-secrets-plugin_v(VERSION), to allow safe upgrades
  ARTIFACTORY_PLUGIN_VERSIONS="0.2.11 0.2.12"
  for ver in ${ARTIFACTORY_PLUGIN_VERSIONS}; do
    curl -sSOL "https://github.com/jfrog/artifactory-secrets-plugin/releases/download/v${ver}/artifactory-secrets-plugin_${ver}_linux_amd64.zip"
    curl -sSL "https://github.com/jfrog/artifactory-secrets-plugin/releases/download/v${ver}/artifactory-secrets-plugin_${ver}_checksums.txt"|grep linux_amd64  > artifactory-secrets-plugin-checksums.txt
    sha256sum -c artifactory-secrets-plugin-checksums.txt
    unzip -jo "artifactory-secrets-plugin_${ver}_linux_amd64.zip" "artifactory-secrets-plugin*"
    if test -f "artifactory-secrets-plugin_v${ver}"; then
      sudo mv "artifactory-secrets-plugin_v${ver}" "${VAULT_PLUGINS_DIR}/artifactory-secrets-plugin_v${ver}" # Keep versioned binary
    else
      sudo mv artifactory-secrets-plugin "${VAULT_PLUGINS_DIR}/artifactory-secrets-plugin_v${ver}" # make the binary versioned
    fi
    sudo chown root:root "${VAULT_PLUGINS_DIR}/artifactory-secrets-plugin_v${ver}"
    sudo chmod 755 "${VAULT_PLUGINS_DIR}/artifactory-secrets-plugin_v${ver}"
  done

Should change the way "version" is detected

This works, as is, but I think we could design the "version check" stuff better. I'd like to make it so that the version is detected once at config time, then maybe during "reload" ? Then we could switch the "checks" to just compare the version from config.

Originally posted by @TJM in #45 (review)

@alexhung - I agree. @danielmkn and I are about to do something similar in the Terraform provider and stores the version in the context.

@alexhung 19 hours ago
You probably can add a field to the Backend and then call InitializeFunc to fetch the version, then store it in the new field.

test: config/rotate with a bad current token returns the wrong error

https://github.com/jfrog/artifactory-secrets-plugin/pull/88/files/4ffd1cba0391435ed41c7067081c3e565fd26eae#r1184453545

This is a matter of opinion, I think that it should contain "that" error, but it does not. It returns the error about the certificate instead. I want to adjust this in a future MR.. trying to not change a bunch of code while writing the tests ;)

I think I want to "return" the correct error (error parsing existing access token) ... maybe including the reason (could not get the certificate). I was just not sure how I wanted to handle it just yet. Trying to emulate these error cases is kinda hard. I think a pure mock test may actually be easier here.

Renaming repository

Rename this repository from artifactory-secrets-plugin to vault-plugin-secrets-artifactory, following the same pattern as other Vault plugin repos (as well as Terraform provider).

Other references to the original name (binary name, path, etc.) would not be affected by this repo name change.

Artifactory version

[tmcneely@local ~]$ docker pull releases-docker.jfrog.io/jfrog/artifactory-jcr:latest
latest: Pulling from jfrog/artifactory-jcr
Digest: sha256:d9ec79a9613627b17a27ae7bbc7cfb7de41cf998e04a7d7bbf945dc3dc3d952c
Status: Image is up to date for releases-docker.jfrog.io/jfrog/artifactory-jcr:latest
releases-docker.jfrog.io/jfrog/artifactory-jcr:latest
[tmcneely@local ~]$ docker images | grep jfrog
releases-docker.jfrog.io/jfrog/artifactory-jcr   7.55.7    d4807e14cca2   34 hours ago   1.63GB
releases-docker.jfrog.io/jfrog/artifactory-jcr   latest    803ee2eab100   6 days ago     1.63GB
releases-docker.jfrog.io/jfrog/artifactory-jcr   7.49.10   9adc79e21925   9 days ago     1.57GB
releases-docker.jfrog.io/jfrog/artifactory-jcr   7.55.2    7eda28873e4f   2 weeks ago    1.63GB
releases-docker.jfrog.io/jfrog/artifactory-jcr   7.39.10   3a88970e5f76   7 months ago   1.26GB

... I wonder whether something just broken during the 7.55.7 release? I was thinking of changing the default value for ARTIFACTORY_VERSION to latest, then maybe adding a docker pull to ensure it updates, but thought I would ask about that.

Tommy

Rotate Admin Token

I know it is listed in the "What's missing" section, but I thought we should have an issue to track it.

This plugin should rotate the admin/config access_token when it's configured (optionally?)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.