{"id":16777824,"url":"https://github.com/falcosuessgott/vops","last_synced_at":"2025-03-17T02:31:38.786Z","repository":{"id":65920173,"uuid":"587635683","full_name":"FalcoSuessgott/vops","owner":"FalcoSuessgott","description":"A wrapper for the HashiCorp Vault CLI","archived":false,"fork":false,"pushed_at":"2024-06-17T08:31:09.000Z","size":1962,"stargazers_count":18,"open_issues_count":10,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-02-27T16:49:16.251Z","etag":null,"topics":["go","hashicorp","hashicorp-vault","vault"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/FalcoSuessgott.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-01-11T08:10:23.000Z","updated_at":"2024-09-12T09:26:09.000Z","dependencies_parsed_at":null,"dependency_job_id":"fa3d5daa-2c55-442a-b62b-344a3872d483","html_url":"https://github.com/FalcoSuessgott/vops","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FalcoSuessgott%2Fvops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FalcoSuessgott%2Fvops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FalcoSuessgott%2Fvops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/FalcoSuessgott%2Fvops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/FalcoSuessgott","download_url":"https://codeload.github.com/FalcoSuessgott/vops/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243841125,"owners_count":20356440,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","hashicorp","hashicorp-vault","vault"],"created_at":"2024-10-13T07:25:59.132Z","updated_at":"2025-03-17T02:31:37.566Z","avatar_url":"https://github.com/FalcoSuessgott.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\u003ch2\u003e A HashiCorp Vault Cluster Management tool \u003c/h2\u003e\n\u003c/div\u003e\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd\u003e Usage \u003c/td\u003e \u003ctd\u003e vops config \u003c/td\u003e\n\u003c/tr\u003e\n\u003ctr\u003e\n\u003ctd\u003e\n\n```bash\n# configure\nVOPS_CONFIG=\"./vops.yaml\"\nVOPS_CLUSTER=\"vault-dev\" \n# print example config\nvops config example\n# list cluster and render configs\nvops config validate\n# initialize\nvops init --cluster \u003ccluster\u003e # -A for all Cluster\n# unseal\nvops unseal -c \u003ccluster\u003e # optional: -n \u003cnode\u003e\n# seal\nvops seal -c \u003ccluster\u003e\n# generate root token\nvops generate-root -c \u003ccluster\u003e\n# rekey unseal/recovery keys\nvops rekey -c \u003ccluster\u003e\n# save/restory snapshots\nvops snapshot save -c \u003ccluster\u003e\nvops snapshot restore -c \u003ccluster\u003e -s \u003csnapshot-file\u003e -f \n# custom commands\nvops custom -c \u003ccluster\u003e -x \u003ccustom command\u003e\n# adhoc commands\nvops adhoc -x \"vault status\" -c \u003ccluster\u003e\n# open UI\nvops ui -c \u003ccluster\u003e\n# copy token\nvops token -c \u003ccluster\u003e\n# vault login \nvops login -c \u003ccluster\u003e\n```\n\n\u003c/td\u003e\n\u003ctd\u003e \n\n```yaml\nCluster:\n  - Name: vault-dev\n    Addr: \"http://127.0.0.1:8200\"\n    TokenExecCmd: \"jq -r '.root_token' {{ .Keys.Path }}\"\n    Keys:\n      Path: \"{{ .Name }}.json\" # https://github.com/FalcoSuessgott/vops#about-the-keypath-file\n      Autounseal: false  # true if autounseal configured\n      Shares: 1 # optional, default: 5\n      Threshold: 1 # optional: default: 3\n    SnapshotDirectory: \"snapshots/\"\n    Nodes:\n      - \"{{ .Addr }}\"\n    ExtraEnv:\n      VAULT_SKIP_VERIFY: true\n\n  - Name: vault-prod\n    Addr: \"https://{{ .Name }}.example.com:8200\"\n    TokenExecCmd: \"vault login $(cat ${{ .ENV.HOME }}/.vault_token)\"\n    Keys:\n      Path: \"{{ .Name }}.json\"\n      Shares: 5\n      Threshold: 3\n    SnapshotDirectory: \"{{ .ENV.HOME }}/snapshots/\"\n    Nodes:\n      - \"{{ .Name }}-01.example.com:8200\"\n      - \"{{ .Name }}-02.example.com:8200\"\n      - \"{{ .Name }}-03.example.com:8200\"\n      - \"{{ .Name }}-04.example.com:8200\"\n      - \"{{ .Name }}-05.example.com:8200\"\n\nCustomCmds:\n  list-peers: 'vault operator raft list-peers'\n  status: 'vault status'\n```\n\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://github.com/FalcoSuessgott/vops/actions/workflows/test.yml/badge.svg\" alt=\"drawing\"/\u003e\n\u003cimg src=\"https://github.com/FalcoSuessgott/vops/actions/workflows/lint.yml/badge.svg\" alt=\"drawing\"/\u003e\n\u003cimg src=\"https://codecov.io/gh/FalcoSuessgott/vops/branch/main/graph/badge.svg\" alt=\"drawing\"/\u003e\n\u003cimg src=\"https://img.shields.io/github/downloads/FalcoSuessgott/vops/total.svg\" alt=\"drawing\"/\u003e\n\u003cimg src=\"https://img.shields.io/github/v/release/FalcoSuessgott/vops\" alt=\"drawing\"/\u003e\n\u003cimg src=\"https://img.shields.io/docker/pulls/falcosuessgott/vops\" alt=\"drawing\"/\u003e\n\u003c/div\u003e\n\n# Background\nI automate, develop and maintain a lot of Vault cluster for different clients. When automating Vault using tools such as `terraform` and `ansible` I was missing a small utility that allows me to quickly perform certain operations like generate a new root token or create a snapshot. Thus I came up with `vops`, which stands for **v**ault-**op**eration**s**\n\n# Features \n* template your `vops.yaml` using [clever naming conventions](https://github.com/FalcoSuessgott/vops#usage)\n* Iterate over all defined cluster (`--all-cluster/-A`) for every supported option\n* [Initialize](https://github.com/FalcoSuessgott/vops#initialize) a Vault \n* [Seal](https://github.com/FalcoSuessgott/vops#seal) \u0026 [Unseal](https://github.com/FalcoSuessgott/vops#unseal) a Vault \n* [Generate a new root token](https://github.com/FalcoSuessgott/vops#generate-root)\n* [save](https://github.com/FalcoSuessgott/vops#snapshot-save) a Vault (raft storage required) Snapshot\n* [open the UI](https://github.com/FalcoSuessgott/vops#ui) in your default browser\n* [perform a vault login](https://github.com/FalcoSuessgott/vops#login) to a specified cluster in order to continue working with the vault CLI\n* [copy the token](https://github.com/FalcoSuessgott/vops#token) from a the token exec command to your clipboard buffer for Vault UI login\n* define [custom commands](https://github.com/FalcoSuessgott/vops#custom-commands) then can be run for any cluster\n* run [adhoc commands](https://github.com/FalcoSuessgott/vops#adhoc-commands)\n\n# Installation\n```bash\n# curl\nversion=$(curl -S \"https://api.github.com/repos/FalcoSuessgott/vops/releases/latest\" | jq -r '.tag_name[1:]')\ncurl -OL \"https://github.com/FalcoSuessgott/vops/releases/latest/download/vops_${version}_$(uname)_$(uname -m).tar.gz\"\ntar xzf \"vops_${version}_$(uname)_$(uname -m).tar.gz\"\n./vops version\n\n# Go \ngo install github.com/FalcoSuessgott/vops@latest\nvops version\n\n# Docker/Podman\ndocker run ghcr.io/falcosuessgott/vops version\n\n# Ubuntu/Debian\nversion=$(curl -S \"https://api.github.com/repos/FalcoSuessgott/vops/releases/latest\" | jq -r '.tag_name[1:]')\ncurl -OL \"https://github.com/FalcoSuessgott/vops/releases/latest/download/vops_${version}_linux_amd64.deb\"\nsudo dpkg -i \"./vops_${version}_linux_amd64.deb\"\nvops version\n\n# Fedora/CentOS/RHEL\nversion=$(curl -S \"https://api.github.com/repos/FalcoSuessgott/vops/releases/latest\" | jq -r '.tag_name[1:]')\ncurl -OL \"https://github.com/FalcoSuessgott/vops/releases/latest/download/vops_${version}_linux_amd64.rpm\"\nsudo dnf localinstall \"./vops_${version}_linux_amd64.rpm\"\nvops version\n\n# Sources\ngit clone https://github.com/FalcoSuessgott/vops \u0026\u0026 cd vops\ngo build \n```\n\n# Quickstart\n## Prerequisites \nStart a Vault with Integrated Storage locally:\n\n```bash\nmkdir raft\ncat \u003c\u003cEOF \u003e vault-cfg.hcl\ncluster_addr = \"http://127.0.0.1:8201\"\napi_addr = \"http://127.0.0.1:8200\"\n\nstorage \"raft\" {\n  path = \"./raft\"\n  node_id = \"node\"\n}\n\nui = true\n\nlistener \"tcp\" {\n  address = \"0.0.0.0:8200\"\n  tls_disable = true\n}\nEOF\nvault server -config=vault-cfg.hcl\n```\n\n## `vops.yaml`\nIn another Terminal create a `vops.yaml` example config:\n\n```bash\nvops config example \u003e vops.yaml\ncat vops.yaml\n```\n\ncreated the following `vops.yaml`:\n\n```yaml\nCluster:\n  - Name: cluster-1\n    Addr: http://127.0.0.1:8200\n    TokenExecCmd: jq -r '.root_token' {{ .Keys.Path }}\n    Keys:\n      Path: '{{ .Name }}.json'\n      Shares: 1\n      Threshold: 1\n    SnapshotDirectory: '{{ .Name }}/'\n    Nodes:\n      - '{{ .Addr }}'\n    ExtraEnv:\n      VAULT_TLS_SKIP_VERIFY: true\nCustomCmds:\n  list-peers: vault operator raft list-peers\n  status: vault status\n```\n\n## List Cluster\n\u003e lists all defined clusters and validates their settings, performs a vault login\n```bash\n$\u003e vops config validate      \n[ Validate ]\nusing ./assets/vops.yaml\n\nName:                   cluster-1\nAddress:                http://127.0.0.1:8200\nTokenExecCmd:           jq -r '.root_token' cluster-1.json\nTokenExecCmd Policies:  [root]\nNodes:                  [http://127.0.0.1:8200]\nKey Config:             {Path: cluster-1.json, Shares: 5, Threshold: 5}\nSnapshot Directory:     snapshots/\n```\n\n\n## Initialize\n\u003e initialize vault cluster \n```bash\n$\u003e vops init -c \u003ccluster\u003e\n[ Intialization ]\nusing vops.yaml\n\n[ cluster-1 ]\nattempting intialization of cluster \"cluster-1\" with 1 shares and a threshold of 1\napplying VAULT_TLS_SKIP_VERIFY\nsuccessfully initialized cluster-1 and wrote keys to cluster-1.json.\n```\n\n**Tip:** You can also specify the cluster by providing a environment variable named `VOPS_CLUSTER` or run the command for all cluster using `-A` or `--all-cluster`.\n\n## Unseal\n\u003e unseal a vault cluster using the specified keyfile\n```bash\n\u003e vops unseal -c \u003ccluster\u003e\n[ Unseal ]\nusing vops.yaml\n\n[ cluster-1 ]\napplying VAULT_TLS_SKIP_VERIFY\nusing keyfile \"cluster-1.json\"\nunsealing node \"http://127.0.0.1:8200\"\ncluster \"cluster-1\" unsealed\n```\n\n## Seal\n\u003e seal a cluster\n```bash\n\u003e vops seal -c \u003ccluster\u003e\n[ Seal ]\nusing vops.yaml\n\n[ cluster-1 ]\napplying VAULT_TLS_SKIP_VERIFY\nexecuted token exec command\ncluster \"cluster-1\" sealed\n```\n\n## Rekey\n\u003e generates new unseal/recover keys\n```bash\n\u003e vops rekey -c \u003ccluster\u003e\n[ Rekey ]\nreading ./assets/vops.yaml\n\n[ cluster-1 ]\nperforming a rekey for cluster-1 with 5 shares and a threshold of 3\napplying VAULT_SKIP_VERIFY\nusing keyfile \"cluster-1.json\"\ninitialized rekey process\n[01/03] successfully entered key\n[02/03] successfully entered key\n[03/03] successfully entered key\nrekeying successfully completed\nrenamed keyfile \"cluster-1.json\" for cluster \"cluster-1\" to \"cluster-1_2023-03-10-16:05:16.json\".\nHint: snapshots depend on the unseal/recovery keys from the moment the snapshot has been created.\nThis way you always have the matching unseal/recovery keys for the specific snapshot if needed ready.\n```\n\n\n## Generate Root\n\u003e generates a new root token\n```bash\n\u003e vops generate-root -c \u003ccluster\u003e\n[ Generate Root Token ]\nusing vops.yaml\n\n[ cluster-1 ]\napplying VAULT_TLS_SKIP_VERIFY\ngenerated on OTP for root token creation\nstarted root token generation process\nroot token generation completed\nnew root token: \"hvs.dmhO9aVPT0aBB1G7nrj3UdDh\" (make sure to update your token exec commands in your vops configfile if necessary.)\n```\n\n## Snapshots\n### Snapshot save\n\u003e creates a snapshot and stores the corresponding keyfile with it (only integrated storage)\n```bash\n\u003e vops snapshot save -c \u003ccluster\u003e\n[ Save ]\nreading ./assets/vops.yaml\n\n[ cluster-1 ]\napplying VAULT_SKIP_VERIFY\nexecuted token exec command\ncreated snapshot file \"snapshots/cluster-1_2023-03-10-16:03:38.gz\" for cluster \"cluster-1\"\ncreated snapshot keyfile \"snapshots/cluster-1_2023-03-10-16:03:38_keyfile.json\" for cluster \"cluster-1\"\n```\n\n### Snapshot Restore\n\u003e restores a snapshot (only integrated storage)\n```bash\n\u003e vos snapshot restore -c \u003ccluster\u003e -s \u003csnapshot-file\u003e\n[ Restore ]\nreading ./assets/vops.yaml\n\n[ cluster-1 ]\napplying VAULT_SKIP_VERIFY\nexecuted token exec command\nrestrored snapshot for cluster-1\nRemember to use the root token und unseal/recovery keys from the snapshot you just restored    \n```\n\n## Custom Commands\nYou can run any defined custom commands:\n\n```bash\n\u003e vops custom --list\n[ Custom ]\nusing vops.yaml\n\n[ Available Commands ]\n\"list-peers\": \"vault operator raft list-peers\"\n\"status\": \"vault status\"\n\nrun any available command with \"vops custom -x \u003ccommand name\u003e -c \u003ccluster-name\u003e\".\n\n\u003e vops custom -x \u003ccustom command\u003e -c \u003ccluster\u003e\n[ Custom ]\nusing vops.yaml\n\n[ cluster-1 ]\napplying VAULT_TLS_SKIP_VERIFY\napplying VAULT_ADDR\napplying VAULT_TOKEN\ntoken exec command successful\n\n$\u003e vault status\nKey                     Value\n---                     -----\nSeal Type               shamir\nInitialized             true\nSealed                  false\nTotal Shares            1\nThreshold               1\nVersion                 1.12.1\nBuild Date              2022-10-27T12:32:05Z\nStorage Type            raft\nCluster Name            vault-cluster-982e7d76\nCluster ID              10939fbf-fdfd-04b3-e037-dd044ce38fa3\nHA Enabled              true\nHA Cluster              https://127.0.0.1:8201\nHA Mode                 active\nActive Since            2023-02-16T14:54:35.541380933Z\nRaft Committed Index    36\nRaft Applied Index      36\n```\n\n## Adhoc Commands\n\u003e similar to Ansible, run a adhoc command for a cluster\n```bash\nvops adhoc -x \"vault status\" -c \u003ccluster\u003e\n[ Adhoc ]\nreading ./assets/vops.yaml\n\n[ cluster-1 ]\napplying VAULT_SKIP_VERIFY\napplying VAULT_ADDR\napplying VAULT_TOKEN\ntoken exec command successful\n\n$\u003e vault status\nKey                     Value\n---                     -----\nSeal Type               shamir\nInitialized             true\nSealed                  false\nTotal Shares            5\nThreshold               5\nVersion                 1.12.1\nBuild Date              2022-10-27T12:32:05Z\nStorage Type            raft\nCluster Name            vault-cluster-39a4f8c3\nCluster ID              c9f326fa-9e59-b527-04a0-c4270995cc7f\nHA Enabled              true\nHA Cluster              https://127.0.0.1:8201\nHA Mode                 active\nActive Since            2023-03-02T17:51:12.542083099Z\nRaft Committed Index    38\nRaft Applied Index      38\n```\n\n## UI\n\u003e opens the Vault Address in your default browser\n\n```bash\nvops ui -c \u003ccluster\u003e\n[ UI ]\nusing ./assets/vops.yaml\n\n[ cluster-1 ]\nopening http://127.0.0.1:8200\n```\n\n## Login \n\u003e performs a vault token login command in order to work with the vault CLI\n\n```bash\nvops login -c \u003ccluster\u003e\n[ Login ]\nusing ./assets/vops.yaml\n\n[ cluster-1 ]\nperforming a vault login to http://127.0.0.1:8200\napplying VAULT_SKIP_VERIFY\napplying VAULT_TLS_CA\napplying VAULT_ADDR\napplying VAULT_TOKEN\nexecuted token exec command\n\n$\u003e vault login $(jq -r '.root_token' cluster-1.json)\nSuccess! You are now authenticated. The token information displayed below\nis already stored in the token helper. You do NOT need to run \"vault login\"\nagain. Future Vault requests will automatically use this token.\n\nKey                  Value\n---                  -----\ntoken                hvs.5aYsklTzIYR26iWRttqFoCm1\ntoken_accessor       R7l5fidrohVB5Tc4pXBcUtoO\ntoken_duration       ∞\ntoken_renewable      false\ntoken_policies       [\"root\"]\nidentity_policies    []\npolicies             [\"root\"]\n```\n\n## Token\n\u003e copy the token from the token exec command to your clipboard buffer\n\n```bash\nvops token -c \u003ccluster\u003e\n\n[ Token ]\nusing ./assets/vops.yaml\n\n[ cluster-1 ]\ncopying token for cluster cluster-1\napplying VAULT_SKIP_VERIFY\napplying VAULT_TLS_CA\napplying VAULT_ADDR\napplying VAULT_TOKEN\ntoken for cluster cluster-1 copied to clipboard buffer.\n```\n\n---\n\n## About the `Key.Path`-file\nfor now, `vops` expect the JSON format output from a `vault operator init` command:\n\n```json\n{\n  \"unseal_keys_b64\": [\n    \"YrnZCLIdwKDNn9RYkUx3A7J9/I4ogORIXYcTtJ/AWtg=\"\n  ],\n  \"unseal_keys_hex\": [\n    \"62b9d908b21dc0a0cd9fd458914c7703b27dfc8e2880e4485d8713b49fc05ad8\"\n  ],\n  \"unseal_shares\": 1,\n  \"unseal_threshold\": 1,\n  \"recovery_keys_b64\": [],\n  \"recovery_keys_hex\": [],\n  \"recovery_keys_shares\": 0,\n  \"recovery_keys_threshold\": 0,\n  \"root_token\": \"hvs.EhCMSSb1uCW1y0aHI1IZ3feO\"\n}\n```\n\nLater you can also just list the unseal/recovery keys in the `vops.yml` aswell, or specifiy pgp encrypted key files.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffalcosuessgott%2Fvops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffalcosuessgott%2Fvops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffalcosuessgott%2Fvops/lists"}