Skip to content

Commit

Permalink
CLI: add 'ais tls validate-certificates' command
Browse files Browse the repository at this point in the history
* also, add load-cert case for secondary proxies (fix)

Signed-off-by: Alex Aizman <[email protected]>
  • Loading branch information
alex-aizman committed Sep 19, 2024
1 parent 508b8ad commit 0a2f25c
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 18 deletions.
15 changes: 8 additions & 7 deletions ais/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -2677,13 +2677,12 @@ func (p *proxy) httpdaeput(w http.ResponseWriter, r *http.Request) {
if err := p.checkAccess(w, r, nil, apc.AceAdmin); err != nil {
return
}
// urlpath-based actions
// urlpath items
if len(apiItems) > 0 {
action := apiItems[0]
p.daePathAction(w, r, action)
p.daeputItems(w, r, apiItems)
return
}
// message-based actions
// action-message
query := r.URL.Query()
msg, err := p.readActionMsg(w, r)
if err != nil {
Expand Down Expand Up @@ -2748,8 +2747,8 @@ func (p *proxy) httpdaeput(w http.ResponseWriter, r *http.Request) {
}
}

func (p *proxy) daePathAction(w http.ResponseWriter, r *http.Request, action string) {
switch action {
func (p *proxy) daeputItems(w http.ResponseWriter, r *http.Request, apiItems []string) {
switch apiItems[0] {
case apc.Proxy:
p.daeSetPrimary(w, r)
case apc.SyncSmap:
Expand All @@ -2768,8 +2767,10 @@ func (p *proxy) daePathAction(w http.ResponseWriter, r *http.Request, action str
nlog.Infof("%s: %s %s done", p, apc.SyncSmap, newsmap)
case apc.ActSetConfig: // set-config #1 - via query parameters and "?n1=v1&n2=v2..."
p.setDaemonConfigQuery(w, r)
case apc.LoadX509:
p.daeLoadX509(w, r)
default:
p.writeErrAct(w, r, action)
p.writeErrAct(w, r, apiItems[0])
}
}

Expand Down
2 changes: 1 addition & 1 deletion cmd/cli/cli/advanced_hdlr.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ func removeNodeFromSmap(c *cli.Context) error {
if node.IsProxy() {
smap, err := getClusterMap(c)
if err != nil {
return err // cannot happen
return err // (unlikely)
}
if smap.IsPrimary(node) {
return fmt.Errorf("%s is primary (cannot remove the primary node)", sname)
Expand Down
3 changes: 2 additions & 1 deletion cmd/cli/cli/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@ const (
cmdBackendEnable = "enable-backend"
cmdBackendDisable = "disable-backend"

cmdLoadTLS = "load-certificate"
cmdLoadTLS = "load-certificate"
cmdValidateTLS = "validate-certificates"

// Node subcommands
cmdJoin = "join"
Expand Down
91 changes: 84 additions & 7 deletions cmd/cli/cli/x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,11 @@
package cli

import (
"fmt"

"github.com/NVIDIA/aistore/api"
"github.com/NVIDIA/aistore/cmd/cli/teb"
"github.com/NVIDIA/aistore/cmn/cos"
"github.com/NVIDIA/aistore/core/meta"
"github.com/urfave/cli"
)
Expand All @@ -28,6 +31,12 @@ var (
Action: loadCertHandler,
BashComplete: suggestAllNodes,
}
validateTLS = cli.Command{
Name: cmdValidateTLS,
Usage: "check that all TLS certficates are identical",
ArgsUsage: optionalNodeIDArgument,
Action: validateCertHandler,
}

// top-level
tlsCmd = cli.Command{
Expand All @@ -36,17 +45,18 @@ var (
Subcommands: []cli.Command{
makeAlias(showTLS, "", true, commandShow),
loadTLS,
validateTLS,
},
}
)

func showCertHandler(c *cli.Context) error {
var (
sid []string
node, sname, er = arg0Node(c)
sid []string
node, sname, e = arg0Node(c)
)
if er != nil {
return er
if e != nil {
return e
}
if node != nil {
sid = append(sid, node.ID())
Expand Down Expand Up @@ -75,15 +85,82 @@ func showCertHandler(c *cli.Context) error {
}

func loadCertHandler(c *cli.Context) (err error) {
s := "Done."
s := "Done: "
if c.NArg() == 0 {
err = api.LoadX509Cert(apiBP, c.Args()...)
s = "Done: all nodes."
s += "all nodes."
} else {
err = api.LoadX509Cert(apiBP, meta.N2ID(c.Args().Get(0)))
node, sname, e := arg0Node(c)
if e != nil {
return e
}
s += sname
err = api.LoadX509Cert(apiBP, node.ID())
}
if err == nil {
actionDone(c, s)
}
return err
}

// TODO: check expiration times as well
func validateCertHandler(c *cli.Context) error {
smap, err := getClusterMap(c)
if err != nil {
return err
}

var (
sid = make([]string, 1)
info, i cos.StrKVs
cnt int
)
sid[0] = smap.Primary.ID()
info, err = api.GetX509Info(apiBP, sid...)
if err != nil {
return V(err)
}
for pid, snode := range smap.Pmap {
if pid == smap.Primary.ID() {
continue
}
sid[0] = pid
i, err = api.GetX509Info(apiBP, sid...)
if err != nil {
actionWarn(c, fmt.Sprintf("%s returned error: %v", snode, V(err)))
continue
}
cnt += compareCerts(c, info, i, smap.Primary, snode)
}
for tid, snode := range smap.Tmap {
sid[0] = tid
i, err = api.GetX509Info(apiBP, sid...)
if err != nil {
actionWarn(c, fmt.Sprintf("%s returned error: %v", snode, V(err)))
continue
}
cnt += compareCerts(c, info, i, smap.Primary, snode)
}

if cnt == 0 {
actionDone(c, "Done: all TLS certificates are identical")
} else if cnt > 1 {
warn := fmt.Sprintf("\n==== %d differences overall ====", cnt)
actionWarn(c, warn)
}
return nil
}

func compareCerts(c *cli.Context, info, i cos.StrKVs, pnode, snode *meta.Snode) int {
for k, v1 := range info {
v2, ok := i[k]
if ok && v1 == v2 {
continue
}
warn := fmt.Sprintf("primary %s and node %s have different TLS certificates: (%s, %q) != (%s, %q)",
pnode, snode, k, v1, k, v2)
actionWarn(c, warn)
return 1
}
return 0
}
5 changes: 3 additions & 2 deletions docs/cli/x509.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,9 @@ USAGE:
ais tls command [command options] [arguments...]

COMMANDS:
show show TLS certificate's version, issuer's common name, and from/to validity bounds
load-certificate load TLS certificate
show show TLS certificate's version, issuer's common name, and from/to validity bounds
load-certificate load TLS certificate
validate-certificates check that all TLS certficates are identical

OPTIONS:
--help, -h show help
Expand Down

0 comments on commit 0a2f25c

Please sign in to comment.