command/revoke: revoke

This commit is contained in:
Mitchell Hashimoto 2015-03-31 19:21:02 -07:00
parent 67e4bdf1e4
commit bbaa137f4e
8 changed files with 218 additions and 1 deletions

View File

@ -14,6 +14,8 @@ func (c *Sys) Renew(id string) (*Secret, error) {
func (c *Sys) Revoke(id string) error {
r := c.c.NewRequest("PUT", "/v1/sys/revoke/"+id)
resp, err := c.c.RawRequest(r)
defer resp.Body.Close()
if err == nil {
defer resp.Body.Close()
}
return err
}

View File

@ -1,3 +1,21 @@
package command
import (
"testing"
"github.com/hashicorp/vault/api"
)
const FixturePath = "./test-fixtures"
func testClient(t *testing.T, addr string, token string) *api.Client {
config := api.DefaultConfig()
config.Address = addr
client, err := api.NewClient(config)
if err != nil {
t.Fatalf("err: %s", err)
}
client.SetToken(token)
return client
}

87
command/revoke.go Normal file
View File

@ -0,0 +1,87 @@
package command
import (
"fmt"
"strings"
)
// RevokeCommand is a Command that mounts a new mount.
type RevokeCommand struct {
Meta
}
func (c *RevokeCommand) Run(args []string) int {
var prefix bool
flags := c.Meta.FlagSet("revoke", FlagSetDefault)
flags.BoolVar(&prefix, "prefix", false, "")
flags.Usage = func() { c.Ui.Error(c.Help()) }
if err := flags.Parse(args); err != nil {
return 1
}
args = flags.Args()
if len(args) != 1 {
flags.Usage()
c.Ui.Error(fmt.Sprintf(
"\nRevoke expects one argument: the ID to revoke"))
return 1
}
vaultId := args[0]
client, err := c.Client()
if err != nil {
c.Ui.Error(fmt.Sprintf(
"Error initializing client: %s", err))
return 2
}
if err := client.Sys().Revoke(vaultId); err != nil {
c.Ui.Error(fmt.Sprintf(
"Revoke error: %s", err))
return 1
}
c.Ui.Output(fmt.Sprintf("Key revoked with ID '%s'.", vaultId))
return 0
}
func (c *RevokeCommand) Synopsis() string {
return "Revoke a secret."
}
func (c *RevokeCommand) Help() string {
helpText := `
Usage: vault revoke [options] id
Revoke a secret by its Vault ID.
This command revokes a secret by its Vault ID that was returned
with it. Once the key is revoked, it is no longer valid.
With the -prefix flag, the revoke is done by prefix: any secret prefixed
with the given partial ID is revoked. Vault IDs are structured in such
a way to make revocation of prefixes useful.
General Options:
-address=TODO The address of the Vault server.
-ca-cert=path Path to a PEM encoded CA cert file to use to
verify the Vault server SSL certificate.
-ca-path=path Path to a directory of PEM encoded CA cert files
to verify the Vault server SSL certificate. If both
-ca-cert and -ca-path are specified, -ca-path is used.
-insecure Do not verify TLS certificate. This is highly
not recommended. This is especially not recommended
for unsealing a vault.
Revoke Options:
-prefix=true Revoke all secrets with the matching prefix. This
defaults to false: an exact revocation.
`
return strings.TrimSpace(helpText)
}

45
command/revoke_test.go Normal file
View File

@ -0,0 +1,45 @@
package command
import (
"testing"
"github.com/hashicorp/vault/http"
"github.com/hashicorp/vault/vault"
"github.com/mitchellh/cli"
)
func TestRevoke(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := http.TestServer(t, core)
defer ln.Close()
ui := new(cli.MockUi)
c := &RevokeCommand{
Meta: Meta{
ClientToken: token,
Ui: ui,
},
}
client := testClient(t, addr, token)
err := client.Logical().Write("secret/foo", map[string]interface{}{
"key": "value",
"lease": "1m",
})
if err != nil {
t.Fatalf("err: %s", err)
}
secret, err := client.Logical().Read("secret/foo")
if err != nil {
t.Fatalf("err: %s", err)
}
args := []string{
"-address", addr,
secret.VaultId,
}
if code := c.Run(args); code != 0 {
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
}
}

View File

@ -42,6 +42,12 @@ func init() {
}, nil
},
"revoke": func() (cli.Command, error) {
return &command.RevokeCommand{
Meta: meta,
}, nil
},
"seal": func() (cli.Command, error) {
return &command.SealCommand{
Meta: meta,

View File

@ -20,6 +20,7 @@ func Handler(core *vault.Core) http.Handler {
mux.Handle("/v1/sys/seal", handleSysSeal(core))
mux.Handle("/v1/sys/unseal", handleSysUnseal(core))
mux.Handle("/v1/sys/mounts/", handleSysMounts(core))
mux.Handle("/v1/sys/revoke/", handleSysRevoke(core))
mux.Handle("/v1/", handleLogical(core))
return mux
}

41
http/sys_lease.go Normal file
View File

@ -0,0 +1,41 @@
package http
import (
"net/http"
"strings"
"github.com/hashicorp/vault/logical"
"github.com/hashicorp/vault/vault"
)
func handleSysRevoke(core *vault.Core) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method != "PUT" {
respondError(w, http.StatusMethodNotAllowed, nil)
return
}
// Determine the path...
prefix := "/v1/sys/revoke/"
if !strings.HasPrefix(r.URL.Path, prefix) {
respondError(w, http.StatusNotFound, nil)
return
}
path := r.URL.Path[len(prefix):]
if path == "" {
respondError(w, http.StatusNotFound, nil)
return
}
_, err := core.HandleRequest(requestAuth(r, &logical.Request{
Operation: logical.WriteOperation,
Path: "sys/revoke/" + path,
}))
if err != nil {
respondError(w, http.StatusBadRequest, err)
return
}
respondOk(w, nil)
})
}

17
http/sys_lease_test.go Normal file
View File

@ -0,0 +1,17 @@
package http
import (
"testing"
"github.com/hashicorp/vault/vault"
)
func TestSysRevoke(t *testing.T) {
core, _, token := vault.TestCoreUnsealed(t)
ln, addr := TestServer(t, core)
defer ln.Close()
TestServerAuth(t, addr, token)
resp := testHttpPut(t, addr+"/v1/sys/revoke/secret/foo/1234", nil)
testResponseStatus(t, resp, 204)
}