Skip to content

Commit

Permalink
feat(adhoc): add adhoc command
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom Morelly committed Mar 2, 2023
1 parent 0568c6f commit 5eac0ec
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 22 deletions.
75 changes: 54 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,18 +90,17 @@ CustomCmds:
I 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**

# Features
* define as many vault cluster as you need
* template your `vops.yaml` and be able to use clever naming convetions
* Iterate over all defined cluster for every supported option
* Initialize a Vault
* Seal & Unseal a Vault
* Rekey a Vault
* Generate a new root token
* save and restore a Vault (raft storage required) Snapshot
* open the UI in your default browser
* perform a vault login to a specified cluster in order to continue working with the vault CLI
* copy the token from a the token exec command to your clipboard buffer for Vault UI login
* define custom commands then can be run for any cluster
* template your `vops.yaml` using [clever naming conventions](https://github.com/FalcoSuessgott/vops#usage)
* Iterate over all defined cluster (`--all-cluster/-A`) for every supported option
* [Initialize](https://github.com/FalcoSuessgott/vops#initialize) a Vault
* [Seal](https://github.com/FalcoSuessgott/vops#seal) & [Unseal](https://github.com/FalcoSuessgott/vops#unseal) a Vault
* [Generate a new root token](https://github.com/FalcoSuessgott/vops#generate-root)
* [save](https://github.com/FalcoSuessgott/vops#snapshot-save) a Vault (raft storage required) Snapshot
* [open the UI](https://github.com/FalcoSuessgott/vops#ui) in your default browser
* [perform a vault login](https://github.com/FalcoSuessgott/vops#login) to a specified cluster in order to continue working with the vault CLI
* [copy the token](https://github.com/FalcoSuessgott/vops#token) from a the token exec command to your clipboard buffer for Vault UI login
* define [custom commands](https://github.com/FalcoSuessgott/vops#custom-commands) then can be run for any cluster
* run [adhoc commands](https://github.com/FalcoSuessgott/vops#adhoc-commands)

# Installation
```bash
Expand Down Expand Up @@ -261,7 +260,7 @@ Snapshot Directory: snapshots/
## Initialize
> initialize vault cluster
```bash
$> vops init --cluster cluster-1
$> vops init -c <cluster>
[ Intialization ]
using vops.yaml
Expand All @@ -276,7 +275,7 @@ successfully initialized cluster-1 and wrote keys to cluster-1.json.
## Unseal
> unseal a vault cluster using the specified keyfile
```bash
> vops unseal --cluster cluster-1
> vops unseal -c <cluster>
[ Unseal ]
using vops.yaml
Expand All @@ -290,7 +289,7 @@ cluster "cluster-1" unsealed
## Seal
> seal a cluster
```bash
> vops seal --cluster cluster-1
> vops seal -c <cluster>
[ Seal ]
using vops.yaml
Expand All @@ -307,7 +306,7 @@ tbd.
## Generate Root
> generates a new root token
```bash
> vops generate-root --cluster cluster-1
> vops generate-root -c <cluster>
[ Generate Root Token ]
using vops.yaml
Expand All @@ -322,7 +321,7 @@ new root token: "hvs.dmhO9aVPT0aBB1G7nrj3UdDh" (make sure to update your token e
## Snapshots
### Snapshot save
```bash
> vops snapshot save --cluster cluster-1
> vops snapshot save -c <cluster>
[ Snapshot Save ]
using vops.yaml
Expand All @@ -349,7 +348,7 @@ using vops.yaml
run any available command with "vops custom -x <command name> -c <cluster-name>".
> vops custom -x status --cluster --cluster-1
> vops custom -x <custom command> -c <cluster>
[ Custom ]
using vops.yaml
Expand Down Expand Up @@ -380,11 +379,45 @@ Raft Committed Index 36
Raft Applied Index 36
```

## Adhoc Commands
> similar to Ansible, run a adhoc command for a cluster
```bash
vops adhoc -x "vault status" -c <cluster>
[ Adhoc ]
reading ./assets/vops.yaml
[ cluster-1 ]
applying VAULT_SKIP_VERIFY
applying VAULT_ADDR
applying VAULT_TOKEN
token exec command successful
$> vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 5
Threshold 5
Version 1.12.1
Build Date 2022-10-27T12:32:05Z
Storage Type raft
Cluster Name vault-cluster-39a4f8c3
Cluster ID c9f326fa-9e59-b527-04a0-c4270995cc7f
HA Enabled true
HA Cluster https://127.0.0.1:8201
HA Mode active
Active Since 2023-03-02T17:51:12.542083099Z
Raft Committed Index 38
Raft Applied Index 38
```

## UI
> opens the Vault Address in your default browser

```bash
vops ui --cluster cluster-1
vops ui -c <cluster>
[ UI ]
using ./assets/vops.yaml
Expand All @@ -396,7 +429,7 @@ opening http://127.0.0.1:8200
> performs a vault token login command in order to work with the vault CLI

```bash
vops login --cluster cluster-1
vops login -c <cluster>
[ Login ]
using ./assets/vops.yaml
Expand Down Expand Up @@ -428,7 +461,7 @@ policies ["root"]
> copy the token from the token exec command to your clipboard buffer

```bash
vops token --cluster cluster-1
vops token -c <cluster>
[ Token ]
using ./assets/vops.yaml
Expand Down
82 changes: 82 additions & 0 deletions cmd/adhoc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package cmd

import (
"fmt"
"strings"

"github.com/FalcoSuessgott/vops/pkg/config"
"github.com/FalcoSuessgott/vops/pkg/exec"
"github.com/spf13/cobra"
)

var command string

func adhocCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "adhoc",
Short: "run any command",
SilenceUsage: true,
SilenceErrors: true,
RunE: func(cmd *cobra.Command, args []string) error {
if command == "" {
return fmt.Errorf("no command specified. Use --command flag")
}

if allCluster {
for _, cluster := range cfg.Cluster {
if err := runAdhocCommand(cluster); err != nil {
return err
}
}

return nil
}

cluster, err := cfg.GetCluster(cluster)
if err != nil {
return err
}

if err := runAdhocCommand(*cluster); err != nil {
return err
}

return nil
},
}

cmd.Flags().StringVarP(&command, "command", "x", command, "the command to run")

return cmd
}

func runAdhocCommand(cluster config.Cluster) error {
parts := strings.Split(command, " ")

fmt.Printf("\n[ %s ]\n", cluster.Name)

cluster.ExtraEnv["VAULT_ADDR"] = cluster.Addr
cluster.ExtraEnv["VAULT_TOKEN"] = cluster.Token

if err := cluster.ApplyEnvironmentVariables(cluster.ExtraEnv); err != nil {
return err
}

if err := cluster.RunTokenExecCommand(); err != nil {
return err
}

fmt.Println("token exec command successful")
fmt.Println()
fmt.Printf("$> %s", command)
fmt.Println()

out, err := exec.Run(parts)
if err != nil {
return err
}

fmt.Println(string(out))

return nil
}
1 change: 1 addition & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func NewRootCmd(v string, writer io.Writer) *cobra.Command {
unsealCmd(),
sealCmd(),
rekeyCmd(),
adhocCmd(),
generateRootCmd(),
versionCmd(v),
snapshotCmd(),
Expand Down
7 changes: 6 additions & 1 deletion cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,12 @@ func TestE2E(t *testing.T) {
},
{
name: "custom",
command: []string{"custom", "-x", "status", "cluster-1"},
command: []string{"custom", "-x", "status", "-c", "cluster-1"},
err: false,
},
{
name: "adhoc",
command: []string{"adhoc", "-x", "vault status", "cluster-1"},
err: false,
},
{
Expand Down
17 changes: 17 additions & 0 deletions cmd/vops.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Cluster:
- Name: cluster-1
Addr: http://127.0.0.1:8200
TokenExecCmd: jq -r '.root_token' {{ .Keys.Path }}
Keys:
Path: '{{ .Name }}.json'
Shares: 1
Threshold: 1
SnapshotDirectory: '{{ .Name }}/'
Nodes:
- '{{ .Addr }}'
ExtraEnv:
VAULT_TLS_SKIP_VERIFY: true
CustomCmds:
list-peers: vault operator raft list-peers
status: vault status

0 comments on commit 5eac0ec

Please sign in to comment.