mirror of
https://github.com/gravitational/teleport.git
synced 2026-10-12 02:15:01 +00:00
Match tctl auth export --type in create-override-csr (#66589)
This commit is contained in:
@@ -17,3 +17,5 @@
|
||||
package subca
|
||||
|
||||
var FindMinHashes = findMinHashes
|
||||
|
||||
var MakeCATypeNames = makeCATypeNames
|
||||
|
||||
@@ -23,6 +23,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/alecthomas/kingpin/v2"
|
||||
@@ -36,6 +37,52 @@ import (
|
||||
tctlcfg "github.com/gravitational/teleport/tool/tctl/common/config"
|
||||
)
|
||||
|
||||
// cliCATypes maps subca.SupportedCATypes() into their CLI-friendly counterparts
|
||||
// (typically by replacing "_" with "-").
|
||||
//
|
||||
// Matches "tctl auth export --types" whenever appropriate.
|
||||
var cliCATypes = makeCATypeNames()
|
||||
|
||||
type caTypeNames struct {
|
||||
// Names holds all CA type names for --help.
|
||||
Names []string
|
||||
// NameToCAType maps a "display" CA type to an actual CA type
|
||||
// (eg, "db-client" -> "db_client").
|
||||
// The map is sparse, ie, CA types that need no mapping aren't present in it.
|
||||
NameToCAType map[string]string
|
||||
}
|
||||
|
||||
func makeCATypeNames() caTypeNames {
|
||||
nameToCAType := make(map[string]string)
|
||||
var names []string
|
||||
|
||||
for _, caType := range subca.SupportedCATypes() {
|
||||
name := strings.ReplaceAll(caType, "_", "-")
|
||||
if name != caType {
|
||||
nameToCAType[name] = caType
|
||||
}
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
slices.Sort(names)
|
||||
|
||||
return caTypeNames{
|
||||
Names: names,
|
||||
NameToCAType: nameToCAType,
|
||||
}
|
||||
}
|
||||
|
||||
// Convert converts a CLI CA type into a subca supported CA type.
|
||||
// The conversion is pass-through by design: it converts known types and lets
|
||||
// others pass. The backend is the source of truth for which types are valid or
|
||||
// not.
|
||||
func (n caTypeNames) Convert(caType string) string {
|
||||
if val, ok := n.NameToCAType[caType]; ok {
|
||||
return val
|
||||
}
|
||||
return caType
|
||||
}
|
||||
|
||||
// SubCAClientSource is the subset of *authclient.Client used by Command.
|
||||
type SubCAClientSource interface {
|
||||
SubCAClient() subcav1.SubCAServiceClient
|
||||
@@ -89,12 +136,12 @@ func (c *Command) Initialize(
|
||||
// Don't over-validate CA types on the client. That's the server's responsibility.
|
||||
createCSRHelp := fmt.Sprintf(
|
||||
"CA type (%s)",
|
||||
strings.Join(subca.SupportedCATypes(), ", "),
|
||||
strings.Join(cliCATypes.Names, ", "),
|
||||
)
|
||||
c.createOverrideCSR.
|
||||
Flag("type", createCSRHelp). // --type mimics other "tctl auth" commands
|
||||
Required().
|
||||
StringVar(&c.createOverrideCSR.caType)
|
||||
StringVar(&c.createOverrideCSR.cliCAType)
|
||||
c.createOverrideCSR.
|
||||
Flag("out", "If set writes CSRs to files using --out as the path prefix").
|
||||
StringVar(&c.createOverrideCSR.out)
|
||||
@@ -153,7 +200,7 @@ type subCommand interface {
|
||||
type createOverrideCSRCommand struct {
|
||||
*kingpin.CmdClause
|
||||
|
||||
caType string
|
||||
cliCAType string
|
||||
out string // Output path prefix.
|
||||
publicKey string
|
||||
subject string
|
||||
@@ -165,9 +212,10 @@ func (c *createOverrideCSRCommand) Run(
|
||||
s *commandState,
|
||||
) error {
|
||||
// Defensive, shouldn't happen.
|
||||
if c.caType == "" {
|
||||
if c.cliCAType == "" {
|
||||
return trace.BadParameter("type required")
|
||||
}
|
||||
caType := cliCATypes.Convert(c.cliCAType)
|
||||
|
||||
var pubKey *subcav1.PublicKeyHash
|
||||
if c.publicKey != "" {
|
||||
@@ -198,7 +246,7 @@ func (c *createOverrideCSRCommand) Run(
|
||||
|
||||
// Request CSRs.
|
||||
resp, err := subCA.CreateCSR(ctx, &subcav1.CreateCSRRequest{
|
||||
CaType: c.caType,
|
||||
CaType: caType,
|
||||
PublicKeyHash: pubKey,
|
||||
CustomSubject: customSubject,
|
||||
})
|
||||
@@ -237,7 +285,7 @@ func (c *createOverrideCSRCommand) Run(
|
||||
|
||||
// Write output files.
|
||||
for i, csr := range resp.Csrs {
|
||||
name := c.out + c.caType + "-" + minHashes[i] + "-csr.pem"
|
||||
name := c.out + caType + "-" + minHashes[i] + "-csr.pem"
|
||||
if err := os.WriteFile(name, []byte(csr.Pem), 0644); err != nil {
|
||||
return trace.Wrap(err)
|
||||
}
|
||||
|
||||
@@ -58,6 +58,17 @@ func TestCommand_CreateOverrideCSR(t *testing.T) {
|
||||
wantStdout string
|
||||
wantFiles map[string]string // filepath to content
|
||||
}{
|
||||
{
|
||||
name: "ok: db-client",
|
||||
flags: []string{
|
||||
"--type", "db-client",
|
||||
},
|
||||
csrPEMs: []string{dbClientCSRPEM},
|
||||
wantReq: &subcav1.CreateCSRRequest{
|
||||
CaType: string(types.DatabaseClientCA),
|
||||
},
|
||||
wantStdout: dbClientCSRPEM + "\n",
|
||||
},
|
||||
{
|
||||
name: "ok: db_client",
|
||||
flags: []string{
|
||||
@@ -259,6 +270,19 @@ func TestFindMinHashes(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMakeCATypeNames(t *testing.T) {
|
||||
got := subca.MakeCATypeNames()
|
||||
want := []string{
|
||||
"db-client",
|
||||
"windows",
|
||||
}
|
||||
assert.Equal(t, want, got.Names, ""+
|
||||
"CAType names mismatch. "+
|
||||
"This is likely because a new entry was added to subca.SupportedCATypes(). "+
|
||||
"Verify the newly added name and, if working as intended, add it to want list above.",
|
||||
)
|
||||
}
|
||||
|
||||
// CSR PEMs for testing.
|
||||
// The simplest way to get these is to run the "tctl auth create-override-csr"
|
||||
// command.
|
||||
|
||||
Reference in New Issue
Block a user