consul/command/acl/bindingrule/create/bindingrule_create.go

198 lines
4.4 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package bindingrulecreate
import (
"flag"
"fmt"
"strings"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/command/acl"
"github.com/hashicorp/consul/command/acl/bindingrule"
"github.com/hashicorp/consul/command/flags"
"github.com/mitchellh/cli"
)
func New(ui cli.Ui) *cmd {
c := &cmd{UI: ui}
c.init()
return c
}
type cmd struct {
UI cli.Ui
flags *flag.FlagSet
http *flags.HTTPFlags
help string
authMethodName string
description string
selector string
bindType string
bindName string
bindVars map[string]string
showMeta bool
format string
}
func (c *cmd) init() {
c.flags = flag.NewFlagSet("", flag.ContinueOnError)
c.flags.BoolVar(
&c.showMeta,
"meta",
false,
"Indicates that binding rule metadata such "+
"as the raft indices should be shown for each entry.",
)
c.flags.StringVar(
&c.authMethodName,
"method",
"",
"The auth method's name for which this binding rule applies. "+
"This flag is required.",
)
c.flags.StringVar(
&c.description,
"description",
"",
"A description of the binding rule.",
)
c.flags.StringVar(
&c.selector,
"selector",
"",
"Selector is an expression that matches against verified identity "+
"attributes returned from the auth method during login.",
)
c.flags.StringVar(
&c.bindType,
"bind-type",
string(api.BindingRuleBindTypeService),
"Type of binding to perform (\"service\", \"role\", \"node\" or \"templated-policy\").",
)
c.flags.Var(
(*flags.FlagMapValue)(&c.bindVars),
"bind-vars",
"Templated policy variables. Can only be used when -bind-type is templated-policy."+
" May be specified multiple times with different variables. Can use ${var} interpolation."+
" Format is VariableName=Value",
)
c.flags.StringVar(
&c.bindName,
"bind-name",
"",
"Name to bind on match. Can use ${var} interpolation. "+
"This flag is required.",
)
c.flags.StringVar(
&c.format,
"format",
bindingrule.PrettyFormat,
fmt.Sprintf("Output format {%s}", strings.Join(bindingrule.GetSupportedFormats(), "|")),
)
c.http = &flags.HTTPFlags{}
flags.Merge(c.flags, c.http.ClientFlags())
flags.Merge(c.flags, c.http.ServerFlags())
flags.Merge(c.flags, c.http.MultiTenancyFlags())
c.help = flags.Usage(help, c.flags)
}
func (c *cmd) Run(args []string) int {
if err := c.flags.Parse(args); err != nil {
return 1
}
if c.authMethodName == "" {
c.UI.Error("Missing required '-method' flag")
c.UI.Error(c.Help())
return 1
} else if c.bindType == "" {
c.UI.Error("Missing required '-bind-type' flag")
c.UI.Error(c.Help())
return 1
} else if c.bindName == "" {
c.UI.Error("Missing required '-bind-name' flag")
c.UI.Error(c.Help())
return 1
}
if api.BindingRuleBindType(c.bindType) != api.BindingRuleBindTypeTemplatedPolicy && len(c.bindVars) > 0 {
c.UI.Error("Cannot specify -bind-vars when -bind-type is not templated-policy")
c.UI.Error(c.Help())
return 1
}
processBindVars, err := acl.ExtractBindVars(c.bindVars)
if err != nil {
c.UI.Error("Failed to decode '-bind-vars'")
c.UI.Error(c.Help())
return 1
}
newRule := &api.ACLBindingRule{
Description: c.description,
AuthMethod: c.authMethodName,
BindType: api.BindingRuleBindType(c.bindType),
BindName: c.bindName,
BindVars: processBindVars,
Selector: c.selector,
}
client, err := c.http.APIClient()
if err != nil {
c.UI.Error(fmt.Sprintf("Error connecting to Consul agent: %s", err))
return 1
}
rule, _, err := client.ACL().BindingRuleCreate(newRule, nil)
if err != nil {
c.UI.Error(fmt.Sprintf("Failed to create new binding rule: %v", err))
return 1
}
formatter, err := bindingrule.NewFormatter(c.format, c.showMeta)
if err != nil {
c.UI.Error(err.Error())
return 1
}
out, err := formatter.FormatBindingRule(rule)
if err != nil {
c.UI.Error(err.Error())
return 1
}
if out != "" {
c.UI.Info(out)
}
return 0
}
func (c *cmd) Synopsis() string {
return synopsis
}
func (c *cmd) Help() string {
return flags.Usage(c.help, nil)
}
const synopsis = "Create an ACL binding rule"
const help = `
Usage: consul acl binding-rule create [options]
Create a new binding rule:
$ consul acl binding-rule create \
-method=minikube \
-bind-type=service \
-bind-name='k8s-${serviceaccount.name}' \
-selector='serviceaccount.namespace==default and serviceaccount.name==web'
`