diff --git a/Makefile b/Makefile index 2aebebd..69f1319 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ BUDDY_GET_TOKEN?=curl BUDDY_BASE_URL?= BUDDY_INSECURE?=false -# bin generates the releaseable binaries for this plugin +# bin generates releaseable binaries for this plugin build: fmtcheck generate @CGO_ENABLED=0 BUILD_TAGS='$(BUILD_TAGS)' sh -c "'$(CURDIR)/scripts/build.sh'" @@ -24,4 +24,4 @@ fmtcheck: fmt: gofmt -w $(GOFMT_FILES) -.PHONY: bin default generate test bootstrap fmt fmtcheck \ No newline at end of file +.PHONY: bin default generate test bootstrap fmt fmtcheck diff --git a/README.md b/README.md index 6ea244b..bd193f1 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,19 @@ -# A [Vault](https://www.vaultproject.io) plugin for [Buddy](https://buddy.works). +# The [HCP Vault](https://www.vaultproject.io) plugin for [Buddy](https://buddy.works). -## Build +## Binaries -Pre-built binaries for Linux, macOS and Windows can be found at [the releases page](https://github.com/buddy/vault-plugin-secrets-buddy/releases). +Pre-built binaries for Linux, macOS and Windows can be found in the [releases directory](https://github.com/buddy/vault-plugin-secrets-buddy/releases). For other platforms, there are currently no pre-built binaries available. -For other platforms, there are not currently pre-built binaries available. +To compile a new binary, clone this repository and run `make` from the project directory. -To build, `git clone` this repository and run `make` from the project directory. +## Vault installation -## Installation +The HCP Vault plugin system is documented on the Hashicorp's [Vault documentation site](https://www.vaultproject.io/docs/internals/plugins.html). -The Vault plugin system is documented on the [Vault documentation site](https://www.vaultproject.io/docs/internals/plugins.html). +To install the vault, define the plugin directory using the `plugin_directory` configuration directive and place the `vault-plugin-secrets-buddy` executable in that directory. -You will need to define a plugin directory using the `plugin_directory` configuration directive, then place the `vault-plugin-secrets-buddy` executable downloaded/generated above in the directory. +Example commands for registering and starting the plugin: -Sample commands for registering and starting to use the plugin: ```sh $ vault plugin register \ -sha256=$(openssl sha256 < vault-plugin-secrets-buddy) \ @@ -26,75 +25,101 @@ $ vault secrets enable buddy Success! Enabled the buddy secrets engine at: buddy/ ``` -## Usage +## Root token configuration -## Configuration +### Generating token -Setup root token that will create short-lived tokens. Root token must have scope `TOKEN_MANAGE` +To create short-lived tokens, you first need to configure a [root token in Buddy](/docs/api/getting-started/oauth2/personal-access-token). The root token must have the scope `TOKEN_MANAGE`: + + + +>**Note** +> You can fortify your tokens by allowing access from selected IP's and/or workspace domains. + +### Saving to vault + +Once generated, copy the value of the token and save it to the vault: ```sh $ vault write buddy/config token=ROOT_TOKEN Success! Data written to: buddy/config ``` -Additional options: - -`token_auto_rotate` - Enable auto rotating of root token. The day before expiration there will be an attempt to rotate it. When error is encountered plugin will try every hour to rotate it until the token expires. +Available options: -`token_ttl_in_days` - The TTL of the new rotated root token in days. Default: 30. Min: 2 +- `token_auto_rotate` – enables auto-rotation of the root token one day before the expiration date. If an error is encountered, the plugin will reattempt to rotate the token on every hour until it eventually expires. -`base_url` - The Buddy API base url. You may need to set this to your Buddy On-Premises API endpoint. Default: `https://api.buddy.works` + > **Warning** + > If no auto-rotation is set, the token should be generated with no expiration date. -`insecure` - Disable SSL verification of API calls. You may need to set this to `true` if you are using Buddy On-Premises without signed certificate. Default: false +- `token_ttl_in_days` – the lease time of the rotated root token in days. Default: `30`. Min: `2` +- `base_url` – the Buddy API base URL. You may need to set this in your Buddy On-Premises API endpoint. Default: `https://api.buddy.works` +- `insecure` – disables the SSL verification of the API calls. You may need to set this to `true` if you are using Buddy On-Premises without a signed certificate. Default: `false` -## Rotate root token +### Rotating root token -Attempt to rotate the root credentials used to communicate with Buddy. Old token will be removed +Updates the root credentials used for communication with Buddy. Rotating the root token removes the old one. To rotate the token, run ```sh $ vault write -f buddy/rotate-root Success! Data written to: buddy/rotate-root ``` -## Roles +## Vault token configuration -Create a role and read its current credentials: +### Creating token role + +To create a role for the token, run `vault write buddy/roles/ROLE_NAME` with the lease time and scopes. + +Example command for creating the RUN_PIPELINE role: ```sh -$ vault write buddy/roles/r1 \ +$ vault write buddy/roles/run_pipeline \ ttl=30 \ scopes=WORKSPACE,EXECUTION_RUN -Success! Data written to: buddy/roles/r1 +Success! Data written to: buddy/roles/run_pipeline ``` -All options: - -`ttl` - Default lease for generated token. Vault will automatically revoke token after the duration. If not set or set to 0, will use system default. - -`max_ttl` - Maximum duration that generated token cab be extended to. If not set or set to 0, will use system default. +Available options: -`scopes` - The comma separated list of scopes +- `ttl` – the default lease time for the generated token after which the token is automatically revoked. If not set or set to `0`, system default is used. +- `max_ttl` – the maximum time the generated token can be extended to before it eventually expires. If not set or set to `0`, system default is used. +- `scopes` – the [list of scopes](https://buddy.works/docs/api/getting-started/oauth2/introduction#supported-scopes) in the role, comma-separated. +- `ip_restrictions` – the list of IP addresses to which the token is restricted, comma-separated. +- `workspace_restrictions` – the list of workspace domains to which the token is restricted, comma-separated. -`ip_restrictions` - The comma separated list of IP addresses +### Generating role credentials -`workspace_restrictions` - The comma separated list of workspace domains - -Read the credentials: +To generate new credentials, run `vault read buddy/creds/ROLE_NAME`: ```sh -$ vault read buddy/creds/r1 +$ vault read buddy/creds/run_pipeline Key Value --- ----- -lease_id buddy/creds/r1/EUwKywNTUy7Msa6jWs3FR8Fq +lease_id buddy/creds/run_pipeline/EUwKywNTUy7Msa6jWs3FR8Fq lease_duration 30s lease_renewable true token 5d225d46-c361-4b3f-ba84-9d83891313a0 ``` -Grab token into env variable: +### Extend/Revoke + +To extend the lease time of the token, run +```sh +$ vault lease renew $lease_id +``` + +To revoke the token, run +```sh +$ vault lease revoke $lease_id +``` + +### Saving into variable + +To save the token into an environment variable, run ```sh -TOKEN=$(vault read -format=json buddy/creds/r1 | jq -r .data.token) +$ TOKEN=$(vault read -format=json buddy/creds/r1 | jq -r .data.token) ``` diff --git a/backend.go b/backend.go index 242dec2..e113a44 100644 --- a/backend.go +++ b/backend.go @@ -139,10 +139,10 @@ func Factory(ctx context.Context, conf *logical.BackendConfig) (logical.Backend, } const backendHelp = ` -The Buddy secrets engine dynamically generates short time lived -personal access tokens based on predefined scopes and filters. +The Buddy secrets engine dynamically generates short-lived +Personal Access Tokens based on predefined scopes and filters. -After mounting this secrets engine, credentials to manage Buddy tokens -must be configured with the "config/" endpoints. You can generate tokens -using the "tokens/" endpoints. +After mounting the secrets engine, the credentials required to manage +Buddy tokens must be configured with the "config/" endpoints. +You can the generate the tokens using the "tokens/" endpoints. ` diff --git a/path_config.go b/path_config.go index 67a8a1a..993e645 100644 --- a/path_config.go +++ b/path_config.go @@ -40,23 +40,23 @@ func pathConfig(b *buddySecretBackend) *framework.Path { Fields: map[string]*framework.FieldSchema{ "token": { Type: framework.TypeString, - Description: "The Personal Access Token. Must have scope `TOKEN_MANAGE`. Required", + Description: "The Personal Access Token (root token) generated in Buddy. Must have the scope `TOKEN_MANAGE`. Required", }, "token_ttl_in_days": { Type: framework.TypeInt, - Description: fmt.Sprintf("The TTL of the new rotated root token in days. Default: %d. Min: %d", defaultRootTokenTTL, minRootTokenTTL), + Description: fmt.Sprintf("The lease time of the rotated root token in days. Default: %d. Min: %d", defaultRootTokenTTL, minRootTokenTTL), }, "token_auto_rotate": { Type: framework.TypeBool, - Description: "Enable auto rotating of root token. The day before expiration there will be an attempt to rotate it. When error is encountered plugin will try every hour to rotate it until the token expires.", + Description: "Enables auto-rotation of the root token one day before the expiration date. If an error is encountered, the plugin will reattempt to rotate the token on every hour until it eventually expires.", }, "base_url": { Type: framework.TypeString, - Description: fmt.Sprintf("The Buddy API base url. You may need to set this to your Buddy On-Premises API endpoint. Default: `%s`", defaultBaseUrl), + Description: fmt.Sprintf("The Buddy API base URL. You may need to set this in your Buddy On-Premises API endpoint. Default: `%s`", defaultBaseUrl), }, "insecure": { Type: framework.TypeBool, - Description: "Disable SSL verification of API calls. You may need to set this to `true` if you are using Buddy On-Premises without signed certificate. Default: false", + Description: "Disables the SSL verification of the API calls. You may need to set this to true if you are using Buddy On-Premises without a signed certificate. Default: false", }, }, Operations: map[logical.Operation]framework.OperationHandler{ @@ -142,7 +142,7 @@ func (b *buddySecretBackend) pathConfigWrite(ctx context.Context, req *logical.R if expiresAtErr == nil && expiresAt.Unix() < rotateAt.Unix() { rotateAt = time.Date(expiresAt.Year(), expiresAt.Month(), expiresAt.Day()-1, expiresAt.Hour(), expiresAt.Minute(), expiresAt.Second(), expiresAt.Nanosecond(), expiresAt.Location()) if rotateAt.Unix() < minExpirationDate.Unix() { - return logical.ErrorResponse("token expiration date must be after %s, insted it expires at: %s", minExpirationDate.Format(time.RFC3339), expiresAt.Format(time.RFC3339)), nil + return logical.ErrorResponse("token expiration date must be set after %s, instead it expires at: %s", minExpirationDate.Format(time.RFC3339), expiresAt.Format(time.RFC3339)), nil } } config.TokenAutoRotateAt = rotateAt @@ -241,6 +241,6 @@ func (b *buddySecretBackend) saveConfig(ctx context.Context, config *buddyConfig const confHelpSyn = "Configure the Buddy Secret backend" const confHelpDesc = ` The Buddy secret backend requires credentials for managing Personal -Access Tokens. This endpoint is used to configure those credentials -as well as default values for the backend in general +Access Tokens). This endpoint is used to configure those credentials, + as well as the default values for the backend in general. ` diff --git a/path_role.go b/path_role.go index 61d04f9..35e0d76 100644 --- a/path_role.go +++ b/path_role.go @@ -27,27 +27,27 @@ func pathRole(b *buddySecretBackend) *framework.Path { Fields: map[string]*framework.FieldSchema{ "name": { Type: framework.TypeLowerCaseString, - Description: "Name of the role", + Description: "The name of the role", }, "ttl": { Type: framework.TypeDurationSecond, - Description: "Default lease for generated token. Vault will automatically revoke token after the duration. If not set or set to 0, will use system default.", + Description: "The default lease time for the generated vault token after which the token is automatically revoked. If not set or set to 0, system default is used.", }, "max_ttl": { Type: framework.TypeDurationSecond, - Description: "Maximum duration that generated token cab be extended to. If not set or set to 0, will use system default.", + Description: "The maximum time the generated token can be extended to before it eventually expires. If not set or set to 0, system default is used.", }, "scopes": { Type: framework.TypeCommaStringSlice, - Description: "The comma separated list of scopes", + Description: "The list of scopes in the role, comma-separated.", }, "ip_restrictions": { Type: framework.TypeCommaStringSlice, - Description: "The comma separated list of IP addresses", + Description: "The list of IP addresses to which the token is restricted, comma-separated.", }, "workspace_restrictions": { Type: framework.TypeCommaStringSlice, - Description: "The comma separated list of workspace domains", + Description: "The list of workspace domains to which the token is restrictred, comma-separated.", }, }, Operations: map[logical.Operation]framework.OperationHandler{ diff --git a/path_rotate_root.go b/path_rotate_root.go index 79d3559..7f527c8 100644 --- a/path_rotate_root.go +++ b/path_rotate_root.go @@ -71,8 +71,8 @@ func (b *buddySecretBackend) pathRotateRoot(ctx context.Context, req *logical.Re const rotateHelpSyn = "Attempt to rotate the root credentials used to communicate with Buddy" const rotateHelpDesc = ` -This path will attempt to generate new root token for the user. -The new token will have the sames scopers and filters as the old one +This path will attempt to generate a new root token for the user. +The new token will have the sames scopes and filters as the old one. The old token will be removed if possible. -The new token won't be returned from this endpoint, nor the read config +The new token will not be returned from this endpoint or by reading the config. ` diff --git a/path_token.go b/path_token.go index 1871584..8ca01b8 100644 --- a/path_token.go +++ b/path_token.go @@ -95,7 +95,7 @@ func pathToken(b *buddySecretBackend) *framework.Path { Fields: map[string]*framework.FieldSchema{ "role": { Type: framework.TypeLowerCaseString, - Description: "Name of the Vault role", + Description: "The name of the Vault role", }, }, Operations: map[logical.Operation]framework.OperationHandler{ @@ -110,8 +110,8 @@ func pathToken(b *buddySecretBackend) *framework.Path { } } -const tokenHelpSyn = "Requet Personal Access Token for a given Vault role." +const tokenHelpSyn = "Request Personal Access Token for the given Vault role." const tokenHelpDesc = ` -This path creates or updates dynamic Personal Access Token. -It will be automatically deleted whe the lease has expired. +This path creates or updates the dynamic Personal Access Token. +It will be automatically deleted when the lease time has expired. ` diff --git a/root-token-config.png b/root-token-config.png new file mode 100644 index 0000000..b2dc3fd Binary files /dev/null and b/root-token-config.png differ diff --git a/scripts/build.sh b/scripts/build.sh index c380546..2078528 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -2,13 +2,13 @@ TOOL=vault-plugin-secrets-buddy -# This script builds the application from source for a platform. +# This script builds the application from the source for the provided platform. set -e GO_CMD=${GO_CMD:-go} -# Get the parent directory of where this script is. +# Get the parent directory of the script location. SOURCE="${BASH_SOURCE[0]}" while [ -h "$SOURCE" ] ; do SOURCE="$(readlink "$SOURCE")"; done DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )" @@ -16,10 +16,10 @@ DIR="$( cd -P "$( dirname "$SOURCE" )/.." && pwd )" # Change into that directory cd "$DIR" -# Set build tags +# Set the build tags BUILD_TAGS="${BUILD_TAGS}:-${TOOL}" -# Get the git commit +# Get the commit GIT_COMMIT="$(git rev-parse HEAD)" GIT_DIRTY="$(test -n "`git status --porcelain`" && echo "+CHANGES" || true)" @@ -30,7 +30,7 @@ case $(uname) in ;; esac -# Delete the old dir +# Delete the old directory echo "Removing old directory..." rm -f bin/* rm -rf pkg/* @@ -45,7 +45,7 @@ ${GO_CMD} build \ -tags "${BUILD_TAGS}" \ "${DIR}/cmd/${TOOL}" -# Move all the compiled things to the $GOPATH/bin +# Move all compiled things to the $GOPATH/bin OLDIFS=$IFS IFS=: MAIN_GOPATH=($GOPATH) IFS=$OLDIFS diff --git a/scripts/dev.sh b/scripts/dev.sh index 6aa5b6f..35da1e5 100755 --- a/scripts/dev.sh +++ b/scripts/dev.sh @@ -32,7 +32,7 @@ function cleanup { } trap cleanup EXIT -echo "Login in Vault" +echo "Logging into Vault" vault login root &>/dev/null echo "Building" diff --git a/scripts/gofmtcheck.sh b/scripts/gofmtcheck.sh index 7f2dbfb..16022b7 100755 --- a/scripts/gofmtcheck.sh +++ b/scripts/gofmtcheck.sh @@ -4,9 +4,9 @@ echo "Checking fmt..." gofmt_files=$(gofmt -l $(find . -name '*.go' | grep -v vendor)) if [[ -n ${gofmt_files} ]]; then - echo 'gofmt needs running on the following files:' + echo 'gofmt must be run on the following files:' echo "${gofmt_files}" - echo "You can use the command: \`make fmt\` to reformat code." + echo "You can use the command: \`make fmt\` to reformat the code." exit 1 else echo "ok" diff --git a/tests/run.sh b/tests/run.sh index a14524c..928443e 100755 --- a/tests/run.sh +++ b/tests/run.sh @@ -87,7 +87,7 @@ function buddy_test_config { api_create_token "$BUDDY_TOKEN" '{ "name": "test2", "expires_in": 2, "scopes": ["TOKEN_MANAGE"] }' t2=$(echo "$BUDDY_FETCH_TOKEN" | jq -r '.token') res=$(vault_cmd write buddy/config token="$t2" token_auto_rotate=true base_url=$BUDDY_BASE_URL insecure=$BUDDY_INSECURE 2>&1 || true) - test_contains "$res" "token expiration date must be after" "Configuration must validate token expiration date" + test_contains "$res" "token expiration date must be set after" "Configuration must validate token expiration date" # read valid config api_create_token "$BUDDY_TOKEN" '{ "name": "test3", "expires_in": 10, "scopes": ["TOKEN_MANAGE"] }' t3=$(echo "$BUDDY_FETCH_TOKEN" | jq -r '.token')